From e1150a98fc7c39b91acc4062402ca23bc63773d0 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Sat, 16 Dec 2023 19:54:42 +0300 Subject: [PATCH] Tidy up ecs library docs --- libs/ecs/include/psemek/ecs/accessor.hpp | 22 ++- libs/ecs/include/psemek/ecs/container.hpp | 224 ++++++++++++++-------- 2 files changed, 157 insertions(+), 89 deletions(-) diff --git a/libs/ecs/include/psemek/ecs/accessor.hpp b/libs/ecs/include/psemek/ecs/accessor.hpp index c5a65af3..03dbe071 100644 --- a/libs/ecs/include/psemek/ecs/accessor.hpp +++ b/libs/ecs/include/psemek/ecs/accessor.hpp @@ -43,22 +43,30 @@ namespace psemek::ecs explicit operator bool() const; - /** Obtain a pointer to the specified component type - * of the accessed entity, or a null pointer if - * the entity doesn't contain this component type. + /** Obtain the component of the specified type of the accessed entity. + * + * @tparam Component The type of component to obtain + * @return A pointer to the component of the specified type, or a null + * pointer if the entity doesn't contain a component of this type */ template Component * get_if(); - /** Obtain a reference to the specified component type - * of the accessed entity. - * If the entity doesn't contain this component type, - * an exception of type `component_not_found_exception` is thrown. + /** Obtain the component of the specified type of the accessed entity. + * + * @tparam Component The type of component to obtain + * @return A reference to the component of the specified type + * @throw component_not_found_exception if the entity doesn't + * contain a component of this type */ template Component & get(); /** Check if the entity contains this component type. + * + * @tparam Component The type of component to obtain + * @return True if the entity contains a component of the specified + * type, false otherwise */ template bool contains() const; diff --git a/libs/ecs/include/psemek/ecs/container.hpp b/libs/ecs/include/psemek/ecs/container.hpp index 75141118..ce923420 100644 --- a/libs/ecs/include/psemek/ecs/container.hpp +++ b/libs/ecs/include/psemek/ecs/container.hpp @@ -33,98 +33,127 @@ namespace psemek::ecs struct container { - /** Create an entity with the specified components. - * It is faster to create an entity with all the components at once, than to - * create it with no components and `attach()` them one-by-one. - * If any two of the passed component types are equal, the call fails with - * a compilation error. - * After the function returns, the new entity is considered alive (`alive(handle)` returns true). - * Creating a new entity invalidates all previously created accessors. + /** Create an entity with the specified components. It is faster to create an entity + * with all the components at once than to create it with no components and `attach()` + * them one-by-one. + * + * After the function returns, the new entity is considered alive (`alive()` returns true). + * * If the entity is created during iteration (inside an `apply()` call), it is unspecified * whether the created entity will be visited by iteration or not. + * + * @param components The components to initialize the entity with + * @return A unique handle to the created entity + * @warning If any two of the passed component types are equal, the call fails with + * a compilation error + * @warning Creating a new entity invalidates all previously created accessors + * @warning It is an error to create or destroy entities during `batch_apply()` */ template handle create(Components && ... components); - /** Check if an entity handle refers to an alive entity (i.e. one that wasn't - * destroyed yet). - * If the handle wasn't previously obtained by a `create()` call, the - * behavior is undefined. + /** Check if an entity handle refers to an alive entity, i.e. one that wasn't + * destroyed yetby a `destroy()` call. + * + * @param entity A handle to the entity + * @return True if the entity is still alive, false otherwise + * @pre The entity was previously obtained by a `create()` call */ bool alive(handle const & entity) const; - /** Destroy an entity specified by a handle. After the call, `alive()` - * returns false for this handle. + /** Destroy an entity specified by a handle. After the call, `alive()` returns false for this handle. + * * If the entity is destroyed during iteration (inside an `apply()` call), the iteration * is guaranteed not to visit the destroyed entity (unless it did so before the entity * was destroyed). - * If the handle wasn't previously obtained by a `create()` call, or - * the refered entity was already destroyed, the behavior is undefined. + * + * @param entity A handle to the entity to be destroyed + * @pre The entity was previously obtained by a `create()` call and is `alive()` + * @warning It is an error to create or destroy entities during `batch_apply()` */ void destroy(handle const & entity); /** Get an accessor for an entity, which provides access to the entity's components. * It is designed to be a single-use object; it cannot be stored as a reference to * the entity. Use handle for that instead. - * Creating or destroying entities, as well as attaching or detaching components, - * invalidates all previously created accessors. - * If the handle wasn't previously obtained by a `create()` call, or - * the referred entity was already destroyed, the behavior is undefined. + * + * @param entity A handle to the entity to be destroyed + * @return An accessor to the specified entity + * @pre The entity was previously obtained by a `create()` call and is `alive()` + * @warning Creating or destroying entities, as well as attaching or detaching components, + * invalidates all previously created accessors */ accessor get(handle const & entity); /** Attach new components to an existing entity, or update existing * components with new values. Other components of this entity * are left untouched. - * Attaching components invalidates all previously created accessors. - * For the purposes of `apply()` semantics, attaching behaves as if the - * entity was destroyed and then recreated with the same handle. - * If any two of the passed component types are equal, the call fails with - * a compilation error. - * If the handle wasn't previously obtained by a `create()` call, or - * the refered entity was already destroyed, the behavior is undefined. + * + * For the purposes of `apply()` semantics, attaching behaves as if + * the entity was destroyed and then recreated with the same handle. + * + * @param entity A handle to the entity to attach components to + * @param components The components to attach to the entity + * @pre The entity was previously obtained by a `create()` call and is `alive()` + * @warning If any two of the passed component types are equal, the call fails with + * a compilation error + * @warning Attaching components invalidates all previously created accessors + * @warning It is an error to attach or detach components during `batch_apply()` */ template void attach(handle const & entity, Components && ... components); - /** Detach (remove) components from an existing entity. Other components of this entity - * are left untouched. Detaching a component that doesn't exist does nothing. - * Detaching components invalidates all previously created accessors. - * For the purposes of `apply()` semantics, detaching behaves as if the - * entity was destroyed and then recreated with the same handle. - * If any two of the passed component types are equal, the call fails with - * a compilation error. - * If the handle wasn't previously obtained by a `create()` call, or - * the refered entity was already destroyed, the behavior is undefined. + /** Detach (remove) components from an existing entity. Other components of this + * entity are left untouched. Detaching a component that doesn't exist is not + * an error, and does nothing. + * + * For the purposes of `apply()` semantics, detaching behaves as if + * the entity was destroyed and then recreated with the same handle. + * + * @param entity A handle to the entity to detach components from + * @tparam Components The component types to detach from the entity + * @pre The entity was previously obtained by a `create()` call and is `alive()` + * @warning If any two of the passed component types are equal, the call fails with + * a compilation error + * @warning Detaching components invalidates all previously created accessors + * @warning It is an error to attach or detach components during `batch_apply()` */ template void detach(handle const & entity); /** Create a query cache that can be used to speed up `apply()` calls. + * + * @tparam Components The component types matching the corresponding `apply()` call + * @return A query cache */ template query_cache cache(); - /** Apply a function to all entities having the specified components, - * in unspecified order. + /** Apply a function to all entities having the specified components, in unspecified order. + * * The function must have one of the following signatures: * void(components...) * void(handle, components...) * void(container, components...) * void(container, handle, components...) + * * The function can freely create or destroy entities, and or attach/detach * components to existing entities. It is unspecified whether the function * will or will not visit newly created entities during this `apply()` call. * The function is guaranteed not to visit destroyed entities (unless it did * so before the entity was destroyed). + * * An optional query cache can be supplied to speed up iteration. - * If any two of the passed component types are equal, the call fails with - * a compilation error. - * If the query cache wasn't created with the exact same sequence of component - * types, the behavior is undefined. - * If the function accesses passed components after destroying the - * currently visited entity, the behavior is undefined. - * If the function recursively calls `apply()` or `batch_apply()`, the behavior is undefined. + * + * @param function The function to apply to all entities with the specified components + * @param cache A query cache + * @pre The query query cache was created with the exact same sequence of component types + * @warning If any two of the passed component types are equal, the call fails with + * a compilation error + * @warning If the function accesses passed components after destroying the + * currently visited entity, the behavior is undefined + * @warning If the function recursively calls `apply()` or `batch_apply()`, the + * behavior is undefined */ template void apply(Function && function, query_cache cache = {}); @@ -133,81 +162,112 @@ namespace psemek::ecs * in unspecified order. Instead of applying the function to each * entity separately, it is applied in "batch" mode, i.e. to array * views of respective components. + * * The function must have one of the following signatures: * void(span...) * void(span, span...) * void(container, span...) * void(container, span, span...) - * The size of all spans within a single function call are the same, + * + * The sizes of all spans within a single function call are the same, * except for empty component types (i.e. std::is_empty_v is true), - * each having an unspecified non-zero size. + * each having an unspecified non-zero size. If all components are empty types, + * the function should use the entity handles array view to compute the number + * of visited entities. + * * An optional query cache can be supplied to speed up iteration. - * If any two of the passed component types are equal, the call fails with - * a compilation error. - * If the query cache wasn't created with the exact same sequence of component - * types, the behavior is undefined. - * If the function creates or destroyes entities, the behavior is undefined. - * If the function recursively calls `apply()` or `batch_apply()`, the behavior is undefined. + * + * @param function The function to batch-apply to all entities with the specified components + * @param cache A query cache + * @pre The query query cache was created with the exact same sequence of component types + * @warning If any two of the passed component types are equal, the call fails with + * a compilation error + * @warning If the function creates or destroyes entities, or attaches or detaches components, + * the behavior is undefined + * @warning If the function recursively calls `apply()` or `batch_apply()`, the behavior is undefined */ template void batch_apply(Function && function, query_cache cache = {}); /** Register a constructor. Each time an entity is created that has - * the specified set of components (including attaching components), - * the constructor is called for this entity immediately after - * it is created. + * the specified set of components, the constructor is called for + * this entity immediately after it is created. + * + * The entity is considered `alive()` during the constructor invocation. + * + * When attaching components to an entity, the constructor is called + * exactly when the entity didn't match the constructor's component types + * before attaching new components, and does match them after attaching. + * * The constructor function must have the same signature as a function * passed to the `apply()` call. - * The returned value is an ownerwhip token. Destroying it removes - * the constructor from the container. - * If any two of the passed component types are equal, the call fails with - * a compilation error. - * If the constructor modifies the entity's archetype (i.e. attaches or + * + * The constructor can immediately destroy the created entity. + * + * @param function A function to be applied to created entity's components + * @return An ownerwhip token; destroying this token removes + * the constructor from this container + * @warning If any two of the passed component types are equal, the call fails with + * a compilation error + * @warning If the constructor modifies the entity's archetype (i.e. attaches or * detaches components), it might be called recursively, leading to * infinite recursion. It is best not to change the archetype from the * constructor. - * The constructor can immediately destroy the created entity. */ // TODO: implement template token constructor(Function && function); /** Register a destructor. Each time an entity is destroyed that has - * the specified set of components (including detaching components), - * the destructor is called for this entity immediately before - * it will be destroyed. + * the specified set of components, the destructor is called for + * this entity immediately before it will be destroyed. + * + * The entity is considered `alive()` during the destructor invocation. + * + * When detaching components from an entity, the destructor is called + * exactly when the entity did match the destructor's component types + * before detaching components, and doesn't match them after detaching. + * * The destructor function must have the same signature as a function * passed to the `apply()` call. - * The returned value is an ownerwhip token. Destroying it removes - * the destructor from the container. - * If any two of the passed component types are equal, the call fails with - * a compilation error. - * If the destructor modifies the entity's archetype (i.e. attaches or - * detaches components), the behavior is undefined. + * * Note that there is no way to cancel the entity's destruction. + * + * @param function A function to be applied to a to-be destroyed entity's components + * @return An ownerwhip token; destroying it removes the destructor from the container + * @warning If any two of the passed component types are equal, the call fails with + * a compilation error + * @warning If the destructor modifies the entity's archetype (i.e. attaches or + * detaches components), the behavior is undefined */ // TODO: implement template token destructor(Function && function); /** Register a component modification callback. Each time an entity that has - * the specified set of components is modified, and the modification only - * affects this callback's components, the callback is called. + * the specified set of components is modified, and the modification affects + * one of this callback's component types, the callback is called. + * * If the modification occurred via an accessor, the callback is called - * when the accessor is destroyed, allowing for transaction-like modification. + * after the accessor is destroyed, allowing for transaction-like modification. + * * If the modification occurred via an `apply()` or `batch_apply()` call, - * the callback is called as if immediately after this call. + * the callback is called immediately after this call. + * * Note that modifications from within a modification callback are not considered * as modifications, i.e. they don't recursively invoke modification callbacks. - * Therefore, it is best to accept const-qualified components in the callback. - * The callback must have the same signature as a function + * + * The callback function must have the same signature as a function * passed to the `apply()` call. - * The returned value is an ownerwhip token. Destroying it removes - * the callback from the container. - * If any two of the passed component types are equal, the call fails with - * a compilation error. - * If the callback modifies the entity's archetype (i.e. attaches or - * detaches components), or destroys the entity, the behavior is undefined. + * + * @param function A function to be applied to modified entity's components + * @return An ownerwhip token; destroying it removes the modification callback from the container + * @warning If any two of the passed component types are equal, the call fails with + * a compilation error + * @warning If the modification callback modifies the entity's archetype (i.e. attaches or + * detaches components), the behavior is undefined + * + * TODO: can we allow the callback to modify the archetype? */ // TODO: implement template