Quellcode durchsuchen

feat: add Scope/ContextScope to better implement Property concept
feat: add Name property for types to represent better naming sense

Sam Jaffe vor 2 Jahren
Ursprung
Commit
bb236c4334

+ 3 - 6
include/reflection/context.h

@@ -13,6 +13,7 @@
 
 #include "reflection/forward.h"
 #include "reflection/object.h"
+#include "reflection/scope.h"
 
 namespace reflection {
 class Context {
@@ -29,12 +30,8 @@ public:
   Object const & get(std::string_view id) const { return data_.at(id); }
   bool has(std::string_view id) const { return data_.count(id); }
 
-  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 Object::get(get(*std::begin(container)), ++std::begin(container),
-                       std::end(container));
+  Object get(ContextScope const &scope) const {
+    return get(scope.context()).get(static_cast<Scope const &>(scope));
   }
 
 private:

+ 18 - 2
include/reflection/forward.h

@@ -17,7 +17,9 @@
 
 namespace reflection {
 class Context;
+class ContextScope;
 class Object;
+class Scope;
 template <typename Obj, typename = void> class Reflection;
 template <typename T> class Proxy;
 template <typename T> class TypeCast;
@@ -28,18 +30,28 @@ template <typename Obj>
 using Accessor = std::function<Object(Obj &, std::string)>;
 template <typename Obj>
 using Getter = std::function<Object(Obj const &, std::string)>;
+
+template <typename T> constexpr std::string_view Name = "";
 }
 
 #define reflect(object) reflection::Object(object, #object)
 
-#define INSTANTIATE_REFLECTION(T)                                              \
+#define INSTANTIATE_REFLECTION_IMPL(T, name, ...)                              \
+  template <> constexpr std::string_view Name<T> = name;                       \
   template Cache<Accessor<T>> Reflection<T>::members_;                         \
   template Cache<Getter<T>> Reflection<T>::const_members_
 
-#define INSTANTIATE_REFLECTION_TYPECAST(T)                                     \
+#define INSTANTIATE_REFLECTION(T, ...)                                         \
+  INSTANTIATE_REFLECTION_IMPL(T, ##__VA_ARGS__, #T)
+
+#define INSTANTIATE_REFLECTION_TYPECAST_IMPL(T, name, ...)                     \
+  template <> constexpr std::string_view Name<T> = name;                       \
   template TypeMap<std::function<T(Object const &)>> TypeCast<T>::get_;        \
   template TypeMap<std::function<void(Object &, T const &)>> TypeCast<T>::set_
 
+#define INSTANTIATE_REFLECTION_TYPECAST(T, ...)                                \
+  INSTANTIATE_REFLECTION_TYPECAST_IMPL(T, ##__VA_ARGS__, #T)
+
 #if !defined(CONCAT)
 #define CONCAT_IMPL(A, B) A##B
 #define CONCAT(A, B) CONCAT_IMPL(A, B)
@@ -50,3 +62,7 @@ using Getter = std::function<Object(Obj const &, std::string)>;
 
 #define REFLECTION_TYPE_CAST(T)                                                \
   bool const CONCAT(type_cast_, __LINE__) = ::reflection::TypeCast<T>()
+
+#define IS_SCOPE_CONTAINER(C) \
+    std::is_constructible_v<std::string_view, \
+                            decltype(*std::begin(std::declval<C>()))>

+ 16 - 8
include/reflection/object.h

@@ -13,6 +13,7 @@
 #include <utility>
 
 #include "reflection/forward.h"
+#include "reflection/scope.h"
 
 namespace reflection {
 class Object {
@@ -31,6 +32,9 @@ public:
   }
   std::string_view path() const { return name_; }
   std::type_index type() const { return type_; }
+  std::string_view type_name() const {
+    return type_name_.empty() ? type_.name() : type_name_;
+  }
 
   template <typename T> bool is_a() const { return type_ == typeid(T); }
 
@@ -47,10 +51,13 @@ public:
   Object get(std::string_view id) & { 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(Scope const & scope) const {
+    if (type_name() != scope.type_name()) { throw std::bad_cast(); }
+    return get(*this, scope.begin(), scope.end());
+  }
 
-  template <typename C,
-            typename = std::enable_if_t<std::is_constructible_v<
-                std::string_view, decltype(*std::begin(std::declval<C>()))>>>
+  template <typename C, typename = std::enable_if_t<IS_SCOPE_CONTAINER(C)>>
   Object get(C const & container) const {
     return get(*this, std::begin(container), std::end(container));
   }
@@ -72,7 +79,8 @@ private:
   }
 
 private:
-  std::type_index type_; //
+  std::type_index type_;
+  std::string_view type_name_; // A more human-readable version of type_
   std::string name_;     // The property name as a dot-separated path
   // Are we using a proxy class to store non-trivial setter behavior
   bool proxy_{false};
@@ -99,23 +107,23 @@ template <typename T> Object Object::accessor(std::string_view id) const {
 
 template <typename T>
 Object::Object(T const & data, std::string name)
-    : type_(typeid(T)), name_(std::move(name)), const_(true),
+    : type_(typeid(T)), type_name_(Name<T>), name_(std::move(name)), const_(true),
       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),
+    : type_(typeid(T)), type_name_(Name<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_(true),
+    : type_(typeid(T)), type_name_(Name<T>), name_(std::move(name)), const_(true),
       data_(std::make_shared<T>(std::move(data))), get_(&Object::getter<T>),
       clone_(&Object::deep<T>) {}
 
 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)), type_name_(Name<T>), name_(std::move(name)), proxy_(true), const_(false),
       data_(std::make_shared<Proxy<T>>(std::move(data))),
       get_(&Object::getter<T>) {}
 

+ 47 - 0
include/reflection/scope.h

@@ -0,0 +1,47 @@
+//
+//  scope.h
+//  reflection
+//
+//  Created by Sam Jaffe on 2/20/23.
+//  Copyright © 2023 Sam Jaffe. All rights reserved.
+//
+
+#pragma once
+
+#include <string>
+#include <string_view>
+#include <vector>
+
+namespace reflection {
+class Scope {
+private:
+  std::string type_name_;
+  std::vector<std::string> path_;
+  
+public:
+  template <typename C, typename = std::enable_if_t<IS_SCOPE_CONTAINER(C)>>
+  Scope(std::string const & type_name, C const & path)
+      : type_name_(type_name), path_(path.begin(), path.end()) {}
+
+  Scope(std::string const & type_name, std::vector<std::string> const & path)
+      : type_name_(type_name), path_(path) {}
+  
+  std::string_view type_name() const { return type_name_; }
+  auto begin() const { return path_.begin(); }
+  auto end() const { return path_.end(); }
+};
+
+class ContextScope : public Scope {
+private:
+  std::string context_;
+  
+public:
+  template <typename C, typename = std::enable_if_t<IS_SCOPE_CONTAINER(C)>>
+  ContextScope(std::string const & context, std::string const & type_name,
+               C const & path)
+      : context_(context), Scope(type_name, path) {}
+
+  std::string_view context() const { return context_; }
+};
+
+}

+ 1 - 1
include/reflection/typecast.h

@@ -108,7 +108,7 @@ INSTANTIATE_REFLECTION_TYPECAST(uint64_t);
 INSTANTIATE_REFLECTION_TYPECAST(float);
 INSTANTIATE_REFLECTION_TYPECAST(double);
 INSTANTIATE_REFLECTION_TYPECAST(long double);
-INSTANTIATE_REFLECTION_TYPECAST(std::string);
+INSTANTIATE_REFLECTION_TYPECAST(std::string, "string");
 
 // Bind boolean types to all integer types
 REFLECTION_TYPE_CAST(bool)

+ 4 - 0
reflection.xcodeproj/project.pbxproj

@@ -10,6 +10,7 @@
 		CD2FF9072310BE8500ABA548 /* reflection_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CD5535251EEC689700108F81 /* reflection_test.cxx */; };
 		CD2FF9092310BE9200ABA548 /* GoogleMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD2FF8F32310BE6D00ABA548 /* GoogleMock.framework */; };
 		CD86DE33289FED0C00647685 /* context_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CD86DE32289FED0C00647685 /* context_test.cxx */; };
+		CDA8565129A3EFA6007493E8 /* scope.h in Headers */ = {isa = PBXBuildFile; fileRef = CDA8565029A3EFA6007493E8 /* scope.h */; };
 		CDA9561B28726949006ACEC2 /* reflection in Headers */ = {isa = PBXBuildFile; fileRef = CDA95611287266E5006ACEC2 /* reflection */; settings = {ATTRIBUTES = (Public, ); }; };
 		CDA9561E28731972006ACEC2 /* object_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDA9561D28731972006ACEC2 /* object_test.cxx */; };
 		CDA956D9287493FE006ACEC2 /* typecast_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDA956D8287493FE006ACEC2 /* typecast_test.cxx */; };
