1
0
Эх сурвалжийг харах

meta: updated documentation

Michele Caini 5 жил өмнө
parent
commit
6e2e030ba7
2 өөрчлөгдсөн 203 нэмэгдсэн , 82 устгасан
  1. 0 4
      TODO
  2. 203 78
      docs/md/meta.md

+ 0 - 4
TODO

@@ -25,11 +25,7 @@ Next:
  - update documentation to describe alternatives
 
 * WIP:
- - meta: update doc
  - static constexpr -> inline constexpr
  - remove internal::find_if
  - add const meta container support to meta any
- - meta_any deref fails if operator* returns a temporary
- - remove dereferenceable detector from type traits (is broken)
- - update meta.md
  - review _t

+ 203 - 78
docs/md/meta.md

@@ -11,6 +11,7 @@
   * [Any as in any type](#any-as-in-any-type)
   * [Enjoy the runtime](#enjoy-the-runtime)
   * [Container support](#container-support)
+  * [Pointer-like types](#pointer-like-types)
   * [Policies: the more, the less](#policies-the-more-the-less)
   * [Named constants and enums](#named-constants-and-enums)
   * [Properties and meta objects](#properties-and-meta-objects)
@@ -407,52 +408,62 @@ 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:
+The meta module supports containers of all types out of the box.<br/>
+Moreover, _containers_ doesn't necessarily mean those offered by the C++
+standard library. In fact, user defined data structures can also work with the
+meta system in many cases.
+
+To make a container be recognized by the meta module, users are required to
+provide specializations for either the `meta_sequence_container_traits` class or
+the `meta_associative_container_traits` class, according with the actual _type_
+of the container.<br/>
+`EnTT` already exports the specializations for some common classes. In
+particular:
+
+* `std::vector` and `std::array` are exported as _sequence containers_.
+* `std::map`, `std::set` and their unordered counterparts are exported as
+  _associative containers_.
+
+It's important to include the header file `container.hpp` to make these
+specializations available to the compiler when needed.<br/>
+The same file also contains many examples for the users that are interested in
+making their own containers available to the meta system.
+
+When a specialization of the `meta_sequence_container_traits` class exists, the
+meta system treats the wrapped type as a sequence container. In a similar way,
+a type is treated as an associative container if a specialization of the
+`meta_associative_container_traits` class is found for it.<br/>
+Proxy objects are returned by dedicated members of the `meta_any` class. The
+following is a deliberately verbose example of how users can access a proxy
+object for a sequence container:
 
 ```cpp
 std::vector<int> vec{1, 2, 3};
 entt::meta_any any{std::ref(vec)};
-entt::meta_container view = any.view();
+
+if(any.type().is_sequence_container()) {
+    if(auto view = any.as_sequence_container(); 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.
+The method to use to get a proxy object for associative containers is
+`as_associative_container` instead.<br/>
+It goes without saying that it's not necessary to perform a double check.
+Instead, it's sufficient to query the meta type or verify that the proxy object
+is valid. In fact, proxies are contextually convertible to bool to know if they
+are valid. For example, invalid proxies are returned when the wrapped object
+isn't a container.<br/>
+In all cases, users aren't expected to _reflect_ containers explicitly. It's
+sufficient to assign a container for which a specialization of the traits
+classes exists to a `meta_any` object to be able to get its proxy object.
 
-All proxy objects offer the same interface, although the available features
-differ from case to case. In particular:
+The interface of the `meta_sequence_container` proxy object is the same for all
+types of sequence containers, although the available features differ from case
+to case. In particular:
+
+* The `value_type` member function returns the meta type of the elements.
 
 * The `size` member function returns the number of elements in the container as
   an unsigned integer value:
@@ -461,6 +472,24 @@ differ from case to case. In particular:
   const auto size = view.size();
   ```
 
+* The `resize` member function allows to resize the wrapped container and
+  returns true in case of succes:
+
+  ```cpp
+  const bool ok = view.resize(3u);
+  ```
+
+  For example, it's not possible to resize fixed size containers.
+
+* The `clear` member function allows to clear the wrapped container and returns
+  true in case of success:
+
+  ```cpp
+  const bool ok = view.clear();
+  ```
+
+  For example, it's not possible to clear fixed size containers.
+
 * The `begin` and `end` member functions return opaque iterators that can be
   used to iterate the container directly:
 
@@ -477,11 +506,7 @@ differ from case to case. In particular:
   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:
+  accepts a meta iterator and the element to insert:
 
   ```cpp
   auto last = view.end();
@@ -489,23 +514,16 @@ differ from case to case. In particular:
   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.
+  This function returns a meta iterator pointing to the inserted element and 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.<br/>
+  Since the meta iterators are contextually convertible to bool, users can rely
+  on them to know if the operation has failed on the actual container or
+  upstream, for example for an argument conversion problem.
 
 * 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:
+  It accepts a meta iterator to the element to remove:
 
   ```cpp
   auto first = view.begin();
@@ -513,44 +531,151 @@ differ from case to case. In particular:
   view.erase(first);
   ```
 
-  As for associative containers instead, the argument is the key to be removed:
+  This function returns a meta iterator following the last removed element and 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.
+
+* The `operator[]` can be used to access elements in a container. It accepts a
+  single argument, that is the position of the element to return:
 
   ```cpp
-  view.erase("key"_hs);
+  for(std::size_t pos{}, last = view.size(); pos < last; ++pos) {
+      entt::meta_any value = view[pos];
+      // ...
+  }
   ```
 
-  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 function returns instances of `meta_any` that directly refer to the actual
+  elements. Modifying the returned object will then directly modify the element
+  inside the container.
 
-* 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:
+Similarly, also the interface of the `meta_associative_container` proxy object
+is the same for all types of associative containers. However, there are some
+differences in behavior in the case of key-only containers. In particular:
+
+* The `key_only` member function returns true if the wrapped container is a
+  key-only one.
+
+* The `key_type` member function returns the meta type of the keys.
+
+* The `mapped_type` member function returns an invalid meta type for key-only
+  containers and the meta type of the mapped values for all other types of
+  containers.
+
+* The `value_type` member function returns the meta type of the elements.<br/>
+  For example, it returns the meta type of `int` for `std::set<int>` while it
+  returns the meta type of `std::pair<const int, char>` for
+  `std::map<int, char>`.
+
+* The `size` member function returns the number of elements in the container as
+  an unsigned integer value:
 
   ```cpp
-  for(std::size_t pos{}, last = view.size(); pos < last; ++pos) {
-      entt::meta_any value = view[pos];
+  const auto size = view.size();
+  ```
+
+* The `clear` member function allows to clear the wrapped container and returns
+  true in case of success:
+
+  ```cpp
+  const bool ok = view.clear();
+  ```
+
+* 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) {
       // ...
   }
   ```
 
-  As for associative containers instead, the argument is the key of the element
-  to return:
+  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 two arguments, respectively the key and the value to be inserted:
 
   ```cpp
-  entt::meta_any value = view["key"_hs];
+  auto last = view.end();
+  // appends an integer to the container
+  view.insert(last.handle(), 42, 'c');
   ```
 
-  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.
+  This function returns a boolean value to indicate whether the operation was
+  successful or not. Note that a call to `insert` may fail when 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 is the key to be removed:
+
+  ```cpp
+  view.erase(42);
+  ```
+
+  This function returns a boolean value to indicate whether the operation was
+  successful or not. Note that a call to `erase` may fail when 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 is the key of the element to return:
+
+  ```cpp
+  entt::meta_any value = view[42];
+  ```
+
+  The function returns instances of `meta_any` that directly refer to the actual
+  elements. Modifying the returned object will then directly modify the element
+  inside the container.
 
 Container support is deliberately minimal but theoretically sufficient to
 satisfy all needs.
 
+## Pointer-like types
+
+As with containers, it's also possible to communicate to the meta system which
+types to consider _pointers_. This will allow to dereference instances of
+`meta_any`, obtaining light _references_ to the pointed objects that are also
+correctly associated with their meta types.<br/>
+To make the meta system recognize a type as _pointer-like_, users can specialize
+the `is_meta_pointer_like` class. `EnTT` already exports the specializations for
+some common classes. In particular:
+
+* All types of raw pointers.
+* `std::uniqe_ptr` and `std::shared_ptr`.
+
+It's important to include the header file `pointer.hpp` to make these
+specializations available to the compiler when needed.<br/>
+The same file also contains many examples for the users that are interested in
+making their own containers available to the meta system.
+
+When a type is recognized as a pointer-like one by the meta system, it's
+possible to dereference the instances of `meta_any` that contain these objects.
+The following is a deliberately verbose example to show how to use this feature:
+
+```cpp
+int value = 42;
+// meta type equivalent to that of int *
+entt::meta_any any{&value};
+
+if(any.type().is_meta_pointer_like()) {
+    // meta type equivalent to that of int
+    if(entt::meta_any ref = *any; ref) {
+        // ...
+    }
+}
+```
+
+It goes without saying that it's not necessary to perform a double check.
+Instead, it's sufficient to query the meta type or verify that the returned
+object is valid. For example, invalid instances are returned when the wrapped
+object hasn't a pointer-like type.<br/>
+Note that dereferencing a pointer-like object returns an instance of `meta_any`
+which refers to the pointed object and allows users to modify it directly.
+
 ## Policies: the more, the less
 
 Policies are a kind of compile-time directives that can be used when recording