Skip to content

Commit

Permalink
Introduce AStorage to refactor common code for storages
Browse files Browse the repository at this point in the history
Linked: #144
  • Loading branch information
AndreasLrx committed Apr 23, 2024
1 parent ad04dca commit 331c583
Show file tree
Hide file tree
Showing 9 changed files with 241 additions and 429 deletions.
178 changes: 178 additions & 0 deletions src/ecstasy/storages/AStorage.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
///
/// @file IStorage.hpp
/// @author Andréas Leroux ([email protected])
/// @brief
/// @version 1.0.0
/// @date 2022-10-19
///
/// @copyright Copyright (c) ECSTASY 2022 - 2024
///
///

#ifndef ECSTASY_STORAGE_ASTORAGE_HPP_
#define ECSTASY_STORAGE_ASTORAGE_HPP_

#include <span>

#include "ecstasy/config.hpp"
#include "ecstasy/resources/entity/Entity.hpp"
#include "ecstasy/storages/IStorage.hpp"
#include "util/BitSet.hpp"

namespace ecstasy
{

///
/// @brief Abstract class for all components storage.
///
/// @tparam C Component type.
///
/// @author Andréas Leroux ([email protected])
/// @since 1.0.0 (2024-04-23)
///
template <typename C>
class AStorage : public IStorage {
public:
/// @brief IsStorage constraint
using Component = C;

/// @brief @ref ecstasy::query::QueryableObject constraint.
using QueryData = C &;
/// @brief @ref ecstasy::query::ConstQueryableObject constraint.
using ConstQueryData = const C &;

///
/// @brief Erase the @b Component instance associated to the given entity.
///
/// @note Does nothing if the index doesn't match with any component (ie if the entity doesn't have a component
/// @b Component)
///
/// @param[in] index Index of the entity.
///
/// @return bool True if the component was erased, false otherwise.
///
/// @author Andréas Leroux ([email protected])
/// @since 1.0.0 (2022-10-19)
///
virtual bool erase(Entity::Index index) = 0;

///
/// @brief Erase multiple @b Component instances associated to the given @p entities.
///
/// @note Does nothing for entity without attached component (ie if the entity doesn't have a component
/// @b Component)
///
/// @param[in] entities target entities.
///
/// @author Andréas Leroux ([email protected])
/// @since 1.0.0 (2022-10-21)
///
void erase(std::span<Entity> entities) override final
{
for (Entity entity : entities)
erase(entity.getIndex());
}

///
/// @brief Test if the entity index match a @b Component instance.
///
/// @param[in] index Index of the entity.
///
/// @return bool True if the entity has a component, false otherwise.
///
/// @author Andréas Leroux ([email protected])
/// @since 1.0.0 (2022-10-19)
///
constexpr bool contains(Entity::Index index) const noexcept
{
return (index < getMask().size()) && getMask()[index];
}

///
/// @brief Retrieve the @b Component instance associated to the given entity and perform bound checking.
///
/// @param[in] index Index of the entity.
///
/// @return QueryData Reference to the associated component.
///
/// @throw std::out_of_range If the entity doesn't have the component.
///
/// @author Andréas Leroux ([email protected])
/// @since 1.0.0 (2024-04-23)
///
Component &at(Entity::Index index)
{
if (!contains(index))
throw std::out_of_range("Entity doesn't have the component");
return (*this)[index];
}

///
/// @brief Retrieve the @b Component instance associated to the given entity and perform bound checking.
///
/// @param[in] index Index of the entity.
///
/// @return QueryData Reference to the associated component.
///
/// @throw std::out_of_range If the entity doesn't have the component.
///
/// @author Andréas Leroux ([email protected])
/// @since 1.0.0 (2024-04-23)
///
const Component &at(Entity::Index index) const
{
if (!contains(index))
throw std::out_of_range("Entity doesn't have the component");
return (*this)[index];
}

///
/// @brief Retrieve the @b Component instance associated to the given entity.
///
/// @warning This function may not perform bound checking. For @ref VectorStorage or @ref MarkerStorage it is
/// noexcept but not for @ref MapStorage for example.
///
/// @param[in] index Index of the entity.
///
/// @return Component& Reference to the associated component.
///
/// @author Andréas Leroux ([email protected])
/// @since 1.0.0 (2022-10-19)
///
virtual Component &operator[](Entity::Index index) = 0;

/// @copydoc operator[](Entity::Index)
///
/// @note @ref ecstasy::query::QueryableObject constraint.
QueryData getQueryData(Entity::Index index)
{
return (*this)[index];
};

///
/// @brief Retrieve the const @b Component instance associated to the given entity.
///
/// @warning This function may not perform bound checking. For @ref VectorStorage or @ref MarkerStorage it is
/// noexcept but not for @ref MapStorage for example.
///
/// @param[in] index Index of the entity.
///
/// @return const Component& Const reference to the associated component.
///
/// @author Andréas Leroux ([email protected])
/// @since 1.0.0 (2022-10-19)
///
virtual const Component &operator[](Entity::Index index) const = 0;

/// @copydoc operator[](Entity::Index)
///
/// @note @ref ecstasy::query::ConstQueryableObject constraint.
ConstQueryData getQueryData(Entity::Index index) const
{
return (*this)[index];
};
};

} // namespace ecstasy

