From af70573634ea89348affaad4320df932995e0256 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Wed, 30 Aug 2017 13:06:30 +0200 Subject: [PATCH] WIP: improvements and new features --- README.md | 4 + src/component_pool.hpp | 235 ---------------------------------------- src/registry.hpp | 207 ++++++++++++++++++----------------- src/sparse_set.hpp | 205 +++++++++++++++++++++++++++++++++++ src/tag_handler.hpp | 97 +++++++++++++++++ test/CMakeLists.txt | 2 +- test/benchmark.cpp | 1 + test/component_pool.cpp | 166 ---------------------------- test/registry.cpp | 9 +- test/sparse_set.cpp | 90 +++++++++++++++ test/tag_handler.cpp | 46 ++++++++ 11 files changed, 561 insertions(+), 501 deletions(-) delete mode 100644 src/component_pool.hpp create mode 100644 src/sparse_set.hpp create mode 100644 src/tag_handler.hpp delete mode 100644 test/component_pool.cpp create mode 100644 test/sparse_set.cpp create mode 100644 test/tag_handler.cpp diff --git a/README.md b/README.md index bcd3a903c..1a5debe44 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,9 @@ # Introduction +WIP. Documentation is coming soon. + + diff --git a/src/component_pool.hpp b/src/component_pool.hpp deleted file mode 100644 index 14877ac91..000000000 --- a/src/component_pool.hpp +++ /dev/null @@ -1,235 +0,0 @@ -#ifndef ENTT_COMPONENT_POOL_HPP -#define ENTT_COMPONENT_POOL_HPP - - -#include -#include -#include - - -namespace entt { - - -template -class ComponentPool; - - -template -class ComponentPool { -public: - using component_type = Component; - using entity_type = Entity; - using pos_type = entity_type; - using size_type = typename std::vector::size_type; - using iterator_type = typename std::vector::iterator; - using const_iterator_type = typename std::vector::const_iterator; - -private: - inline bool valid(entity_type entity) const noexcept { - return entity < reverse.size() && reverse[entity] < direct.size() && direct[reverse[entity]] == entity; - } - -public: - explicit ComponentPool(size_type dim = 4098) noexcept { - assert(!(dim < 0)); - data.reserve(dim); - } - - ComponentPool(ComponentPool &&) = default; - - ~ComponentPool() noexcept { - assert(empty()); - } - - ComponentPool & operator=(ComponentPool &&) = default; - - bool empty() const noexcept { - return data.empty(); - } - - size_type capacity() const noexcept { - return data.capacity(); - } - - size_type size() const noexcept { - return data.size(); - } - - iterator_type begin() noexcept { - return direct.begin(); - } - - const_iterator_type cbegin() const noexcept { - return direct.cbegin(); - } - - iterator_type end() noexcept { - return direct.end(); - } - - const_iterator_type cend() const noexcept { - return direct.cend(); - } - - bool has(entity_type entity) const noexcept { - return valid(entity); - } - - const component_type & get(entity_type entity) const noexcept { - assert(valid(entity)); - return data[reverse[entity]]; - } - - component_type & get(entity_type entity) noexcept { - return const_cast(const_cast(this)->get(entity)); - } - - template - component_type & construct(entity_type entity, Args... args) { - assert(!valid(entity)); - - if(!(entity < reverse.size())) { - reverse.resize(entity+1); - } - - reverse[entity] = pos_type(direct.size()); - direct.emplace_back(entity); - data.push_back({ args... }); - - return data.back(); - } - - void destroy(entity_type entity) { - assert(valid(entity)); - - auto last = direct.size() - 1; - - reverse[direct[last]] = reverse[entity]; - direct[reverse[entity]] = direct[last]; - data[reverse[entity]] = std::move(data[last]); - - direct.pop_back(); - data.pop_back(); - } - - void reset() { - data.clear(); - reverse.resize(0); - direct.clear(); - } - -private: - std::vector data; - std::vector reverse; - std::vector direct; -}; - - -template -class ComponentPool - : ComponentPool, ComponentPool... -{ - template - using Pool = ComponentPool; - -public: - using entity_type = typename Pool::entity_type; - using pos_type = typename Pool::pos_type; - using size_type = typename Pool::size_type; - using iterator_type = typename Pool::iterator_type; - using const_iterator_type = typename Pool::const_iterator_type; - - explicit ComponentPool(size_type dim = 4098) noexcept -#ifdef _MSC_VER - : ComponentPool{dim}, ComponentPool{dim}... -#else - : Pool{dim}, Pool{dim}... -#endif - { - assert(!(dim < 0)); - } - - ComponentPool(const ComponentPool &) = delete; - ComponentPool(ComponentPool &&) = delete; - - ComponentPool & operator=(const ComponentPool &) = delete; - ComponentPool & operator=(ComponentPool &&) = delete; - - template - bool empty() const noexcept { - return Pool::empty(); - } - - template - size_type capacity() const noexcept { - return Pool::capacity(); - } - - template - size_type size() const noexcept { - return Pool::size(); - } - - template - iterator_type begin() noexcept { - return Pool::begin(); - } - - template - const_iterator_type cbegin() const noexcept { - return Pool::cbegin(); - } - - template - iterator_type end() noexcept { - return Pool::end(); - } - - template - const_iterator_type cend() const noexcept { - return Pool::cend(); - } - - template - bool has(entity_type entity) const noexcept { - return Pool::has(entity); - } - - template - const Comp & get(entity_type entity) const noexcept { - return Pool::get(entity); - } - - template - Comp & get(entity_type entity) noexcept { - return const_cast(const_cast(this)->get(entity)); - } - - template - Comp & construct(entity_type entity, Args... args) { - return Pool::construct(entity, args...); - } - - template - void destroy(entity_type entity) { - Pool::destroy(entity); - } - - template - void reset() { - Pool::reset(); - } - - void reset() { - using accumulator_type = int[]; - Pool::reset(); - accumulator_type accumulator = { (Pool::reset(), 0)... }; - (void)accumulator; - } -}; - - -} - - -#endif // ENTT_COMPONENT_POOL_HPP diff --git a/src/registry.hpp b/src/registry.hpp index 3b6096e41..b0afc3199 100644 --- a/src/registry.hpp +++ b/src/registry.hpp @@ -2,6 +2,7 @@ #define ENTT_REGISTRY_HPP +#include #include #include #include @@ -9,30 +10,29 @@ #include #include #include -#include "component_pool.hpp" +#include "sparse_set.hpp" #include "ident.hpp" namespace entt { -template +template class View; -template class Pool, typename Entity, typename... Components, typename Type, typename... Types> -class View, Type, Types...> final { - using pool_type = Pool; - using entity_type = typename pool_type::entity_type; - using mask_type = std::bitset; - using underlying_iterator_type = typename pool_type::const_iterator_type; +template +class View final { + using pool_type = Pool; + using mask_type = std::bitset::value + 1>; + using underlying_iterator_type = typename std::tuple_element_t::iterator_type; class ViewIterator; public: using iterator_type = ViewIterator; - using const_iterator_type = iterator_type; - using size_type = typename pool_type::size_type; + using entity_type = typename std::tuple_element_t::index_type; + using size_type = typename std::tuple_element_t::size_type; private: class ViewIterator { @@ -42,10 +42,6 @@ class View, Type, Types...> final { public: using value_type = entity_type; - using difference_type = std::ptrdiff_t; - using reference = entity_type &; - using pointer = entity_type *; - using iterator_category = std::input_iterator_tag; ViewIterator(underlying_iterator_type begin, underlying_iterator_type end, const mask_type &bitmask, const mask_type *mask) noexcept : begin{begin}, end{end}, bitmask{bitmask}, mask{mask} @@ -85,133 +81,137 @@ class View, Type, Types...> final { const mask_type *mask; }; - template + template void prefer(size_type &size) noexcept { - auto sz = pool.template size(); + auto &&cpool = std::get(*pool); + auto sz = cpool.size(); if(sz < size) { - from = pool.template begin(); - to = pool.template end(); + from = cpool.begin(); + to = cpool.end(); size = sz; } } public: - explicit View(pool_type &pool, const mask_type *mask) noexcept - : from{pool.template begin()}, - to{pool.template end()}, + explicit View(const pool_type *pool, const mask_type *mask) noexcept + : from{std::get(*pool).begin()}, + to{std::get(*pool).end()}, pool{pool}, mask{mask} { using accumulator_type = int[]; - size_type size = pool.template size(); - bitmask.set(ident.template get()); - accumulator_type types = { 0, (bitmask.set(ident.template get()), 0)... }; - accumulator_type pref = { 0, (prefer(size), 0)... }; + size_type size = std::get(*pool).size(); + bitmask.set(Ident); + accumulator_type types = { 0, (bitmask.set(Other), 0)... }; + accumulator_type pref = { 0, (prefer(size), 0)... }; (void)types, (void)pref; } - const_iterator_type begin() const noexcept { + iterator_type begin() const noexcept { return ViewIterator{from, to, bitmask, mask}; } - iterator_type begin() noexcept { - return const_cast(this)->begin(); - } - - const_iterator_type end() const noexcept { + iterator_type end() const noexcept { return ViewIterator{to, to, bitmask, mask}; } - iterator_type end() noexcept { - return const_cast(this)->end(); - } - void reset() noexcept { using accumulator_type = int[]; - from = pool.template begin(); - to = pool.template end(); - size_type size = pool.template size(); - accumulator_type accumulator = { 0, (prefer(size), 0)... }; + auto &&cpool = std::get(*pool); + from = cpool.begin(); + to = cpool.end(); + size_type size = cpool.size(); + accumulator_type accumulator = { 0, (prefer(size), 0)... }; (void)accumulator; } private: underlying_iterator_type from; underlying_iterator_type to; - pool_type &pool; + const pool_type *pool; const mask_type *mask; mask_type bitmask; }; -template class Pool, typename Entity, typename... Components, typename Type> -class View, Type> final { - using pool_type = Pool; +template +class View final { + using pool_type = std::tuple_element_t; public: + using iterator_type = typename pool_type::iterator_type; + using entity_type = typename pool_type::index_type; using size_type = typename pool_type::size_type; - using iterator_type = typename pool_type::const_iterator_type; - using const_iterator_type = iterator_type; + using raw_type = typename pool_type::type; - explicit View(pool_type &pool) noexcept - : pool{pool} + explicit View(const Pool *pool) noexcept + : pool{&std::get(*pool)} {} - const_iterator_type cbegin() const noexcept { - return pool.template cbegin(); + raw_type * raw() noexcept { + return pool->raw(); } - iterator_type begin() noexcept { - return pool.template begin(); + const raw_type * raw() const noexcept { + return pool->raw(); } - const_iterator_type cend() const noexcept { - return pool.template cend(); + const entity_type * data() const noexcept { + return pool->data(); } - iterator_type end() noexcept { - return pool.template end(); + size_type size() const noexcept { + return pool->size(); } - size_type size() const noexcept { - return pool.template size(); + iterator_type begin() const noexcept { + return pool->begin(); + } + + iterator_type end() const noexcept { + return pool->end(); } private: - pool_type &pool; + const pool_type *pool; }; -template +template class Registry; -template class Pool, typename Entity, typename... Components> -class Registry> { - static_assert(sizeof...(Components) > 1, "!"); +template class... Pool, typename Entity, typename... Component> +class Registry...> { + using pool_type = std::tuple...>; + using mask_type = std::bitset; - using pool_type = Pool; - using mask_type = std::bitset; - - static constexpr auto validity_bit = sizeof...(Components); + static constexpr auto validity_bit = sizeof...(Component); public: - using entity_type = typename pool_type::entity_type; + using entity_type = Entity; using size_type = typename std::vector::size_type; + template + using view_type = View.template get()...>; + private: template void clone(entity_type to, entity_type from) { - if(entities[from].test(ident.template get())) { - assign(to, pool.template get(from)); + constexpr auto index = ident.template get(); + + if(entities[from].test(index)) { + assign(to, std::get(pool).get(from)); } } template void sync(entity_type to, entity_type from) { - bool src = entities[from].test(ident.template get()); - bool dst = entities[to].test(ident.template get()); + constexpr auto index = ident.template get(); + + bool src = entities[from].test(index); + bool dst = entities[to].test(index); if(src && dst) { copy(to, from); @@ -223,9 +223,6 @@ class Registry> { } public: - template - using view_type = View; - template Registry(Args&&... args) : pool{std::forward(args)...} @@ -247,7 +244,8 @@ class Registry> { template bool empty() const noexcept { - return pool.template empty(); + constexpr auto index = ident.template get(); + return std::get(pool).empty(); } bool empty() const noexcept { @@ -286,7 +284,7 @@ class Registry> { void destroy(entity_type entity) { assert(valid(entity)); using accumulator_type = int[]; - accumulator_type accumulator = { 0, (reset(entity), 0)... }; + accumulator_type accumulator = { 0, (reset(entity), 0)... }; available.push_back(entity); entities[entity].reset(); (void)accumulator; @@ -295,15 +293,17 @@ class Registry> { template Comp & assign(entity_type entity, Args... args) { assert(valid(entity)); - entities[entity].set(ident.template get()); - return pool.template construct(entity, args...); + constexpr auto index = ident.template get(); + entities[entity].set(index); + return std::get(pool).construct(entity, args...); } template void remove(entity_type entity) { assert(valid(entity)); - entities[entity].reset(ident.template get()); - pool.template destroy(entity); + constexpr auto index = ident.template get(); + entities[entity].reset(index); + std::get(pool).destroy(entity); } template @@ -312,31 +312,36 @@ class Registry> { using accumulator_type = bool[]; bool all = true; auto &mask = entities[entity]; - accumulator_type accumulator = { true, (all = all && mask.test(ident.template get()))... }; + accumulator_type accumulator = { true, (all = all && mask.test(ident.template get()))... }; (void)accumulator; return all; } template const Comp & get(entity_type entity) const noexcept { - return pool.template get(entity); + constexpr auto index = ident.template get(); + return std::get(pool).get(entity); } template Comp & get(entity_type entity) noexcept { - return pool.template get(entity); + constexpr auto index = ident.template get(); + return std::get(pool).get(entity); } template Comp & replace(entity_type entity, Args... args) { - return (pool.template get(entity) = Comp{args...}); + constexpr auto index = ident.template get(); + return (std::get(pool).get(entity) = Comp{args...}); } template Comp & accomodate(entity_type entity, Args... args) { assert(valid(entity)); - return (entities[entity].test(ident.template get()) + constexpr auto index = ident.template get(); + + return (entities[entity].test(index) ? this->template replace(entity, std::forward(args)...) : this->template assign(entity, std::forward(args)...)); } @@ -345,19 +350,21 @@ class Registry> { assert(valid(from)); using accumulator_type = int[]; auto to = create(); - accumulator_type accumulator = { 0, (clone(to, from), 0)... }; + accumulator_type accumulator = { 0, (clone(to, from), 0)... }; (void)accumulator; return to; } template Comp & copy(entity_type to, entity_type from) { - return (pool.template get(to) = pool.template get(from)); + constexpr auto index = ident.template get(); + auto &&cpool = std::get(pool); + return (cpool.get(to) = cpool.get(from)); } void copy(entity_type to, entity_type from) { using accumulator_type = int[]; - accumulator_type accumulator = { 0, (sync(to, from), 0)... }; + accumulator_type accumulator = { 0, (sync(to, from), 0)... }; (void)accumulator; } @@ -365,33 +372,39 @@ class Registry> { void reset(entity_type entity) { assert(valid(entity)); - if(entities[entity].test(ident.template get())) { + constexpr auto index = ident.template get(); + + if(entities[entity].test(index)) { remove(entity); } } template void reset() { + constexpr auto index = ident.template get(); + for(entity_type entity = 0, last = entity_type(entities.size()); entity < last; ++entity) { - if(entities[entity].test(ident.template get())) { + if(entities[entity].test(index)) { remove(entity); } } } void reset() { + using accumulator_type = int[]; + accumulator_type acc = { 0, (std::get.template get()>(pool).reset(), 0)... }; entities.clear(); available.clear(); - pool.reset(); + (void)acc; } template std::enable_if_t<(sizeof...(Comp) == 1), view_type> - view() noexcept { return view_type{pool}; } + view() noexcept { return view_type{&pool}; } template std::enable_if_t<(sizeof...(Comp) > 1), view_type> - view() noexcept { return view_type{pool, entities.data()}; } + view() noexcept { return view_type{&pool, entities.data()}; } private: std::vector entities; @@ -400,12 +413,12 @@ class Registry> { }; -template -using StandardRegistry = Registry>; +template +using StandardRegistry = Registry...>; -template -using DefaultRegistry = Registry>; +template +using DefaultRegistry = Registry...>; } diff --git a/src/sparse_set.hpp b/src/sparse_set.hpp new file mode 100644 index 000000000..a128d91bc --- /dev/null +++ b/src/sparse_set.hpp @@ -0,0 +1,205 @@ +#ifndef ENTT_COMPONENT_POOL_HPP +#define ENTT_COMPONENT_POOL_HPP + + +#include +#include +#include +#include + + +namespace entt { + + +template +class SparseSet; + + +template +class SparseSet { + struct SparseSetIterator; + +public: + using index_type = Index; + using pos_type = index_type; + using size_type = std::size_t; + using iterator_type = SparseSetIterator; + +private: + struct SparseSetIterator { + using value_type = index_type; + + SparseSetIterator(const std::vector *direct, size_type pos) + : direct{direct}, pos{pos} + {} + + SparseSetIterator & operator++() noexcept { + return --pos, *this; + } + + SparseSetIterator operator++(int) noexcept { + SparseSetIterator orig = *this; + return ++(*this), orig; + } + + bool operator==(const SparseSetIterator &other) const noexcept { + return other.pos == pos && other.direct == direct; + } + + bool operator!=(const SparseSetIterator &other) const noexcept { + return !(*this == other); + } + + value_type operator*() const noexcept { + return (*direct)[pos-1]; + } + + private: + const std::vector *direct; + size_type pos; + }; + + inline bool valid(Index idx) const noexcept { + return idx < reverse.size() && reverse[idx] < direct.size() && direct[reverse[idx]] == idx; + } + +public: + explicit SparseSet() = default; + + SparseSet(const SparseSet &) = delete; + SparseSet(SparseSet &&) = default; + + virtual ~SparseSet() noexcept { + assert(empty()); + } + + SparseSet & operator=(const SparseSet &) = delete; + SparseSet & operator=(SparseSet &&) = default; + + bool empty() const noexcept { + return direct.empty(); + } + + const index_type * data() const noexcept { + return direct.data(); + } + + size_type size() const noexcept { + return direct.size(); + } + + iterator_type begin() const noexcept { + return SparseSetIterator{&direct, direct.size()}; + } + + iterator_type end() const noexcept { + return SparseSetIterator{&direct, 0}; + } + + bool has(index_type idx) const noexcept { + return valid(idx); + } + + pos_type get(index_type idx) const noexcept { + assert(valid(idx)); + return reverse[idx]; + } + + pos_type construct(index_type idx) { + assert(!valid(idx)); + + if(!(idx < reverse.size())) { + reverse.resize(idx+1); + } + + auto pos = pos_type(direct.size()); + reverse[idx] = pos; + direct.emplace_back(idx); + + return pos; + } + + pos_type destroy(index_type idx) { + assert(valid(idx)); + + auto last = direct.size() - 1; + auto pos = reverse[idx]; + + reverse[direct[last]] = pos; + direct[pos] = direct[last]; + direct.pop_back(); + + return pos; + } + + void reset() { + reverse.resize(0); + direct.clear(); + } + +private: + std::vector reverse; + std::vector direct; +}; + + +template +class SparseSet final: public SparseSet { +public: + using type = Type; + using index_type = typename SparseSet::index_type; + using pos_type = typename SparseSet::pos_type; + using size_type = typename SparseSet::size_type; + using iterator_type = typename SparseSet::iterator_type; + + explicit SparseSet() = default; + + SparseSet(const SparseSet &) = delete; + SparseSet(SparseSet &&) = default; + + SparseSet & operator=(const SparseSet &) = delete; + SparseSet & operator=(SparseSet &&) = default; + + type * raw() noexcept { + return instances.data(); + } + + const type * raw() const noexcept { + return instances.data(); + } + + const type & get(index_type idx) const noexcept { + return instances[SparseSet::get(idx)]; + } + + type & get(index_type idx) noexcept { + return const_cast(const_cast(this)->get(idx)); + } + + template + type & construct(index_type idx, Args... args) { + SparseSet::construct(idx); + instances.push_back({ args... }); + return instances.back(); + } + + void destroy(index_type idx) { + auto pos = SparseSet::destroy(idx); + instances[pos] = std::move(instances[SparseSet::size()]); + instances.pop_back(); + } + + void reset() { + SparseSet::reset(); + instances.clear(); + } + +private: + std::vector instances; +}; + + +} + + +#endif // ENTT_COMPONENT_POOL_HPP diff --git a/src/tag_handler.hpp b/src/tag_handler.hpp new file mode 100644 index 000000000..b1acb7518 --- /dev/null +++ b/src/tag_handler.hpp @@ -0,0 +1,97 @@ +#ifndef ENTT_TAG_HANDLER_HPP +#define ENTT_TAG_HANDLER_HPP + + +#include +#include +#include +#include + + +namespace entt { + + +template +struct TagHandler { + using type = Type; + using index_type = Index; + using pos_type = index_type; + using size_type = std::size_t; + using iterator_type = const type *; + +private: + inline bool valid(index_type idx) const noexcept { + return !idx && tag; + } + +public: + explicit TagHandler() = default; + + TagHandler(const TagHandler &) = delete; + TagHandler(TagHandler &&) = default; + + ~TagHandler() noexcept { + assert(not tag); + } + + TagHandler & operator=(const TagHandler &) = delete; + TagHandler & operator=(TagHandler &&) = default; + + bool empty() const noexcept { + return !tag; + } + + size_type size() const noexcept { + return tag ? size_type{1} : size_type{0}; + } + + iterator_type begin() const noexcept { + return tag; + } + + iterator_type end() const noexcept { + return tag ? tag + 1 : tag; + } + + bool has(index_type idx) const noexcept { + return valid(idx); + } + + const type & get(index_type idx) const noexcept { + assert(valid(idx)); + return *tag; + } + + type & get(index_type idx) noexcept { + return const_cast(const_cast(this)->get(idx)); + } + + template + type & construct(index_type idx, Args... args) { + assert(!valid(idx)); + tag = new(&chunk) Type{std::forward(args)...}; + return *tag; + } + + void destroy(index_type idx) { + assert(valid(idx)); + tag->~Type(); + tag = nullptr; + } + + void reset() { + if(tag) { + destroy(index_type{0}); + } + } + +private: + std::aligned_storage_t chunk; + Type *tag{nullptr}; +}; + + +} + + +#endif // ENTT_TAG_HANDLER_HPP diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index aff036159..8c7f91276 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -11,7 +11,7 @@ set(TARGET_BENCHMARK benchmark) # Test TARGET_ENTT -add_executable(${TARGET_ENTT} component_pool.cpp registry.cpp) +add_executable(${TARGET_ENTT} registry.cpp sparse_set.cpp tag_handler.cpp) target_include_directories(${TARGET_ENTT} PRIVATE ${PROJECT_SRC_DIR}) target_link_libraries(${TARGET_ENTT} PRIVATE ${COMMON_LINK_LIBS}) add_test(NAME ${TARGET_ENTT} COMMAND ${TARGET_ENTT}) diff --git a/test/benchmark.cpp b/test/benchmark.cpp index 36b1b4253..739f3f06e 100644 --- a/test/benchmark.cpp +++ b/test/benchmark.cpp @@ -38,6 +38,7 @@ TEST(DefaultRegistry, Construct) { std::cout << "Constructing 10000000 entities" << std::endl; Timer timer; + for (uint64_t i = 0; i < 10000000L; i++) { registry.create(); } diff --git a/test/component_pool.cpp b/test/component_pool.cpp deleted file mode 100644 index f654d27b2..000000000 --- a/test/component_pool.cpp +++ /dev/null @@ -1,166 +0,0 @@ -#include -#include -#include - -TEST(ComponentPool, Functionalities) { - using pool_type = entt::ComponentPool; - - pool_type pool{0}; - - ASSERT_TRUE(pool.empty()); - ASSERT_TRUE(pool.empty()); - ASSERT_EQ(pool.capacity(), pool_type::size_type{0}); - ASSERT_EQ(pool.capacity(), pool_type::size_type{0}); - ASSERT_EQ(pool.size(), pool_type::size_type{0}); - ASSERT_EQ(pool.size(), pool_type::size_type{0}); - ASSERT_EQ(pool.begin(), pool.end()); - ASSERT_EQ(pool.begin(), pool.end()); - ASSERT_FALSE(pool.has(0)); - ASSERT_FALSE(pool.has(0)); -} - -TEST(ComponentPool, ConstructDestroy) { - using pool_type = entt::ComponentPool; - - pool_type pool{4}; - - ASSERT_EQ(pool.construct(0, 42), 42); - ASSERT_FALSE(pool.empty()); - ASSERT_TRUE(pool.empty()); - ASSERT_EQ(pool.capacity(), pool_type::size_type{4}); - ASSERT_EQ(pool.capacity(), pool_type::size_type{4}); - ASSERT_EQ(pool.size(), pool_type::size_type{1}); - ASSERT_EQ(pool.size(), pool_type::size_type{0}); - ASSERT_TRUE(pool.has(0)); - ASSERT_FALSE(pool.has(0)); - ASSERT_FALSE(pool.has(1)); - ASSERT_FALSE(pool.has(1)); - - ASSERT_EQ(pool.construct(1), 0); - ASSERT_FALSE(pool.empty()); - ASSERT_TRUE(pool.empty()); - ASSERT_EQ(pool.capacity(), pool_type::size_type{4}); - ASSERT_EQ(pool.capacity(), pool_type::size_type{4}); - ASSERT_EQ(pool.size(), pool_type::size_type{2}); - ASSERT_EQ(pool.size(), pool_type::size_type{0}); - ASSERT_TRUE(pool.has(0)); - ASSERT_FALSE(pool.has(0)); - ASSERT_TRUE(pool.has(1)); - ASSERT_FALSE(pool.has(1)); - ASSERT_NE(pool.get(0), pool.get(1)); - ASSERT_NE(&pool.get(0), &pool.get(1)); - - ASSERT_NO_THROW(pool.destroy(0)); - ASSERT_FALSE(pool.empty()); - ASSERT_TRUE(pool.empty()); - ASSERT_EQ(pool.capacity(), pool_type::size_type{4}); - ASSERT_EQ(pool.capacity(), pool_type::size_type{4}); - ASSERT_EQ(pool.size(), pool_type::size_type{1}); - ASSERT_EQ(pool.size(), pool_type::size_type{0}); - ASSERT_FALSE(pool.has(0)); - ASSERT_FALSE(pool.has(0)); - ASSERT_TRUE(pool.has(1)); - ASSERT_FALSE(pool.has(1)); - - ASSERT_NO_THROW(pool.destroy(1)); - ASSERT_TRUE(pool.empty()); - ASSERT_TRUE(pool.empty()); - ASSERT_EQ(pool.capacity(), pool_type::size_type{4}); - ASSERT_EQ(pool.capacity(), pool_type::size_type{4}); - ASSERT_EQ(pool.size(), pool_type::size_type{0}); - ASSERT_EQ(pool.size(), pool_type::size_type{0}); - ASSERT_FALSE(pool.has(0)); - ASSERT_FALSE(pool.has(0)); - ASSERT_FALSE(pool.has(1)); - ASSERT_FALSE(pool.has(1)); - - int *comp[] = { - &pool.construct(0, 0), - &pool.construct(1, 1), - nullptr, - &pool.construct(3, 3) - }; - - ASSERT_FALSE(pool.empty()); - ASSERT_TRUE(pool.empty()); - ASSERT_EQ(pool.capacity(), pool_type::size_type{4}); - ASSERT_EQ(pool.capacity(), pool_type::size_type{4}); - ASSERT_EQ(pool.size(), pool_type::size_type{3}); - ASSERT_EQ(pool.size(), pool_type::size_type{0}); - ASSERT_TRUE(pool.has(0)); - ASSERT_FALSE(pool.has(0)); - ASSERT_TRUE(pool.has(1)); - ASSERT_FALSE(pool.has(1)); - ASSERT_FALSE(pool.has(2)); - ASSERT_FALSE(pool.has(2)); - ASSERT_TRUE(pool.has(3)); - ASSERT_FALSE(pool.has(3)); - ASSERT_EQ(&pool.get(0), comp[0]); - ASSERT_EQ(&pool.get(1), comp[1]); - ASSERT_EQ(&pool.get(3), comp[3]); - ASSERT_EQ(pool.get(0), 0); - ASSERT_EQ(pool.get(1), 1); - ASSERT_EQ(pool.get(3), 3); - - ASSERT_NO_THROW(pool.destroy(0)); - ASSERT_NO_THROW(pool.destroy(1)); - ASSERT_NO_THROW(pool.destroy(3)); -} - -TEST(ComponentPool, HasGet) { - using pool_type = entt::ComponentPool; - - pool_type pool; - const pool_type &cpool = pool; - - int &comp = pool.construct(0, 42); - - ASSERT_EQ(pool.get(0), comp); - ASSERT_EQ(pool.get(0), 42); - ASSERT_TRUE(pool.has(0)); - - ASSERT_EQ(cpool.get(0), comp); - ASSERT_EQ(cpool.get(0), 42); - ASSERT_TRUE(cpool.has(0)); - - ASSERT_NO_THROW(pool.destroy(0)); -} - -TEST(ComponentPool, BeginEndReset) { - using pool_type = entt::ComponentPool; - - pool_type pool{2}; - - ASSERT_EQ(pool.construct(0, 0), 0); - ASSERT_EQ(pool.construct(2, 2), 2); - ASSERT_EQ(pool.construct(3, 3), 3); - ASSERT_EQ(pool.construct(1, 1), 1); - - ASSERT_EQ(pool.size(), decltype(pool.size()){4}); - ASSERT_EQ(*(pool.begin()+0), typename pool_type::entity_type{0}); - ASSERT_EQ(*(pool.begin()+1), typename pool_type::entity_type{2}); - ASSERT_EQ(*(pool.begin()+2), typename pool_type::entity_type{3}); - ASSERT_EQ(*(pool.begin()+3), typename pool_type::entity_type{1}); - - pool.destroy(2); - - ASSERT_EQ(pool.size(), decltype(pool.size()){3}); - ASSERT_EQ(*(pool.begin()+0), typename pool_type::entity_type{0}); - ASSERT_EQ(*(pool.begin()+1), typename pool_type::entity_type{1}); - ASSERT_EQ(*(pool.begin()+2), typename pool_type::entity_type{3}); - - ASSERT_EQ(pool.construct(0, 'c'), 'c'); - - ASSERT_FALSE(pool.empty()); - ASSERT_FALSE(pool.empty()); - - ASSERT_NO_THROW(pool.reset()); - - ASSERT_FALSE(pool.empty()); - ASSERT_TRUE(pool.empty()); - - ASSERT_NO_THROW(pool.reset()); - - ASSERT_TRUE(pool.empty()); - ASSERT_TRUE(pool.empty()); -} diff --git a/test/registry.cpp b/test/registry.cpp index 008b53bd9..7c20b5c29 100644 --- a/test/registry.cpp +++ b/test/registry.cpp @@ -199,7 +199,7 @@ TEST(DefaultRegistry, ViewMultipleComponent) { ASSERT_NO_THROW(registry.reset()); } -TEST(DefaultRegistry, EmptyViewSingleComponent) { +TEST(DefaultRegistry, ViewSingleComponentEmpty) { using registry_type = entt::DefaultRegistry; registry_type registry; @@ -211,10 +211,15 @@ TEST(DefaultRegistry, EmptyViewSingleComponent) { ASSERT_EQ(view.size(), registry_type::size_type{0}); + for(auto entity: view) { + (void)entity; + FAIL(); + } + registry.reset(); } -TEST(DefaultRegistry, EmptyViewMultipleComponent) { +TEST(DefaultRegistry, ViewMultipleComponentEmpty) { using registry_type = entt::DefaultRegistry; registry_type registry; diff --git a/test/sparse_set.cpp b/test/sparse_set.cpp new file mode 100644 index 000000000..12eb4369a --- /dev/null +++ b/test/sparse_set.cpp @@ -0,0 +1,90 @@ +#include +#include + +TEST(SparseSetNoType, Functionalities) { + using SparseSet = entt::SparseSet; + + SparseSet set; + + ASSERT_TRUE(set.empty()); + ASSERT_EQ(set.size(), 0u); + ASSERT_EQ(set.begin(), set.end()); + ASSERT_FALSE(set.has(0)); + ASSERT_FALSE(set.has(42)); + + ASSERT_EQ(set.construct(42), 0u); + + ASSERT_FALSE(set.empty()); + ASSERT_EQ(set.size(), 1u); + ASSERT_NE(set.begin(), set.end()); + ASSERT_FALSE(set.has(0)); + ASSERT_TRUE(set.has(42)); + + auto begin = set.begin(); + + ASSERT_EQ(*begin, 42u); + ASSERT_EQ(++begin, set.end()); + ASSERT_EQ(set.get(42), 0u); + + ASSERT_EQ(set.destroy(42), 0u); + + ASSERT_TRUE(set.empty()); + ASSERT_EQ(set.size(), 0u); + ASSERT_EQ(set.begin(), set.end()); + ASSERT_FALSE(set.has(0)); + ASSERT_FALSE(set.has(42)); + + ASSERT_EQ(set.construct(42), 0u); + + set.reset(); + + ASSERT_TRUE(set.empty()); + ASSERT_EQ(set.size(), 0u); + ASSERT_EQ(set.begin(), set.end()); + ASSERT_FALSE(set.has(0)); + ASSERT_FALSE(set.has(42)); +} + +TEST(SparseSetWithType, Functionalities) { + using SparseSet = entt::SparseSet; + + SparseSet set; + + ASSERT_TRUE(set.empty()); + ASSERT_EQ(set.size(), 0u); + ASSERT_EQ(set.begin(), set.end()); + ASSERT_FALSE(set.has(0)); + ASSERT_FALSE(set.has(42)); + + ASSERT_EQ(set.construct(42, 3), 3); + + ASSERT_FALSE(set.empty()); + ASSERT_EQ(set.size(), 1u); + ASSERT_NE(set.begin(), set.end()); + ASSERT_FALSE(set.has(0)); + ASSERT_TRUE(set.has(42)); + + auto begin = set.begin(); + + ASSERT_EQ(*begin, 42u); + ASSERT_EQ(set.get(42), 3); + ASSERT_EQ(++begin, set.end()); + + set.destroy(42); + + ASSERT_TRUE(set.empty()); + ASSERT_EQ(set.size(), 0u); + ASSERT_EQ(set.begin(), set.end()); + ASSERT_FALSE(set.has(0)); + ASSERT_FALSE(set.has(42)); + + ASSERT_EQ(set.construct(42, 12), 12); + + set.reset(); + + ASSERT_TRUE(set.empty()); + ASSERT_EQ(set.size(), 0u); + ASSERT_EQ(set.begin(), set.end()); + ASSERT_FALSE(set.has(0)); + ASSERT_FALSE(set.has(42)); +} diff --git a/test/tag_handler.cpp b/test/tag_handler.cpp new file mode 100644 index 000000000..ab2c205ba --- /dev/null +++ b/test/tag_handler.cpp @@ -0,0 +1,46 @@ +#include +#include + +TEST(TagHandler, Functionalities) { + using TagHandler = entt::TagHandler; + + TagHandler handler; + + ASSERT_TRUE(handler.empty()); + ASSERT_EQ(handler.size(), 0u); + ASSERT_EQ(handler.begin(), handler.end()); + ASSERT_FALSE(handler.has(0)); + ASSERT_FALSE(handler.has(1)); + + ASSERT_EQ(handler.construct(0, 42), 42); + + ASSERT_FALSE(handler.empty()); + ASSERT_EQ(handler.size(), 1u); + ASSERT_NE(handler.begin(), handler.end()); + ASSERT_TRUE(handler.has(0)); + ASSERT_FALSE(handler.has(1)); + + auto begin = handler.begin(); + + ASSERT_EQ(*begin, 42); + ASSERT_EQ(handler.get(0), 42); + ASSERT_EQ(++begin, handler.end()); + + handler.destroy(0); + + ASSERT_TRUE(handler.empty()); + ASSERT_EQ(handler.size(), 0u); + ASSERT_EQ(handler.begin(), handler.end()); + ASSERT_FALSE(handler.has(0)); + ASSERT_FALSE(handler.has(1)); + + ASSERT_EQ(handler.construct(0, 12), 12); + + handler.reset(); + + ASSERT_TRUE(handler.empty()); + ASSERT_EQ(handler.size(), 0u); + ASSERT_EQ(handler.begin(), handler.end()); + ASSERT_FALSE(handler.has(0)); + ASSERT_FALSE(handler.has(1)); +}