Procházet zdrojové kódy

meta: full support for constant values and enums

Michele Caini před 7 roky
rodič
revize
9c164e1cea
4 změnil soubory, kde provedl 116 přidání a 27 odebrání
  1. 0 1
      TODO
  2. 44 5
      docs/meta.md
  3. 40 21
      src/entt/meta/factory.hpp
  4. 32 0
      test/entt/meta/meta.cpp

+ 0 - 1
TODO

@@ -14,7 +14,6 @@
 * work stealing job system (see #100)
 * work stealing job system (see #100)
 * composable looper so as to pack erased systems, compose runners at different rates and run them at once in the loop
 * composable looper so as to pack erased systems, compose runners at different rates and run them at once in the loop
 * meta: sort of meta view based on meta stuff to iterate entities, void * and meta info objects
 * meta: sort of meta view based on meta stuff to iterate entities, void * and meta info objects
-* meta: move to head elements and forms LRU lists
 * registry::probe<component>(entt) (returns a component * if entt has the component, nullptr otherwise)
 * registry::probe<component>(entt) (returns a component * if entt has the component, nullptr otherwise)
 * hashed string: add implicit check on construction for uniqueness (optional)
 * hashed string: add implicit check on construction for uniqueness (optional)
 * add a note about multithreading support to the README file
 * add a note about multithreading support to the README file

+ 44 - 5
docs/meta.md

@@ -9,6 +9,7 @@
 * [Reflection in a nutshell](#reflection-in-a-nutshell)
 * [Reflection in a nutshell](#reflection-in-a-nutshell)
 * [Any as in any type](#any-as-in-any-type)
 * [Any as in any type](#any-as-in-any-type)
 * [Enjoy the runtime](#enjoy-the-runtime)
 * [Enjoy the runtime](#enjoy-the-runtime)
+* [Named constants and enums](#named-constants-and-enums)
 * [Properties and meta objects](#properties-and-meta-objects)
 * [Properties and meta objects](#properties-and-meta-objects)
 <!--
 <!--
 @endcond TURN_OFF_DOXYGEN
 @endcond TURN_OFF_DOXYGEN
@@ -69,10 +70,10 @@ It can be used to extend the reflected type and add the following:
   entt::reflect<my_type>("reflected").dtor<&destroy>();
   entt::reflect<my_type>("reflected").dtor<&destroy>();
   ```
   ```
 
 
-* _Data members_. Both real data members of the underlying type and static or
-  global variables can be attached to a meta type. From a client's point of
-  view, all the variables associated with the reflected type will appear as if
-  they were part of the type.<br/>
+* _Data members_. Both real data members of the underlying type and static and
+  global variables, as well as constants of any kind, can be attached to a meta
+  type. From a client's point of view, all the variables associated with the
+  reflected type will appear as if they were part of the type itself.<br/>
   Use the `data` member function for this purpose:
   Use the `data` member function for this purpose:
 
 
   ```cpp
   ```cpp
@@ -89,7 +90,7 @@ It can be used to extend the reflected type and add the following:
 * _Member functions_. Both real member functions of the underlying type and free
 * _Member functions_. Both real member functions of the underlying type and free
   functions can be attached to a meta type. From a client's point of view, all
   functions can be attached to a meta type. From a client's point of view, all
   the functions associated with the reflected type will appear as if they were
   the functions associated with the reflected type will appear as if they were
-  part of the type.<br/>
+  part of the type itself.<br/>
   Use the `func` member function for this purpose:
   Use the `func` member function for this purpose:
 
 
   ```cpp
   ```cpp
@@ -317,6 +318,44 @@ unfortunately beyond the scope of this document.<br/>
 I invite anyone interested in the subject to look at the code, experiment and
 I invite anyone interested in the subject to look at the code, experiment and
 read the official documentation to get the best out of this powerful tool.
 read the official documentation to get the best out of this powerful tool.
 
 
+# Named constants and enums
+
+A special mention should be made for constant values and enums. It wouldn't be
+necessary, but it will help distracted readers.
+
+As mentioned, the `data` member function can be used to reflect constants of any
+type among the other things.<br/>
+This allows users to create meta types for enums that will work exactly like any
+other meta type built from a class. Similarly, arithmetic types can be enriched
+with constants of special meaning where required.<br/>
+Personally, I find it very useful not to export what is the difference between
+enums and classes in C++ directly in the space of the reflected types.
+
+All the values thus exported will appear to users as if they were constant data
+members of the reflected types.
+
+Exporting constant values or elements from an enum is as simple as ever:
+
+```cpp
+entt::reflect<my_enum>()
+        .data<my_enum::a_value>("a_value")
+        .data<my_enum::another_value>("another_value");
+
+entt::reflect<int>().data<2048>("max_int");
+```
+
+It goes without saying that accessing them is trivial as well. It's a matter of
+doing the following, as with any other data member of a meta type:
+
+```cpp
+auto value = entt::resolve<my_enum>().data("a_value").get({}).cast<my_enum>();
+auto max = entt::resolve<int>().data("max_int").get({}).cast<int>();
+```
+
+As a side note, remember that all this happens behind the scenes without any
+allocation because of the small object optimization performed by the meta any
+class.
+
 # Properties and meta objects
 # Properties and meta objects
 
 
 Sometimes (ie when it comes to creating an editor) it might be useful to be able
 Sometimes (ie when it comes to creating an editor) it might be useful to be able

+ 40 - 21
src/entt/meta/factory.hpp

@@ -40,7 +40,7 @@ class meta_factory {
     actual_type();
     actual_type();
 
 
     template<auto Data>
     template<auto Data>
-    static std::enable_if_t<!std::is_member_object_pointer_v<decltype(Data)>, decltype(*Data)>
+    static std::enable_if_t<std::is_pointer_v<decltype(Data)>, decltype(*Data)>
     actual_type();
     actual_type();
 
 
     template<auto Data>
     template<auto Data>
@@ -284,10 +284,10 @@ public:
     /**
     /**
      * @brief Assigns a meta data to a meta type.
      * @brief Assigns a meta data to a meta type.
      *
      *
-     * Both data members and static or global variables can be assigned to a
-     * meta type.<br/>
+     * Both data members and static and global variables, as well as constants
+     * of any kind, can be assigned to a meta type.<br/>
      * From a client's point of view, all the variables associated with the
      * From a client's point of view, all the variables associated with the
-     * reflected object will appear as if they were part of the type.
+     * reflected object will appear as if they were part of the type itself.
      *
      *
      * @tparam Data The actual variable to attach to the meta type.
      * @tparam Data The actual variable to attach to the meta type.
      * @tparam Property Types of properties to assign to the meta data.
      * @tparam Property Types of properties to assign to the meta data.
@@ -299,22 +299,41 @@ public:
     meta_factory & data(const char *str, Property &&... property) ENTT_NOEXCEPT {
     meta_factory & data(const char *str, Property &&... property) ENTT_NOEXCEPT {
         auto * const type = internal::meta_info<Type>::resolve();
         auto * const type = internal::meta_info<Type>::resolve();
 
 
-        static internal::meta_data_node node{
-            hashed_string{str},
-            type->data,
-            type,
-            properties<std::integral_constant<decltype(Data), Data>>(std::forward<Property>(property)...),
-            std::is_const_v<data_type<Data>>,
-            !std::is_member_object_pointer_v<decltype(Data)>,
-            &internal::meta_info<data_type<Data>>::resolve,
-            &internal::setter<std::is_const_v<data_type<Data>>, Type, Data>,
-            &internal::getter<Type, Data>
-        };
-
-        assert(!duplicate(hashed_string{str}, node.next));
-        assert((!internal::meta_info<Type>::template data<Data>));
-        internal::meta_info<Type>::template data<Data> = &node;
-        type->data = &node;
+        if constexpr(std::is_same_v<Type, decltype(Data)>) {
+            static internal::meta_data_node node{
+                hashed_string{str},
+                type->data,
+                type,
+                properties<std::integral_constant<Type, Data>>(std::forward<Property>(property)...),
+                true,
+                true,
+                &internal::meta_info<Type>::resolve,
+                [](meta_handle, meta_any &) { return false; },
+                [](meta_handle) -> meta_any { return Data; }
+            };
+
+            assert(!duplicate(hashed_string{str}, node.next));
+            assert((!internal::meta_info<Type>::template data<Data>));
+            internal::meta_info<Type>::template data<Data> = &node;
+            type->data = &node;
+        } else {
+            static internal::meta_data_node node{
+                hashed_string{str},
+                type->data,
+                type,
+                properties<std::integral_constant<decltype(Data), Data>>(std::forward<Property>(property)...),
+                std::is_const_v<data_type<Data>>,
+                !std::is_member_object_pointer_v<decltype(Data)>,
+                &internal::meta_info<data_type<Data>>::resolve,
+                &internal::setter<std::is_const_v<data_type<Data>>, Type, Data>,
+                &internal::getter<Type, Data>
+            };
+
+            assert(!duplicate(hashed_string{str}, node.next));
+            assert((!internal::meta_info<Type>::template data<Data>));
+            internal::meta_info<Type>::template data<Data> = &node;
+            type->data = &node;
+        }
 
 
         return *this;
         return *this;
     }
     }
@@ -325,7 +344,7 @@ public:
      * Both member functions and free functions can be assigned to a meta
      * Both member functions and free functions can be assigned to a meta
      * type.<br/>
      * type.<br/>
      * From a client's point of view, all the functions associated with the
      * From a client's point of view, all the functions associated with the
-     * reflected object will appear as if they were part of the type.
+     * reflected object will appear as if they were part of the type itself.
      *
      *
      * @tparam Func The actual function to attach to the meta type.
      * @tparam Func The actual function to attach to the meta type.
      * @tparam Property Types of properties to assign to the meta function.
      * @tparam Property Types of properties to assign to the meta function.

+ 32 - 0
test/entt/meta/meta.cpp

@@ -106,6 +106,12 @@ struct Meta: public ::testing::Test {
 
 
         entt::reflect<char>("char", std::make_pair(properties::prop_int, 42));
         entt::reflect<char>("char", std::make_pair(properties::prop_int, 42));
 
 
+        entt::reflect<properties>()
+                .data<properties::prop_bool>("prop_bool")
+                .data<properties::prop_int>("prop_int");
+
+        entt::reflect<unsigned int>().data<0u>("min").data<100u>("max");
+
         entt::reflect<base_type>("base");
         entt::reflect<base_type>("base");
 
 
         entt::reflect<derived_type>("derived", std::make_pair(properties::prop_int, 99))
         entt::reflect<derived_type>("derived", std::make_pair(properties::prop_int, 99))
@@ -1323,3 +1329,29 @@ TEST_F(Meta, AbstractClass) {
 
 
     ASSERT_EQ(instance.i, -3);
     ASSERT_EQ(instance.i, -3);
 }
 }
+
+TEST_F(Meta, EnumAndNamedConstants) {
+    auto type = entt::resolve<properties>();
+
+    ASSERT_TRUE(type.data("prop_bool"));
+    ASSERT_TRUE(type.data("prop_int"));
+
+    ASSERT_EQ(type.data("prop_bool").type(), type);
+    ASSERT_EQ(type.data("prop_int").type(), type);
+
+    ASSERT_EQ(type.data("prop_bool").get({}).cast<properties>(), properties::prop_bool);
+    ASSERT_EQ(type.data("prop_int").get({}).cast<properties>(), properties::prop_int);
+}
+
+TEST_F(Meta, ArithmeticTypeAndNamedConstants) {
+    auto type = entt::resolve<unsigned int>();
+
+    ASSERT_TRUE(type.data("min"));
+    ASSERT_TRUE(type.data("max"));
+
+    ASSERT_EQ(type.data("min").type(), type);
+    ASSERT_EQ(type.data("max").type(), type);
+
+    ASSERT_EQ(type.data("min").get({}).cast<unsigned int>(), 0u);
+    ASSERT_EQ(type.data("max").get({}).cast<unsigned int>(), 100u);
+}