Kaynağa Gözat

doc: meta, container support

Michele Caini 5 yıl önce
ebeveyn
işleme
0c777e10e5
2 değiştirilmiş dosya ile 151 ekleme ve 54 silme
  1. 2 52
      TODO
  2. 149 2
      docs/md/meta.md

+ 2 - 52
TODO

@@ -27,56 +27,6 @@ Next:
 * WIP:
 * WIP:
  - meta: update doc
  - meta: update doc
  - static constexpr -> inline constexpr
  - static constexpr -> inline constexpr
- - test: meta type seq/assoc traits, containers
- - document meta type traits
  - remove internal::find_if
  - remove internal::find_if
-
-
-struct meta_view_node {
-    using size_type = std::size_t;
-    meta_type_node *(* const key_type)() ENTT_NOEXCEPT;
-    meta_type_node *(* const value_type)() ENTT_NOEXCEPT;
-    void(* const next)(meta_handle) ENTT_NOEXCEPT;
-    void(* const prev)(meta_handle) ENTT_NOEXCEPT;
-    bool(* const empty)(meta_handle) ENTT_NOEXCEPT;
-    void(* const clear)(meta_handle);
-    size_type(* const size)(meta_handle) ENTT_NOEXCEPT;
-    meta_any(* const begin)(meta_handle) ENTT_NOEXCEPT;
-    meta_any(* const end)(meta_handle) ENTT_NOEXCEPT;
-    meta_any(* const erase)(meta_handle, meta_handle);
-    meta_any(* const insert)(meta_handle, meta_any, meta_any);
-    bool(* const set)(meta_handle, meta_any, meta_any);
-    meta_any(* const get)(meta_handle, meta_any);
-};
-
-static meta_view_node * view() ENTT_NOEXCEPT {
-    if constexpr(is_container_v<Type>) {
-        static meta_view_node node{
-            []() {
-                if constexpr(is_sequence_container_v<Type>) {
-                    return &internal::meta_node<typename Type::size_type>::resolve;
-                } else {
-                    return &internal::meta_node<typename Type::key_type>::resolve;
-                }
-            },
-            &internal::meta_node<typename Type::value_type>::resolve,
-            nullptr, // void(* const next)(meta_handle) ENTT_NOEXCEPT;
-            nullptr, // void(* const prev)(meta_handle) ENTT_NOEXCEPT;
-            nullptr, // bool(* const empty)(meta_handle) ENTT_NOEXCEPT;
-            nullptr, // void(* const clear)(meta_handle);
-            [](meta_handle instance) -> typename meta_view_node::size_type {
-                return (*instance).cast<Type>().size();
-            }, // size_type(* const size)(meta_handle) ENTT_NOEXCEPT;
-            nullptr, // meta_any(* const begin)(meta_handle) ENTT_NOEXCEPT;
-            nullptr, // meta_any(* const end)(meta_handle) ENTT_NOEXCEPT;
-            nullptr, // meta_any(* const erase)(meta_handle, meta_handle);
-            nullptr, // meta_any(* const insert)(meta_handle, meta_any, meta_any);
-            nullptr, // bool(* const set)(meta_handle, meta_any, meta_any);
-            nullptr // meta_any(* const get)(meta_handle, meta_any);
-        };
-
-        return &node;
-    } else {
-        return nullptr;
-    }
-}
+ - add meta_handle::operator-> that returns a meta_any * (easier to use directly)
+ - use a dedicate class template to specialize meta views for a better support to customizations

+ 149 - 2
docs/md/meta.md