#endif /* !ECSTASY_STORAGE_ASTORAGE_HPP_ */
1 change: 1 addition & 0 deletions src/ecstasy/storages/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ set(SRC
${INCROOT}/include.hpp
${INCROOT}/Instances.hpp
${INCROOT}/IStorage.hpp
${INCROOT}/AStorage.hpp
${INCROOT}/MapStorage.hpp
${INCROOT}/MarkerStorage.hpp
${INCROOT}/VectorStorage.hpp
Expand Down
142 changes: 10 additions & 132 deletions src/ecstasy/storages/MapStorage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@

#include <unordered_map>

#include "IStorage.hpp"
#include "ecstasy/resources/entity/Entity.hpp"
#include "util/BitSet.hpp"
#include "AStorage.hpp"

namespace ecstasy
{
Expand All @@ -30,16 +28,9 @@ namespace ecstasy
/// @since 1.0.0 (2022-10-19)
///
template <typename C>
class MapStorage : public IStorage {
class MapStorage : public AStorage<C> {
public:
/// @brief IsStorage constraint
using Component = C;

/// @brief @ref ecstasy::query::QueryableObject constraint.
using QueryData = C &;
/// @brief @ref ecstasy::query::ConstQueryableObject constraint.
using ConstQueryData = const C &;

using Component = typename AStorage<C>::Component;
///
/// @brief Construct a new Map Storage for a given Component type.
///
Expand Down Expand Up @@ -81,18 +72,8 @@ namespace ecstasy
return _components.emplace(std::make_pair(index, Component(std::forward<Args>(args)...))).first->second;
}

///
/// @brief Erase the @b Component instance associated to the given entity.
///
/// @note Does nothing if the index doesn't match with any component (ie if the entity doesn't have a component
/// @b Component)
///
/// @param[in] index Index of the entity.
///
/// @author Andréas Leroux ([email protected])
/// @since 1.0.0 (2022-10-19)
///
bool erase(Entity::Index index)
/// @copydoc AStorage::erase(Entity::Index)
bool erase(Entity::Index index) override final
{
auto it = _components.find(index);

Expand All @@ -104,110 +85,18 @@ namespace ecstasy
return false;
}

///
/// @brief Erase multiple @b Component instances associated to the given @p entities.
///
/// @note Does nothing for entity without attached component (ie if the entity doesn't have a component
/// @b Component)
///
/// @param[in] entities target entities.
///
/// @author Andréas Leroux ([email protected])
/// @since 1.0.0 (2022-10-21)
///
void erase(std::span<Entity> entities) override final
{
for (Entity entity : entities)
erase(entity.getIndex());
}

///
/// @brief Retrieve the @b Component instance associated to the given entity.
///
/// @param[in] index Index of the entity.
///
/// @return const Component& Const reference to the associated component.
///
/// @throw std::out_of_range If the entity doesn't have the component.
///
/// @author Andréas Leroux ([email protected])
/// @since 1.0.0 (2022-10-19)
///
const Component &operator[](Entity::Index index) const
/// @copydoc AStorage::operator[]
Component &operator[](Entity::Index index) override final
{
return _components.at(index);
}

///
/// @brief Retrieve the @b Component instance associated to the given entity.
///
/// @param[in] index Index of the entity.
///
/// @return Component& Reference to the associated component.
///
/// @throw std::out_of_range If the entity doesn't have the component.
///
/// @author Andréas Leroux ([email protected])
/// @since 1.0.0 (2022-10-19)
///
Component &operator[](Entity::Index index)
/// @copydoc AStorage::operator[]
const Component &operator[](Entity::Index index) const override final
{
return _components.at(index);
}

///
/// @brief Retrieve the @b Component instance associated to the given entity.
///
/// @note @ref ecstasy::query::QueryableObject constraint.
///
/// @param[in] index Index of the entity.
///
/// @return Component& Reference to the associated component.
///
/// @throw std::out_of_range If the entity doesn't have the component.
///
/// @author Andréas Leroux ([email protected])
/// @since 1.0.0 (2022-10-19)
///
Component &getQueryData(Entity::Index index)
{
return _components.at(index);
}

///
/// @brief Retrieve the const @b Component instance associated to the given entity.
///
/// @note @ref ecstasy::query::ConstQueryableObject constraint.
///
/// @param[in] index Index of the entity.
///
/// @return const Component& Const reference to the associated component.
///
/// @throw std::out_of_range If the entity doesn't have the component.
///
/// @author Andréas Leroux ([email protected])
/// @since 1.0.0 (2024-04-03)
///
const Component &getQueryData(Entity::Index index) const
{
return _components.at(index);
}

///
/// @brief Test if the entity index match a @b Component instance.
///
/// @param[in] index Index of the entity.
///
/// @return bool True if the entity has a component, false otherwise.
///
/// @author Andréas Leroux ([email protected])
/// @since 1.0.0 (2022-10-19)
///
bool contains(Entity::Index index) const
{
return _components.find(index) != _components.end();
}

///
/// @brief Get the number of @b Component instances.
///
Expand All @@ -221,18 +110,7 @@ namespace ecstasy
return _components.size();
}

///
/// @brief Get the Component Mask.
///
/// @note Each bit set to true mean the entity at the bit index has a component @b C.
/// @note @ref ecstasy::query::QueryableObject constraint.
/// @warning The mask might be smaller than the entity count.
///
/// @return const util::BitSet& Component mask.
///
/// @author Andréas Leroux ([email protected])
/// @since 1.0.0 (2022-10-20)
///
/// @copydoc IStorage::getMask
constexpr const util::BitSet &getMask() const override final
{
return _mask;
Expand Down
Loading

0 comments on commit 331c583

Please sign in to comment.