|
@@ -17,9 +17,9 @@
|
|
|
namespace reflection {
|
|
namespace reflection {
|
|
|
class Object {
|
|
class Object {
|
|
|
public:
|
|
public:
|
|
|
- template <typename T> Object(T const &data, std::string name = "this");
|
|
|
|
|
- template <typename T> Object(T &data, std::string name = "this");
|
|
|
|
|
- template <typename T> Object(T &&data, std::string name = "this");
|
|
|
|
|
|
|
+ template <typename T> Object(T const & data, std::string name = "this");
|
|
|
|
|
+ template <typename T> Object(T & data, std::string name = "this");
|
|
|
|
|
+ template <typename T> Object(T && data, std::string name = "this");
|
|
|
template <typename T> Object(Proxy<T> data, std::string name = "this");
|
|
template <typename T> Object(Proxy<T> data, std::string name = "this");
|
|
|
|
|
|
|
|
Object own() const { return clone_(*this); }
|
|
Object own() const { return clone_(*this); }
|
|
@@ -28,13 +28,15 @@ public:
|
|
|
return std::string_view(name_).substr(name_.rfind('.') + 1);
|
|
return std::string_view(name_).substr(name_.rfind('.') + 1);
|
|
|
}
|
|
}
|
|
|
std::string_view path() const { return name_; }
|
|
std::string_view path() const { return name_; }
|
|
|
- char const *type() const { return type_.name(); }
|
|
|
|
|
-
|
|
|
|
|
|
|
+ char const * type() const { return type_.name(); }
|
|
|
|
|
+
|
|
|
template <typename T> bool is_a() const { return type_ == typeid(T); }
|
|
template <typename T> bool is_a() const { return type_ == typeid(T); }
|
|
|
|
|
|
|
|
template <typename T> operator T &() const & { return cast<T &>(); }
|
|
template <typename T> operator T &() const & { return cast<T &>(); }
|
|
|
- template <typename T> operator T const &() const & { return cast<T const &>(); }
|
|
|
|
|
- template <typename T> operator T () && {
|
|
|
|
|
|
|
+ template <typename T> operator T const &() const & {
|
|
|
|
|
+ return cast<T const &>();
|
|
|
|
|
+ }
|
|
|
|
|
+ template <typename T> operator T() && {
|
|
|
return is_a<T>() ? std::move(cast<T &>()) : cast<T const &>();
|
|
return is_a<T>() ? std::move(cast<T &>()) : cast<T const &>();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -42,13 +44,13 @@ public:
|
|
|
Object get(std::string_view id) const & { return (this->*get_)(id); }
|
|
Object get(std::string_view id) const & { return (this->*get_)(id); }
|
|
|
Object get(std::string_view id) && { return (this->*get_)(id).own(); }
|
|
Object get(std::string_view id) && { return (this->*get_)(id).own(); }
|
|
|
|
|
|
|
|
- template <typename C, typename =
|
|
|
|
|
- std::enable_if_t<std::is_constructible_v<std::string_view,
|
|
|
|
|
- decltype(*std::begin(std::declval<C>()))>>>
|
|
|
|
|
- Object get(C const &container) const {
|
|
|
|
|
|
|
+ template <typename C,
|
|
|
|
|
+ typename = std::enable_if_t<std::is_constructible_v<
|
|
|
|
|
+ std::string_view, decltype(*std::begin(std::declval<C>()))>>>
|
|
|
|
|
+ Object get(C const & container) const {
|
|
|
return get(*this, std::begin(container), std::end(container));
|
|
return get(*this, std::begin(container), std::end(container));
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
private:
|
|
private:
|
|
|
template <typename It> static Object get(Object o, It it, It const end) {
|
|
template <typename It> static Object get(Object o, It it, It const end) {
|
|
|
for (; it != end; ++it) {
|
|
for (; it != end; ++it) {
|
|
@@ -56,7 +58,7 @@ private:
|
|
|
}
|
|
}
|
|
|
return o;
|
|
return o;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
template <typename T> T cast() const {
|
|
template <typename T> T cast() const {
|
|
|
// Why can we decay this away?
|
|
// Why can we decay this away?
|
|
|
using V = std::remove_const_t<std::remove_reference_t<T>>;
|
|
using V = std::remove_const_t<std::remove_reference_t<T>>;
|
|
@@ -65,27 +67,26 @@ private:
|
|
|
// 2) We guard against using mutable-reference on immutable Object here
|
|
// 2) We guard against using mutable-reference on immutable Object here
|
|
|
if (std::is_same_v<T, V &> && const_) { throw std::bad_cast(); }
|
|
if (std::is_same_v<T, V &> && const_) { throw std::bad_cast(); }
|
|
|
// 3) Proxy always contains mutable data
|
|
// 3) Proxy always contains mutable data
|
|
|
- if (proxy_) {
|
|
|
|
|
- return T(*std::static_pointer_cast<Proxy<V>>(data_));
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (proxy_) { return T(*std::static_pointer_cast<Proxy<V>>(data_)); }
|
|
|
// 4) The const will be re-added by type coercion
|
|
// 4) The const will be re-added by type coercion
|
|
|
return *std::static_pointer_cast<V>(data_);
|
|
return *std::static_pointer_cast<V>(data_);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
template <typename T> Object getter(std::string_view id) const;
|
|
template <typename T> Object getter(std::string_view id) const;
|
|
|
template <typename T> Object accessor(std::string_view id) const;
|
|
template <typename T> Object accessor(std::string_view id) const;
|
|
|
- template <typename T> static Object deep(Object const &obj) {
|
|
|
|
|
|
|
+ template <typename T> static Object deep(Object const & obj) {
|
|
|
return Object(obj.cast<T>(), obj.name_);
|
|
return Object(obj.cast<T>(), obj.name_);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
private:
|
|
|
- std::type_index type_; //
|
|
|
|
|
- std::string name_; // The property name as a dot-separated path
|
|
|
|
|
- bool proxy_{false}; // Are we using a proxy class to store non-trivial setter behavior
|
|
|
|
|
|
|
+ std::type_index type_; //
|
|
|
|
|
+ std::string name_; // The property name as a dot-separated path
|
|
|
|
|
+ bool proxy_{
|
|
|
|
|
+ false}; // Are we using a proxy class to store non-trivial setter behavior
|
|
|
bool const_; // Is the object immutable (const-ref or rvalue)
|
|
bool const_; // Is the object immutable (const-ref or rvalue)
|
|
|
std::shared_ptr<void> data_;
|
|
std::shared_ptr<void> data_;
|
|
|
Object (Object::*get_)(std::string_view) const;
|
|
Object (Object::*get_)(std::string_view) const;
|
|
|
- Object (*clone_)(Object const &) = [](Object const &obj) { return obj; };
|
|
|
|
|
|
|
+ Object (*clone_)(Object const &) = [](Object const & obj) { return obj; };
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -93,27 +94,34 @@ private:
|
|
|
|
|
|
|
|
namespace reflection {
|
|
namespace reflection {
|
|
|
template <typename T> Object Object::getter(std::string_view id) const {
|
|
template <typename T> Object Object::getter(std::string_view id) const {
|
|
|
- return Reflection<T>::getter(id)(cast<T const &>(), name_ + "." + std::string(id));
|
|
|
|
|
|
|
+ return Reflection<T>::getter(id)(cast<T const &>(),
|
|
|
|
|
+ name_ + "." + std::string(id));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
template <typename T> Object Object::accessor(std::string_view id) const {
|
|
template <typename T> Object Object::accessor(std::string_view id) const {
|
|
|
- return Reflection<T>::accessor(id)(cast<T &>(), name_ + "." + std::string(id));
|
|
|
|
|
|
|
+ return Reflection<T>::accessor(id)(cast<T &>(),
|
|
|
|
|
+ name_ + "." + std::string(id));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-template <typename T> Object::Object(T const &data, std::string name)
|
|
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+Object::Object(T const & data, std::string name)
|
|
|
: type_(typeid(T)), name_(std::move(name)), const_(true),
|
|
: type_(typeid(T)), name_(std::move(name)), const_(true),
|
|
|
- data_(const_cast<T *>(&data), [](auto*){}), get_(&Object::getter<T>) {}
|
|
|
|
|
|
|
+ data_(const_cast<T *>(&data), [](auto *) {}), get_(&Object::getter<T>) {}
|
|
|
|
|
|
|
|
-template <typename T> Object::Object(T &data, std::string name)
|
|
|
|
|
- : type_(typeid(T)), name_(std::move(name)), const_(false), data_(&data, [](auto*){}),
|
|
|
|
|
- get_(&Object::accessor<T>) {}
|
|
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+Object::Object(T & data, std::string name)
|
|
|
|
|
+ : type_(typeid(T)), name_(std::move(name)), const_(false),
|
|
|
|
|
+ data_(&data, [](auto *) {}), get_(&Object::accessor<T>) {}
|
|
|
|
|
|
|
|
-template <typename T> Object::Object(T &&data, std::string name)
|
|
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+Object::Object(T && data, std::string name)
|
|
|
: type_(typeid(T)), name_(std::move(name)), const_(true),
|
|
: type_(typeid(T)), name_(std::move(name)), const_(true),
|
|
|
data_(std::make_shared<T>(std::move(data))), get_(&Object::getter<T>),
|
|
data_(std::make_shared<T>(std::move(data))), get_(&Object::getter<T>),
|
|
|
clone_(&Object::deep<T>) {}
|
|
clone_(&Object::deep<T>) {}
|
|
|
|
|
|
|
|
-template <typename T> Object::Object(Proxy<T> data, std::string name)
|
|
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+Object::Object(Proxy<T> data, std::string name)
|
|
|
: type_(typeid(T)), name_(std::move(name)), proxy_(true), const_(false),
|
|
: type_(typeid(T)), name_(std::move(name)), proxy_(true), const_(false),
|
|
|
- data_(std::make_shared<Proxy<T>>(std::move(data))), get_(&Object::getter<T>) {}
|
|
|
|
|
|
|
+ data_(std::make_shared<Proxy<T>>(std::move(data))),
|
|
|
|
|
+ get_(&Object::getter<T>) {}
|
|
|
}
|
|
}
|