@@ -10,6 +10,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)
+  * [Container support](#container-support)
   * [Policies: the more, the less](#policies-the-more-the-less)
   * [Policies: the more, the less](#policies-the-more-the-less)
   * [Named constants and enums](#named-constants-and-enums)
   * [Named constants and enums](#named-constants-and-enums)
   * [Properties and meta objects](#properties-and-meta-objects)
   * [Properties and meta objects](#properties-and-meta-objects)
@@ -28,7 +29,7 @@ allocations. In one word: unsatisfactory.<br/>
 I finally decided to write a built-in, non-intrusive and macro-free runtime
 I finally decided to write a built-in, non-intrusive and macro-free runtime
 reflection system for `EnTT`. Maybe I didn't do better than others or maybe yes,
 reflection system for `EnTT`. Maybe I didn't do better than others or maybe yes,
 time will tell me, but at least I can model this tool around the library to
 time will tell me, but at least I can model this tool around the library to
-which it belongs and not vice versa.
+which it belongs and not the opposite.
 
 
 # Names and identifiers
 # Names and identifiers
 
 
@@ -40,7 +41,7 @@ This means that users can assign any type of identifier to the meta objects, as
 long as they are numeric. It doesn't matter if they are generated at runtime, at
 long as they are numeric. It doesn't matter if they are generated at runtime, at
 compile-time or with custom functions.
 compile-time or with custom functions.
 
 
-However, the examples in the following sections are all based on the
+That being said, the examples in the following sections are all based on the
 `hashed_string` class as provided by this library. Therefore, where an
 `hashed_string` class as provided by this library. Therefore, where an
 identifier is required, it's likely that a user defined literal is used as
 identifier is required, it's likely that a user defined literal is used as
 follows:
 follows:
@@ -412,6 +413,152 @@ 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 inline documentation to get the best out of this powerful tool.
 read the inline documentation to get the best out of this powerful tool.
 
 
+## Container support
+
+The meta module offers minimal support for containers of all types.<br/>
+Here _containers_ doesn't necessarily mean those offered by the C++ standard
+library. As long as the user defined containers are subject to the following
+rules, they will be automatically intercepted by the reflection system:
+
+* A type is generally considered a container if the `begin`/`end` functions
+  exist and are resolvable through unqualified lookup.
+
+* A type is considered an associative container if it's a container **and** it
+  has a public alias declaration called `key_type`.
+
+* A type is considered a key-only associative container if it's an associative
+  container **and** the public alias declarations `key_type` and `value_type`
+  refer to the same type.
+
+* A type is considered a sequence container if it's a container and it's not an
+  associative container.
+
+* A type is considered a dynamic sequence container if it's a sequence container
+  **and** it offers an `insert` member function that accepts an iterator and a
+  value to insert.
+
+In addition to the above points, a container must exhibit a set of features that
+comply with the standard library guidelines. For example, it must offer a `size`
+method and a public alias declaration called `value_type`.
+
+Proxy objects for containers are returned by the `view` member function of the
+`meta_any` class:
+
+```cpp
+std::vector<int> vec{1, 2, 3};
+entt::meta_any any{std::ref(vec)};
+entt::meta_container view = any.view();
+```
+
+Users aren't expected to _reflect_ containers explicitly. It's sufficient to
+assign a container to a `meta_any` object to be able to get its proxy. A proxy
+is also contextually convertible to bool to know if it's valid. For example,
+invalid proxies are returned when the wrapped object isn't a container.<br/>
+To find out if an instance of `meta_any` contains a container or not, simply
+query the associated meta type. The latter exposes some methods such as for
+example `is_sequence_container` and `is_associative_container` which allow users
+to _explore_ the underlying type.
+
+All proxy objects offer the same interface, although the available features
+differ from case to case. In particular:
+
+* The `size` member function returns the number of elements in the container as
+  an unsigned integer value:
+
+  ```cpp
+  const auto size = view.size();
+  ```
+
+* The `begin` and `end` member functions return opaque iterators that can be
+  used to iterate the container directly:
+
+  ```cpp
+  for(entt::meta_any element: view) {
+      // ...
+  }
+  ```
+
+  In all cases, given an underlying container of type `C`, the returned element
+  contains an object of type `C::value_type` which therefore depends on the
+  actual container.<br/>
+  All meta iterators are input iterators and don't offer an indirection operator
+  on purpose.
+
+* The `insert` member function can be used to add elements to the container. It
+  accepts a couple of erased objects that take on different meaning depending on
+  the type of container.<br/>
+  In case of sequence containers, the first argument is a handle to the actual
+  iterator before which the element will be inserted while the second argument
+  is the element to insert:
+
+  ```cpp
+  auto last = view.end();
+  // appends an integer to the container
+  view.insert(last.handle(), 42);
+  ```
+
+  As for associative containers instead, the two arguments are respectively the
+  key and the value to be inserted:
+
+  ```cpp
+  view.insert("key"_hs, "value");
+  ```
+
+  This function returns a boolean value to indicate whether the operation was
+  successful or not. Note that a call to `insert` may silently fail in case of
+  fixed size containers or whether the arguments aren't at least convertible to
+  the required types.
+
+* The `erase` member function can be used to remove elements from the container.
+  It accepts a single argument that takes on different meaning depending on the
+  type of container.<br/>
+  In case of sequence containers, the argument is a handle to the actual
+  iterator to the element to remove:
+
+  ```cpp
+  auto first = view.begin();
+  // removes the first element from the container
+  view.erase(first);
+  ```
+
+  As for associative containers instead, the argument is the key to be removed:
+
+  ```cpp
+  view.erase("key"_hs);
+  ```
+
+  This function returns a boolean value to indicate whether the operation was
+  successful or not. Note that a call to `erase` may silently fail in case of
+  fixed size containers or whether the argument isn't at least convertible to
+  the required type.
+
+* The `operator[]` can be used to access elements in a container. It accepts a
+  single argument that takes on different meaning depending on the type of
+  container.<br/>
+  In case of sequence containers, the argument is the position of the element to
+  return:
+
+  ```cpp
+  for(std::size_t pos{}, last = view.size(); pos < last; ++pos) {
+      entt::meta_any value = view[pos];
+      // ...
+  }
+  ```
+
+  As for associative containers instead, the argument is the key of the element
+  to return:
+
+  ```cpp
+  entt::meta_any value = view["key"_hs];
+  ```
+
+  In both cases, the function returns an instance of `meta_any` that directly
+  refers to the actual element. This object may be invalid, for example when
+  the argument isn't at least convertible to the required type.
+
+Container support is deliberately minimal but theoretically sufficient to
+satisfy all needs.
+
 ## Policies: the more, the less
 ## Policies: the more, the less
 
 
 Policies are a kind of compile-time directives that can be used when recording
 Policies are a kind of compile-time directives that can be used when recording