@@ -53,6 +54,7 @@
 		CD5535251EEC689700108F81 /* reflection_test.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = reflection_test.cxx; sourceTree = "<group>"; };
 		CD86DE2D289F55A100647685 /* context.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = context.h; sourceTree = "<group>"; };
 		CD86DE32289FED0C00647685 /* context_test.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = context_test.cxx; sourceTree = "<group>"; };
+		CDA8565029A3EFA6007493E8 /* scope.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = scope.h; sourceTree = "<group>"; };
 		CDA9560A28726665006ACEC2 /* reflection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = reflection.h; sourceTree = "<group>"; };
 		CDA9560F287266C9006ACEC2 /* forward.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = forward.h; sourceTree = "<group>"; };
 		CDA95610287266CE006ACEC2 /* object.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = object.h; sourceTree = "<group>"; };
@@ -160,6 +162,7 @@
 				CD86DE2D289F55A100647685 /* context.h */,
 				CDA9561228726723006ACEC2 /* proxy.h */,
 				CDA95610287266CE006ACEC2 /* object.h */,
+				CDA8565029A3EFA6007493E8 /* scope.h */,
 				CDA956D32873E1C7006ACEC2 /* typecast.h */,
 			);
 			path = reflection;
@@ -173,6 +176,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				CDA9561B28726949006ACEC2 /* reflection in Headers */,
+				CDA8565129A3EFA6007493E8 /* scope.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};