From 9a08be9d5e9a899729cdbdef3b65f420d2f4bdc5 Mon Sep 17 00:00:00 2001 From: Lucy Date: Tue, 21 Jan 2025 08:47:27 +0100 Subject: [PATCH 01/23] Update config.md --- docs/md/config.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/md/config.md b/docs/md/config.md index 1679b4f95..55d58a03e 100644 --- a/docs/md/config.md +++ b/docs/md/config.md @@ -60,7 +60,7 @@ default type if necessary. It's known that the ECS module of `EnTT` is based on _sparse sets_. What is less known perhaps is that the sparse arrays are paged to reduce memory usage.
Default size of pages (that is, the number of elements they contain) is 4096 but -users can adjust it if appropriate. In all case, the chosen value **must** be a +users can adjust it if appropriate. In all cases, the chosen value **must** be a power of 2. ## ENTT_PACKED_PAGE @@ -69,7 +69,7 @@ As it happens with sparse arrays, packed arrays are also paginated. However, in this case the aim isn't to reduce memory usage but to have pointer stability upon component creation.
Default size of pages (that is, the number of elements they contain) is 1024 but -users can adjust it if appropriate. In all case, the chosen value **must** be a +users can adjust it if appropriate. In all cases, the chosen value **must** be a power of 2. ## ENTT_ASSERT From d74a95b16035eb0ec4901332fc3564ce0de12118 Mon Sep 17 00:00:00 2001 From: theaddon Date: Tue, 21 Jan 2025 09:02:20 +0100 Subject: [PATCH 02/23] correct grammar --- docs/md/container.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/md/container.md b/docs/md/container.md index fd07f03cb..0ff41f36e 100644 --- a/docs/md/container.md +++ b/docs/md/container.md @@ -78,7 +78,7 @@ The internal implementation is purposely supported by a tuple of containers rather than a container of tuples. The purpose is to allow efficient access to single columns and not just access to the entire data set of the table. -When a row is accessed, all data are returned in the form of a tuple containing +When a row is accessed, all data is returned in the form of a tuple containing (possibly const) references to the elements of the row itself.
Similarly, when a table is iterated, tuples of references to table elements are returned for each row. From 1dddb293057a71d200d197cd9f129bbe8fb6f07b Mon Sep 17 00:00:00 2001 From: theaddon Date: Tue, 21 Jan 2025 09:02:38 +0100 Subject: [PATCH 03/23] fix wide chars section link --- docs/md/core.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/md/core.md b/docs/md/core.md index dbba9d775..23f7a6017 100644 --- a/docs/md/core.md +++ b/docs/md/core.md @@ -10,7 +10,7 @@ * [Compressed pair](#compressed-pair) * [Enum as bitmask](#enum-as-bitmask) * [Hashed strings](#hashed-strings) - * [Wide characters](wide-characters) + * [Wide characters](#wide-characters) * [Conflicts](#conflicts) * [Iterators](#iterators) * [Input iterator pointer](#input-iterator-pointer) From d73abee3ab8f56cb4f4cd802750f936eb968f472 Mon Sep 17 00:00:00 2001 From: theaddon Date: Tue, 21 Jan 2025 09:17:27 +0100 Subject: [PATCH 04/23] fix general grammar issues in core --- docs/md/core.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/md/core.md b/docs/md/core.md index 23f7a6017..c6422bbe5 100644 --- a/docs/md/core.md +++ b/docs/md/core.md @@ -695,7 +695,7 @@ Fortunately, there are several easy ways to deal with this: * A fully customized identifier generation policy (based for example on enum classes or preprocessing steps) may represent yet another option. -These are just some examples of possible approaches to the problem but there are +These are just some examples of possible approaches to the problem, but there are many others. As already mentioned above, since users have full control over their types, this problem is in any case easy to solve and should not worry too much.
@@ -831,7 +831,7 @@ type list: * `type_list_transform[_t]` to _transform_ a range and create another type list. I'm also pretty sure that more and more utilities will be added over time as -needs become apparent.
+needs to become apparent.
Many of these functionalities also exist in their version dedicated to value lists. We therefore have `value_list_element[_v]` as well as `value_list_cat[_t]`and so on. @@ -840,9 +840,9 @@ lists. We therefore have `value_list_element[_v]` as well as Sometimes it's useful to be able to give unique, sequential numeric identifiers to types either at compile-time or runtime.
-There are plenty of different solutions for this out there and I could have used +There are plenty of different solutions for this out there, and I could have used one of them. However, I decided to spend my time to define a couple of tools -that fully embraces what the modern C++ has to offer. +that fully embrace what modern C++ has to offer. ## Compile-time generator @@ -873,7 +873,7 @@ where constant expressions are required. As long as the list remains unchanged, identifiers are also guaranteed to be stable across different runs. In case they have been used in a production -environment and a type has to be removed, one can just use a placeholder to +environment, and a type has to be removed; one can just use a placeholder to leave the other identifiers unchanged: ```cpp @@ -886,7 +886,7 @@ using id = entt::ident< >; ``` -Perhaps a bit ugly to see in a codebase but it gets the job done at least. +Perhaps a bit ugly to see in a codebase, but it gets the job done at least. ## Runtime generator @@ -979,5 +979,5 @@ life of developers: the language doesn't make it possible to do much better. This is a rundown of the (actually few) utilities made available by `EnTT`. The -list will probably grow over time but the size of each will remain rather small, +list will probably grow over time, but the size of each will remain rather small, as has been the case so far. From ca8aa11a01705e66e724a598485a05af8449752b Mon Sep 17 00:00:00 2001 From: theaddon Date: Tue, 21 Jan 2025 09:29:51 +0100 Subject: [PATCH 05/23] fix general grammar issues in faq --- docs/md/faq.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/md/faq.md b/docs/md/faq.md index d3a7d593f..c5c223662 100644 --- a/docs/md/faq.md +++ b/docs/md/faq.md @@ -16,7 +16,7 @@ This is a constantly updated section where I'm trying to put the answers to the most frequently asked questions.
-If you don't find your answer here, there are two cases: nobody has done it yet +If you don't find your answer here, there are two cases: nobody has done it yet, or this section needs updating. In both cases, you can [open a new issue](https://github.com/skypjack/entt/issues/new) or enter either the [gitter channel](https://gitter.im/skypjack/entt) or the @@ -34,7 +34,7 @@ likely that some classes you're working with are using standard containers under the hood.
Unfortunately, it's known that the standard containers aren't particularly performing in debugging (the reasons for this go beyond this document) and are -even less so on Windows apparently. Fortunately this can also be mitigated a +even less so on Windows, apparently. Fortunately, this can also be mitigated a lot, achieving good results in many cases. First of all, there are two things to do in a Windows project: @@ -53,7 +53,7 @@ macro to disable internal debug checks in `EnTT`: #define ENTT_ASSERT(...) ((void)0) ``` -These asserts are introduced to help the users but they require to access to the +These asserts are introduced to help the users, but they require access to the underlying containers and therefore risk ruining the performance in some cases. With these changes, debug performance should increase enough in most cases. If @@ -64,7 +64,7 @@ preferably `O1`. This is one of the first questions that anyone makes when starting to work with the entity-component-system architectural pattern.
-There are several approaches to the problem and the best one depends mainly on +There are several approaches to the problem, and the best one depends mainly on the real problem one is facing. In all cases, how to do it doesn't strictly depend on the library in use, but the latter certainly allows or not different techniques depending on how the data are laid out. @@ -72,7 +72,7 @@ techniques depending on how the data are laid out. I tried to describe some of the approaches that fit well with the model of `EnTT`. [This](https://skypjack.github.io/2019-06-25-ecs-baf-part-4/) is the first post of a series that tries to _explore_ the problem. More will probably -come in future.
+come in the future.
In addition, `EnTT` also offers the possibility to create stable storage types and therefore have pointer stability for one, all or some components. This is by far the most convenient solution when it comes to creating hierarchies and @@ -184,7 +184,7 @@ owned by the entity that is destroyed. ## Duplicate storage for the same component -It's rare but you can see double sometimes, especially when it comes to storage. +It's rare, but you can see double sometimes, especially when it comes to storage. This can be caused by a conflict in the hash assigned to the various component types (one of a kind) or by bugs in your compiler ([more common](https://github.com/skypjack/entt/issues/1063) apparently).
From 1cb320c330844968fc6ee3acc2631555fe53451f Mon Sep 17 00:00:00 2001 From: theaddon Date: Tue, 21 Jan 2025 10:27:34 +0100 Subject: [PATCH 06/23] fix general grammar issues in graph --- docs/md/graph.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/md/graph.md b/docs/md/graph.md index 407ac1adc..51ce139ac 100644 --- a/docs/md/graph.md +++ b/docs/md/graph.md @@ -24,7 +24,7 @@ some tools such as the _flow builder_. As anticipated in the introduction, the aim isn't to offer all possible data structures suitable for representing and working with graphs. Many will likely -be added or refined over time. However I want to discourage anyone expecting +be added or refined over time. However, I want to discourage anyone expecting tight scheduling on the subject.
The data structures presented in this section are mainly useful for the development and support of some tools which are also part of the same submodule. @@ -108,7 +108,7 @@ Both the functions expect the vertex to visit (that is, to return the in- or out-edges for) as an argument.
Finally, the adjacency matrix is an allocator-aware container and offers most of the functionalities one would expect from this type of containers, such as -`clear` or 'get_allocator` and so on. +`clear` or 'get_allocator' and so on. ## Graphviz dot language @@ -165,7 +165,7 @@ particular data structure. On the other hand, it requires the user to keep track of the association between identifiers and operations or actual data. Once a flow builder is created (which requires no constructor arguments), the -first thing to do is to bind a task. This tells to the builder _who_ intends to +first thing to do is to bind a task. This tells the builder _who_ intends to consume the resources that are specified immediately after: ```cpp @@ -194,7 +194,7 @@ builder .rw("resource_2"_hs) ``` -As mentioned, many functions return the builder itself and it's therefore easy +As mentioned, many functions return the builder itself, and it's therefore easy to concatenate the different calls.
Also in the case of resources, they are identified by numeric values of type `id_type`. As above, the choice is not entirely random. This goes well with the @@ -274,7 +274,7 @@ loop between the two tasks. As a general rule, rebinding resources and tasks is highly discouraged because it could lead to subtle bugs if users don't know what they're doing.
However, once the mechanisms of resource-based graph generation are understood, -it can offer to the expert user a flexibility and a range of possibilities +it can offer to the expert user flexibility and a range of possibilities otherwise inaccessible. ## Fake resources and order of execution @@ -322,7 +322,7 @@ builder In this case, since there are a number of processes that want to read a specific resource, they will do so in parallel by forcing `task_3` to run after all the -others tasks. +other tasks. ## Sync points @@ -335,7 +335,7 @@ builder, then the `sync` function is invoked: builder.bind("sync_point"_hs).sync(); ``` -The choice to assign an _identity_ to this type of nodes lies in the fact that, +The choice to assign an _identity_ to this type of node lies in the fact that, more often than not, they also perform operations on resources.
If this isn't the case, it will still be possible to create no-op vertices to which empty tasks are assigned. From 8c14d4bf7af92ec5053106246973aaf4d169fc42 Mon Sep 17 00:00:00 2001 From: theaddon Date: Tue, 21 Jan 2025 10:34:57 +0100 Subject: [PATCH 07/23] fix general grammar issues in lib --- docs/md/lib.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/md/lib.md b/docs/md/lib.md index 6be3881d0..31624a8fc 100644 --- a/docs/md/lib.md +++ b/docs/md/lib.md @@ -20,12 +20,14 @@ Fortunately, nowadays `EnTT` works smoothly across boundaries. Many classes in `EnTT` make extensive use of type erasure for their purposes. This raises the need to identify objects whose type has been erased.
The `type_hash` class template is how identifiers are generated and thus made -available to the rest of the library. In general, this class doesn't arouse much -interest. The only exception is when a conflict between identifiers occurs +available to the rest of the library. +In general, this class arouses little interest. +The only exception is when a conflict between identifiers occurs (definitely uncommon though) or when the default solution proposed by `EnTT` isn't suitable for the user's purposes.
The section dedicated to `type_info` contains all the details to get around the -issue in a concise and elegant way. Please refer to the specific documentation. +issue in a concise and elegant way. +Please refer to the specific documentation. When working with linked libraries, compile definitions `ENTT_API_EXPORT` and `ENTT_API_IMPORT` are to import or export symbols, so as to make everything work @@ -60,8 +62,8 @@ thus discarding or storing aside the local one: entt::locator::reset(handle); ``` -From now on, both spaces refer to the same context and on it are attached all -new meta types, no matter where they are created.
+From now on, both spaces refer to the same context and to it are all +new meta-types attached, no matter where they are created.
Note that _replacing_ the main context doesn't also propagate changes across boundaries. In other words, replacing a context results in the decoupling of the two sides and therefore a divergence in the contents. @@ -81,7 +83,7 @@ is unknown to the former, a dedicated pool is created within the registry on first use.
As one can guess, this pool is instantiated on a different side of the boundary from the `registry`. Therefore, the instance is now managing memory from -different spaces and this can quickly lead to crashes if not properly addressed. +different spaces, and this can quickly lead to crashes if not properly addressed. To overcome the risk, it's recommended to use well-defined interfaces that make fundamental types pass through the boundaries, isolating the instances of the From a3e193dd15b6589a0aa9676e64562baebd45a8aa Mon Sep 17 00:00:00 2001 From: theaddon Date: Tue, 21 Jan 2025 10:55:18 +0100 Subject: [PATCH 08/23] fix general grammar and spelling issues in links.md --- docs/md/links.md | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/docs/md/links.md b/docs/md/links.md index 705132a85..a921b737a 100644 --- a/docs/md/links.md +++ b/docs/md/links.md @@ -23,7 +23,7 @@ Where I put the word _apparently_ means that the use of `EnTT` is documented but the authors didn't make explicit announcements or contacted me directly. If you know of other resources out there that are about `EnTT`, feel free to -open an issue or a PR and I'll be glad to add them to this page.
+open an issue or a PR. I'll be glad to add them to this page.
I hope the following lists can grow much more in the future. # EnTT in Action @@ -48,7 +48,7 @@ I hope the following lists can grow much more in the future. * [Apparently](https://www.youtube.com/watch?v=P8xvOA3ikrQ&t=1105s) [Call of Duty: Vanguard](https://www.callofduty.com/vanguard) by [Sledgehammer Games](https://www.sledgehammergames.com/): I can neither - confirm nor deny but there is a license I know in the credits. + confirm nor deny, but there is a license I know in the credits. * Apparently [D&D Dark Alliance](https://darkalliance.wizards.com) by [Wizards of the Coast](https://company.wizards.com): your party, their funeral. @@ -97,17 +97,16 @@ I hope the following lists can grow much more in the future. by Quake. * [Destroid](https://github.com/tyrannicaltoucan/destroid): _one-bazillionth_ arcade game about shooting dirty rocks in space, inspired by Asteroids. - * [Wanderer](https://github.com/albin-johansson/wanderer): a 2D exploration - based indie game. - * [Spelunky® Classic remake](https://github.com/dbeef/spelunky-psp): a truly + * [Wanderer](https://github.com/albin-johansson/wanderer): a 2D exploration-based indie game. + * [Spelunky® Classic remake](https://github.com/dbeef/spelunky-psp): a truly multiplatform experience with a rewrite from scratch. * [CubbyTower](https://github.com/utilForever/CubbyTower): a simple tower defense game using C++ with Entity Component System (ECS). * [Runeterra](https://github.com/utilForever/Runeterra): Legends of Runeterra simulator using C++ with some reinforcement learning. * [Black Sun](https://store.steampowered.com/app/1670930/Black_Sun/): fly your - space ship through a large 2D open world. - * [PokeMaster](https://github.com/utilForever/PokeMaster): Pokemon Battle + spaceship through a large 2D open world. + * [PokeMaster](https://github.com/utilForever/PokeMaster): Pokémon Battle simulator using C++ with some reinforcement learning. * [HomeHearth](https://youtu.be/GrEWl8npL9Y): choose your hero, protect the town, before it's too late. @@ -190,7 +189,7 @@ I hope the following lists can grow much more in the future. framework in C++17 for backend development. * [Unity/EnTT](https://github.com/TongTungGiang/unity-entt): tech demo of a native simulation layer using `EnTT` and `Unity` as a rendering engine. - * [OverEngine](https://github.com/OverShifted/OverEngine): an over-engineered + * [OverEngine](https://github.com/OverShifted/OverEngine): an overengineered game engine. * [Electro](https://github.com/Electro-Technologies/Electro): high performance 3D game engine with a high emphasis on rendering. @@ -199,13 +198,13 @@ I hope the following lists can grow much more in the future. * [Becketron](https://github.com/Doctor-Foxling/Becketron): a game engine written mostly in C++. * [Spatial Engine](https://github.com/luizgabriel/Spatial.Engine): a - cross-platform engine created on top of google's filament rendering engine. + cross-platform engine created on top of Google's filament rendering engine. * [Kaguya](https://github.com/KaiH0717/Kaguya): D3D12 Rendering Engine. * [OpenAWE](https://github.com/OpenAWE-Project/OpenAWE): open implementation of the Alan Wake Engine. * [Nazara Engine](https://github.com/DigitalPulseSoftware/NazaraEngine): fast, cross-platform, object-oriented API to help in daily developer life. - * [Billy Engine](https://github.com/billy4479/BillyEngine): some kind of a 2D + * [Billy Engine](https://github.com/billy4479/BillyEngine): some kind of 2D engine based on `SDL2` and `EnTT`. * [Ducktape](https://github.com/DucktapeEngine/Ducktape): an open source C++ 2D & 3D game engine that focuses on being fast and powerful. @@ -310,7 +309,7 @@ I hope the following lists can grow much more in the future. * [ArcGIS Runtime SDKs](https://developers.arcgis.com/arcgis-runtime/) by [Esri](https://www.esri.com/): they use `EnTT` for the internal ECS and the - cross platform C++ rendering engine. The SDKs are utilized by a lot of + cross-platform C++ rendering engine. The SDKs are utilized by a lot of enterprise custom apps, as well as by Esri for its own public applications such as [Explorer](https://play.google.com/store/apps/details?id=com.esri.explorer), @@ -326,7 +325,7 @@ I hope the following lists can grow much more in the future. * [Project Lagrange](https://github.com/adobe/lagrange): a robust geometry processing library by [Adobe](https://github.com/adobe). * [AtomicDEX](https://github.com/KomodoPlatform/atomicDEX-Desktop): a secure - wallet and non-custodial decentralized exchange rolled into one application. + wallet and noncustodial decentralized exchange rolled into one application. * [Apparently](https://www.linkedin.com/in/skypjack/) [NIO](https://www.nio.io/): there was a collaboration to make some changes to `EnTT`, at the time used for internal projects. From 195bed8a11d7aa0dc391bce7206ec6366da5d8ad Mon Sep 17 00:00:00 2001 From: theaddon Date: Tue, 21 Jan 2025 11:06:01 +0100 Subject: [PATCH 09/23] fix general grammar and spelling issues in locator.md --- docs/md/locator.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/md/locator.md b/docs/md/locator.md index 6676c18be..9acf14fcd 100644 --- a/docs/md/locator.md +++ b/docs/md/locator.md @@ -8,8 +8,8 @@ # Introduction -Usually, service locators are tightly bound to the services they expose and it's -hard to define a general purpose solution.
+Usually, service locators are tightly bound to the services they expose. +It's hard to define a general purpose solution.
This tiny class tries to fill the gap and gets rid of the burden of defining a different specific locator for each application. @@ -74,9 +74,9 @@ and use them with other locators. Of course, all a user will get is to have an uninitialized service elsewhere as well. Note that exporting a service allows users to _share_ the object currently set -in a locator. Replacing it won't replace the element even where a service has +in a locator. Replacing it won't replace the element, even where a service has been configured with a handle to the previous item.
In other words, if an audio service is replaced with a null object to silence an application and the original service was shared, this operation won't propagate -to the other locators. Therefore, a module that share the ownership of the +to the other locators. Therefore, a module that shares the ownership of the original audio service is still able to emit sounds. From 7c9d51cb234931650cb71a1642ef15be10d6a117 Mon Sep 17 00:00:00 2001 From: theaddon Date: Tue, 21 Jan 2025 14:46:07 +0100 Subject: [PATCH 10/23] fix general grammar and spelling issues in meta.md --- docs/md/meta.md | 194 ++++++++++++++++++++++++------------------------ 1 file changed, 97 insertions(+), 97 deletions(-) diff --git a/docs/md/meta.md b/docs/md/meta.md index dda6c0dae..937050572 100644 --- a/docs/md/meta.md +++ b/docs/md/meta.md @@ -39,7 +39,7 @@ 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.
-This means that users can assign any type of identifier to the meta objects, as +This means that users can assign any type of identifier to the meta-objects, as long as they're numeric. It doesn't matter if they're generated at runtime, at compile-time or with custom functions. @@ -74,15 +74,15 @@ entt::meta_factory factory{}; The returned value is a _factory object_ to use to continue building the meta type. -By default, a meta type is associated with the identifier returned by the +By default, a meta-type is associated with the identifier returned by the runtime type identification system built-in in `EnTT`.
-However, it's also possible to assign custom identifiers to meta types: +However, it's also possible to assign custom identifiers to meta-types: ```cpp entt::meta_factory{}.type("reflected_type"_hs); ``` -Identifiers are used to _retrieve_ meta types at runtime by _name_ other than by +Identifiers are used to _retrieve_ meta-types at runtime by _name_ other than by type.
However, users can be interested in adding features to a reflected type so that the reflection system can use it correctly under the hood, while they don't want @@ -92,7 +92,7 @@ to also make the type _searchable_. In this case, it's sufficient not to invoke A factory is such that all its member functions return the factory itself. It's generally used to create the following: -* _Constructors_. A constructors is assigned to a reflected type by specifying +* _Constructors_. A constructor is assigned to a reflected type by specifying its _list of arguments_. Free functions are also accepted if the return type is the expected one. From a client perspective, nothing changes between a free function or an actual constructor: @@ -101,7 +101,7 @@ generally used to create the following: entt::meta_factory{}.ctor().ctor<&factory>(); ``` - Meta default constructors are implicitly generated, if possible. + Meta-default constructors are implicitly generated, if possible. * _Destructors_. Both free functions and member functions are valid destructors: @@ -114,7 +114,7 @@ generally used to create the following: A function should neither delete nor explicitly invoke the destructor of a given instance. -* _Data members_. Meta data members are actual data members of the underlying +* _Data members_. Meta-data members are actual data members of the underlying type but also static and global variables or constants of any kind. From the point of view of the client, all the variables associated with the reflected type appear as if they were part of the type itself: @@ -126,7 +126,7 @@ generally used to create the following: .data<&global_variable>("global"_hs); ``` - The `data` function requires the identifier to use for the meta data member. + The `data` function requires the identifier to use for the meta-data member. Users can then access it by _name_ at runtime.
Data members are also defined by means of a setter and getter pair. These are either free functions, class members or a mix of them. This approach is also @@ -154,7 +154,7 @@ generally used to create the following: .func<&free_function>("free"_hs); ``` - The `func` function requires the identifier to use for the meta data function. + The `func` function requires the identifier to use for the meta-data function. Users can then access it by _name_ at runtime.
Overloading of meta functions is supported. Overloaded functions are resolved at runtime by the reflection system according to the types of the arguments. @@ -177,15 +177,15 @@ generally used to create the following: entt::meta_factory{}.conv(); ``` -This is everything users need to create meta types. Refer to the inline -documentation for further details. +This is everything users need to create meta-types. +Refer to the inline documentation for further details. ## Any to the rescue The reflection system offers a kind of _extended version_ of the `entt::any` class (see the core module for more details).
The purpose is to add some feature on top of those already present, so as to -integrate it with the meta type system without having to duplicate the code. +integrate it with the meta-type system without having to duplicate the code. The API is very similar to that of the `any` type. The class `meta_any` _wraps_ many of the feature to infer a meta node, before forwarding some or all of the @@ -205,7 +205,7 @@ entt::meta_any other{std::in_place_type}; ``` While `any` considers both as empty, `meta_any` treats objects initialized with -`void` as if they were _valid_ ones. This allows to differentiate between failed +`void` as if they were _valid_ ones. This allows differentiating between failed function calls and function calls that are successful but return nothing. Finally, the member functions `try_cast`, `cast` and `allow_cast` are used to @@ -242,21 +242,21 @@ for(auto &&[id, type]: entt::resolve()) { ``` In all cases, the returned value is an instance of `meta_type` (possibly with -its id). This kind of objects offer an API to know their _runtime identifiers_, -to iterate all the meta objects associated with them and even to build instances +its id). This kind of objects offers an API to know their _runtime identifiers_, +to iterate all the meta-objects associated with them and even to build instances of the underlying type.
-Meta data members and functions are accessed by name: +Meta-data members and functions are accessed by name: -* Meta data members: +* Meta-data members: ```cpp auto data = entt::resolve().data("member"_hs); ``` - The returned type is `meta_data` and may be invalid if there is no meta data + The returned type is `meta_data` and may be invalid if there is no meta-data object associated with the given identifier.
- A meta data object offers an API to query the underlying type (for example, to - know if it's a const or a static one), to get the meta type of the variable + A meta-data object offers an API to query the underlying type (for example, to + know if it's a const or a static one), to get the meta-type of the variable and to set or get the contained value. * Meta function members: @@ -269,11 +269,11 @@ Meta data members and functions are accessed by name: function object associated with the given identifier.
A meta function object offers an API to query the underlying type (for example, to know if it's a const or a static function), to know the number of - arguments, the meta return type and the meta types of the parameters. In + arguments, the meta return type and the meta-types of the parameters. In addition, a meta function object is used to invoke the underlying function and then get the return value in the form of a `meta_any` object. -All the meta objects thus obtained as well as the meta types explicitly convert +All the meta-objects thus obtained as well as the meta-types explicitly convert to a boolean value to check for validity: ```cpp @@ -282,7 +282,7 @@ if(auto func = entt::resolve().func("member"_hs); func) { } ``` -Furthermore, all them (and a few more, like meta basis) are returned by a bunch +Furthermore, all of them (and a few more, like meta-basis) are returned by a bunch of overloads that provide the caller with iterable ranges of top-level elements. As an example: @@ -292,22 +292,22 @@ for(auto &&[id, type]: entt::resolve().base()) { } ``` -Meta type are also used to `construct` actual instances of the underlying +Meta-types are also used to `construct` actual instances of the underlying type.
In particular, the `construct` member function accepts a variable number of arguments and searches for a match. It then returns a `meta_any` object that may or may not be initialized, depending on whether a suitable constructor was found or not. -There is no object that wraps the destructor of a meta type nor a `destroy` +There is no object that wraps the destructor of a meta-type nor a `destroy` member function in its API. Destructors are invoked implicitly by `meta_any` behind the scenes and users have not to deal with them explicitly. Furthermore, they've no name, cannot be searched and wouldn't have member functions to expose anyway.
Similarly, conversion functions aren't directly accessible. They're used -internally by `meta_any` and the meta objects when needed. +internally by `meta_any` and the meta-objects when needed. -Meta types and meta objects in general contain much more than what was said. +Meta-types and meta-objects in general contain much more than what was said. Refer to the inline documentation for further details. ## Container support @@ -315,7 +315,7 @@ Refer to the inline documentation for further details. The runtime reflection system also supports containers of all types.
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. +meta-system in many cases. To make a container be recognized as such by the meta system, users are required to provide specializations for either the `meta_sequence_container_traits` class @@ -333,10 +333,10 @@ particular: It's important to include the header file `container.hpp` to make these specializations available to the compiler when needed.
The same file also contains many examples for the users that are interested in -making their own containers available to the meta system. +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, +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.
Proxy objects are returned by dedicated members of the `meta_any` class. The @@ -357,31 +357,31 @@ if(any.type().is_sequence_container()) { The method to use to get a proxy object for associative containers is `as_associative_container` instead.
It's not necessary to perform a double check actually. Instead, it's enough to -query the meta type or verify that the proxy object is valid. In fact, proxies +query the meta-type or verify that the proxy object is valid. In fact, proxies are contextually convertible to bool to check for validity. For example, invalid proxies are returned when the wrapped object isn't a container.
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 +sufficient to assign a container for which a specialization of the trait classes exists to a `meta_any` object to be able to get its proxy object. 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 `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. -* The `resize` member function allows to resize the wrapped container and +* The `resize` member function allows resizing the wrapped container and returns true in case of success.
For example, it's not possible to resize fixed size containers. -* The `clear` member function allows to clear the wrapped container and returns +* The `clear` member function allows clearing the wrapped container and returns true in case of success.
For example, it's not possible to clear fixed size containers. -* The `reserve` member function allows to increase the capacity of the wrapped +* The `reserve` member function allows increasing the capacity of the wrapped container and returns true in case of success.
For example, it's not possible to increase capacity of fixed size containers. @@ -455,24 +455,24 @@ 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 `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 +* 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.
- For example, it returns the meta type of `int` for `std::set` while it - returns the meta type of `std::pair` for +* The `value_type` member function returns the meta-type of the elements.
+ For example, it returns the meta-type of `int` for `std::set` while it + returns the meta-type of `std::pair` for `std::map`. * The `size` member function returns the number of elements in the container as an unsigned integer value. -* The `clear` member function allows to clear the wrapped container and returns +* The `clear` member function allows clearing the wrapped container and returns true in case of success. -* The `reserve` member function allows to increase the capacity of the wrapped +* The `reserve` member function allows increasing the capacity of the wrapped container and returns true in case of success.
For example, it's not possible to increase capacity of standard maps. @@ -498,7 +498,7 @@ differences in behavior in the case of key-only containers. In particular: modifies the element inside the container. * The `insert` member function is used to add elements to a container. It gets - two arguments, respectively the key and the value to insert: + two arguments, respectively, the key and the value to insert: ```cpp auto last = view.end(); @@ -536,11 +536,11 @@ Container support is minimal but likely sufficient to satisfy all needs. ## Pointer-like types -As with containers, it's also possible to _tell_ to the meta system which types +As with containers, it's also possible to _tell_ to the meta-system which types are _pointers_. This makes it possible to dereference instances of `meta_any`, thus obtaining light _references_ to pointed objects that are also correctly -associated with their meta types.
-To make the meta system recognize a type as _pointer-like_, users can specialize +associated with their meta-types.
+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: @@ -552,17 +552,17 @@ specializations available to the compiler when needed.
The same file also contains many examples for the users that are interested in making their own pointer-like types available to the meta system. -When a type is recognized as a pointer-like one by the meta system, it's +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 * +// meta-type equivalent to that of int * entt::meta_any any{&value}; if(any.type().is_pointer_like()) { - // meta type equivalent to that of int + // meta-type equivalent to that of int if(entt::meta_any ref = *any; ref) { // ... } @@ -570,7 +570,7 @@ if(any.type().is_pointer_like()) { ``` It's not necessary to perform a double check. Instead, it's enough to query the -meta type or verify that the returned object is valid. For example, invalid +meta-type or verify that the returned object is valid. For example, invalid instances are returned when the wrapped object isn't a pointer-like type.
Dereferencing a pointer-like object returns an instance of `meta_any` which _refers_ to the pointed object. Modifying it means modifying the pointed object @@ -607,29 +607,29 @@ of the pointed type, no user intervention is required. ## Template information -Meta types also provide a minimal set of information about the _nature_ of the +Meta-types also provide a minimal set of information about the _nature_ of the original type in case it's a class template.
By default, this works out of the box and requires no user action. However, it's important to include the header file `template.hpp` to make this information available to the compiler when needed. -Meta template information are easily found: +Meta-template information is easily found: ```cpp // this method returns true if the type is recognized as a class template specialization if(auto type = entt::resolve>(); type.is_template_specialization()) { - // meta type of the class template conveniently wrapped by entt::meta_class_template_tag + // meta-type of the class template conveniently wrapped by entt::meta_class_template_tag auto class_type = type.template_type(); // number of template arguments std::size_t arity = type.template_arity(); - // meta type of the i-th argument + // meta-type of the i-th argument auto arg_type = type.template_arg(0u); } ``` -Typically, when template information for a type are required, what the library +Typically, when template information for a type is required, what the library provides is sufficient. However, there are some cases where a user may want more details or a different set of information.
Consider the case of a class template that is meant to wrap function types: @@ -657,7 +657,7 @@ struct entt::meta_template_traits> { ``` The reflection system doesn't verify the accuracy of the information nor infer a -correspondence between real types and meta types.
+correspondence between real types and meta-types.
Therefore, the specialization is used as is and the information it contains is associated with the appropriate type when required. @@ -697,7 +697,7 @@ double value = any.cast(); ``` With no need for registration, the conversion takes place automatically under -the hood. The same goes for a call to `allow_cast` involving a meta type: +the hood. The same goes for a call to `allow_cast` involving a meta-type: ```cpp entt::meta_type type = entt::resolve(); @@ -708,27 +708,27 @@ int value = any.cast(); This makes working with arithmetic types and scoped or unscoped enums as easy as it is in C++.
-It's still possible to set up conversion functions manually and these are always -preferred over the automatic ones. +It's still possible to set up conversion functions manually, and these are +always preferred over the automatic ones. ## Implicitly generated default constructor -Creating objects of default constructible types through the reflection system -while not having to explicitly register the meta type or its default constructor +Creating objects of default-constructible types through the reflection system +while not having to explicitly register the meta-type or its default constructor is also possible.
For example, in the case of primitive types like `int` or `char`, but not just them. -For default constructible types only, default constructors are automatically -defined and associated with their meta types, whether they are explicitly or +For default-constructible types only, default constructors are automatically +defined and associated with their meta-types, whether they are explicitly or implicitly generated.
-Therefore, this is all is needed to construct an integer from its meta type: +Therefore, this is all needed to construct an integer from its meta-type: ```cpp entt::resolve().construct(); ``` -Where the meta type is for example the one returned from a meta container, +Where the meta-type is, for example, the one returned from a meta-container, useful for building keys without knowing or having to register the actual types. In all cases, when users register default constructors, they are preferred both @@ -736,7 +736,7 @@ during searches and when the `construct` member function is invoked. ## From void to any -Sometimes all a user has is an opaque pointer to an object of a known meta type. +Sometimes all a user has is an opaque pointer to an object of a known meta-type. It would be handy in this case to be able to construct a `meta_any` element from it.
For this purpose, the `meta_type` class offers a `from_void` member function @@ -769,10 +769,10 @@ There are a few alternatives available at the moment: since it's implicitly selected if no other policy is specified.
In this case, the return values of the functions as well as the properties exposed as data members are always returned by copy in a dedicated wrapper and - therefore associated with their original meta types. + therefore associated with their original meta-types. * The _as-void_ policy, associated with the type `entt::as_void_t`.
- Its purpose is to discard the return value of a meta object, whatever it is, + Its purpose is to discard the return value of a meta-object, whatever it is, thus making it appear as if its type were `void`: ```cpp @@ -809,8 +809,8 @@ obvious corner cases that can in turn be solved with the use of policies. As mentioned, the `data` member function is used to reflect constants of any type.
-This allows users to create meta types for enums that work exactly like any -other meta type built from a class. Similarly, arithmetic types are _enriched_ +This allows users to create meta-types for enums that work exactly like any +other meta-type built from a class. Similarly, arithmetic types are _enriched_ with constants of special meaning where required.
All values thus exported appear to users as if they were constant data members of the reflected types. This avoids the need to _export_ what is the difference @@ -827,7 +827,7 @@ entt::meta_factory{}.data<2048>("max_int"_hs); ``` Accessing them is trivial as well. It's a matter of doing the following, as with -any other data member of a meta type: +any other data member of a meta-type: ```cpp auto value = entt::resolve().data("a_value"_hs).get({}).cast(); @@ -840,7 +840,7 @@ object optimization performed by the `meta_any` class. ## User defined data Sometimes (for example, when it comes to creating an editor) it might be useful -to attach _traits_ or arbitrary _custom data_ to the meta objects created. +to attach _traits_ or arbitrary _custom data_ to the meta-objects created. The main difference between them is that: @@ -851,7 +851,7 @@ The main difference between them is that: * Custom data are stored in a generic quick access area reserved for the user and which the library will never use under any circumstances. -In all cases, this support is currently available only for meta types, meta data +In all cases, this support is currently available only for meta-types, meta-data and meta functions. ### Traits @@ -862,14 +862,14 @@ User-defined traits are set via a meta factory: entt::meta_factory{}.traits(my_traits::required | my_traits::hidden); ``` -In the example above, `EnTT` bitmask enum support is used but any integral value +In the example above, `EnTT` bitmask enum support is used, but any integral value is fine, as long as it doesn't exceed 16 bits.
It's not possible to assign traits at different times. Therefore, multiple calls to the `traits` function overwrite previous values. However, traits can be read -from meta objects and used to update existing data with a factory, effectively +from meta-objects and used to update existing data with a factory, effectively extending them as needed.
-Likewise, users can also set traits on meta objects later if needed, as long as -the factory is reset to the meta object of interest: +Likewise, users can also set traits on meta-objects later if needed, as long as +the factory is reset to the meta-object of interest: ```cpp entt::meta_factory{} @@ -877,7 +877,7 @@ entt::meta_factory{} .traits(my_traits::internal); ``` -Once created, all meta objects offer a member function named `traits` to get the +Once created, all meta-objects offer a member function named `traits` to get the currently set value: ```cpp @@ -890,7 +890,7 @@ correctly. ### Custom data -Custom arbitrary data are set via a meta factory: +Custom arbitrary data are set via a meta-factory: ```cpp entt::meta_factory{}.custom("name"); @@ -900,10 +900,10 @@ The way to do this is by specifying the data type to the `custom` function and passing the necessary arguments to construct it correctly.
It's not possible to assign custom data at different times. Therefore, multiple calls to the `custom` function overwrite previous values. However, this value -can be read from meta objects and used to update existing data with a factory, +can be read from meta-objects and used to update existing data with a factory, effectively updating them as needed.
-Likewise, users can also set custom data on meta objects later if needed, as -long as the factory is reset to the meta object of interest: +Likewise, users can also set custom data on meta-objects later if needed, as +long as the factory is reset to the meta-object of interest: ```cpp entt::meta_factory{} @@ -911,7 +911,7 @@ entt::meta_factory{} .custom("tooltip"); ``` -Once created, all meta objects offer a member function named `custom` to get the +Once created, all meta-objects offer a member function named `custom` to get the currently set value as a reference or as a pointer to an element: ```cpp @@ -929,8 +929,8 @@ A type registered with the reflection system can also be _unregistered_. This means unregistering all its data members, member functions, conversion functions and so on. However, base classes aren't unregistered as well, since they don't necessarily depend on it.
-Roughly speaking, unregistering a type means disconnecting all associated meta -objects from it and making its identifier no longer available: +Roughly speaking, unregistering a type means disconnecting all associated +meta-objects from it and making its identifier no longer available: ```cpp entt::meta_reset(); @@ -943,7 +943,7 @@ entt::meta_reset("my_type"_hs); ``` Finally, there exists a non-template overload of the `meta_reset` function that -doesn't accept arguments and resets all meta types at once: +doesn't accept arguments and resets all meta-types at once: ```cpp entt::meta_reset(); @@ -953,14 +953,14 @@ A type can be re-registered later with a completely different name and form. ## Meta context -All meta types and their parts are created at runtime and stored in a default +All meta-types and their parts are created at runtime and stored in a default _context_. This is obtained via a service locator as: ```cpp auto &&context = entt::locator::value_or(); ``` -By itself, a context is an opaque object that the user cannot do much with. +By itself, a context is an opaque object that the user can do little with. However, users can replace an existing context with another at any time: ```cpp @@ -970,12 +970,12 @@ std::swap(context, other); ``` This is useful for testing purposes or to define multiple context objects with -different meta type to use as appropriate. +different meta-types to use as appropriate. If _replacing_ the default context isn't enough, `EnTT` also offers the ability to use multiple and externally managed contexts with the runtime reflection system.
-For example, to create new meta types within a context other than the default +For example, to create new meta-types within a context other than the default one, simply pass it as an argument to the `meta_factory` constructor: ```cpp @@ -983,7 +983,7 @@ entt::meta_ctx context{}; entt::meta_factory{context}.type("reflected_type"_hs); ``` -By doing so, the new meta type isn't available in the default context but is +By doing so, the new meta-type isn't available in the default context but is usable by passing around the new context when needed, such as when creating a new `meta_any` object: @@ -991,7 +991,7 @@ new `meta_any` object: entt::meta_any any{context, std::in_place_type}; ``` -Similarly, to search for meta types in a context other than the default one, +Similarly, to search for meta-types in a context other than the default one, it's necessary to pass it to the `resolve` function: ```cpp @@ -1001,8 +1001,8 @@ entt::meta_type type = entt::resolve(context, "reflected_type"_hs) More generally, when using externally managed contexts, it's always required to provide the system with the context to use, at least at the _entry point_.
For example, once the `meta_type` instant is obtained, it's no longer necessary -to pass the context around as the meta type takes the information with it and +to pass the context around as the meta-type takes the information with it and eventually propagates it to all its parts.
-On the other hand, it's necessary to instruct the library on where meta types +On the other hand, it's necessary to instruct the library on where meta-types are to be fetched when `meta_any`s and `meta_handle`s are constructed, a factory -created or a meta type resolved. +created or a meta-type resolved. From 4edb3c8f053890e12f546e146944c49902cfe068 Mon Sep 17 00:00:00 2001 From: theaddon Date: Tue, 21 Jan 2025 14:51:11 +0100 Subject: [PATCH 11/23] fix general grammar and spelling issues in poly.md --- docs/md/poly.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/md/poly.md b/docs/md/poly.md index 644d73827..4ce7085ad 100644 --- a/docs/md/poly.md +++ b/docs/md/poly.md @@ -45,12 +45,12 @@ The ones that I like more are: object wrapper. The former is admittedly an experimental library, with many interesting ideas. -I've some doubts about the usefulness of some feature in real world projects, +I've some doubts about the usefulness of some features in real world projects, but perhaps my lack of experience comes into play here. In my opinion, its only -flaw is the API which I find slightly more cumbersome than other solutions.
-The latter was undoubtedly a source of inspiration for this module, although I +flaw is the API that I find slightly more cumbersome than other solutions.
+The latter was undoubtedly a source of inspiration for this module. Although I opted for different choices in the implementation of both the final API and some -feature. +features. Either way, the authors are gurus of the C++ community, people I only have to learn from. @@ -63,7 +63,7 @@ types will have to adhere to.
For this purpose, the library offers a single class that supports both deduced and fully defined interfaces. Although having interfaces deduced automatically is convenient and allows users to write less code in most cases, it has some -limitations and it's therefore useful to be able to get around the deduction by +limitations. It's therefore useful to be able to get around the deduction by providing a custom definition for the static virtual table. Once the interface is defined, a generic implementation is needed to fulfill the @@ -342,7 +342,7 @@ entt::basic_poly The default size is `sizeof(double[2])`, which seems like a good compromise between a buffer that is too large and one unable to hold anything larger than -an integer. The alignment requirement is optional and by default such that it's +an integer. The alignment requirement is optional, and by default such that it's the most stringent (the largest) for any object whose size is at most equal to the one provided.
It's worth noting that providing a size of 0 (which is an accepted value in all From 205bb64b5b4faf81d56b457b21fe512a17775138 Mon Sep 17 00:00:00 2001 From: theaddon Date: Tue, 21 Jan 2025 14:56:27 +0100 Subject: [PATCH 12/23] fix general grammar and spelling issues in process.md --- docs/md/process.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/md/process.md b/docs/md/process.md index bf931a423..517274c8e 100644 --- a/docs/md/process.md +++ b/docs/md/process.md @@ -29,7 +29,7 @@ to _override_ the default behavior): This is invoked once per tick until a process is explicitly aborted or ends either with or without errors. Even though it's not mandatory to declare this - member function, as a rule of thumb each process should at least define it to + member function. As a rule of thumb, each process should at least define it to work _properly_. The `void *` parameter is an opaque pointer to user data (if any) forwarded directly to the process during an update. @@ -110,21 +110,21 @@ Parameters have the following meaning: Both `succeed` and `fail` accept no parameters at all. Note that usually users shouldn't worry about creating adaptors at all. A -scheduler creates them internally each and every time a lambda or a functor is +scheduler creates them internally, each and every time a lambda or a functor is used as a process. # The scheduler -A cooperative scheduler runs different processes and helps managing their life +A cooperative scheduler runs different processes and helps manage their life cycles. Each process is invoked once per tick. If it terminates, it's removed -automatically from the scheduler and it's never invoked again. Otherwise, it's -a good candidate to run one more time the next tick.
+automatically from the scheduler, and it's never invoked again. Otherwise, +it's a good candidate to run one more time the next tick.
A process can also have a _child_. In this case, the parent process is replaced with its child when it terminates and only if it returns with success. In case of errors, both the parent process and its child are discarded. This way, it's -easy to create chain of processes to run sequentially. +easy to create a chain of processes to run sequentially. Using a scheduler is straightforward. To create it, users must provide only the type for the elapsed times and no arguments at all: @@ -154,7 +154,7 @@ entt::scheduler::size_type size = scheduler.size(); scheduler.clear(); ``` -To attach a process to a scheduler there are mainly two ways: +To attach a process to a scheduler, there are mainly two ways: * If the process inherits from the `process` class template, it's enough to indicate its type and submit all the parameters required to construct it to From 794313a0b6c4deaa4bf1b31d3023cc3dd610b5fe Mon Sep 17 00:00:00 2001 From: theaddon Date: Tue, 21 Jan 2025 14:58:59 +0100 Subject: [PATCH 13/23] fix general grammar and spelling issues in reference.md --- docs/md/reference.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/md/reference.md b/docs/md/reference.md index 02bec2266..6e7d0afde 100644 --- a/docs/md/reference.md +++ b/docs/md/reference.md @@ -14,7 +14,7 @@ Others developed different architectures from scratch and therefore offer alternative solutions with their pros and cons. If you know of other similar projects out there, feel free to open an issue or a -PR and I'll be glad to add them to this page.
+PR, and I'll be glad to add them to this page.
I hope the following lists can grow much more in the future. # Similar projects @@ -34,12 +34,12 @@ details. * [lent](https://github.com/nem0/lent): the Donald Trump of the ECS libraries. * C++: - * [decs](https://github.com/vblanco20-1/decs): a chunk based archetype ECS. + * [decs](https://github.com/vblanco20-1/decs): a chunk-based archetype ECS. * [ecst](https://github.com/SuperV1234/ecst): a multithreaded compile-time ECS that uses sparse sets to keep track of entities in systems. * [EntityX](https://github.com/alecthomas/entityx): a bitset based ECS that uses a single large matrix of components indexed with entities. - * [Gaia-ECS](https://github.com/richardbiely/gaia-ecs): a chunk based + * [Gaia-ECS](https://github.com/richardbiely/gaia-ecs): a chunk-based archetype ECS. * [Polypropylene](https://github.com/pmbittner/Polypropylene): a hybrid solution between an ECS and dynamic mixins. @@ -53,10 +53,10 @@ details. with focus on performance and minimal GC allocations. * [LeoECS](https://github.com/Leopotam/ecs): simple lightweight C# Entity Component System framework. - * [Massive ECS](https://github.com/nilpunch/massive): sparse set based ECS + * [Massive ECS](https://github.com/nilpunch/massive): sparse set-based ECS featuring rollbacks. * [Svelto.ECS](https://github.com/sebas77/Svelto.ECS): a very interesting - platform agnostic and table based ECS framework. + platform-agnostic- and table-based ECS framework. * Go: * [gecs](https://github.com/tutumagi/gecs): a sparse sets based ECS inspired @@ -79,7 +79,7 @@ details. * Rust: * [Shipyard](https://github.com/leudz/shipyard): it borrows some ideas from `EnTT` and offers a sparse sets based ECS with grouping functionalities. - * [Sparsey](https://github.com/LechintanTudor/sparsey): sparse set based ECS + * [Sparsey](https://github.com/LechintanTudor/sparsey): sparse set-based ECS written in Rust. * [Specs](https://github.com/amethyst/specs): a parallel ECS based mainly on hierarchical bitsets that allows different types of storage as needed. From 5a1300d5d19fc73b4f80e71494283c88a2220a42 Mon Sep 17 00:00:00 2001 From: theaddon Date: Tue, 21 Jan 2025 15:03:20 +0100 Subject: [PATCH 14/23] fix general grammar and spelling issues in resource.md --- docs/md/resource.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/md/resource.md b/docs/md/resource.md index 23998eabc..d9b5db945 100644 --- a/docs/md/resource.md +++ b/docs/md/resource.md @@ -31,7 +31,7 @@ The _resource_ is an image, an audio, a video or any other type: struct my_resource { const int value; }; ``` -The _loader_ is a callable type the aim of which is to load a specific resource: +The _loader_ is a callable type, the aim of which is to load a specific resource: ```cpp struct my_loader final { @@ -180,6 +180,6 @@ It's worth mentioning that the iterators of a cache as well as its indexing operators return resource handles rather than instances of the mapped type.
Since the cache has no control over the loader and a resource isn't required to also be convertible to bool, these handles can be invalid. This usually means an -error in the user logic but it may also be an _expected_ event.
+error in the user logic, but it may also be an _expected_ event.
It's therefore recommended to verify handles validity with a check in debug (for example, when loading) or an appropriate logic in retail. From 77ceb3389746c202cb3b6f22e0138f56d8e67c08 Mon Sep 17 00:00:00 2001 From: theaddon Date: Tue, 21 Jan 2025 15:17:19 +0100 Subject: [PATCH 15/23] fix general grammar and spelling issues in signal.md --- docs/md/signal.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/md/signal.md b/docs/md/signal.md index 188ee5386..705267aa2 100644 --- a/docs/md/signal.md +++ b/docs/md/signal.md @@ -19,7 +19,7 @@ in general.
They help to decouple the various parts of a system while allowing them to communicate with each other somehow. -The so called _modern C++_ comes with a tool that can be useful in this regard, +The so-called _modern C++_ comes with a tool that can be useful in this regard, the `std::function`. As an example, it can be used to create delegates.
However, there is no guarantee that an `std::function` doesn't perform allocations under the hood and this could be problematic sometimes. Furthermore, @@ -75,7 +75,7 @@ function type of the delegate is such that the parameter list is empty and the value of the data member is at least convertible to the return type. Free functions having type equivalent to `void(T &, args...)` are accepted as -well. The first argument `T &` is considered a payload and the function will +well. The first argument `T &` is considered a payload, and the function will receive it back every time it's invoked. In other terms, this works just fine with the above definition: @@ -107,7 +107,7 @@ In fact, this filtering works both ways. The class tries to pass its first _count_ arguments **first**, then the last _count_. Watch out for conversion rules if in doubt when connecting a listener!
Arbitrary functions that pull random arguments from the delegate list aren't -supported instead. Other feature were preferred, such as support for functions +supported instead. Other features were preferred, such as support for functions with compatible argument lists although not equal to those of the delegate. To create and initialize a delegate at once, there are a few specialized @@ -143,7 +143,7 @@ fine. As a side note, members of classes may or may not be associated with instances. If they are not, the first argument of the function type must be that of the -class on which the members operate and an instance of this class must obviously +class on which the members operate, and an instance of this class must obviously be passed when invoking the delegate: ```cpp @@ -252,12 +252,12 @@ particular delegate through its descriptive _traits_ instead. # Signals -Signal handlers work with references to classes, function pointers and pointers -to members. Listeners can be any kind of objects and users are in charge of +Signal handlers work with references to classes, function pointers, and pointers +to members. Listeners can be any kind of objects, and users are in charge of connecting and disconnecting them from a signal to avoid crashes due to different lifetimes. On the other side, performance shouldn't be affected that much by the presence of such a signal handler.
-Signals make use of delegates internally and therefore they undergo the same +Signals make use of delegates internally, and therefore they undergo the same rules and offer similar functionalities. It may be a good idea to consult the documentation of the `delegate` class for further information. @@ -476,7 +476,7 @@ parameter for it but rather a different function: dispatcher.enqueue_hint("custom"_hs, 42); ``` -This is mainly due to the template argument deduction rules and unfortunately +This is mainly due to the template argument deduction rules, and unfortunately, there is no real (elegant) way to avoid it. # Event emitter @@ -556,4 +556,4 @@ if(emitter.contains()) { This class introduces a _nice-to-have_ model based on events and listeners.
More in general, it's a handy tool when the derived classes _wrap_ asynchronous -operations but it's not limited to such uses. +operations, but it's not limited to such uses. From 376a04814c47ee73baf62464a734072965dce9cb Mon Sep 17 00:00:00 2001 From: theaddon Date: Tue, 21 Jan 2025 15:57:32 +0100 Subject: [PATCH 16/23] use full forms in every file --- docs/md/config.md | 18 +-- docs/md/container.md | 6 +- docs/md/core.md | 102 +++++++-------- docs/md/entity.md | 302 +++++++++++++++++++++---------------------- docs/md/faq.md | 26 ++-- docs/md/graph.md | 46 +++---- docs/md/lib.md | 16 +-- docs/md/links.md | 12 +- docs/md/locator.md | 18 +-- docs/md/meta.md | 122 ++++++++--------- docs/md/poly.md | 40 +++--- docs/md/process.md | 24 ++-- docs/md/reference.md | 8 +- docs/md/resource.md | 24 ++-- docs/md/signal.md | 56 ++++---- docs/md/unreal.md | 6 +- 16 files changed, 413 insertions(+), 413 deletions(-) diff --git a/docs/md/config.md b/docs/md/config.md index 55d58a03e..02f82ef39 100644 --- a/docs/md/config.md +++ b/docs/md/config.md @@ -22,14 +22,14 @@ respects. These variables are just one of the many ways to customize how it works.
In the vast majority of cases, users will have no interest in changing the default parameters. For all other cases, the list of possible configurations -with which it's possible to adjust the behavior of the library at runtime can be +with which it is possible to adjust the behavior of the library at runtime can be found below. # Definitions All options are intended as parameters to the compiler (or user-defined macros within the compilation units, if preferred).
-Each parameter can result in internal library definitions. It's not recommended +Each parameter can result in internal library definitions. It is not recommended to try to also modify these definitions, since there is no guarantee that they will remain stable over time unlike the options below. @@ -42,10 +42,10 @@ also limited to this library only. ## ENTT_USE_ATOMIC -In general, `EnTT` doesn't offer primitives to support multi-threading. Many of +In general, `EnTT` does not offer primitives to support multi-threading. Many of the features can be split over multiple threads without any explicit control and the user is the one who knows if a synchronization point is required.
-However, some features aren't easily accessible to users and are made +However, some features are not easily accessible to users and are made thread-safe by means of this definition. ## ENTT_ID_TYPE @@ -57,7 +57,7 @@ default type if necessary. ## ENTT_SPARSE_PAGE -It's known that the ECS module of `EnTT` is based on _sparse sets_. What is less +It is known that the ECS module of `EnTT` is based on _sparse sets_. What is less known perhaps is that the sparse arrays are paged to reduce memory usage.
Default size of pages (that is, the number of elements they contain) is 4096 but users can adjust it if appropriate. In all cases, the chosen value **must** be a @@ -66,7 +66,7 @@ power of 2. ## ENTT_PACKED_PAGE As it happens with sparse arrays, packed arrays are also paginated. However, in -this case the aim isn't to reduce memory usage but to have pointer stability +this case the aim is not to reduce memory usage but to have pointer stability upon component creation.
Default size of pages (that is, the number of elements they contain) is 1024 but users can adjust it if appropriate. In all cases, the chosen value **must** be a @@ -74,7 +74,7 @@ power of 2. ## ENTT_ASSERT -For performance reasons, `EnTT` doesn't use exceptions or any other control +For performance reasons, `EnTT` does not use exceptions or any other control structures. In fact, it offers many features that result in undefined behavior if not used correctly.
To get around this, the library relies on a lot of asserts for the purpose of @@ -83,7 +83,7 @@ are allowed to overwrite its behavior by setting this variable. ### ENTT_ASSERT_CONSTEXPR -Usually, an assert within a `constexpr` function isn't a big deal. However, in +Usually, an assert within a `constexpr` function is not a big deal. However, in case of extreme customizations, it might be useful to differentiate.
For this purpose, `EnTT` introduces an admittedly badly named variable to make the job easier in this regard. By default, this variable forwards its arguments @@ -109,6 +109,6 @@ dedicated storage for them. `EnTT` mixes non-standard language features with others that are perfectly compliant to offer some of its functionalities.
This definition prevents the library from using non-standard techniques, that -is, functionalities that aren't fully compliant with the standard C++.
+is, functionalities that are not fully compliant with the standard C++.
While there are no known portability issues at the time of this writing, this should make the library fully portable anyway if needed. diff --git a/docs/md/container.md b/docs/md/container.md index 0ff41f36e..43aa0eaac 100644 --- a/docs/md/container.md +++ b/docs/md/container.md @@ -12,16 +12,16 @@ # Introduction The standard C++ library offers a wide range of containers and adaptors already. -It's really difficult to do better (although it's very easy to do worse, as many +It is really difficult to do better (although it is very easy to do worse, as many examples available online demonstrate).
-`EnTT` doesn't try in any way to replace what is offered by the standard. Quite +`EnTT` does not try in any way to replace what is offered by the standard. Quite the opposite, given the widespread use that is made of standard containers.
However, the library also tries to fill a gap in features and functionalities by making available some containers and adaptors initially developed for internal use. This section of the library is likely to grow larger over time. However, for the -moment it's quite small and mainly aimed at satisfying some internal needs.
+moment it is quite small and mainly aimed at satisfying some internal needs.
For all containers and adaptors made available, full test coverage and stability over time is guaranteed as usual. diff --git a/docs/md/core.md b/docs/md/core.md index c6422bbe5..541ff2b80 100644 --- a/docs/md/core.md +++ b/docs/md/core.md @@ -41,7 +41,7 @@ `EnTT` comes with a bunch of core functionalities mostly used by the other parts of the library.
-Many of these tools are also useful in everyday work. Therefore, it's worth +Many of these tools are also useful in everyday work. Therefore, it is worth describing them so as not to reinvent the wheel in case of need. # Any as in any type @@ -49,7 +49,7 @@ describing them so as not to reinvent the wheel in case of need. `EnTT` offers its own `any` type. It may seem redundant considering that C++17 introduced `std::any`, but it is not (hopefully).
First of all, the _type_ returned by an `std::any` is a const reference to an -`std::type_info`, an implementation defined class that's not something everyone +`std::type_info`, an implementation defined class that is not something everyone wants to see in a software. Furthermore, there is no way to bind it to the type system of the library and therefore with its integrated RTTI support. @@ -76,7 +76,7 @@ entt::any in_place{std::in_place, std::make_unique(42).release()}; ``` Alternatively, the `make_any` function serves the same purpose. It requires to -always be explicit about the type and doesn't support taking ownership: +always be explicit about the type and does not support taking ownership: ```cpp entt::any any = entt::make_any(42); @@ -85,8 +85,8 @@ entt::any any = entt::make_any(42); In all cases, the `any` class takes the burden of destroying the contained element when required, regardless of the storage strategy used for the specific object.
-Furthermore, an instance of `any` isn't tied to an actual type. Therefore, the -wrapper is reconfigured when it's assigned a new object of a type other than +Furthermore, an instance of `any` is not tied to an actual type. Therefore, the +wrapper is reconfigured when it is assigned a new object of a type other than the one it contains. There is also a way to directly assign a value to the variable contained by an @@ -118,7 +118,7 @@ The type is also used internally when comparing two `any` objects: if(any == empty) { /* ... */ } ``` -In this case, before proceeding with a comparison, it's verified that the _type_ +In this case, before proceeding with a comparison, it is verified that the _type_ of the two objects is actually the same.
Refer to the `EnTT` type system documentation for more details about how `type_info` works and the possible risks of a comparison. @@ -138,9 +138,9 @@ any.emplace(value); In other words, whenever `any` is explicitly told to construct an _alias_, it acts as a pointer to the original instance rather than making a copy of it or -moving it internally. The contained object is never destroyed and users must +moving it internally. The contained object is never destroyed, and users must ensure that its lifetime exceeds that of the container.
-Similarly, it's possible to create non-owning copies of `any` from an existing +Similarly, it is possible to create non-owning copies of `any` from an existing object: ```cpp @@ -148,12 +148,12 @@ object: entt::any ref = other.as_ref(); ``` -In this case, it doesn't matter if the original container actually holds an +In this case, it does not matter if the original container actually holds an object or is as a reference for unmanaged elements already. The new instance -thus created doesn't create copies and only serves as a reference for the +thus created does not create copies and only serves as a reference for the original item. -It's worth mentioning that, while everything works transparently when it comes +It is worth mentioning that, while everything works transparently when it comes to non-const references, there are some exceptions when it comes to const references.
In particular, the `data` member function invoked on a non-const instance of @@ -161,7 +161,7 @@ In particular, the `data` member function invoked on a non-const instance of To cast an instance of `any` to a type, the library offers a set of `any_cast` functions in all respects similar to their most famous counterparts.
-The only difference is that, in the case of `EnTT`, they won't raise exceptions +The only difference is that, in the case of `EnTT`, they will not raise exceptions but will only trigger an assert in debug mode, otherwise resulting in undefined behavior in case of misuse in release mode. @@ -188,7 +188,7 @@ and always dynamically allocates objects (except for aliasing cases). The alignment requirement is optional and by default the most stringent (the largest) for any object whose size is at most equal to the one provided.
-It's provided as an optional second parameter following the desired size for the +It is provided as an optional second parameter following the desired size for the internal storage: ```cpp @@ -234,16 +234,16 @@ entt::compressed_pair pair{0, 3.}; pair.first() = 42; ``` -There isn't much to describe then. It's recommended to rely on documentation and -intuition. At the end of the day, it's just a pair and nothing more. +There is not much to describe then. It is recommended to rely on documentation and +intuition. At the end of the day, it is just a pair and nothing more. # Enum as bitmask -Sometimes it's useful to be able to use enums as bitmasks. However, enum classes -aren't really suitable for the purpose. Main problem is that they don't convert +Sometimes it is useful to be able to use enums as bitmasks. However, enum classes +are not really suitable for the purpose. Main problem is that they do not convert implicitly to their underlying type.
The choice is then between using old-fashioned enums (with all their problems -that I don't want to discuss here) or writing _ugly_ code. +that I do not want to discuss here) or writing _ugly_ code. Fortunately, there is also a third way: adding enough operators in the global scope to treat enum classes as bitmasks transparently.
@@ -276,7 +276,7 @@ struct entt::enum_as_bitmask ``` This is handy when dealing with enum classes defined by third party libraries -and over which the user has no control. However, it's also verbose and can be +and over which the user has no control. However, it is also verbose and can be avoided by adding a specific value to the enum class itself: ```cpp @@ -339,7 +339,7 @@ entt::hashed_string str{orig.c_str()}; const auto hash = entt::hashed_string::value(orig.c_str()); ``` -This possibility shouldn't be exploited in tight loops, since the computation +This possibility should not be exploited in tight loops, since the computation takes place at runtime and no longer at compile-time. It could therefore affect performance to some degrees. @@ -362,16 +362,16 @@ The hash type of `hashed_wstring` is the same as its counterpart. The hashed string class uses FNV-1a internally to hash strings. Because of the _pigeonhole principle_, conflicts are possible. This is a fact.
There is no silver bullet to solve the problem of conflicts when dealing with -hashing functions. In this case, the best solution is likely to give up. That's +hashing functions. In this case, the best solution is likely to give up. That is all.
-After all, human-readable unique identifiers aren't something strictly defined +After all, human-readable unique identifiers are not something strictly defined and over which users have not the control. Choosing a slightly different identifier is probably the best solution to make the conflict disappear in this case. # Iterators -Writing and working with iterators isn't always easy. More often than not it +Writing and working with iterators is not always easy. More often than not it also leads to duplicated code.
`EnTT` tries to overcome this problem by offering some utilities designed to make this hard work easier. @@ -379,12 +379,12 @@ make this hard work easier. ## Input iterator pointer When writing an input iterator that returns in-place constructed values if -dereferenced, it's not always straightforward to figure out what `value_type` is +dereferenced, it is not always straightforward to figure out what `value_type` is and how to make it behave like a full-fledged pointer.
Conversely, it would be very useful to have an `operator->` available on the iterator itself that always works without too much complexity. -The input iterator pointer is meant for this. It's a small class that wraps the +The input iterator pointer is meant for this. It is a small class that wraps the in-place constructed value and adds some functions on top of it to make it suitable for use with input iterators: @@ -436,7 +436,7 @@ _iterable_ object with all the expected methods like `begin`, `end` and whatnot. The library uses this class extensively.
Think for example of views, which can be iterated to access entities but also -offer a method of obtaining an iterable object that returns tuples of entities +offer a method for obtaining an iterable object that returns tuples of entities and components at once.
Another example is the registry class which allows users to iterate its storage by returning an iterable object for the purpose. @@ -452,13 +452,13 @@ everyday problems. The former are very specific and for niche problems. These are tools designed to unwrap fancy or plain pointers (`to_address`) or to help forget the meaning of acronyms like _POCCA_, _POCMA_ or _POCS_.
-I won't describe them here in detail. Instead, I recommend reading the inline +I will not describe them here in detail. Instead, I recommend reading the inline documentation to those interested in the subject. ## Allocator aware unique pointers A nasty thing in C++ (at least up to C++20) is the fact that shared pointers -support allocators while unique pointers don't.
+support allocators while unique pointers do not.
There is a proposal at the moment that also shows (among the other things) how this can be implemented without any compiler support. @@ -509,9 +509,9 @@ library or that will never be. Runtime type identification support (or RTTI) is one of the most frequently disabled features in the C++ world, especially in the gaming sector. Regardless -of the reasons for this, it's often a shame not to be able to rely on opaque +of the reasons for this, it is often a shame not to be able to rely on opaque type information at runtime.
-The library tries to fill this gap by offering a built-in system that doesn't +The library tries to fill this gap by offering a built-in system that does not serve as a replacement but comes very close to being one and offers similar information to that provided by its counterpart. @@ -523,7 +523,7 @@ Basically, the whole system relies on a handful of classes. In particular: auto index = entt::type_index::value(); ``` - The returned value isn't guaranteed to be stable across different runs.
+ The returned value is not guaranteed to be stable across different runs.
However, it can be very useful as index in associative and unordered associative containers or for positional accesses in a vector or an array. @@ -551,7 +551,7 @@ Basically, the whole system relies on a handful of classes. In particular: ``` In general, the `value` function exposed by `type_hash` is also `constexpr` - but this isn't guaranteed for all compilers and platforms (although it's valid + but this is not guaranteed for all compilers and platforms (although it is valid with the most well-known and popular ones). This function **can** use non-standard features of the language for its own @@ -574,7 +574,7 @@ Basically, the whole system relies on a handful of classes. In particular: This value is extracted from some information generally made available by the compiler in use. Therefore, it may differ depending on the compiler and may be - empty in the event that this information isn't available.
+ empty in the event that this information is not available.
For example, given the following class: ```cpp @@ -586,7 +586,7 @@ Basically, the whole system relies on a handful of classes. In particular: Most of the time the name is also retrieved at compile-time and is therefore always returned through an `std::string_view`. Users can easily access it and modify it as needed, for example by removing the word `struct` to normalize - the result. `EnTT` doesn't do this for obvious reasons, since it would be + the result. `EnTT` does not do this for obvious reasons, since it would be creating a new string at runtime otherwise. This function **can** use non-standard features of the language for its own @@ -602,8 +602,8 @@ similar to that made available by the standard library. ### Type info -The `type_info` class isn't a drop-in replacement for `std::type_info` but can -provide similar information which are not implementation defined and don't +The `type_info` class is not a drop-in replacement for `std::type_info` but can +provide similar information which are not implementation defined and do not require to enable RTTI.
Therefore, they can sometimes be even more reliable than those obtained otherwise. @@ -676,7 +676,7 @@ described above. Since the default non-standard, compile-time implementation of `type_hash` makes use of hashed strings, it may happen that two types are assigned the same hash value.
-In fact, although this is quite rare, it's not entirely excluded. +In fact, although this is quite rare, it is not entirely excluded. Another case where two types are assigned the same identifier is when classes from different contexts (for example two or more libraries loaded at runtime) @@ -685,8 +685,8 @@ value for the two types.
Fortunately, there are several easy ways to deal with this: * The most trivial one is to define the `ENTT_STANDARD_CPP` macro. Runtime - identifiers don't suffer from the same problem in fact. However, this solution - doesn't work well with a plugin system, where the libraries aren't linked. + identifiers do not suffer from the same problem in fact. However, this solution + does not work well with a plugin system, where the libraries are not linked. * Another possibility is to specialize the `type_name` class for one of the conflicting types, in order to assign it a custom identifier. This is probably @@ -712,10 +712,10 @@ offered by this module. ### Size of The standard operator `sizeof` complains if users provide it with functions or -incomplete types. On the other hand, it's guaranteed that its result is always +incomplete types. On the other hand, it is guaranteed that its result is always non-zero, even if applied to an empty class type.
This small class combines the two and offers an alternative to `sizeof` that -works under all circumstances, returning zero if the type isn't supported: +works under all circumstances, returning zero if the type is not supported: ```cpp const auto size = entt::size_of_v; @@ -750,7 +750,7 @@ using type = entt::constness_as_t; ``` The trait is subject to the rules of the language. For example, _transferring_ -constness between references won't give the desired effect. +constness between references will not give the desired effect. ### Member class type @@ -808,7 +808,7 @@ where types would be required otherwise. As an example: registry.emplace>(entity); ``` -However, this isn't the only permitted use. Literally any value convertible to +However, this is not the only permitted use. Literally any value convertible to `id_type` is a good candidate, such as the named constants of an unscoped enum. ### Type list and value list @@ -830,7 +830,7 @@ type list: * `type_list_diff[_t]` to remove types from type lists. * `type_list_transform[_t]` to _transform_ a range and create another type list. -I'm also pretty sure that more and more utilities will be added over time as +I am also pretty sure that more and more utilities will be added over time as needs to become apparent.
Many of these functionalities also exist in their version dedicated to value lists. We therefore have `value_list_element[_v]` as well as @@ -838,7 +838,7 @@ lists. We therefore have `value_list_element[_v]` as well as # Unique sequential identifiers -Sometimes it's useful to be able to give unique, sequential numeric identifiers +Sometimes it is useful to be able to give unique, sequential numeric identifiers to types either at compile-time or runtime.
There are plenty of different solutions for this out there, and I could have used one of them. However, I decided to spend my time to define a couple of tools @@ -908,17 +908,17 @@ numeric identifier for the given type.
The generator is customizable, so as to get different _sequences_ for different purposes if needed. -Identifiers aren't guaranteed to be stable across different runs. Indeed it +Identifiers are not guaranteed to be stable across different runs. Indeed it mostly depends on the flow of execution. # Utilities -It's not possible to escape the temptation to add utilities of some kind to a +It is not possible to escape the temptation to add utilities of some kind to a library. In fact, `EnTT` also provides a handful of tools to simplify the life of developers: * `entt::identity`: the identity function object that will be available with - C++20. It returns its argument unchanged and nothing more. It's useful as a + C++20. It returns its argument unchanged and nothing more. It is useful as a sort of _do nothing_ function in template programming. * `entt::overload`: a tool to disambiguate different overloads from their @@ -964,7 +964,7 @@ life of developers: callable object that supports multiple types at once. * `entt::y_combinator`: this is a C++ implementation of **the** _y-combinator_. - If it's not clear what it is, there is probably no need for this utility.
+ If it is not clear what it is, there is probably no need for this utility.
Below is a small example to show its use: ```cpp @@ -975,8 +975,8 @@ life of developers: const auto result = gauss(3u); ``` - Maybe convoluted at a first glance but certainly effective. Unfortunately, - the language doesn't make it possible to do much better. + Maybe convoluted at first glance but certainly effective. Unfortunately, + the language does not make it possible to do much better. This is a rundown of the (actually few) utilities made available by `EnTT`. The list will probably grow over time, but the size of each will remain rather small, diff --git a/docs/md/entity.md b/docs/md/entity.md index 9fb5419ff..b84110a73 100644 --- a/docs/md/entity.md +++ b/docs/md/entity.md @@ -74,7 +74,7 @@ used mostly in game development. ## Type-less and bitset-free -The library implements a sparse set based model that doesn't require users to +The library implements a sparse set-based model that does not require users to specify the set of components neither at compile-time nor at runtime.
This is why users can instantiate the core class simply like: @@ -88,18 +88,18 @@ In place of its more annoying and error-prone counterpart: entt::registry registry; ``` -Furthermore, it isn't necessary to announce the existence of a component type. -When the time comes, just use it and that's all. +Furthermore, it is not necessary to announce the existence of a component type. +When the time comes, just use it and that is all. ## Build your own The ECS module (as well as the rest of the library) is designed as a set of containers that are used as needed, just like a vector or any other container. -It doesn't attempt in any way to take over on the user codebase, nor to control +It does not attempt in any way to take over on the user codebase, nor to control its main loop or process scheduling.
Unlike other more or less well known models, it also makes use of independent pools that are extended via _static mixins_. The built-in signal support is an -example of this flexible design: defined as a mixin, it's easily disabled if not +example of this flexible design: defined as a mixin, it is easily disabled if not needed. Similarly, the storage class has a specialization that shows how everything is customizable down to the smallest detail. @@ -112,7 +112,7 @@ When it comes to using an entity-component system, the tradeoff is usually between performance and memory usage. The faster it is, the more memory it uses. Even worse, some approaches tend to heavily affect other functionalities like the construction and destruction of components to favor iterations, even when it -isn't strictly required. In fact, slightly worse performance along non-critical +is not strictly required. In fact, slightly worse performance along non-critical paths are the right price to pay to reduce memory usage and have overall better performance.
`EnTT` follows a completely different approach. It gets the best out from the @@ -130,12 +130,12 @@ designed around this need and give the possibility to get this information. # Vademecum The `entt::entity` type implements the concept of _entity identifier_. An entity -(the _E_ of an _ECS_) is an opaque element to use as-is. Inspecting it isn't +(the _E_ of an _ECS_) is an opaque element to use as-is. Inspecting it is not recommended since its format can change in future.
Components (the _C_ of an _ECS_) are of any type, without any constraints, not even that of being movable. No need to register them nor their types.
Systems (the _S_ of an _ECS_) are plain functions, functors, lambdas and so on. -It's not required to announce them in any case and have no requirements. +It is not required to announce them in any case and have no requirements. The next sections go into detail on how to use the entity-component system part of the `EnTT` library.
@@ -177,7 +177,7 @@ registry.destroy(view.begin(), view.end()); In addition to offering an overload to force the version upon destruction.
This function removes all components from an entity before releasing it. There -also exists a _lighter_ alternative that doesn't query component pools, for use +also exists a _lighter_ alternative that does not query component pools, for use with orphaned entities: ```cpp @@ -186,7 +186,7 @@ registry.release(entity); ``` As with the `destroy` function, also in this case entity ranges are supported -and it's possible to force a _version_. +and it is possible to force a _version_. In both cases, when an identifier is released, the registry can freely reuse it internally. In particular, the version of an entity is increased (unless the @@ -226,7 +226,7 @@ vel.dy = 0.; The default storage _detects_ aggregate types internally and exploits aggregate initialization when possible.
-Therefore, it's not strictly necessary to define a constructor for each type. +Therefore, it is not strictly necessary to define a constructor for each type. The `insert` member function works with _ranges_ and is used to: @@ -260,7 +260,7 @@ registry.patch(entity, [](auto &pos) { pos.x = pos.y = 0.; }); registry.replace(entity, 0., 0.); ``` -When it's unknown whether an entity already owns an instance of a component, +When it is unknown whether an entity already owns an instance of a component, `emplace_or_replace` is the function to use instead: ```cpp @@ -331,7 +331,7 @@ const auto [cpos, cvel] = cregistry.get(entity); auto [pos, vel] = registry.get(entity); ``` -If the existence of the component isn't certain, `try_get` is the more suitable +If the existence of the component is not certain, `try_get` is the more suitable function instead. ## Observe changes @@ -394,7 +394,7 @@ There are also some limitations on what a listener can and cannot do: listener should be avoided. It can lead to undefined behavior in some cases. * Removing the component from within the body of a listener that observes the - construction or update of instances of a given type isn't allowed. + construction or update of instances of a given type is not allowed. * Assigning and removing components from within the body of a listener that observes the destruction of instances of a given type should be avoided. It @@ -404,9 +404,9 @@ There are also some limitations on what a listener can and cannot do: Please, refer to the documentation of the signal class to know about all the features it offers.
-There are many useful but less known functionalities that aren't described here, +There are many useful but less known functionalities that are not described here, such as the connection objects or the possibility to attach listeners with a -list of parameters that is shorter than that of the signal itself. +list of parameters that are shorter than that of the signal itself. ### Entity lifecycle @@ -417,11 +417,11 @@ type instead of the component type: registry.on_construct().connect<&my_listener>(); ``` -Since entity storage is unique within a registry, if a _name_ is provided it's +Since entity storage is unique within a registry, if a _name_ is provided it is ignored and therefore discarded.
As for the function signature, this is exactly the same as the components. -Entities support all types of signals: construct, destroy and update. The latter +Entities support all types of signals: construct, destroy, and update. The latter is perhaps ambiguous as an entity is not truly _updated_. Rather, its identifier is created and finally released.
Indeed, the update signal is meant to send _general notifications_ regarding an @@ -443,12 +443,12 @@ making it difficult for the user to write component listeners. The destruction order of the storage classes and therefore the disconnection of the listeners is completely random.
-There are no guarantees today and while a logic is easily discerned, it's not +There are no guarantees today, and while the logic is easily discerned, it is not guaranteed that it will remain so in the future. For example, a listener getting disconnected after a component is discarded as a result of pool destruction is most likely a recipe for problems.
-Rather, it's advisable to invoke the `clear` function of the registry before +Rather, it is advisable to invoke the `clear` function of the registry before destroying it. This forces the deletion of all components and entities without ever discarding the pools.
As a result, a listener that wants to access components, entities, or pools can @@ -457,14 +457,14 @@ the various elements as appropriate. ## They call me reactive storage -Signals are the basic tools to construct reactive systems, even if they aren't +Signals are the basic tools to construct reactive systems, even if they are not enough on their own. `EnTT` tries to take another step in that direction with its _reactive mixin_.
In order to explain what reactive systems are, this is a slightly revised quote from the documentation of the library that first introduced this tool, [Entitas](https://github.com/sschmid/Entitas-CSharp): -> Imagine you have 100 fighting units on the battlefield but only 10 of them +> Imagine you have 100 fighting units on the battlefield, but only 10 of them > changed their positions. Instead of using a normal system and updating all 100 > entities depending on the position, you can use a reactive system which will > only update the 10 changed units. So efficient. @@ -489,7 +489,7 @@ storage.bind(registry); In this case, it must be provided with a reference registry for subsequent operations.
-Alternatively, when using the value type provided by `EnTT`, it's also possible +Alternatively, when using the value type provided by `EnTT`, it is also possible to create a reactive storage directly inside a registry: ```cpp @@ -497,9 +497,9 @@ entt::registry registry{}; auto &storage = registry.storage("observer"_hs); ``` -In the latter case there is the advantage that, in the event of destruction of +In the latter case, there is the advantage that, in the event of destruction of an entity, this storage is also automatically cleaned up.
-Also note that, unlike all other storage, these classes don't support signals by +Also note that, unlike all other storage, these classes do not support signals by default (although they can be enabled if necessary). Once it has been created and associated with a registry, the reactive mixin @@ -517,7 +517,7 @@ storage .on_destroy(); ``` -It goes without saying that it's possible to observe multiple events of the same +It goes without saying that it is possible to observe multiple events of the same type or of different types with the same storage.
For example, to know which entities have been assigned or updated a component of a certain type: @@ -572,7 +572,7 @@ options: As highlighted in the last example, the reactive mixin tracks the entities that match the given conditions and saves them aside. However, this behavior can be changed.
-For example, it's possible to _capture_ all and only the entities for which a +For example, it is possible to _capture_ all and only the entities for which a certain component has been updated but only if a specific value is within a given range: @@ -592,7 +592,7 @@ storage.on_update(); This makes reactive storage extremely flexible and usable in a large number of cases.
-Finally, once the entities of interest have been collected, it's possible to +Finally, once the entities of interest have been collected, it is possible to _visit_ the storage like any other: ```cpp @@ -625,7 +625,7 @@ available via the `registry` function. It should be noted that a reactive storage never deletes its entities (and elements, if any). To process and then discard entities at regular intervals, refer to the `clear` function available by default for each storage type.
-Similarly, the reactive mixin doesn't disconnect itself from observed storages +Similarly, the reactive mixin does not disconnect itself from observed storages upon destruction. Therefore, users have to do this themselves: ```cpp @@ -641,7 +641,7 @@ result in undefined behavior. ## Sorting: is it possible? Sorting entities and components is possible using an in-place algorithm that -doesn't require memory allocations and is therefore quite convenient.
+does not require memory allocations and is therefore quite convenient.
There are two functions that respond to slightly different needs: * Components are sorted either directly: @@ -677,7 +677,7 @@ components. Refer to the specific documentation for more details. ## Helpers -The so called _helpers_ are small classes and functions mainly designed to offer +The so-called _helpers_ are small classes and functions mainly designed to offer built-in support for the most basic functionalities. ### Null entity @@ -689,7 +689,7 @@ The library guarantees that the following expression always returns false: registry.valid(entt::null); ``` -A registry rejects the null entity in all cases because it isn't considered +A registry rejects the null entity in all cases because it is not considered valid. It also means that the null entity cannot own components.
The type of the null entity is internal and should not be used for any purpose other than defining the null entity itself. However, there exist implicit @@ -709,8 +709,8 @@ const bool null = (entity == entt::null); As for its integral form, the null entity only affects the entity part of an identifier and is instead completely transparent to its version. -Be aware that `entt::null` and entity 0 aren't the same thing. Likewise, a zero -initialized entity isn't the same as `entt::null`. Therefore, although +Be aware that `entt::null` and entity 0 are different. Likewise, a zero +initialized entity is not the same as `entt::null`. Therefore, although `entt::entity{}` is in some sense an alias for entity 0, none of them are used to create a null entity. @@ -749,8 +749,8 @@ const auto entity = registry.create(); const bool tombstone = (entity == entt::tombstone); ``` -Be aware that `entt::tombstone` and entity 0 aren't the same thing. Likewise, a -zero initialized entity isn't the same as `entt::tombstone`. Therefore, although +Be aware that `entt::tombstone` and entity 0 are different. Likewise, a +zero initialized entity is not the same as `entt::tombstone`. Therefore, although `entt::entity{}` is in some sense an alias for entity 0, none of them are used to create tombstones. @@ -764,7 +764,7 @@ const auto entity = entt::to_entity(registry.storage(), instance); ``` Where `instance` is a component of type `position`. A null entity is returned in -case the instance doesn't belong to the registry. +case the instance does not belong to the registry. ### Dependencies @@ -823,7 +823,7 @@ entt::sigh_helper{registry} Runtime pools are also supported by providing an identifier when calling `with`, as shown in the previous snippet. Refer to the following sections for more information about runtime pools.
-Obviously, this helper doesn't make the code disappear but it should at least +Obviously, this helper does not make the code disappear but it should at least reduce the boilerplate in the most complex cases. ### Handle @@ -831,11 +831,11 @@ reduce the boilerplate in the most complex cases. A handle is a thin wrapper around an entity and a registry. It _replicates_ the API of a registry by offering functions such as `get` or `emplace`. The difference being that the entity is implicitly passed to the registry.
-It's default constructible as an invalid handle that contains a null registry +It is default-constructible as an invalid handle that contains a null registry and a null entity. When it contains a null registry, calling functions that -delegate execution to the registry causes undefined behavior. It's recommended +delegate execution to the registry causes undefined behavior. It is recommended to test for validity with its implicit cast to `bool` if in doubt.
-A handle is also non-owning, meaning that it's freely copied and moved around +A handle is also non-owning, meaning that it is freely copied and moved around without affecting its entity (in fact, handles happen to be trivially copyable). An implication of this is that mutability becomes part of the type. @@ -859,7 +859,7 @@ users might want to consider using handles, either const or non-const. The `organizer` class template offers support for creating an execution graph from a set of functions and their requirements on resources.
-The resulting tasks aren't executed in any case. This isn't the goal of this +The resulting tasks are not executed in any case. This is not the goal of this tool. Instead, they are returned to the user in the form of a graph that allows for safe execution. @@ -894,7 +894,7 @@ clazz instance; organizer.emplace(+[](const void *, entt::registry &) { /* ... */ }, &instance); ``` -In all cases, it's also possible to associate a name with the task when creating +In all cases, it is also possible to associate a name with the task when creating it. For example: ```cpp @@ -906,12 +906,12 @@ considered a _resource_ (views are _unpacked_ and their types are treated as resources). The _constness_ of a type also dictates its access mode (RO/RW). In turn, this affects the resulting graph, since it influences the possibility of launching tasks in parallel.
-As for the registry, if a function doesn't explicitly request it or requires a -constant reference to it, it's considered a read-only access. Otherwise, it's +As for the registry, if a function does not explicitly request it or requires a +constant reference to it, it is considered a read-only access. Otherwise, it is considered as read-write access. All functions have the registry among their resources. -When registering a function, users can also require resources that aren't in the +When registering a function, users can also require resources that are not in the list of parameters of the function itself. These are declared as template parameters: @@ -927,7 +927,7 @@ organizer.emplace<&free_function, const renderable>("func"); ``` In this case, even if `renderable` appears among the parameters of the function -as not constant, it's treated as constant as regards the generation of the task +as not constant, it is treated as constant as regards the generation of the task graph. To generate the task graph, the organizer offers the `graph` member function: @@ -961,7 +961,7 @@ following features: * `children`: the vertices reachable from the given node, in the form of indices within the adjacency list. -Since the creation of pools and resources within the registry isn't necessarily +Since the creation of pools and resources within the registry is not necessarily thread safe, each vertex also offers a `prepare` function which is used to setup a registry for execution with the created graph: @@ -980,8 +980,8 @@ use the preferred tool. ## Context variables Each registry has a _context_ associated with it, which is an `any` object map -accessible by both type and _name_ for convenience. The _name_ isn't really a -name though. In fact, it's a numeric id of type `id_type` used as a key for the +accessible by both type and _name_ for convenience. The _name_ is not really a +name though. In fact, it is a numeric id of type `id_type` used as a key for the variable. Any value is accepted, even runtime ones.
The context is returned via the `ctx` functions and offers a minimal set of features including the following: @@ -1013,9 +1013,9 @@ registry.ctx().erase("my_variable"_hs); ``` A context variable must be both default constructible and movable. If the -supplied type doesn't match that of the variable when using a _name_, the +supplied type does not match that of the variable when using a _name_, the operation fails.
-For all users who want to use the context but don't want to create elements, the +For all users who want to use the context but do not want to create elements, the `contains` and `find` functions are also available: ```cpp @@ -1028,7 +1028,7 @@ the variable to look up, as does `at`. ### Aliased properties -A context also supports creating _aliases_ for existing variables that aren't +A context also supports creating _aliases_ for existing variables that are not directly managed by the registry. Const and therefore read-only variables are also accepted.
To do that, the type used upon construction must be a reference type and an @@ -1045,14 +1045,14 @@ Read-only aliased properties are created using const types instead: registry.ctx().emplace(clock); ``` -Note that `insert_or_assign` doesn't support aliased properties and users must +Note that `insert_or_assign` does not support aliased properties and users must necessarily use `emplace` or `emplace_as` for this purpose.
When `insert_or_assign` is used to update an aliased property, it _converts_ the property itself into a non-aliased one. From the point of view of the user, there are no differences between a variable that is managed by the registry and an aliased property. However, read-only -variables aren't accessible as non-const references: +variables are not accessible as non-const references: ```cpp // read-only variables only support const access @@ -1061,12 +1061,12 @@ const my_type &var = registry.ctx().get(); ``` Aliased properties are erased as it happens with any other variable. Similarly, -it's also possible to assign them a _name_. +it is also possible to assign them a _name_. ## Snapshot: complete vs continuous -This module comes with bare minimum support to serialization.
-It doesn't convert components to bytes directly, there wasn't the need of +This module comes with bare minimum support for serialization.
+It does not convert components to bytes directly, there was not the need of another tool for serialization out there. Instead, it accepts an opaque object with a suitable interface (namely an _archive_) to serialize its internal data structures and restore them later. The way types and instances are converted to @@ -1091,12 +1091,12 @@ entt::snapshot{registry} .get(output); ``` -It isn't necessary to invoke all functions each and every time. What functions +It is not necessary to invoke all functions each and every time. What functions to use in which case mostly depends on the goal. When _getting_ an entity type, the snapshot class serializes all entities along with their versions.
-In all other case, entities and components from a given storage are passed to +In all other cases, entities and components from a given storage are passed to the archive. Named pools are also supported: ```cpp @@ -1105,7 +1105,7 @@ entt::snapshot{registry}.get(output, "other"_hs); There exists another version of the `get` member function that accepts a range of entities to serialize. It can be used to _filter_ out those entities that -shouldn't be serialized for some reasons: +should not be serialized for some reasons: ```cpp const auto view = registry.view(); @@ -1136,7 +1136,7 @@ entt::snapshot_loader{registry} .orphans(); ``` -It isn't necessary to invoke all functions each and every time. What functions +It is not necessary to invoke all functions each and every time. What functions to use in which case mostly depends on the goal.
For obvious reasons, what is important is that the data are restored in exactly the same order in which they were serialized. @@ -1144,7 +1144,7 @@ the same order in which they were serialized. When _getting_ an entity type, a snapshot loader restores all entities with the versions that they originally had at the source.
In all other cases, entities and components are restored in a given storage. If -the registry doesn't contain the entity, it's also created accordingly. As for +the registry does not contain the entity, it is also created accordingly. As for the snapshot class, named pools are supported too: ```cpp @@ -1189,7 +1189,7 @@ loader .orphans(); ``` -It isn't necessary to invoke all functions each and every time. What functions +It is not necessary to invoke all functions each and every time. What functions to use in which case mostly depends on the goal.
For obvious reasons, what is important is that the data are restored in exactly the same order in which they were serialized. @@ -1199,7 +1199,7 @@ each entity to a local counterpart when required. For each remote identifier not yet registered by the loader, a local identifier is created so as to keep the local entity in sync with the remote one.
In all other cases, entities and components are restored in a given storage. If -the registry doesn't contain the entity, it's also tracked accordingly. As for +the registry does not contain the entity, it is also tracked accordingly. As for the snapshot class, named pools are supported too: ```cpp @@ -1242,7 +1242,7 @@ In particular: ``` The output archive can freely decide how to serialize the data. The registry - isn't affected at all by the decision. + is not affected at all by the decision. * An input archive (the one used when restoring a snapshot) exposes a function call operator with the following signature to load entities: @@ -1280,7 +1280,7 @@ a well known library for serialization as an archive. It uses [`Cereal C++`](https://uscilab.github.io/cereal/) under the hood, mainly because I wanted to learn how it works at the time I was writing the code. -The code **isn't** production-ready and it isn't neither the only nor (probably) +The code **is not** production-ready and it is not neither the only nor (probably) the best way to do it. However, feel free to use it at your own risk.
The basic idea is to store everything in a group of queues in memory, then bring everything back to the registry with different loaders. @@ -1289,7 +1289,7 @@ everything back to the registry with different loaders. Pools of components are _specialized versions_ of the sparse set class. Each pool contains all the instances of a single component type and all the entities -to which it's assigned.
+to which it is assigned.
Sparse arrays are _paged_ to avoid wasting memory. Packed arrays of components are also paged to have pointer stability upon additions. Packed arrays of entities are not instead.
@@ -1326,7 +1326,7 @@ struct transform { The `component_traits` class template takes care of _extracting_ the properties from the supplied type.
-Plus, it's _sfinae-friendly_ and also supports feature-based specializations. +Plus, it is _sfinae-friendly_ and also supports feature-based specializations. ## Empty type optimization @@ -1336,13 +1336,13 @@ the same types for which _empty base optimization_ (EBO) is possible.
performance and memory usage. However, this also has consequences that are worth mentioning. -When an empty type is detected, it's not instantiated by default. Therefore, -only the entities to which it's assigned are made available. There doesn't exist +When an empty type is detected, it is not instantiated by default. Therefore, +only the entities to which it is assigned are made available. There does not exist a way to _get_ empty types from a storage or a registry. Views and groups never return their instances too (for example, during a call to `each`).
On the other hand, iterations are faster because only the entities to which the type is assigned are considered. Moreover, less memory is used, mainly because -there doesn't exist any instance of the component, no matter how many entities +there does not exist any instance of the component, no matter how many entities it is assigned to. More in general, none of the feature offered by the library is affected, but for @@ -1357,12 +1357,12 @@ optimization selectively rather than globally. A void storage (or `entt::storage` or `entt::basic_storage`), is a fully functional storage type used to create pools not associated with a particular component type.
-From a technical point of view, it's in all respects similar to a storage for +From a technical point of view, it is in all respects similar to a storage for empty types when their optimization is enabled. Pagination is disabled as well as pointer stability (as not necessary).
However, this should be preferred to using a simple sparse set. In particular, a void storage offers all those feature normally offered by other storage types. -Therefore, it's a perfectly valid pool for use with views and groups or within a +Therefore, it is a perfectly valid pool for use with views and groups or within a registry. ## Entity storage @@ -1382,7 +1382,7 @@ fact, entities are subject to different rules with respect to components to existing entities. * The `each` function iterates only the entities _in use_, that is, those not - marked as _ready for reuse_. To iterate all the entities it's necessary to + marked as _ready for reuse_. To iterate all the entities it is necessary to iterate the underlying sparse set instead. This kind of storage is designed to be used where any other storage is fine and @@ -1392,7 +1392,7 @@ can therefore be combined with views, groups and so on. Within the registry, an entity storage is treated in all respects like any other storage.
-Therefore, it's possible to add mixins to it as well as retrieve it via the +Therefore, it is possible to add mixins to it as well as retrieve it via the `storage` function. It can also be used as storage in a view (for exclude-only views for example): @@ -1400,10 +1400,10 @@ views for example): auto view = registry.view(entt::exclude); ``` -However, it's also subject to a couple of exceptions, partly out of necessity +However, it is also subject to a couple of exceptions, partly out of necessity and partly for ease of use. -In particular, it's not possible to create multiple elements of this type.
+In particular, it is not possible to create multiple elements of this type.
This means that the _name_ used to retrieve this kind of storage is ignored and the registry will only ever return the same element to the caller. For example: @@ -1418,7 +1418,7 @@ equivalent to the following: auto &storage = registry.storage(); ``` -Because entity storage doesn't have a name, it can't be retrieved via the opaque +Because entity storage does not have a name, it cannot be retrieved via the opaque `storage` function either.
It would make no sense to try anyway, given that the type of the registry and therefore its entity type are known regardless. @@ -1433,7 +1433,7 @@ for(auto [id, storage]: registry.storage()) { ``` Entity storage is never returned. This simplifies many tasks (such as copying an -entity) and fits perfectly with the fact that this type of storage doesn't have +entity) and fits perfectly with the fact that this type of storage does not have an identifier inside the registry. ## Pointer stability @@ -1441,9 +1441,9 @@ an identifier inside the registry. The ability to achieve pointer stability for one, several or all components is a direct consequence of the design of `EnTT` and of its default storage.
In fact, although it contains what is commonly referred to as a _packed array_, -the default storage is paged and doesn't suffer from invalidation of references +the default storage is paged and does not suffer from invalidation of references when it runs out of space and has to reallocate.
-However, this isn't enough to ensure pointer stability in case of deletion. For +However, this is not enough to ensure pointer stability in case of deletion. For this reason, a _stable_ deletion method is also offered. This one is such that the position of the elements is preserved by creating tombstones upon deletion rather than trying to fill the holes that are created. @@ -1470,11 +1470,11 @@ deletion policy than the default. In particular: In other words, the more generic version of a view is provided in case of stable storage, even for a single type view.
In no case a tombstone is returned from the view itself. Likewise, non-existent -components aren't returned, which could otherwise result in an UB. +components are not returned, which could otherwise result in an UB. ### Hierarchies and the like -`EnTT` doesn't attempt in any way to offer built-in methods with hidden or +`EnTT` does not attempt in any way to offer built-in methods with hidden or unclear costs to facilitate the creation of hierarchies.
There are various solutions to the problem, such as using the following class: @@ -1505,9 +1505,9 @@ struct transform { }; ``` -Furthermore, it's quite common for a group of elements to be created close in +Furthermore, it is quite common for a group of elements to be created close in time and therefore fallback into adjacent positions, thus favoring locality even -on random accesses. Locality that isn't sacrificed over time given the stability +on random accesses. Locality that is not sacrificed over time given the stability of storage positions, with undoubted performance advantages. # Meet the runtime @@ -1515,8 +1515,8 @@ of storage positions, with undoubted performance advantages. `EnTT` takes advantage of what the language offers at compile-time. However, this can have its downsides (well known to those familiar with type erasure techniques).
-To fill the gap, the library also provides a bunch of utilities and feature that -are very useful to handle types and pools at runtime. +To fill the gap, the library also provides a bunch of utilities and features that +are invaluable to handle types and pools at runtime. ## A base class to rule them all @@ -1527,7 +1527,7 @@ The aim is to limit the need for customizations as much as possible, offering what is usually necessary for the vast majority of cases. When a storage is used through its base class (for example, when its actual type -isn't known), there is always the possibility of receiving a `type_info` object +is not known), there is always the possibility of receiving a `type_info` object for the type of elements associated with the entities (if any): ```cpp @@ -1568,7 +1568,7 @@ pointer and behaves differently depending on the case: * When the pointer is not null, the function tries to copy-construct an instance of the object to bind to the entity and returns true on success. -This means that, starting from a reference to the base, it's possible to bind +This means that, starting from a reference to the base, it is possible to bind components with entities without knowing their actual type and even initialize them by copy if needed: @@ -1595,9 +1595,9 @@ using namespace entt::literals; auto &&storage = registry.storage("second pool"_hs); ``` -If a name isn't provided, the default storage associated with the given type is +If a name is not provided, the default storage associated with the given type is always returned.
-Since the storage are also self-contained, the registry doesn't _duplicate_ its +Since the storage are also self-contained, the registry does not _duplicate_ its own API for them. However, there is still no limit to the possibilities of use: ```cpp @@ -1647,8 +1647,8 @@ runtime (also known as `runtime_view`).
The former requires a compile-time list of component (or storage) types and can make several optimizations because of that. The latter is constructed at runtime using numerical type identifiers instead and is a bit slower to iterate.
-In both cases, creating and destroying views isn't expensive at all since they -don't have any type of initialization. +In both cases, creating and destroying views is not expensive at all since they +do not have any type of initialization. Groups come in three different flavors: _full-owning groups_, _partial-owning groups_ and _non-owning groups_. The main difference between them is in terms of @@ -1665,7 +1665,7 @@ different APIs. Single type views are specialized to give a performance boost in all cases. There is nothing as fast as a single type view. They just walk through packed (actually paged) arrays of elements and return them directly.
-This kind of views also allow to get the exact number of elements they are going +This kind of views also allows getting the exact number of elements they are going to return.
Refer to the inline documentation for all the details. @@ -1676,7 +1676,7 @@ This kind of views only allow to get the estimated number of elements they are going to return.
Refer to the inline documentation for all the details. -Storing aside views isn't required as they are extremely cheap to construct. In +Storing aside views is not required as they are extremely cheap to construct. In fact, this is even discouraged when creating a view from a const registry. Since all storage are lazily initialized, they may not exist when the view is created. Thus, while perfectly usable, the view may contain pending references that are @@ -1736,12 +1736,12 @@ for(auto &&[entity, pos, vel]: registry.view().each()) { Note that entities can also be excluded from the parameter list when received through a callback and this can improve even further the performance during iterations.
-Since they aren't explicitly instantiated, empty components aren't returned in +Since they are not explicitly instantiated, empty components are not returned in any case. -As a side note, in the case of single type views, `get` accepts but doesn't +As a side note, in the case of single type views, `get` accepts but does not strictly require a template parameter, since the type is implicitly defined. -However, when the type isn't specified, the instance is returned using a tuple +However, when the type is not specified, the instance is returned using a tuple for consistency with multi type views: ```cpp @@ -1760,7 +1760,7 @@ registry during iterations to get the types iterated by the view itself. Views support lazy initialization as well as _storage swapping_.
An empty (or partially initialized) view is such that it returns false when -converted to bool (to let the user know that it isn't fully initialized) but it +converted to bool (to let the user know that it is not fully initialized) but it also works as-is like any other view. In order to initialize a view one piece at a time, it allows users to inject @@ -1773,7 +1773,7 @@ entt::view> view{}; view.storage(storage); ``` -If there are multiple storages of the same type, it's possible to disambiguate +If there are multiple storages of the same type, it is possible to disambiguate using the _index_ of the element to be replaced: ```cpp @@ -1810,25 +1810,25 @@ Finally, it should be noted that the lack of a storage is treated to all intents and purposes as if it were an _empty_ element.
Thus, a _get_ storage (as in `entt::get_t`) makes the view empty automatically while an _exclude_ storage (as in `entt::exclude_t`) is ignored as if that part -of the filter didn't exist. +of the filter did not exist. ### Exclude-only -_Exclude-only_ views aren't really a thing in `EnTT`.
+_Exclude-only_ views are not really a thing in `EnTT`.
However, the same result can be achieved by combining the right storage into a simple view. If one gets to the root of the problem, the purpose of an exclude-only view is -to return entities that don't meet certain requirements.
+to return entities that do not meet certain requirements.
Since entity storage, unlike exclude-only views, **is** a thing in `EnTT`, users -can leverage it for these kinds of queries. It's also guaranteed to be unique +can leverage it for these kinds of queries. It is also guaranteed to be unique within a registry and is always accessible when creating a view: ```cpp auto view = registry.view(entt::exclude); ``` -The returned view is such that it will return only the entities that don't have +The returned view is such that it will return only the entities that do not have the `my_type` component, regardless of what other components they have. ### View pack @@ -1866,9 +1866,9 @@ for(auto entity: registry.view()) { } ``` -Moreover, the order of types when constructing a view doesn't matter. Neither +Moreover, the order of types when constructing a view does not matter. Neither does the order of views in a view pack.
-However, it's possible to _enforce_ iteration of a view by given component order +However, it is possible to _enforce_ iteration of a view by given component order by means of the `use` function: ```cpp @@ -1891,8 +1891,8 @@ for(auto it = view.rbegin(), last = view.rend(); it != last; ++iter) { } ``` -Unfortunately, multi type views don't offer reverse iterators. Therefore, in -this case it's a must to implement this functionality manually or to use single +Unfortunately, multi type views do not offer reverse iterators. Therefore, in +this case it is a must to implement this functionality manually or to use single type views to lead the iteration. ### Runtime views @@ -1901,7 +1901,7 @@ Multi type views iterate entities that have at least all the given components. During construction, they look at the number of elements available in each pool and use the smallest set in order to speed up iterations.
They offer more or less the same functionalities of a multi type view. However, -they don't expose a `get` member function and users should refer to the registry +they do not expose a `get` member function and users should refer to the registry that generated the view to access components.
Refer to the inline documentation for all the details. @@ -1938,7 +1938,7 @@ entt::runtime_view view{}; view.iterate(registry.storage()).exclude(registry.storage()); ``` -Runtime views are meant for when users don't know at compile-time what types to +Runtime views are meant for when users do not know at compile-time what types to _use_ to iterate entities. The `storage` member function of a registry could be useful in this regard. @@ -1948,16 +1948,16 @@ Groups are meant to iterate multiple components at once and to offer a faster alternative to multi type views.
Groups overcome the performance of the other tools available but require to get the ownership of components. This sets some constraints on their pools. On the -other hand, groups aren't an automatism that increases memory consumption, +other hand, groups are not an automatism that increases memory consumption, affects functionalities and tries to optimize iterations for all the possible combinations of components. Users can decide when to pay for groups and to what extent.
The most interesting aspect of groups is that they fit _usage patterns_. Other solutions around usually try to optimize everything, because it is known that somewhere within the _everything_ there are also our usage patterns. However -this has a cost that isn't negligible, both in terms of performance and memory -usage. Ironically, users pay the price also for things they don't want and this -isn't something I like much. Even worse, one cannot easily disable such a +this has a cost that is not negligible, both in terms of performance and memory +usage. Ironically, users pay the price also for things they do not want and this +is not something I like much. Even worse, one cannot easily disable such a behavior. Groups work differently instead and are designed to optimize only the real use cases when users find they need to.
Another nice-to-have feature of groups is that they have no impact on memory @@ -1967,13 +1967,13 @@ avoided as long as possible. All groups affect to an extent the creation and destruction of their components. This is due to the fact that they must _observe_ changes in the pools of interest and arrange data _correctly_ when needed for the types they own.
-In all cases, a group allows to get the exact number of elements it's going to +In all cases, a group allows to get the exact number of elements it is going to return.
Refer to the inline documentation for all the details. -Storing aside groups isn't required as they are extremely cheap to create, even +Storing aside groups is not required as they are extremely cheap to create, even though valid groups can be copied without problems and reused freely.
-A group performs an initialization step the very first time it's requested and +A group performs an initialization step the very first time it is requested and this could be quite costly. To avoid it, consider creating the group when no components have been assigned yet. If the registry is empty, preparation is extremely fast. @@ -2016,7 +2016,7 @@ for(auto &&[entity, pos, vel]: registry.group(entt::get).eac Note that entities can also be excluded from the parameter list when received through a callback and this can improve even further the performance during iterations.
-Since they aren't explicitly instantiated, empty components aren't returned in +Since they are not explicitly instantiated, empty components are not returned in any case. **Note**: prefer the `get` member function of a group instead of that of a @@ -2054,9 +2054,9 @@ Sorting a full-owning group affects all its instances. A partial-owning group works similarly to a full-owning group for the components it owns, but relies on indirection to get components owned by other groups.
-This isn't as fast as a full-owning group, but it's already much faster than a +This is not as fast as a full-owning group, but it is already much faster than a view when there are only one or two free components to retrieve (the most common -cases likely). In the worst case, it's not slower than views anyway. +cases likely). In the worst case, it is not slower than views anyway. A partial-owning group is created as: @@ -2072,7 +2072,7 @@ auto group = registry.group(entt::get, entt::exclude(entt::get, entt::exclude); ``` -The group doesn't receive the ownership of any type of component in this +The group does not receive the ownership of any type of component in this case. This type of groups is therefore the least performing in general, but also the only one that can be used in any situation to slightly improve performance. @@ -2136,7 +2136,7 @@ std::tuple tup = view.get ctup = view.get(entity); ``` -It's not possible to get non-const references to `velocity` components from the +It is not possible to get non-const references to `velocity` components from the same view instead. Therefore, these result in compilation errors: ```cpp @@ -2174,7 +2174,7 @@ for(auto entity: registry.view()) { As a rule of thumb, consider using a view or a group if the goal is to iterate entities that have a determinate set of components. These tools are usually much faster than filtering entities with a bunch of custom tests.
-In all the other cases, this is the way to go. For example, it's possible to +In all the other cases, this is the way to go. For example, it is possible to combine this view with the `orphan` member function to clean up orphan entities (that is, entities that are still in use and have no assigned components): @@ -2188,12 +2188,12 @@ for(auto entity: registry.view()) { In general, iterating all entities can result in poor performance. It should not be done frequently to avoid the risk of a performance hit.
-However, it's convenient when initializing an editor or to reclaim pending +However, it is convenient when initializing an editor or to reclaim pending identifiers. ## What is allowed and what is not -Most of the _ECS_ available out there don't allow to create and destroy entities +Most of the _ECS_ available out there do not allow to create and destroy entities and components during iterations, nor to have pointer stability.
`EnTT` partially solves the problem with a few limitations: @@ -2202,7 +2202,7 @@ and components during iterations, nor to have pointer stability.
* Deleting the current entity or removing its components is allowed during iterations but it could invalidate references. For all the other entities, - destroying them or removing their iterated components isn't allowed and can + destroying them or removing their iterated components is not allowed and can result in undefined behavior. * When pointer stability is enabled for the type leading the iteration, adding @@ -2214,7 +2214,7 @@ and components during iterations, nor to have pointer stability.
under any circumstances. It could quickly lead to undefined behaviors. In other terms, iterators are rarely invalidated. Also, component references -aren't invalidated when a new element is added while they could be invalidated +are not invalidated when a new element is added while they could be invalidated upon destruction due to the _swap-and-pop_ policy, unless the type leading the iteration undergoes in-place deletion.
As an example, consider the following snippet: @@ -2227,15 +2227,15 @@ registry.view().each([&](const auto entity, auto &pos) { }); ``` -The `each` member function won't break (because iterators remain valid) nor will +The `each` member function will not break (because iterators remain valid) nor will any reference be invalidated. Instead, more attention should be paid to the destruction of entities or the removal of components.
Use a common range-for loop and get components directly from the view or move the deletion of entities and components at the end of the function to avoid dangling pointers. -For all types that don't offer stable pointers, iterators are also invalidated -and the behavior is undefined if an entity is modified or destroyed and it's not +For all types that do not offer stable pointers, iterators are also invalidated +and the behavior is undefined if an entity is modified or destroyed and it is not the one currently returned by the iterator nor a newly created one.
To work around it, possible approaches are: @@ -2254,11 +2254,11 @@ Groups are a faster alternative to views. However, the higher the performance, the greater the constraints on what is allowed and what is not.
In particular, groups add in some rare cases a limitation on the creation of components during iterations. It happens in quite particular cases. Given the -nature and the scope of the groups, it isn't something in which it will happen -to come across probably, but it's good to know it anyway. +nature and the scope of the groups, it is not something in which it will happen +to come across probably, but it is good to know it anyway. First of all, it must be said that creating components while iterating a group -isn't a problem at all and is done freely as it happens with the views. The same +is not a problem at all and is done freely as it happens with the views. The same applies to the destruction of components and entities, for which the rules mentioned above apply. @@ -2266,7 +2266,7 @@ The additional limitation arises instead when a given component that is owned by a group is iterated outside of it. In this case, adding components that are part of the group itself may invalidate the iterators. There are no further limitations to the destruction of components and entities.
-Fortunately, this isn't always true. In fact, it almost never is and only +Fortunately, this is not always true. In fact, it almost never is and only happens under certain conditions. In particular: * Iterating a type of component that is part of a group with a single type view @@ -2277,9 +2277,9 @@ happens under certain conditions. In particular: and adding to an entity all the components required to get it into the group can invalidate the iterators, unless users specify another type of component to use to induce the order of iteration of the view (in this case, the former - is treated as a free type and isn't affected by the limitation). + is treated as a free type and is not affected by the limitation). -In other words, the limitation doesn't exist as long as a type is treated as a +In other words, the limitation does not exist as long as a type is treated as a free type (as an example with multi type views and partial- or non-owning groups) or iterated with its own group, but it can occur if the type is used as a main type to rule on an iteration.
@@ -2290,12 +2290,12 @@ groups or as free types with multi type views and groups in general. # Multithreading -In general, the entire registry isn't thread safe as it is. Thread safety isn't +In general, the entire registry is not thread safe as it is. Thread safety is not something that users should want out of the box for several reasons. Just to mention one of them: performance.
Views, groups and consequently the approach adopted by `EnTT` are the great -exception to the rule. It's true that views, groups and iterators in general -aren't thread safe by themselves. Because of this users shouldn't try to iterate +exception to the rule. It is true that views, groups and iterators in general +are not thread safe by themselves. Because of this users should not try to iterate a set of components and modify the same set concurrently. However: * As long as a thread iterates the entities that have the component `X` or @@ -2311,9 +2311,9 @@ a set of components and modify the same set concurrently. However: of which will access the components that carry information about velocity and position for its entities. -This kind of entity-component systems can be used in single threaded +This kind of entity-component systems can be used in single-threaded applications as well as along with async stuff or multiple threads. Moreover, -typical thread based models for _ECS_ don't require a fully thread safe registry +typical thread based models for _ECS_ do not require a fully thread-safe registry to work. Actually, users can reach the goal with the registry as it is while working with most of the common models. @@ -2324,7 +2324,7 @@ expedients. Finally, `EnTT` is configured via a few compile-time definitions to make some of its parts implicitly thread-safe, roughly speaking only the ones that really -make sense and can't be turned around.
+make sense and can not be turned around.
In particular, when multiple instances of objects referencing the type index generator (such as the `registry` class) are used in different threads, then it might be useful to define `ENTT_USE_ATOMIC`.
@@ -2336,7 +2336,7 @@ A special mention is needed for the iterators returned by views and groups. Most of the time they meet the requirements of random access iterators, in all cases they meet at least the requirements of forward iterators.
In other terms, they are suitable for use with the parallel algorithms of the -standard library. If it's not clear, this is a great thing. +standard library. If it is not clear, this is a great thing. As an example, this kind of iterators are used in combination with `std::for_each` and `std::execution::par` to parallelize the visit and therefore @@ -2360,22 +2360,22 @@ means that the default iterators provided by the library cannot return proxy objects as references and **must** return actual reference types instead.
This may change in the future and the iterators will almost certainly return both the entities and a list of references to their components by default sooner -or later. Multi-pass guarantee won't break in any case and the performance +or later. Multi-pass guarantee will not break in any case and the performance should even benefit from it further. ## Const registry -A const registry is also fully thread safe. This means that it's not able to +A const registry is also fully thread safe. This means that it is not able to lazily initialize a missing storage when a view is generated.
The reason for this is easy to explain. To avoid requiring types to be _announced_ in advance, a registry lazily creates the storage objects for the -different components. However, this isn't possible for a thread safe const +different components. However, this is not possible for a thread safe const registry. Returned views are always valid and behave as expected in the context of the caller. However, they may contain dangling references to non-existing storage when created from a const registry.
-As a result, such a view may misbehave over time if it's kept aside for a second +As a result, such a view may misbehave over time if it is kept aside for a second use.
Therefore, if the general advice is to create views when necessary and discard them immediately afterwards, this becomes almost a rule when it comes to views @@ -2397,5 +2397,5 @@ things could be forgotten, others could have been omitted on purpose to reduce the size of this file. Unfortunately, some parts may even be outdated and still to be updated. -For further information, it's recommended to refer to the documentation included +For further information, it is recommended to refer to the documentation included in the code itself or join the official channels to ask a question. diff --git a/docs/md/faq.md b/docs/md/faq.md index c5c223662..bdcfe79f5 100644 --- a/docs/md/faq.md +++ b/docs/md/faq.md @@ -14,9 +14,9 @@ # Introduction -This is a constantly updated section where I'm trying to put the answers to the +This is a constantly updated section where I am trying to put the answers to the most frequently asked questions.
-If you don't find your answer here, there are two cases: nobody has done it yet, +If you do not find your answer here, there are two cases: nobody has done it yet, or this section needs updating. In both cases, you can [open a new issue](https://github.com/skypjack/entt/issues/new) or enter either the [gitter channel](https://gitter.im/skypjack/entt) or the @@ -29,10 +29,10 @@ part of the documentation. ## Why is my debug build on Windows so slow? `EnTT` is an experimental project that I also use to keep me up-to-date with the -latest revision of the language and the standard library. For this reason, it's -likely that some classes you're working with are using standard containers under +latest revision of the language and the standard library. For this reason, it is +likely that some classes you are working with are using standard containers under the hood.
-Unfortunately, it's known that the standard containers aren't particularly +Unfortunately, it is known that the standard containers are not particularly performing in debugging (the reasons for this go beyond this document) and are even less so on Windows, apparently. Fortunately, this can also be mitigated a lot, achieving good results in many cases. @@ -65,7 +65,7 @@ preferably `O1`. This is one of the first questions that anyone makes when starting to work with the entity-component-system architectural pattern.
There are several approaches to the problem, and the best one depends mainly on -the real problem one is facing. In all cases, how to do it doesn't strictly +the real problem one is facing. In all cases, how to do it does not strictly depend on the library in use, but the latter certainly allows or not different techniques depending on how the data are laid out. @@ -83,7 +83,7 @@ what concerns the `component_traits` class for further details. Custom entity identifiers are definitely a good idea in two cases at least: -* If `std::uint32_t` isn't large enough for your purposes, since this is the +* If `std::uint32_t` is not large enough for your purposes, since this is the underlying type of `entt::entity`. * If you want to avoid conflicts when using multiple registries. @@ -104,8 +104,8 @@ On Windows, a header file defines two macros `min` and `max` which may result in conflicts with their counterparts in the standard library and therefore in errors during compilation. -It's a pretty big problem but fortunately it's not a problem of `EnTT` and there -is a fairly simple solution to it.
+It is a pretty big problem. However, fortunately it is not a problem of `EnTT` +and there is a fairly simple solution to it.
It consists in defining the `NOMINMAX` macro before including any other header so as to get rid of the extra definitions: @@ -119,7 +119,7 @@ more details. ## The standard and the non-copyable types `EnTT` uses internally the trait `std::is_copy_constructible_v` to check if a -component is actually copyable. However, this trait doesn't really check whether +component is actually copyable. However, this trait does not really check whether a type is actually copyable. Instead, it just checks that a suitable copy constructor and copy operator exist.
This can lead to surprising results due to some idiosyncrasies of the standard. @@ -163,7 +163,7 @@ to mitigate the problem makes it manageable. Storage classes offer three _signals_ that are emitted following specific operations. Maybe not everyone knows what these operations are, though.
-If this isn't clear, below you can find a _vademecum_ for this purpose: +If this is not clear, below you can find a _vademecum_ for this purpose: * `on_created` is invoked when a component is first added (neither modified nor replaced) to an entity. @@ -174,7 +174,7 @@ If this isn't clear, below you can find a _vademecum_ for this purpose: from an entity. Among the most controversial functions can be found `emplace_or_replace` and -`destroy`. However, following the above rules, it's quite simple to know what +`destroy`. However, following the above rules, it is quite simple to know what will happen.
In the first case, `on_created` is invoked if the entity has not the component, otherwise the latter is replaced and therefore `on_update` is triggered. As for @@ -184,7 +184,7 @@ owned by the entity that is destroyed. ## Duplicate storage for the same component -It's rare, but you can see double sometimes, especially when it comes to storage. +It is rare, but you can see double sometimes, especially when it comes to storage. This can be caused by a conflict in the hash assigned to the various component types (one of a kind) or by bugs in your compiler ([more common](https://github.com/skypjack/entt/issues/1063) apparently).
diff --git a/docs/md/graph.md b/docs/md/graph.md index 51ce139ac..325135078 100644 --- a/docs/md/graph.md +++ b/docs/md/graph.md @@ -14,7 +14,7 @@ # Introduction -`EnTT` doesn't aim to offer everything one needs to work with graphs. Therefore, +`EnTT` does not aim to offer everything one needs to work with graphs. Therefore, anyone looking for this in the _graph_ submodule will be disappointed.
Quite the opposite is true though. This submodule is minimal and contains only the data structures and algorithms strictly necessary for the development of @@ -22,12 +22,12 @@ some tools such as the _flow builder_. # Data structures -As anticipated in the introduction, the aim isn't to offer all possible data +As anticipated in the introduction, the aim is not to offer all possible data structures suitable for representing and working with graphs. Many will likely be added or refined over time. However, I want to discourage anyone expecting tight scheduling on the subject.
The data structures presented in this section are mainly useful for the -development and support of some tools which are also part of the same submodule. +development and support of some tools that are also part of the same submodule. ## Adjacency matrix @@ -112,7 +112,7 @@ the functionalities one would expect from this type of containers, such as ## Graphviz dot language -As it's one of the most popular formats, the library offers minimal support for +As it is one of the most popular formats, the library offers minimal support for converting a graph to a Graphviz dot snippet.
The simplest way is to pass both an output stream and a graph to the `dot` function: @@ -122,7 +122,7 @@ std::ostringstream output{}; entt::dot(output, adjacency_matrix); ``` -It's also possible to provide a callback to which the vertices are passed and +It is also possible to provide a callback to which the vertices are passed and which can be used to add (`dot`) properties to the output as needed: ```cpp @@ -139,7 +139,7 @@ externally managed data to the graph being converted. # Flow builder A flow builder is used to create execution graphs from tasks and resources.
-The implementation is as generic as possible and doesn't bind to any other part +The implementation is as generic as possible and does not bind to any other part of the library. This class is designed as a sort of _state machine_ to which a specific task is @@ -175,14 +175,14 @@ builder.bind("task_1"_hs); The example uses the `EnTT` hashed string to generate an identifier for the task.
-Indeed, the use of `id_type` as an identifier type isn't by accident. In fact, -it matches well with the internal hashed string class. Moreover, it's also the +Indeed, the use of `id_type` as an identifier type is not by accident. In fact, +it matches well with the internal hashed string class. Moreover, it is also the same type returned by the hash function of the internal RTTI system, in case the user wants to rely on that.
However, being an integral value, it leaves the user full freedom to rely on his own tools if necessary. -Once a task is associated with the flow builder, it's also assigned read-only or +Once a task is associated with the flow builder, it has also assigned read-only or read-write resources as appropriate: ```cpp @@ -194,7 +194,7 @@ builder .rw("resource_2"_hs) ``` -As mentioned, many functions return the builder itself, and it's therefore easy +As mentioned, many functions return the builder itself, and it is therefore easy to concatenate the different calls.
Also in the case of resources, they are identified by numeric values of type `id_type`. As above, the choice is not entirely random. This goes well with the @@ -208,13 +208,13 @@ pair of iterators, so that one can pass a range of resources in one go. The `flow` class is resource based rather than task based. This means that graph generation is driven by resources and not by the order of _appearance_ of tasks during flow definition.
-Although this concept is particularly important, it's almost irrelevant for the +Although this concept is particularly important, it is almost irrelevant for the vast majority of cases. However, it becomes relevant when _rebinding_ resources or tasks. In fact, nothing prevents rebinding elements to a flow.
However, the behavior changes slightly from case to case and has some nuances -that it's worth knowing about. +that it is worth knowing about. Directly rebinding a resource without the task being replaced trivially results in the task's access mode for that resource being updated: @@ -225,7 +225,7 @@ builder.bind("task"_hs).rw("resource"_hs).ro("resource"_hs) In this case, the resource is accessed in read-only mode, regardless of the first call to `rw`.
-Behind the scenes, the call doesn't actually _replace_ the previous one but is +Behind the scenes, the call does not actually _replace_ the previous one but is queued after it instead, overwriting it when generating the graph. Thus, a large number of resource rebindings may even impact processing times (very difficult to observe but theoretically possible). @@ -249,9 +249,9 @@ What happens here is that the resource first _sees_ a read-only access request from the first task, then a read-write request from the second task and finally a new read-only request from the first task.
Although this definition would probably be counted as an error, the resulting -graph may be unexpected. This in fact consists of a single edge outgoing from +graph may be unexpected. This, in fact, consists of a single edge outgoing from the second task and directed to the first task.
-To intuitively understand what happens, it's enough to think of the fact that a +To intuitively understand what happens, it is enough to think of the fact that a task never has an edge pointing to itself. While not obvious, this approach has its pros and cons like any other solution. @@ -272,21 +272,21 @@ As expected, this definition leads to the creation of two edges that define a loop between the two tasks. As a general rule, rebinding resources and tasks is highly discouraged because -it could lead to subtle bugs if users don't know what they're doing.
+it could lead to subtle bugs if users do not know what they are doing.
However, once the mechanisms of resource-based graph generation are understood, it can offer to the expert user flexibility and a range of possibilities otherwise inaccessible. ## Fake resources and order of execution -The flow builder doesn't offer the ability to specify when a task should execute +The flow builder does not offer the ability to specify when a task should execute before or after another task.
In fact, the order of _registration_ on the resources also determines the order in which the tasks are processed during the generation of the execution graph. However, there is a way to _force_ the execution order of two processes.
Briefly, since accessing a resource in opposite modes requires sequential rather -than parallel scheduling, it's possible to make use of fake resources to rule on +than parallel scheduling, it is possible to make use of fake resources to rule on the execution order: ```cpp @@ -305,7 +305,7 @@ builder This snippet forces the execution of `task_1` **before** `task_2` and `task_3`. This is due to the fact that the former sets a read-write requirement on a fake resource that the other tasks also want to access in read-only mode.
-Similarly, it's possible to force a task to run **after** a certain group: +Similarly, it is possible to force a task to run **after** a certain group: ```cpp builder @@ -326,9 +326,9 @@ other tasks. ## Sync points -Sometimes it's useful to assign the role of _sync point_ to a node.
+Sometimes it is useful to assign the role of _sync point_ to a node.
Whether it accesses new resources or is simply a watershed, the procedure for -assigning this role to a vertex is always the same. First it's tied to the flow +assigning this role to a vertex is always the same. First it is tied to the flow builder, then the `sync` function is invoked: ```cpp @@ -337,7 +337,7 @@ builder.bind("sync_point"_hs).sync(); The choice to assign an _identity_ to this type of node lies in the fact that, more often than not, they also perform operations on resources.
-If this isn't the case, it will still be possible to create no-op vertices to +If this is not the case, it will still be possible to create no-op vertices to which empty tasks are assigned. ## Execution graph @@ -361,6 +361,6 @@ for(auto &&vertex: graph) { } ``` -Then it's possible to instantiate an execution graph by means of other functions +Then it is possible to instantiate an execution graph by means of other functions such as `out_edges` to retrieve the children of a given task or `edges` to get the identifiers. diff --git a/docs/md/lib.md b/docs/md/lib.md index 31624a8fc..634187545 100644 --- a/docs/md/lib.md +++ b/docs/md/lib.md @@ -24,7 +24,7 @@ available to the rest of the library. In general, this class arouses little interest. The only exception is when a conflict between identifiers occurs (definitely uncommon though) or when the default solution proposed by `EnTT` -isn't suitable for the user's purposes.
+is not suitable for the user's purposes.
The section dedicated to `type_info` contains all the details to get around the issue in a concise and elegant way. Please refer to the specific documentation. @@ -33,19 +33,19 @@ When working with linked libraries, compile definitions `ENTT_API_EXPORT` and `ENTT_API_IMPORT` are to import or export symbols, so as to make everything work nicely across boundaries.
On the other hand, everything should run smoothly when working with plugins or -shared libraries that don't export any symbols. +shared libraries that do not export any symbols. For those who need more details, the test suite contains many examples covering the most common cases (see the `lib` directory for all details).
-It goes without saying that it's impossible to cover **all** possible cases. +It goes without saying that it is impossible to cover **all** possible cases. However, what is offered should hopefully serve as a basis for all of them. ## Meta context The runtime reflection system deserves a special mention when it comes to using it across boundaries.
-Since it's linked already to a static context to which the elements are attached -and different contexts don't relate to each other, they must be _shared_ to +Since it is linked already to a static context to which the elements are attached +and different contexts do not relate to each other, they must be _shared_ to allow the use of meta types across boundaries. Fortunately, sharing a context is also trivial to do. First of all, the local @@ -55,7 +55,7 @@ one is acquired in the main space: auto handle = entt::locator::handle(); ``` -Then, it's passed to the receiving space that sets it as its default context, +Then, it is passed to the receiving space that sets it as its default context, thus discarding or storing aside the local one: ```cpp @@ -64,7 +64,7 @@ entt::locator::reset(handle); From now on, both spaces refer to the same context and to it are all new meta-types attached, no matter where they are created.
-Note that _replacing_ the main context doesn't also propagate changes across +Note that _replacing_ the main context does not also propagate changes across boundaries. In other words, replacing a context results in the decoupling of the two sides and therefore a divergence in the contents. @@ -85,7 +85,7 @@ As one can guess, this pool is instantiated on a different side of the boundary from the `registry`. Therefore, the instance is now managing memory from different spaces, and this can quickly lead to crashes if not properly addressed. -To overcome the risk, it's recommended to use well-defined interfaces that make +To overcome the risk, it is recommended to use well-defined interfaces that make fundamental types pass through the boundaries, isolating the instances of the `EnTT` classes from time to time and as appropriate.
Refer to the test suite for some examples, read the documentation available diff --git a/docs/md/links.md b/docs/md/links.md index a921b737a..7d9bf59ee 100644 --- a/docs/md/links.md +++ b/docs/md/links.md @@ -14,16 +14,16 @@ `EnTT` is widely used in private and commercial applications. I cannot even mention most of them because of some signatures I put on some documents time ago. Fortunately, there are also people who took the time to implement open -source projects based on `EnTT` and didn't hold back when it came to documenting +source projects based on `EnTT` and did not hold back when it came to documenting them. Below an incomplete list of games, applications and articles that can be used as a reference.
Where I put the word _apparently_ means that the use of `EnTT` is documented but -the authors didn't make explicit announcements or contacted me directly. +the authors did not make explicit announcements or contacted me directly. If you know of other resources out there that are about `EnTT`, feel free to -open an issue or a PR. I'll be glad to add them to this page.
+open an issue or a PR. I will be glad to add them to this page.
I hope the following lists can grow much more in the future. # EnTT in Action @@ -109,7 +109,7 @@ I hope the following lists can grow much more in the future. * [PokeMaster](https://github.com/utilForever/PokeMaster): Pokémon Battle simulator using C++ with some reinforcement learning. * [HomeHearth](https://youtu.be/GrEWl8npL9Y): choose your hero, protect the - town, before it's too late. + town, before it is too late. * [City Builder Game](https://github.com/PhiGei2000/CityBuilderGame): a simple city-building game using C++ and OpenGL. * [BattleSub](https://github.com/bfeldpw/battlesub): two player 2D submarine @@ -277,7 +277,7 @@ I hope the following lists can grow much more in the future. by [linkdd](https://github.com/linkdd): an interesting walkthrough of developing a game (also) with EnTT. * [Use EnTT When You Need An ECS](https://www.codingwiththomas.com/blog/use-entt-when-you-need-an-ecs) - by [Thomas](https://www.codingwiththomas.com/): I couldn't have said it + by [Thomas](https://www.codingwiththomas.com/): I could not have said it better. * [Space Battle: Huge edition](http://victor.madtriangles.com/code%20experiment/2018/06/11/post-ecs-battle-huge.html): huge space battle built entirely from scratch. @@ -309,7 +309,7 @@ I hope the following lists can grow much more in the future. * [ArcGIS Runtime SDKs](https://developers.arcgis.com/arcgis-runtime/) by [Esri](https://www.esri.com/): they use `EnTT` for the internal ECS and the - cross-platform C++ rendering engine. The SDKs are utilized by a lot of + cross-platform C++ rendering engine. The SDKs are used by a lot of enterprise custom apps, as well as by Esri for its own public applications such as [Explorer](https://play.google.com/store/apps/details?id=com.esri.explorer), diff --git a/docs/md/locator.md b/docs/md/locator.md index 9acf14fcd..2c6516480 100644 --- a/docs/md/locator.md +++ b/docs/md/locator.md @@ -9,7 +9,7 @@ # Introduction Usually, service locators are tightly bound to the services they expose. -It's hard to define a general purpose solution.
+It is hard to define a general purpose solution.
This tiny class tries to fill the gap and gets rid of the burden of defining a different specific locator for each application. @@ -27,7 +27,7 @@ entt::locator::allocate_emplace(allocator, argument); The difference is that the latter expects an allocator as the first argument and uses it to allocate the service itself.
-Once a service is set up, it's retrieved using the `value` function: +Once a service is set up, it is retrieved using the `value` function: ```cpp interface &service = entt::locator::value(); @@ -45,17 +45,17 @@ if(entt::locator::has_value()) { interface &service = entt::locator::value_or(argument); ``` -All arguments are used only if necessary, that is, if a service doesn't already +All arguments are used only if necessary, that is, if a service does not already exist and therefore the fallback service is constructed and returned. In all other cases, they are discarded.
Finally, to reset a service, use the `reset` function. ## Opaque handles -Sometimes it's useful to _transfer_ a copy of a service to another locator. For -example, when working across boundaries it's common to _share_ a service with a +Sometimes it is useful to _transfer_ a copy of a service to another locator. For +example, when working across boundaries it is common to _share_ a service with a dynamically loaded module.
-Options aren't much in this case. Among these is the possibility of _exporting_ +Options are not much in this case. Among these is the possibility of _exporting_ services and assigning them to a different locator. This is what the `handle` and `reset` functions are meant for.
@@ -69,14 +69,14 @@ auto handle = entt::locator::handle(); entt::locator::reset(handle); ``` -It's worth noting that it's possible to get handles for uninitialized services +It is worth noting that it is possible to get handles for uninitialized services and use them with other locators. Of course, all a user will get is to have an uninitialized service elsewhere as well. Note that exporting a service allows users to _share_ the object currently set -in a locator. Replacing it won't replace the element, even where a service has +in a locator. Replacing it will not replace the element, even where a service has been configured with a handle to the previous item.
In other words, if an audio service is replaced with a null object to silence an -application and the original service was shared, this operation won't propagate +application and the original service was shared, this operation will not propagate to the other locators. Therefore, a module that shares the ownership of the original audio service is still able to emit sounds. diff --git a/docs/md/meta.md b/docs/md/meta.md index 937050572..c14af62e3 100644 --- a/docs/md/meta.md +++ b/docs/md/meta.md @@ -26,33 +26,33 @@ Reflection (or rather, its lack) is a trending topic in the C++ world and a tool that can unlock a lot of interesting features in the specific case of `EnTT`. 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 +came across some details that I did not like: macros, being intrusive, too many allocations, and so on.
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 did not 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 the opposite. # Names and identifiers -The meta system doesn't force users to rely on the tools provided by the library +The meta system does not 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.
This means that users can assign any type of identifier to the meta-objects, as -long as they're numeric. It doesn't matter if they're generated at runtime, at +long as they are numeric. It does not matter if they are generated at runtime, at compile-time or with custom functions. 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 +identifier is required, it is likely that a user defined literal is used as follows: ```cpp entt::meta_factory{}.type("reflected_type"_hs); ``` -For what it's worth, this is completely equivalent to: +For what it is worth, this is completely equivalent to: ```cpp entt::meta_factory{}.type(42u); @@ -76,7 +76,7 @@ type. By default, a meta-type is associated with the identifier returned by the runtime type identification system built-in in `EnTT`.
-However, it's also possible to assign custom identifiers to meta-types: +However, it is also possible to assign custom identifiers to meta-types: ```cpp entt::meta_factory{}.type("reflected_type"_hs); @@ -85,11 +85,11 @@ entt::meta_factory{}.type("reflected_type"_hs); Identifiers are used to _retrieve_ meta-types at runtime by _name_ other than by type.
However, users can be interested in adding features to a reflected type so that -the reflection system can use it correctly under the hood, while they don't want -to also make the type _searchable_. In this case, it's sufficient not to invoke +the reflection system can use it correctly under the hood, while they do not want +to also make the type _searchable_. In this case, it is sufficient not to invoke `type`. -A factory is such that all its member functions return the factory itself. It's +A factory is such that all its member functions return the factory itself. It is generally used to create the following: * _Constructors_. A constructor is assigned to a reflected type by specifying @@ -191,7 +191,7 @@ The API is very similar to that of the `any` type. The class `meta_any` _wraps_ many of the feature to infer a meta node, before forwarding some or all of the arguments to the underlying storage.
Among the few relevant differences, `meta_any` adds support for containers and -pointer-like types, while `any` doesn't.
+pointer-like types, while `any` does not.
Similar to `any`, this class is also used to create _aliases_ for unmanaged objects either with `forward_as_meta` or using the `std::in_place_type` disambiguation tag, as well as from an existing object by means of the `as_ref` @@ -216,7 +216,7 @@ There is in fact no `any_cast` equivalent for `meta_any`. ## Enjoy the runtime -Once the web of reflected types is constructed, it's a matter of using it at +Once the web of reflected types is constructed, it is a matter of using it at runtime where required.
There are a few options to search for a reflected type: @@ -256,7 +256,7 @@ Meta-data members and functions are accessed by name: The returned type is `meta_data` and may be invalid if there is no meta-data object associated with the given identifier.
A meta-data object offers an API to query the underlying type (for example, to - know if it's a const or a static one), to get the meta-type of the variable + know if it is a const or a static one), to get the meta-type of the variable and to set or get the contained value. * Meta function members: @@ -268,7 +268,7 @@ Meta-data members and functions are accessed by name: The returned type is `meta_func` and may be invalid if there is no meta function object associated with the given identifier.
A meta function object offers an API to query the underlying type (for - example, to know if it's a const or a static function), to know the number of + example, to know if it is a const or a static function), to know the number of arguments, the meta return type and the meta-types of the parameters. In addition, a meta function object is used to invoke the underlying function and then get the return value in the form of a `meta_any` object. @@ -302,9 +302,9 @@ or not. There is no object that wraps the destructor of a meta-type nor a `destroy` member function in its API. Destructors are invoked implicitly by `meta_any` behind the scenes and users have not to deal with them explicitly. Furthermore, -they've no name, cannot be searched and wouldn't have member functions to expose +they have no name, cannot be searched and would not have member functions to expose anyway.
-Similarly, conversion functions aren't directly accessible. They're used +Similarly, conversion functions are not directly accessible. They are used internally by `meta_any` and the meta-objects when needed. Meta-types and meta-objects in general contain much more than what was said. @@ -313,7 +313,7 @@ Refer to the inline documentation for further details. ## Container support The runtime reflection system also supports containers of all types.
-Moreover, _containers_ doesn't necessarily mean those offered by the C++ +Moreover, _containers_ does not 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. @@ -330,7 +330,7 @@ particular: * `std::map`, `std::set` and their unordered counterparts are supported as _associative containers_. -It's important to include the header file `container.hpp` to make these +It is important to include the header file `container.hpp` to make these specializations available to the compiler when needed.
The same file also contains many examples for the users that are interested in making their own containers available to the meta-system. @@ -356,11 +356,11 @@ if(any.type().is_sequence_container()) { The method to use to get a proxy object for associative containers is `as_associative_container` instead.
-It's not necessary to perform a double check actually. Instead, it's enough to +It is not necessary to perform a double check actually. Instead, it is enough to query the meta-type or verify that the proxy object is valid. In fact, proxies are contextually convertible to bool to check for validity. For example, invalid -proxies are returned when the wrapped object isn't a container.
-In all cases, users aren't expected to _reflect_ containers explicitly. It's +proxies are returned when the wrapped object is not a container.
+In all cases, users are not expected to _reflect_ containers explicitly. It is sufficient to assign a container for which a specialization of the trait classes exists to a `meta_any` object to be able to get its proxy object. @@ -375,15 +375,15 @@ to case. In particular: * The `resize` member function allows resizing the wrapped container and returns true in case of success.
- For example, it's not possible to resize fixed size containers. + For example, it is not possible to resize fixed size containers. * The `clear` member function allows clearing the wrapped container and returns true in case of success.
- For example, it's not possible to clear fixed size containers. + For example, it is not possible to clear fixed size containers. * The `reserve` member function allows increasing the capacity of the wrapped container and returns true in case of success.
- For example, it's not possible to increase capacity of fixed size containers. + For example, it is not possible to increase capacity of fixed size containers. * The `begin` and `end` member functions return opaque iterators that is used to iterate the container directly: @@ -397,7 +397,7 @@ to case. In particular: 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.
- All meta iterators are input iterators and don't offer an indirection operator + All meta iterators are input iterators and do not offer an indirection operator on purpose. * The `insert` member function is used to add elements to the container. It @@ -412,7 +412,7 @@ to case. In particular: This function returns a meta iterator pointing to the inserted element and a boolean value to indicate whether the operation was successful or not. 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.
+ arguments are not at least convertible to the required types.
Since meta iterators are contextually convertible to bool, users can rely on them to know if the operation failed on the actual container or upstream, for example due to an argument conversion problem. @@ -474,7 +474,7 @@ differences in behavior in the case of key-only containers. In particular: * The `reserve` member function allows increasing the capacity of the wrapped container and returns true in case of success.
- For example, it's not possible to increase capacity of standard maps. + For example, it is not possible to increase capacity of standard maps. * The `begin` and `end` member functions return opaque iterators that are used to iterate the container directly: @@ -487,9 +487,9 @@ differences in behavior in the case of key-only containers. In particular: In all cases, given an underlying container of type `C`, the returned element is a key-value pair where the key has type `C::key_type` and the value has - type `C::mapped_type`. Since key-only containers don't have a mapped type, + type `C::mapped_type`. Since key-only containers do not have a mapped type, their _value_ is nothing more than an invalid `meta_any` object.
- All meta iterators are input iterators and don't offer an indirection operator + All meta iterators are input iterators and do not offer an indirection operator on purpose. While the accessed key is usually constant in the associative containers and @@ -507,7 +507,7 @@ differences in behavior in the case of key-only containers. In particular: ``` This function returns a boolean value to indicate whether the operation was - successful or not. A call to `insert` may fail when the arguments aren't at + successful or not. A call to `insert` may fail when the arguments are not at least convertible to the required types. * The `erase` member function is used to remove elements from a container. It @@ -518,7 +518,7 @@ differences in behavior in the case of key-only containers. In particular: ``` This function returns a boolean value to indicate whether the operation was - successful or not. A call to `erase` may fail when the argument isn't at least + successful or not. A call to `erase` may fail when the argument is not at least convertible to the required type. * The `operator[]` is used to access elements in a container. It gets a single @@ -536,7 +536,7 @@ Container support is minimal but likely sufficient to satisfy all needs. ## Pointer-like types -As with containers, it's also possible to _tell_ to the meta-system which types +As with containers, it is also possible to _tell_ to the meta-system which types are _pointers_. This makes it possible to dereference instances of `meta_any`, thus obtaining light _references_ to pointed objects that are also correctly associated with their meta-types.
@@ -547,12 +547,12 @@ some common classes. In particular: * All types of raw pointers. * `std::unique_ptr` and `std::shared_ptr`. -It's important to include the header file `pointer.hpp` to make these +It is important to include the header file `pointer.hpp` to make these specializations available to the compiler when needed.
The same file also contains many examples for the users that are interested in making their own pointer-like types available to the meta system. -When a type is recognized as a pointer-like one by the meta-system, it's +When a type is recognized as a pointer-like one by the meta-system, it is 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: @@ -569,17 +569,17 @@ if(any.type().is_pointer_like()) { } ``` -It's not necessary to perform a double check. Instead, it's enough to query the +It is not necessary to perform a double check. Instead, it is enough to query the meta-type or verify that the returned object is valid. For example, invalid -instances are returned when the wrapped object isn't a pointer-like type.
+instances are returned when the wrapped object is not a pointer-like type.
Dereferencing a pointer-like object returns an instance of `meta_any` which _refers_ to the pointed object. Modifying it means modifying the pointed object directly (unless the returned element is const). In general, _dereferencing_ a pointer-like type boils down to a `*ptr`. However, -`EnTT` also supports classes that don't offer an `operator*`. In particular: +`EnTT` also supports classes that do not offer an `operator*`. In particular: -* It's possible to exploit a solution based on ADL lookup by offering a function +* It is possible to exploit a solution based on ADL lookup by offering a function (also a template one) named `dereference_meta_pointer_like`: ```cpp @@ -589,7 +589,7 @@ In general, _dereferencing_ a pointer-like type boils down to a `*ptr`. However, } ``` -* When not in control of the type's namespace, it's possible to inject into the +* When not in control of the type's namespace, it is possible to inject into the `entt` namespace a specialization of the `adl_meta_pointer_like` class template to bypass the adl lookup as a whole: @@ -608,8 +608,8 @@ of the pointed type, no user intervention is required. ## Template information Meta-types also provide a minimal set of information about the _nature_ of the -original type in case it's a class template.
-By default, this works out of the box and requires no user action. However, it's +original type in case it is a class template.
+By default, this works out of the box and requires no user action. However, it is important to include the header file `template.hpp` to make this information available to the compiler when needed. @@ -656,7 +656,7 @@ struct entt::meta_template_traits> { }; ``` -The reflection system doesn't verify the accuracy of the information nor infer a +The reflection system does not verify the accuracy of the information nor infer a correspondence between real types and meta-types.
Therefore, the specialization is used as is and the information it contains is associated with the appropriate type when required. @@ -708,7 +708,7 @@ int value = any.cast(); This makes working with arithmetic types and scoped or unscoped enums as easy as it is in C++.
-It's still possible to set up conversion functions manually, and these are +It is still possible to set up conversion functions manually, and these are always preferred over the automatic ones. ## Implicitly generated default constructor @@ -746,7 +746,7 @@ designed to convert an opaque pointer into a `meta_any`: entt::meta_any any = entt::resolve(id).from_void(element); ``` -Unfortunately, it's not possible to do a check on the actual type. Therefore, +Unfortunately, it is not possible to do a check on the actual type. Therefore, this call can be considered as a _static cast_ with all its _problems_.
On the other hand, the ability to construct a `meta_any` from an opaque pointer opens the door to some pretty interesting uses that are worth exploring. @@ -759,14 +759,14 @@ Their purpose is to require slightly different behavior than the default in some specific cases. For example, when reading a given data member, its value is returned wrapped in a `meta_any` object which, by default, makes a copy of it. For large objects or if the caller wants to access the original instance, this -behavior isn't desirable. Policies are there to offer a solution to this and +behavior is not desirable. Policies are there to offer a solution to this and other problems. There are a few alternatives available at the moment: * The _as-is_ policy, associated with the type `entt::as_is_t`.
This is the default policy. In general, it should never be used explicitly, - since it's implicitly selected if no other policy is specified.
+ since it is implicitly selected if no other policy is specified.
In this case, the return values of the functions as well as the properties exposed as data members are always returned by copy in a dedicated wrapper and therefore associated with their original meta-types. @@ -782,7 +782,7 @@ There are a few alternatives available at the moment: If the use with functions is obvious, perhaps less so is use with constructors and data members. In the first case, the returned wrapper is always empty even though the constructor is still invoked. In the second case, the property - isn't accessible for reading instead. + is not accessible for reading instead. * The _as-ref_ and _as-cref_ policies, associated with the types `entt::as_ref_t` and `entt::as_cref_t`.
@@ -802,7 +802,7 @@ There are a few alternatives available at the moment: `as_ref_t` _adapts_ to the constness of the passed object and to that of the return type if any. -Some uses are rather trivial, but it's useful to note that there are some less +Some uses are rather trivial, but it is useful to note that there are some less obvious corner cases that can in turn be solved with the use of policies. ## Named constants and enums @@ -826,7 +826,7 @@ entt::meta_factory{} entt::meta_factory{}.data<2048>("max_int"_hs); ``` -Accessing them is trivial as well. It's a matter of doing the following, as with +Accessing them is trivial as well. It is a matter of doing the following, as with any other data member of a meta-type: ```cpp @@ -863,8 +863,8 @@ entt::meta_factory{}.traits(my_traits::required | my_traits::hidden); ``` In the example above, `EnTT` bitmask enum support is used, but any integral value -is fine, as long as it doesn't exceed 16 bits.
-It's not possible to assign traits at different times. Therefore, multiple calls +is fine, as long as it does not exceed 16 bits.
+It is not possible to assign traits at different times. Therefore, multiple calls to the `traits` function overwrite previous values. However, traits can be read from meta-objects and used to update existing data with a factory, effectively extending them as needed.
@@ -898,7 +898,7 @@ entt::meta_factory{}.custom("name"); The way to do this is by specifying the data type to the `custom` function and passing the necessary arguments to construct it correctly.
-It's not possible to assign custom data at different times. Therefore, multiple +It is not possible to assign custom data at different times. Therefore, multiple calls to the `custom` function overwrite previous values. However, this value can be read from meta-objects and used to update existing data with a factory, effectively updating them as needed.
@@ -927,7 +927,7 @@ null pointer is returned to inform the user of the failed attempt. A type registered with the reflection system can also be _unregistered_. This means unregistering all its data members, member functions, conversion functions -and so on. However, base classes aren't unregistered as well, since they don't +and so on. However, base classes are not unregistered as well, since they do not necessarily depend on it.
Roughly speaking, unregistering a type means disconnecting all associated meta-objects from it and making its identifier no longer available: @@ -936,14 +936,14 @@ meta-objects from it and making its identifier no longer available: entt::meta_reset(); ``` -It's also possible to reset types by their unique identifiers: +It is also possible to reset types by their unique identifiers: ```cpp entt::meta_reset("my_type"_hs); ``` Finally, there exists a non-template overload of the `meta_reset` function that -doesn't accept arguments and resets all meta-types at once: +does not accept arguments and resets all meta-types at once: ```cpp entt::meta_reset(); @@ -972,7 +972,7 @@ std::swap(context, other); This is useful for testing purposes or to define multiple context objects with different meta-types to use as appropriate. -If _replacing_ the default context isn't enough, `EnTT` also offers the ability +If _replacing_ the default context is not enough, `EnTT` also offers the ability to use multiple and externally managed contexts with the runtime reflection system.
For example, to create new meta-types within a context other than the default @@ -983,7 +983,7 @@ entt::meta_ctx context{}; entt::meta_factory{context}.type("reflected_type"_hs); ``` -By doing so, the new meta-type isn't available in the default context but is +By doing so, the new meta-type is not available in the default context but is usable by passing around the new context when needed, such as when creating a new `meta_any` object: @@ -992,17 +992,17 @@ entt::meta_any any{context, std::in_place_type}; ``` Similarly, to search for meta-types in a context other than the default one, -it's necessary to pass it to the `resolve` function: +it is necessary to pass it to the `resolve` function: ```cpp entt::meta_type type = entt::resolve(context, "reflected_type"_hs) ``` -More generally, when using externally managed contexts, it's always required to +More generally, when using externally managed contexts, it is always required to provide the system with the context to use, at least at the _entry point_.
-For example, once the `meta_type` instant is obtained, it's no longer necessary +For example, once the `meta_type` instant is obtained, it is no longer necessary to pass the context around as the meta-type takes the information with it and eventually propagates it to all its parts.
-On the other hand, it's necessary to instruct the library on where meta-types +On the other hand, it is necessary to instruct the library on where meta-types are to be fetched when `meta_any`s and `meta_handle`s are constructed, a factory created or a meta-type resolved. diff --git a/docs/md/poly.md b/docs/md/poly.md index 4ce7085ad..be7e93589 100644 --- a/docs/md/poly.md +++ b/docs/md/poly.md @@ -45,7 +45,7 @@ The ones that I like more are: object wrapper. The former is admittedly an experimental library, with many interesting ideas. -I've some doubts about the usefulness of some features in real world projects, +I have some doubts about the usefulness of some features in real world projects, but perhaps my lack of experience comes into play here. In my opinion, its only flaw is the API that I find slightly more cumbersome than other solutions.
The latter was undoubtedly a source of inspiration for this module. Although I @@ -63,7 +63,7 @@ types will have to adhere to.
For this purpose, the library offers a single class that supports both deduced and fully defined interfaces. Although having interfaces deduced automatically is convenient and allows users to write less code in most cases, it has some -limitations. It's therefore useful to be able to get around the deduction by +limitations. It is therefore useful to be able to get around the deduction by providing a custom definition for the static virtual table. Once the interface is defined, a generic implementation is needed to fulfill the @@ -86,7 +86,7 @@ struct Drawable: entt::type_list<> { }; ``` -It's recognizable by the fact that it inherits from an empty type list.
+It is recognizable by the fact that it inherits from an empty type list.
Functions can also be const, accept any number of parameters and return a type other than `void`: @@ -104,7 +104,7 @@ struct Drawable: entt::type_list<> { In this case, all parameters are passed to `invoke` after the reference to `this` and the return value is whatever the internal call returns.
As for `invoke`, this is a name that is injected into the _concept_ through -`Base`, from which one must necessarily inherit. Since it's also a dependent +`Base`, from which one must necessarily inherit. Since it is also a dependent name, the `this-> template` form is unfortunately necessary due to the rules of the language. However, there also exists an alternative that goes through an external call: @@ -171,9 +171,9 @@ If the concept exposes a member function called `draw` with function type * Or through a lambda that makes use of existing member functions from the interface itself. -In other words, it's not possible to make use of functions not belonging to the -interface, even if they're part of the types that fulfill the concept.
-Similarly, it's not possible to deduce a function in the static virtual table +In other words, it is not possible to make use of functions not belonging to the +interface, even if they are part of the types that fulfill the concept.
+Similarly, it is not possible to deduce a function in the static virtual table with a function type different from that of the associated member function in the interface itself. @@ -182,7 +182,7 @@ allows maximum flexibility when providing the implementation for a concept. ## Fulfill a concept -The `impl` alias template of a concept is used to define how it's fulfilled: +The `impl` alias template of a concept is used to define how it is fulfilled: ```cpp struct Drawable: entt::type_list<> { @@ -193,7 +193,7 @@ struct Drawable: entt::type_list<> { }; ``` -In this case, it's stated that the `draw` method of a generic type is enough to +In this case, it is stated that the `draw` method of a generic type is enough to satisfy the requirements of the `Drawable` concept.
Both member functions and free functions are supported to fulfill concepts: @@ -211,9 +211,9 @@ struct Drawable: entt::type_list { Likewise, as long as the parameter types and return type support conversions to and from those of the function type referenced in the static virtual table, the -actual implementation may differ in its function type since it's erased +actual implementation may differ in its function type since it is erased internally.
-Moreover, the `self` parameter isn't strictly required by the system and can be +Moreover, the `self` parameter is not strictly required by the system and can be left out for free functions if not required. Refer to the inline documentation for more details. @@ -221,7 +221,7 @@ Refer to the inline documentation for more details. # Inheritance _Concept inheritance_ is straightforward due to how poly looks like in `EnTT`. -Therefore, it's quite easy to build hierarchies of concepts if necessary.
+Therefore, it is quite easy to build hierarchies of concepts if necessary.
The only constraint is that all concepts in a hierarchy must belong to the same _family_, that is, they must be either all deduced or all defined. @@ -253,7 +253,7 @@ in appending the new functions to the previous list. As for a defined concept instead, the list of types is _extended_ in a similar way to what is shown for the implementation of the above concept.
-To do this, it's useful to declare a function that allows to convert a _concept_ +To do this, it is useful to declare a function that allows to convert a _concept_ into its underlying `type_list` object: ```cpp @@ -261,7 +261,7 @@ template entt::type_list as_type_list(const entt::type_list &); ``` -The definition isn't strictly required, since the function is only used through +The definition is not strictly required, since the function is only used through a `decltype` as it follows: ```cpp @@ -278,7 +278,7 @@ Everything else is the same as already shown instead. # Static polymorphism in the wild -Once the _concept_ and implementation are defined, it's possible to use the +Once the _concept_ and implementation are defined, it is possible to use the `poly` class template to _wrap_ instances that meet the requirements: ```cpp @@ -312,15 +312,15 @@ circle shape; drawable instance{std::in_place_type, shape}; ``` -Similarly, it's possible to create non-owning copies of `poly` from an existing +Similarly, it is possible to create non-owning copies of `poly` from an existing object: ```cpp drawable other = instance.as_ref(); ``` -In both cases, although the interface of the `poly` object doesn't change, it -doesn't construct any element or take care of destroying the referenced objects. +In both cases, although the interface of the `poly` object does not change, it +does not construct any element or take care of destroying the referenced objects. Note also how the underlying concept is accessed via a call to `operator->` and not directly as `instance.draw()`.
@@ -342,9 +342,9 @@ entt::basic_poly The default size is `sizeof(double[2])`, which seems like a good compromise between a buffer that is too large and one unable to hold anything larger than -an integer. The alignment requirement is optional, and by default such that it's +an integer. The alignment requirement is optional, and by default such that it is the most stringent (the largest) for any object whose size is at most equal to the one provided.
-It's worth noting that providing a size of 0 (which is an accepted value in all +It is worth noting that providing a size of 0 (which is an accepted value in all respects) will force the system to dynamically allocate the contained objects in all cases. diff --git a/docs/md/process.md b/docs/md/process.md index 517274c8e..29f037515 100644 --- a/docs/md/process.md +++ b/docs/md/process.md @@ -22,13 +22,13 @@ CRTP idiom. Moreover, derived classes specify what the intended type for elapsed times is. A process should expose publicly the following member functions whether needed -(note that it isn't required to define a function unless the derived class wants +(note that it is not required to define a function unless the derived class wants to _override_ the default behavior): * `void update(Delta, void *);` This is invoked once per tick until a process is explicitly aborted or ends - either with or without errors. Even though it's not mandatory to declare this + either with or without errors. Even though it is not mandatory to declare this member function. As a rule of thumb, each process should at least define it to work _properly_. The `void *` parameter is an opaque pointer to user data (if any) forwarded directly to the process during an update. @@ -36,8 +36,8 @@ to _override_ the default behavior): * `void init();` This is invoked when the process joins the running queue of a scheduler. It - happens usually as soon as the process is attached to the scheduler if it's a - top level one, otherwise when it replaces its parent if it's a _continuation_. + happens usually as soon as the process is attached to the scheduler if it is a + top level one, otherwise when it replaces its parent if it is a _continuation_. * `void succeeded();` @@ -87,7 +87,7 @@ private: ## Adaptor -Lambdas and functors can't be used directly with a scheduler because they aren't +Lambdas and functors cannot be used directly with a scheduler because they are not properly defined processes with managed life cycles.
This class helps in filling the gap and turning lambdas and functors into full-featured processes usable by a scheduler. @@ -109,7 +109,7 @@ Parameters have the following meaning: Both `succeed` and `fail` accept no parameters at all. -Note that usually users shouldn't worry about creating adaptors at all. A +Note that usually users should not worry about creating adaptors at all. A scheduler creates them internally, each and every time a lambda or a functor is used as a process. @@ -118,12 +118,12 @@ used as a process. A cooperative scheduler runs different processes and helps manage their life cycles. -Each process is invoked once per tick. If it terminates, it's removed -automatically from the scheduler, and it's never invoked again. Otherwise, -it's a good candidate to run one more time the next tick.
+Each process is invoked once per tick. If it terminates, it is removed +automatically from the scheduler, and it is never invoked again. Otherwise, +it is a good candidate to run one more time the next tick.
A process can also have a _child_. In this case, the parent process is replaced with its child when it terminates and only if it returns with success. In case -of errors, both the parent process and its child are discarded. This way, it's +of errors, both the parent process and its child are discarded. This way, it is easy to create a chain of processes to run sequentially. Using a scheduler is straightforward. To create it, users must provide only the @@ -156,7 +156,7 @@ scheduler.clear(); To attach a process to a scheduler, there are mainly two ways: -* If the process inherits from the `process` class template, it's enough to +* If the process inherits from the `process` class template, it is enough to indicate its type and submit all the parameters required to construct it to the `attach` member function: @@ -164,7 +164,7 @@ To attach a process to a scheduler, there are mainly two ways: scheduler.attach(1000u); ``` -* Otherwise, in case of a lambda or a functor, it's enough to provide an +* Otherwise, in case of a lambda or a functor, it is enough to provide an instance of the class to the `attach` member function: ```cpp diff --git a/docs/md/reference.md b/docs/md/reference.md index 6e7d0afde..305b74342 100644 --- a/docs/md/reference.md +++ b/docs/md/reference.md @@ -14,13 +14,13 @@ Others developed different architectures from scratch and therefore offer alternative solutions with their pros and cons. If you know of other similar projects out there, feel free to open an issue or a -PR, and I'll be glad to add them to this page.
+PR, and I will be glad to add them to this page.
I hope the following lists can grow much more in the future. # Similar projects -Below an incomplete list of similar projects that I've come across so far.
-If some terms or designs aren't clear, I recommend referring to the +Below an incomplete list of similar projects that I have come across so far.
+If some terms or designs are not clear, I recommend referring to the [_ECS Back and Forth_](https://skypjack.github.io/tags/#ecs) series for all the details. @@ -65,7 +65,7 @@ details. * Javascript: * [\@javelin/ecs](https://github.com/3mcd/javelin/tree/master/packages/ecs): an archetype ECS in TypeScript. - * [ecsy](https://github.com/MozillaReality/ecsy): I haven't had the time to + * [ecsy](https://github.com/MozillaReality/ecsy): I have not had the time to investigate the underlying design of `ecsy` but it looks cool anyway. * Perl: diff --git a/docs/md/resource.md b/docs/md/resource.md index d9b5db945..12a9764af 100644 --- a/docs/md/resource.md +++ b/docs/md/resource.md @@ -17,7 +17,7 @@ requirements of the piece of software in which they are used.
Examples are loading everything on start, loading on request, predictive loading, and so on. -`EnTT` doesn't pretend to offer a _one-fits-all_ solution for the different +`EnTT` does not pretend to offer a _one-fits-all_ solution for the different cases.
Instead, the library comes with a minimal, general purpose resource cache that might be useful in many cases. @@ -68,9 +68,9 @@ discarded when a player leaves it. ## Resource handle -Resources aren't returned directly to the caller. Instead, they are wrapped in a +Resources are not returned directly to the caller. Instead, they are wrapped in a _resource handle_, an instance of the `entt::resource` class template.
-For those who know the _flyweight design pattern_ already, that's exactly what +For those who know the _flyweight design pattern_ already, that is exactly what it is. To all others, this is the time to brush up on some notions instead. A shared pointer could have been used as a resource handle. In fact, the default @@ -84,21 +84,21 @@ more or all resource types could help over time. ## Loaders A loader is responsible for _loading_ resources (quite obviously).
-By default, it's just a callable object that forwards its arguments to the +By default, it is just a callable object that forwards its arguments to the resource itself. That is, a _passthrough type_. All the work is demanded to the constructor(s) of the resource itself.
Loaders also are fully customizable as expected. A custom loader is a class with at least one function call operator and a member type named `result_type`.
-The loader isn't required to return a resource handle. As long as `return_type` -is suitable for constructing a handle, that's fine. +The loader is not required to return a resource handle. As long as `return_type` +is suitable for constructing a handle, that is fine. When using the default handle, it expects a resource type which is convertible to or suitable for constructing an `std::shared_ptr` (where `Type` is the actual resource type).
In other terms, the loader should return shared pointers to the given resource -type. However, this isn't mandatory. Users can easily get around this constraint +type. However, this is not mandatory. Users can easily get around this constraint by specializing both the handle and the loader. A cache forwards all its arguments to the loader if required. This means that @@ -139,7 +139,7 @@ entt::resource_cache cache{}; Under the hood, a cache is nothing more than a map where the key value has type `entt::id_type` while the mapped value is whatever type its loader returns.
For this reason, it offers most of the functionalities a user would expect from -a map, such as `empty` or `size` and so on. Similarly, it's an iterable type +a map, such as `empty` or `size` and so on. Similarly, it is an iterable type that also supports indexing by resource id: ```cpp @@ -158,7 +158,7 @@ functions (such as `contains` or `erase`). Set aside the part of the API that this class _shares_ with a map, it also adds something on top of it in order to address the most common requirements of a resource cache.
-In particular, it doesn't have an `emplace` member function which is replaced by +In particular, it does not have an `emplace` member function which is replaced by `load` and `force_load` instead (where the former loads a new resource only if not present while the second triggers a forced loading in any case): @@ -176,10 +176,10 @@ Note that the hashed string is used for convenience in the example above.
Resource identifiers are nothing more than integral values. Therefore, plain numbers as well as non-class enum value are accepted. -It's worth mentioning that the iterators of a cache as well as its indexing +It is worth mentioning that the iterators of a cache as well as its indexing operators return resource handles rather than instances of the mapped type.
-Since the cache has no control over the loader and a resource isn't required to +Since the cache has no control over the loader and a resource is not required to also be convertible to bool, these handles can be invalid. This usually means an error in the user logic, but it may also be an _expected_ event.
-It's therefore recommended to verify handles validity with a check in debug (for +It is therefore recommended to verify handles validity with a check in debug (for example, when loading) or an appropriate logic in retail. diff --git a/docs/md/signal.md b/docs/md/signal.md index 705267aa2..63bc0efd0 100644 --- a/docs/md/signal.md +++ b/docs/md/signal.md @@ -21,12 +21,12 @@ communicate with each other somehow. The so-called _modern C++_ comes with a tool that can be useful in this regard, the `std::function`. As an example, it can be used to create delegates.
-However, there is no guarantee that an `std::function` doesn't perform +However, there is no guarantee that an `std::function` does not perform allocations under the hood and this could be problematic sometimes. Furthermore, it solves a problem but may not adapt well to other requirements that may arise from time to time. -In case that the flexibility and power of an `std::function` isn't required or +In case that the flexibility and power of an `std::function` is not required or if the price to pay for them is too high, `EnTT` offers a complete set of lightweight classes to solve the same and many other problems. @@ -35,8 +35,8 @@ lightweight classes to solve the same and many other problems. A delegate can be used as a general purpose invoker with no memory overhead for free functions, lambdas and members provided along with an instance on which to invoke them.
-It doesn't claim to be a drop-in replacement for an `std::function`, so don't -expect to use it whenever an `std::function` fits well. That said, it's most +It does not claim to be a drop-in replacement for an `std::function`, so do not +expect to use it whenever an `std::function` fits well. That said, it is most likely even a better fit than an `std::function` in a lot of cases, so expect to use it quite a lot anyway. @@ -76,7 +76,7 @@ value of the data member is at least convertible to the return type. Free functions having type equivalent to `void(T &, args...)` are accepted as well. The first argument `T &` is considered a payload, and the function will -receive it back every time it's invoked. In other terms, this works just fine +receive it back every time it is invoked. In other terms, this works just fine with the above definition: ```cpp @@ -106,7 +106,7 @@ is used as a building block of a signal-slot system.
In fact, this filtering works both ways. The class tries to pass its first _count_ arguments **first**, then the last _count_. Watch out for conversion rules if in doubt when connecting a listener!
-Arbitrary functions that pull random arguments from the delegate list aren't +Arbitrary functions that pull random arguments from the delegate list are not supported instead. Other features were preferred, such as support for functions with compatible argument lists although not equal to those of the delegate. @@ -118,7 +118,7 @@ means of the `entt::connect_arg` variable template: entt::delegate func{entt::connect_arg<&f>}; ``` -Aside `connect`, a `disconnect` counterpart isn't provided. Instead, there +Aside `connect`, a `disconnect` counterpart is not provided. Instead, there exists a `reset` member function to use to clear a delegate.
To know if a delegate is empty, it can be used explicitly in every conditional statement: @@ -136,7 +136,7 @@ already shown in the examples above: auto ret = delegate(42); ``` -In all cases, listeners don't have to strictly follow the signature of the +In all cases, listeners do not have to strictly follow the signature of the delegate. As long as a listener can be invoked with the given arguments to yield a result that is convertible to the given result type, everything works just fine. @@ -154,8 +154,8 @@ my_struct instance; delegate(instance, 42); ``` -In this case, it's not possible to _deduce_ the function type since the first -argument doesn't necessarily have to be a reference (for example, it can be a +In this case, it is not possible to _deduce_ the function type since the first +argument does not necessarily have to be a reference (for example, it can be a pointer, as well as a const reference).
Therefore, the function type must be declared explicitly for unbound members. @@ -164,13 +164,13 @@ Therefore, the function type must be declared explicitly for unbound members. The `delegate` class is meant to be used primarily with template arguments. However, as a consequence of its design, it also offers minimal support for runtime arguments.
-When used like this, some features aren't supported though. In particular: +When used like this, some features are not supported though. In particular: -* Curried functions aren't accepted. -* Functions with an argument list that differs from that of the delegate aren't +* Curried functions are not accepted. +* Functions with an argument list that differs from that of the delegate are not supported. * Return type and types of arguments **must** coincide with those of the - delegate and _being at least convertible_ isn't enough anymore. + delegate and _being at least convertible_ is not enough anymore. Moreover, for a given function type `Ret(Args...)`, the signature of the functions connected at runtime must necessarily be `Ret(const void *, Args...)`. @@ -200,12 +200,12 @@ explained. ## Lambda support -In general, the `delegate` class doesn't fully support lambda functions in all -their nuances. The reason is pretty simple: a `delegate` isn't a drop-in +In general, the `delegate` class does not fully support lambda functions in all +their nuances. The reason is pretty simple: a `delegate` is not a drop-in replacement for an `std::function`. Instead, it tries to overcome the problems with the latter.
That being said, non-capturing lambda functions are supported, even though some -features aren't available in this case. +features are not available in this case. This is a logical consequence of the support for connecting functions at runtime. Therefore, lambda functions undergo the same rules and @@ -228,7 +228,7 @@ delegate.connect([](const void *ptr, int value) { }, &instance); ``` -As above, the first parameter (`const void *`) isn't part of the function type +As above, the first parameter (`const void *`) is not part of the function type of the delegate and is used to dispatch arbitrary user data back and forth. In other terms, the function type of the delegate above is `int(int)`. @@ -255,7 +255,7 @@ particular delegate through its descriptive _traits_ instead. Signal handlers work with references to classes, function pointers, and pointers to members. Listeners can be any kind of objects, and users are in charge of connecting and disconnecting them from a signal to avoid crashes due to -different lifetimes. On the other side, performance shouldn't be affected that +different lifetimes. On the other side, performance should not be affected that much by the presence of such a signal handler.
Signals make use of delegates internally, and therefore they undergo the same rules and offer similar functionalities. It may be a good idea to consult the @@ -271,7 +271,7 @@ The API of a signal handler is straightforward. If a collector is supplied to the signal when something is published, all the values returned by its listeners are literally _collected_ and used later by the caller. Otherwise, the class works just like a plain signal that emits events from time to time.
-To create instances of signal handlers it's sufficient to provide the type of +To create instances of signal handlers it is sufficient to provide the type of function to which they refer: ```cpp @@ -315,7 +315,7 @@ sink.disconnect(&instance); sink.disconnect(); ``` -As shown above, listeners don't have to strictly follow the signature of the +As shown above, listeners do not have to strictly follow the signature of the signal. As long as a listener can be invoked with the given arguments to yield a result that is convertible to the given return type, everything works just fine.
@@ -357,7 +357,7 @@ assert(vec[1] == 1); A collector must expose a function operator that accepts as an argument a type to which the return type of the listeners can be converted. Moreover, it can optionally return a boolean value that is true to stop collecting data, false -otherwise. This way one can avoid calling all the listeners in case it isn't +otherwise. This way one can avoid calling all the listeners in case it is not necessary.
Functors can also be used in place of a lambda. Since the collector is copied when invoking the `collect` member function, `std::ref` is the way to go in this @@ -383,7 +383,7 @@ signal.collect(std::ref(collector)); The event dispatcher class allows users to trigger immediate events or to queue and publish them all together later.
-This class lazily instantiates its queues. Therefore, it's not necessary to +This class lazily instantiates its queues. Therefore, it is not necessary to _announce_ the event types in advance: ```cpp @@ -430,7 +430,7 @@ dispatcher.trigger(an_event{42}); dispatcher.trigger(); ``` -Listeners are invoked immediately, order of execution isn't guaranteed. This +Listeners are invoked immediately, order of execution is not guaranteed. This method can be used to push around urgent messages like an _is terminating_ notification on a mobile app. @@ -459,7 +459,7 @@ once per tick to their systems. All queues within a dispatcher are associated by default with an event type and then retrieved from it.
-However, it's possible to create queues with different _names_ (and therefore +However, it is possible to create queues with different _names_ (and therefore also multiple queues for a single type). In fact, more or less all functions also take an additional parameter. As an example: @@ -495,7 +495,7 @@ struct my_emitter: emitter { } ``` -Handlers for the different events are created internally on the fly. It's not +Handlers for the different events are created internally on the fly. It is not required to specify in advance the full list of accepted events.
Moreover, whenever an event is published, an emitter also passes a reference to itself to its listeners. @@ -555,5 +555,5 @@ if(emitter.contains()) { ``` This class introduces a _nice-to-have_ model based on events and listeners.
-More in general, it's a handy tool when the derived classes _wrap_ asynchronous -operations, but it's not limited to such uses. +More in general, it is a handy tool when the derived classes _wrap_ asynchronous +operations, but it is not limited to such uses. diff --git a/docs/md/unreal.md b/docs/md/unreal.md index 9044ac711..702268b50 100644 --- a/docs/md/unreal.md +++ b/docs/md/unreal.md @@ -24,7 +24,7 @@ CppStandard = CppStandardVersion.Cpp17; Replace `.h` with the name of the already existing PCH header file, if any.
-In case the project doesn't already contain a file of this type, it's possible +In case the project does not already contain a file of this type, it is possible to create one with the following content: ```cpp @@ -37,7 +37,7 @@ this point, C++17 support should be in place.
Try to compile the project to ensure it works as expected before following further steps. -Note that updating a *project* to C++17 doesn't necessarily mean that the IDE in +Note that updating a *project* to C++17 does not necessarily mean that the IDE in use will also start to recognize its syntax.
If the plan is to use C++17 in the project too, check the specific instructions for the IDE in use. @@ -62,7 +62,7 @@ Source \---entt (GitHub repository content inside) ``` -To make this happen, create the folder `ThirdParty` under `Source` if it doesn't +To make this happen, create the folder `ThirdParty` under `Source` if it does not exist already. Then, add an `EnTT` folder under `ThirdParty`.
Within the latter, create a new file `EnTT.Build.cs` with the following content: From e8d3a85e5eb230d43a098ba77bc990dad877308b Mon Sep 17 00:00:00 2001 From: theaddon Date: Thu, 23 Jan 2025 20:35:29 +0100 Subject: [PATCH 17/23] correct can not to cannot in entity.md --- docs/md/entity.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/md/entity.md b/docs/md/entity.md index b84110a73..3c5559fc7 100644 --- a/docs/md/entity.md +++ b/docs/md/entity.md @@ -2324,7 +2324,7 @@ expedients. Finally, `EnTT` is configured via a few compile-time definitions to make some of its parts implicitly thread-safe, roughly speaking only the ones that really -make sense and can not be turned around.
+make sense and cannot be turned around.
In particular, when multiple instances of objects referencing the type index generator (such as the `registry` class) are used in different threads, then it might be useful to define `ENTT_USE_ATOMIC`.
From 30998ba2965cfabb27fe89bc1c764f3ea783fa66 Mon Sep 17 00:00:00 2001 From: theaddon Date: Sun, 26 Jan 2025 21:29:28 +0100 Subject: [PATCH 18/23] fixup get_allocator code formatting --- docs/md/graph.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/md/graph.md b/docs/md/graph.md index 325135078..e3f52a8a6 100644 --- a/docs/md/graph.md +++ b/docs/md/graph.md @@ -108,7 +108,7 @@ Both the functions expect the vertex to visit (that is, to return the in- or out-edges for) as an argument.
Finally, the adjacency matrix is an allocator-aware container and offers most of the functionalities one would expect from this type of containers, such as -`clear` or 'get_allocator' and so on. +`clear` or `get_allocator` and so on. ## Graphviz dot language From dd01af140ed618f72e7f32f603836de2ea278478 Mon Sep 17 00:00:00 2001 From: theaddon Date: Sun, 26 Jan 2025 21:31:30 +0100 Subject: [PATCH 19/23] replace default-constructible with default constructible --- docs/md/entity.md | 2 +- docs/md/meta.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/md/entity.md b/docs/md/entity.md index 3c5559fc7..4f84e3b63 100644 --- a/docs/md/entity.md +++ b/docs/md/entity.md @@ -831,7 +831,7 @@ reduce the boilerplate in the most complex cases. A handle is a thin wrapper around an entity and a registry. It _replicates_ the API of a registry by offering functions such as `get` or `emplace`. The difference being that the entity is implicitly passed to the registry.
-It is default-constructible as an invalid handle that contains a null registry +It is default constructible as an invalid handle that contains a null registry and a null entity. When it contains a null registry, calling functions that delegate execution to the registry causes undefined behavior. It is recommended to test for validity with its implicit cast to `bool` if in doubt.
diff --git a/docs/md/meta.md b/docs/md/meta.md index c14af62e3..0275a2e2c 100644 --- a/docs/md/meta.md +++ b/docs/md/meta.md @@ -713,13 +713,13 @@ always preferred over the automatic ones. ## Implicitly generated default constructor -Creating objects of default-constructible types through the reflection system +Creating objects of default constructible types through the reflection system while not having to explicitly register the meta-type or its default constructor is also possible.
For example, in the case of primitive types like `int` or `char`, but not just them. -For default-constructible types only, default constructors are automatically +For default constructible types only, default constructors are automatically defined and associated with their meta-types, whether they are explicitly or implicitly generated.
Therefore, this is all needed to construct an integer from its meta-type: From 82e6fddd05a69e3d767b70de61be62df3f4334d0 Mon Sep 17 00:00:00 2001 From: theaddon Date: Sun, 26 Jan 2025 21:32:33 +0100 Subject: [PATCH 20/23] needs to replaced by needs --- docs/md/core.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/md/core.md b/docs/md/core.md index 541ff2b80..4cdacc6d1 100644 --- a/docs/md/core.md +++ b/docs/md/core.md @@ -831,7 +831,7 @@ type list: * `type_list_transform[_t]` to _transform_ a range and create another type list. I am also pretty sure that more and more utilities will be added over time as -needs to become apparent.
+needs become apparent.
Many of these functionalities also exist in their version dedicated to value lists. We therefore have `value_list_element[_v]` as well as `value_list_cat[_t]`and so on. From 04b865daa4aba6cae797d7681bc1be7f6290c57a Mon Sep 17 00:00:00 2001 From: theaddon Date: Sun, 26 Jan 2025 21:34:27 +0100 Subject: [PATCH 21/23] Replace ; with . for proper grammar --- docs/md/core.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/md/core.md b/docs/md/core.md index 4cdacc6d1..fc2305537 100644 --- a/docs/md/core.md +++ b/docs/md/core.md @@ -873,7 +873,7 @@ where constant expressions are required. As long as the list remains unchanged, identifiers are also guaranteed to be stable across different runs. In case they have been used in a production -environment, and a type has to be removed; one can just use a placeholder to +environment, and a type has to be removed. One can just use a placeholder to leave the other identifiers unchanged: ```cpp From 29bdbf1837ccf070a78ff1305b5dc89fe1188730 Mon Sep 17 00:00:00 2001 From: theaddon Date: Sun, 26 Jan 2025 21:36:09 +0100 Subject: [PATCH 22/23] dehyphenate sparse set-based --- docs/md/entity.md | 2 +- docs/md/reference.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/md/entity.md b/docs/md/entity.md index 4f84e3b63..70eb6c1da 100644 --- a/docs/md/entity.md +++ b/docs/md/entity.md @@ -74,7 +74,7 @@ used mostly in game development. ## Type-less and bitset-free -The library implements a sparse set-based model that does not require users to +The library implements a sparse set based model that does not require users to specify the set of components neither at compile-time nor at runtime.
This is why users can instantiate the core class simply like: diff --git a/docs/md/reference.md b/docs/md/reference.md index 305b74342..616a1b00b 100644 --- a/docs/md/reference.md +++ b/docs/md/reference.md @@ -53,7 +53,7 @@ details. with focus on performance and minimal GC allocations. * [LeoECS](https://github.com/Leopotam/ecs): simple lightweight C# Entity Component System framework. - * [Massive ECS](https://github.com/nilpunch/massive): sparse set-based ECS + * [Massive ECS](https://github.com/nilpunch/massive): sparse set based ECS featuring rollbacks. * [Svelto.ECS](https://github.com/sebas77/Svelto.ECS): a very interesting platform-agnostic- and table-based ECS framework. @@ -79,7 +79,7 @@ details. * Rust: * [Shipyard](https://github.com/leudz/shipyard): it borrows some ideas from `EnTT` and offers a sparse sets based ECS with grouping functionalities. - * [Sparsey](https://github.com/LechintanTudor/sparsey): sparse set-based ECS + * [Sparsey](https://github.com/LechintanTudor/sparsey): sparse set based ECS written in Rust. * [Specs](https://github.com/amethyst/specs): a parallel ECS based mainly on hierarchical bitsets that allows different types of storage as needed. From 34a91d1b5be55e24f27d454daac7827b490fe95a Mon Sep 17 00:00:00 2001 From: theaddon Date: Sun, 26 Jan 2025 21:52:37 +0100 Subject: [PATCH 23/23] correct break --- docs/md/process.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/md/process.md b/docs/md/process.md index 29f037515..be02f917b 100644 --- a/docs/md/process.md +++ b/docs/md/process.md @@ -28,10 +28,10 @@ to _override_ the default behavior): * `void update(Delta, void *);` This is invoked once per tick until a process is explicitly aborted or ends - either with or without errors. Even though it is not mandatory to declare this - member function. As a rule of thumb, each process should at least define it to - work _properly_. The `void *` parameter is an opaque pointer to user data (if - any) forwarded directly to the process during an update. + either with or without errors. Technically speaking, this member function is + not strictly required. However, each process should at least define it to work + _properly_. The `void *` parameter is an opaque pointer to user data (if any) + forwarded directly to the process during an update. * `void init();`