doc: meta, container support
This commit is contained in:
54
TODO
54
TODO
@@ -27,56 +27,6 @@ Next:
|
||||
* WIP:
|
||||
- meta: update doc
|
||||
- static constexpr -> inline constexpr
|
||||
- test: meta type seq/assoc traits, containers
|
||||
- document meta type traits
|
||||
- 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
|
||||
|
||||
151
docs/md/meta.md
151
docs/md/meta.md
@@ -10,6 +10,7 @@
|
||||
* [Reflection in a nutshell](#reflection-in-a-nutshell)
|
||||
* [Any as in any type](#any-as-in-any-type)
|
||||
* [Enjoy the runtime](#enjoy-the-runtime)
|
||||
* [Container support](#container-support)
|
||||
* [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)
|
||||
@@ -28,7 +29,7 @@ allocations. In one word: unsatisfactory.<br/>
|
||||
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,
|
||||
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
|
||||
|
||||
@@ -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
|
||||
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
|
||||
identifier is required, it's likely that a user defined literal is used as
|
||||
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
|
||||
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 are a kind of compile-time directives that can be used when recording
|
||||
|
||||
Reference in New Issue
Block a user