<commit_before># Crash Course: runtime reflection system

<!--
@cond TURN_OFF_DOXYGEN
-->
# Table of Contents

* [Introduction](#introduction)
* [Names and identifiers](#names-and-identifiers)
* [Reflection in a nutshell](#reflection-in-a-nutshell)
  * [Any as in any type](#any-as-in-any-type)
  * [Enjoy the runtime](#enjoy-the-runtime)
  * [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)
  * [Unregister types](#unregister-types)
<!--
@endcond TURN_OFF_DOXYGEN
-->

# Introduction

Reflection (or rather, its lack) is a trending topic in the C++ world and, in
the specific case of `EnTT`, a tool that can unlock a lot of other features. I
looked for a third-party library that met my needs on the subject, but I always
came across some details that I didn't like: macros, being intrusive, too many
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.

# Names and identifiers

The meta system doesn't force users to rely on the tools provided by the library
when it comes to working with names and identifiers. It does this by offering an
API that works with opaque identifiers that may or may not be generated by means
of a hashed string.<br/>
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
`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:

```cpp
auto factory = entt::meta<my_type>().type("reflected_type"_hs);
```

For what it's worth, this is likely completely equivalent to:

```cpp
auto factory = entt::meta<my_type>().type(42);
```

Obviously, human-readable identifiers are more convenient to use and highly
recommended.

# Reflection in a nutshell

Reflection always starts from real types (users cannot reflect imaginary types
and it would not make much sense, we wouldn't be talking about reflection
anymore).<br/>
To create a meta node, the library provides the `meta` function that accepts a
type to reflect as a template parameter:

```cpp
auto factory = entt::meta<my_type>();
```

This isn't enough to _export_ the given type and make it visible though.<br/>
The returned value is a factory object to use to continue building the meta
type. In order to make the type _visible_, users can assign it an identifier:

```cpp
auto factory = entt::meta<my_type>().type("reflected_type"_hs);
```

Or use the default one, that is, the built-in identifier for the given type:

```cpp
auto factory = entt::meta<my_type>().type();
```

Identifiers are important because users can retrieve meta types at runtime by
searching for them by _name_ other than by type.<br/>
On the other hand, there are cases in which users can be interested in adding
features to a reflected type so that the reflection system can use it correctly
under the hood, but they don't want to also make the type _searchable_. In this
case, it's sufficient not to invoke `type`.

A factory is such that all its member functions returns the factory itself or
a decorated version of it. This object can be used to add the following:

* _Constructors_. Actual constructors can be assigned to a reflected type by
  specifying their list of arguments. Free functions (namely, factories) can be
  used as well, as long as the return type is the expected one. From a client's
  point of view, nothing changes if a constructor is a free function or an
  actual constructor.<br/>
  Use the `ctor` member function for this purpose:

  ```cpp
  entt::meta<my_type>().ctor<int, char>().ctor<&factory>();
  ```

* _Destructors_. Free functions can be set as destructors of reflected types.
  The purpose is to give users the ability to free up resources that require
  special treatment before an object is actually destroyed.<br/>
  Use the `dtor` member function for this purpose:

  ```cpp
  entt::meta<my_type>().dtor<&destroy>();
  ```

  A function should neither delete nor explicitly invoke the destructor of a
  given instance.

* _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:

  ```cpp
  entt::meta<my_type>()
      .data<&my_type::static_variable>("static"_hs)
      .data<&my_type::data_member>("member"_hs)
      .data<&global_variable>("global"_hs);
  ```

  This function requires as an argument the identifier to give to the meta data
  once created. Users can then access meta data at runtime by searching for them
  by _name_.<br/>
  Data members can be set also by means of a couple of functions, namely a
  setter and a getter. Setters and getters can be either free functions, member
  functions or mixed ones, as long as they respect the required signatures.<br/>
  Refer to the inline documentation for all the details.

* _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
  the functions associated with the reflected type will appear as if they were
  part of the type itself.<br/>
  Use the `func` member function for this purpose:

  ```cpp
  entt::meta<my_type>()
      .func<&my_type::static_function>("static"_hs)
      .func<&my_type::member_function>("member"_hs)
      .func<&free_function>("free"_hs);
  ```

  This function requires as an argument the identifier to give to the meta
  function once created. Users can then access meta functions at runtime by
  searching for them by _name_.<commit_msg>doc: updated documentation for meta<commit_after># Crash Course: runtime reflection system

<!--
@cond TURN_OFF_DOXYGEN
-->
# Table of Contents

* [Introduction](#introduction)
* [Names and identifiers](#names-and-identifiers)
* [Reflection in a nutshell](#reflection-in-a-nutshell)
  * [Any as in any type](#any-as-in-any-type)
  * [Enjoy the runtime](#enjoy-the-runtime)
  * [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)
  * [Unregister types](#unregister-types)
<!--
@endcond TURN_OFF_DOXYGEN
-->

# Introduction

Reflection (or rather, its lack) is a trending topic in the C++ world and, in
the specific case of `EnTT`, a tool that can unlock a lot of other features. I
looked for a third-party library that met my needs on the subject, but I always
came across some details that I didn't like: macros, being intrusive, too many
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.

# Names and identifiers

The meta system doesn't force users to rely on the tools provided by the library
when it comes to working with names and identifiers. It does this by offering an
API that works with opaque identifiers that may or may not be generated by means
of a hashed string.<br/>
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
`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:

```cpp
auto factory = entt::meta<my_type>().type("reflected_type"_hs);
```

For what it's worth, this is likely completely equivalent to:

```cpp
auto factory = entt::meta<my_type>().type(42);
```

Obviously, human-readable identifiers are more convenient to use and highly
recommended.

# Reflection in a nutshell

Reflection always starts from real types (users cannot reflect imaginary types
and it would not make much sense, we wouldn't be talking about reflection
anymore).<br/>
To create a meta node, the library provides the `meta` function that accepts a
type to reflect as a template parameter:

```cpp
auto factory = entt::meta<my_type>();
```

This isn't enough to _export_ the given type and make it visible though.<br/>
The returned value is a factory object to use to continue building the meta
type. In order to make the type _visible_, users can assign it an identifier:

```cpp
auto factory = entt::meta<my_type>().type("reflected_type"_hs);
```

Or use the default one, that is, the built-in identifier for the given type:

```cpp
auto factory = entt::meta<my_type>().type();
```

Identifiers are important because users can retrieve meta types at runtime by
searching for them by _name_ other than by type.<br/>
On the other hand, there are cases in which users can be interested in adding
features to a reflected type so that the reflection system can use it correctly
under the hood, but they don't want to also make the type _searchable_. In this
case, it's sufficient not to invoke `type`.

A factory is such that all its member functions returns the factory itself or
a decorated version of it. This object can be used to add the following:

* _Constructors_. Actual constructors can be assigned to a reflected type by
  specifying their list of arguments. Free functions (namely, factories) can be
  used as well, as long as the return type is the expected one. From a client's
  point of view, nothing changes if a constructor is a free function or an
  actual constructor.<br/>
  Use the `ctor` member function for this purpose:

  ```cpp
  entt::meta<my_type>().ctor<int, char>().ctor<&factory>();
  ```

* _Destructors_. Free functions can be set as destructors of reflected types.
  The purpose is to give users the ability to free up resources that require
  special treatment before an object is actually destroyed.<br/>
  Use the `dtor` member function for this purpose:

  ```cpp
  entt::meta<my_type>().dtor<&destroy>();
  ```

  A function should neither delete nor explicitly invoke the destructor of a
  given instance.

* _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:

  ```cpp
  entt::meta<my_type>()
      .data<&my_type::static_variable>("static"_hs)
      .data<&my_type::data_member>("member"_hs)
      .data<&global_variable>("global"_hs);
  ```

  This function requires as an argument the identifier to give to the meta data
  once created. Users can then access meta data at runtime by searching for them
  by _name_.<br/>
  Data members can also be defined by means of a _setter_ and _getter_. Setters
  and getters can be either free functions, class members or a mix of them, as
  long as they respect the required signatures. This approach is also convenient
  to create a read-only variable from a non-const data member:

  ```cpp
  entt::meta<my_type>().data<nullptr, &my_type::data_member>("member"_hs);
  ```

  Refer to the inline documentation for all the details.

* _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
  the functions associated with the reflected type will appear as if they were
  part of the type itself.<br/>
  Use the `func` member function for this purpose:

  ```cpp
  entt::meta<my_type>()
      .func<&my_type::static_function>("static"_hs)
      .func<&my_type::member_function>("member"_hs)
      .func<&free_function>("free"_hs);
  ```

  This function requires as an argument the identifier to give to the meta
  function once created. Users can then access meta functions at runtime by
  searching for them by _name_.
{'fraction_non_alphanumeric': 0.07802033257151864, 'fraction_numerical': 0.00031523366695563086, 'mean_word_length': 4.327455919395466, 'pattern_counts': {'":': 0, '<': 66, '<?xml version=': 0, '>': 66, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3342002', 'n_tokens_mistral': 3501, 'n_tokens_neox': 3387, 'n_words': 1783}