diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b91256adc..c06fa20ea 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -97,6 +97,7 @@ endif() if(BUILD_EXAMPLE) SETUP_BASIC_TEST(custom_identifier example/custom_identifier.cpp) + SETUP_BASIC_TEST(multi_instance_storage example/multi_instance_storage.cpp) endif() # Test lib diff --git a/test/example/multi_instance_storage.cpp b/test/example/multi_instance_storage.cpp new file mode 100644 index 000000000..8bc233f9a --- /dev/null +++ b/test/example/multi_instance_storage.cpp @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include +#include +#include + +/** + * Yeah, I could have used a single memory chunk and a free list and associated + * entities with a pointer to their first element, but this is just an example + * of how to create a custom storage class. + * You can have fun regarding the actual implementation. + */ +template +struct multi_instance_storage: entt::basic_storage> { + using underlying_storage = entt::basic_storage>; + + using value_type = typename underlying_storage::value_type; + using entity_type = typename underlying_storage::entity_type; + using size_type = typename underlying_storage::size_type; + using iterator = typename underlying_storage::iterator; + using const_iterator = typename underlying_storage::const_iterator; + + template + void insert(Args &&...) = delete; + + using underlying_storage::erase; + + template + Type & emplace(const entity_type entt, Args &&... args) { + std::vector *vec = underlying_storage::try_get(entt); + + if(!vec) { + vec = &underlying_storage::emplace(entt); + } + + return vec->emplace_back(Type{std::forward(args)...}); + } + + void erase(const entity_type entt, const size_type index) { + auto &vec = underlying_storage::get(entt); + vec.erase(vec.begin() + index); + + if(vec.empty()) { + underlying_storage::erase(entt); + } + } +}; + +struct single_instance_type { int value; }; +struct multi_instance_type { int value; }; + +template +struct entt::pool { + using type = storage_adapter>; +}; + +TEST(Example, MultiInstanceStorage) { + entt::registry registry; + const auto entity = registry.create(); + + ASSERT_FALSE(registry.has(entity)); + + registry.emplace(entity, 0); + + ASSERT_TRUE(registry.has(entity)); + ASSERT_EQ(registry.get(entity).size(), 1u); + + registry.remove(entity, 0u); + + ASSERT_FALSE(registry.has(entity)); + + registry.emplace(entity, 42); + registry.emplace(entity, 3); + registry.emplace(entity, 0); + + ASSERT_EQ(registry.get(entity).size(), 3u); + ASSERT_EQ(registry.get(entity)[0].value, 42); + ASSERT_EQ(registry.get(entity)[1].value, 3); + ASSERT_EQ(registry.get(entity)[2].value, 0); + + registry.remove(entity, 1u); + + ASSERT_TRUE(registry.has(entity)); + ASSERT_EQ(registry.get(entity).size(), 2u); + ASSERT_EQ(registry.get(entity)[0].value, 42); + ASSERT_EQ(registry.get(entity)[1].value, 0); + + registry.remove(entity); + + ASSERT_FALSE(registry.has(entity)); +}