registry: uses type_id_v rather than families

This commit is contained in:
Michele Caini
2019-12-16 23:28:40 +01:00
parent d4d2db228e
commit 83bea8b654
14 changed files with 206 additions and 177 deletions

5
TODO
View File

@@ -19,6 +19,7 @@
* any-of rule for views/groups (eg entity has A and any of B/C/D)
* sparse set: there exists an alternative to paginated sparse arrays?
* see warning (vs2017 only): d:\a\entt\entt\src\entt\entity\registry.hpp(108)
* remove duktape example (and eventually provide a new one)?
* registry
- ::assure -> pool_type<T> &
- ::group improve, reduce code
@@ -26,6 +27,10 @@
* Mission: get rid of named types
- make it possible to use custom generators (eg for plugins)
* registry
* remove entt::component
* clean-up superfluous to_integer
* ENTT_ID_TYPE id() (eg dispatcher) can be a data member rather than a virtual function
* define a kind of assure also for context variables
* meta: use type_id, remove import, everything should work transparently
* type_id_enabled and fallback on old-fashioned families otherwise
* add discard pool functionality (+ test)

View File

@@ -11,9 +11,8 @@
#include <algorithm>
#include <type_traits>
#include "../config/config.h"
#include "../core/family.hpp"
#include "../core/algorithm.hpp"
#include "../core/attribute.h"
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "../signal/sigh.hpp"
#include "runtime_view.hpp"
@@ -42,15 +41,6 @@ namespace entt {
*/
template<typename Entity>
class basic_registry {
struct ENTT_API registry_context_family;
struct ENTT_API registry_component_family;
template<typename Type>
using context_family = family<Type, registry_context_family>;
template<typename Type>
using component_family = family<Type, registry_component_family>;
using traits_type = entt_traits<std::underlying_type_t<Entity>>;
template<typename Component>
@@ -157,6 +147,7 @@ class basic_registry {
};
struct pool_data {
ENTT_ID_TYPE id;
std::unique_ptr<sparse_set<Entity>> pool;
void(* assure)(basic_registry &, const sparse_set<Entity> &);
void(* remove)(sparse_set<Entity> &, basic_registry &, const Entity);
@@ -166,23 +157,28 @@ class basic_registry {
struct group_data {
std::size_t extent[3];
std::unique_ptr<void, void(*)(void *)> group;
bool(* owned)(const component) ENTT_NOEXCEPT;
bool(* get)(const component) ENTT_NOEXCEPT;
bool(* exclude)(const component) ENTT_NOEXCEPT;
bool(* owned)(const ENTT_ID_TYPE) ENTT_NOEXCEPT;
bool(* get)(const ENTT_ID_TYPE) ENTT_NOEXCEPT;
bool(* exclude)(const ENTT_ID_TYPE) ENTT_NOEXCEPT;
};
struct basic_variable {
virtual ~basic_variable() = default;
virtual ENTT_ID_TYPE id() const ENTT_NOEXCEPT = 0;
};
template<typename Type>
struct variable_handler: basic_variable {
Type value;
template<typename... Args>
variable_handler(Args &&... args)
: value{std::forward<Args>(args)...}
{}
Type value;
ENTT_ID_TYPE id() const ENTT_NOEXCEPT override {
return type_id_v<Type>;
}
};
auto generate() {
@@ -214,31 +210,37 @@ class basic_registry {
template<typename Component, typename... Args>
const pool_type<Component> * assure(Args &&... args) const {
const auto ctype = to_integer(type<Component>());
static_assert(std::is_same_v<Component, std::decay_t<Component>>);
static std::size_t index{pools.size()};
if(!(ctype < pools.size())) {
pools.resize(ctype+1);
}
if(!(index < pools.size()) || pools[index].id != type_id_v<Component>) {
index = std::find_if(pools.cbegin(), pools.cend(), [](auto &&cpool) {
return cpool.id == type_id_v<Component>;
}) - pools.cbegin();
if(!pools[ctype].pool) {
pools[ctype].pool = std::make_unique<pool_type<Component>>(std::forward<Args>(args)...);
if(index == pools.size()) {
auto &&pdata = pools.emplace_back();
pools[ctype].remove = [](sparse_set<Entity> &cpool, basic_registry &owner, const Entity entt) {
static_cast<pool_type<Component> &>(cpool).remove(owner, entt);
};
pdata.id = type_id_v<Component>;
pdata.pool = std::make_unique<pool_type<Component>>(std::forward<Args>(args)...);
if constexpr(std::is_copy_constructible_v<std::decay_t<Component>>) {
pools[ctype].assure = [](basic_registry &other, const sparse_set<Entity> &cpool) {
other.assure<Component>(static_cast<const pool_type<Component> &>(cpool));
pdata.remove = [](sparse_set<Entity> &cpool, basic_registry &owner, const Entity entt) {
static_cast<pool_type<Component> &>(cpool).remove(owner, entt);
};
pools[ctype].stomp = [](basic_registry &other, const Entity dst, const sparse_set<Entity> &cpool, const Entity src) {
other.assign_or_replace<Component>(dst, static_cast<const pool_type<Component> &>(cpool).get(src));
};
if constexpr(std::is_copy_constructible_v<std::decay_t<Component>>) {
pdata.assure = [](basic_registry &other, const sparse_set<Entity> &cpool) {
other.assure<Component>(static_cast<const pool_type<Component> &>(cpool));
};
pdata.stomp = [](basic_registry &other, const Entity dst, const sparse_set<Entity> &cpool, const Entity src) {
other.assign_or_replace<Component>(dst, static_cast<const pool_type<Component> &>(cpool).get(src));
};
}
}
}
return static_cast<pool_type<Component> *>(pools[ctype].pool.get());
return static_cast<pool_type<Component> *>(pools[index].pool.get());
}
template<typename Component>
@@ -263,20 +265,6 @@ public:
/*! @brief Default move assignment operator. @return This registry. */
basic_registry & operator=(basic_registry &&) = default;
/**
* @brief Returns the opaque identifier of a component.
*
* The given component doesn't need to be necessarily in use.<br/>
* Identifiers aren't guaranteed to be stable between different runs.
*
* @tparam Component Type of component to query.
* @return The opaque identifier of the given type of component.
*/
template<typename Component>
static component type() ENTT_NOEXCEPT {
return component{component_family<std::decay_t<Component>>::type()};
}
/**
* @brief Prepares a pool for the given type if required.
* @tparam Component Type of component for which to prepare a pool.
@@ -285,7 +273,7 @@ public:
*/
template<typename Component, typename... Args>
void prepare(Args &&... args) {
ENTT_ASSERT(!(to_integer(type<Component>()) < pools.size()) || !pools[to_integer(type<Component>())].pool);
ENTT_ASSERT(std::none_of(pools.cbegin(), pools.cend(), [](auto &&pdata) { return pdata.id == type_id_v<Component>; }));
assure<Component>(std::forward<Args>(args)...);
}
@@ -569,7 +557,7 @@ public:
ENTT_ASSERT(valid(entity));
for(auto pos = pools.size(); pos; --pos) {
if(auto &pdata = pools[pos-1]; pdata.pool && pdata.pool->has(entity)) {
if(auto &pdata = pools[pos-1]; pdata.pool->has(entity)) {
pdata.remove(*pdata.pool, *this, entity);
}
}
@@ -956,8 +944,7 @@ public:
bool orphan = true;
for(std::size_t pos{}, last = pools.size(); pos < last && orphan; ++pos) {
const auto &pdata = pools[pos];
orphan = !(pdata.pool && pdata.pool->has(entity));
orphan = !pools[pos].pool->has(entity);
}
return orphan;
@@ -1216,7 +1203,7 @@ public:
template<typename... Component, typename... Exclude>
entt::basic_view<Entity, exclude_t<Exclude...>, Component...> view(exclude_t<Exclude...> = {}) {
static_assert(sizeof...(Component) > 0);
return { assure<Component>()..., assure<Exclude>()... };
return { assure<std::decay_t<Component>>()..., assure<Exclude>()... };
}
/*! @copydoc view */
@@ -1272,15 +1259,15 @@ public:
using handler_type = group_handler<exclude_t<Exclude...>, get_t<Get...>, Owned...>;
[[maybe_unused]] constexpr auto size = sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude);
const auto cpools = std::make_tuple(assure<Owned>()..., assure<Get>()..., assure<Exclude>()...);
const auto cpools = std::make_tuple(assure<std::decay_t<Owned>>()..., assure<std::decay_t<Get>>()..., assure<Exclude>()...);
const std::size_t extent[3]{sizeof...(Owned), sizeof...(Get), sizeof...(Exclude)};
handler_type *handler = nullptr;
if(auto it = std::find_if(groups.cbegin(), groups.cend(), [&extent](const auto &gdata) {
return std::equal(std::begin(extent), std::end(extent), std::begin(gdata.extent))
&& (gdata.owned(type<Owned>()) && ...)
&& (gdata.get(type<Get>()) && ...)
&& (gdata.exclude(type<Exclude>()) && ...);
&& (gdata.owned(type_id_v<std::decay_t<Owned>>) && ...)
&& (gdata.get(type_id_v<std::decay_t<Get>>) && ...)
&& (gdata.exclude(type_id_v<Exclude>) && ...);
}); it != groups.cend())
{
handler = static_cast<handler_type *>(it->group.get());
@@ -1293,26 +1280,31 @@ public:
group_data gdata{
{ sizeof...(Owned), sizeof...(Get), sizeof...(Exclude) },
decltype(group_data::group){new handler_type{cpools}, [](void *gptr) { delete static_cast<handler_type *>(gptr); }},
[](const component ctype) ENTT_NOEXCEPT { return ((ctype == type<Owned>()) || ...); },
[](const component ctype) ENTT_NOEXCEPT { return ((ctype == type<Get>()) || ...); },
[](const component ctype) ENTT_NOEXCEPT { return ((ctype == type<Exclude>()) || ...); }
[](const auto ctype) ENTT_NOEXCEPT { return ((ctype == type_id_v<std::decay_t<Owned>>) || ...); },
[](const auto ctype) ENTT_NOEXCEPT { return ((ctype == type_id_v<std::decay_t<Get>>) || ...); },
[](const auto ctype) ENTT_NOEXCEPT { return ((ctype == type_id_v<Exclude>) || ...); }
};
if constexpr(sizeof...(Owned) == 0) {
handler = static_cast<handler_type *>(groups.emplace_back(std::move(gdata)).group.get());
} else {
ENTT_ASSERT(std::all_of(groups.cbegin(), groups.cend(), [&extent](const auto &curr) {
const std::size_t diff[3]{ (0u + ... + curr.owned(type<Owned>())), (0u + ... + curr.get(type<Get>())), (0u + ... + curr.exclude(type<Exclude>())) };
const std::size_t diff[3]{
(0u + ... + curr.owned(type_id_v<std::decay_t<Owned>>)),
(0u + ... + curr.get(type_id_v<std::decay_t<Get>>)),
(0u + ... + curr.exclude(type_id_v<Exclude>))
};
return !diff[0] || ((std::equal(std::begin(diff), std::end(diff), extent) || std::equal(std::begin(diff), std::end(diff), curr.extent)));
}));
const auto next = std::find_if_not(groups.cbegin(), groups.cend(), [&size](const auto &curr) {
const std::size_t diff = (0u + ... + curr.owned(type<Owned>()));
const std::size_t diff = (0u + ... + curr.owned(type_id_v<std::decay_t<Owned>>));
return !diff || (size > (curr.extent[0] + curr.extent[1] + curr.extent[2]));
});
const auto prev = std::find_if(std::make_reverse_iterator(next), groups.crend(), [](const auto &curr) {
return (0u + ... + curr.owned(type<Owned>()));
return (0u + ... + curr.owned(type_id_v<std::decay_t<Owned>>));
});
maybe_valid_if = (next == groups.cend() ? maybe_valid_if : next->group.get());
@@ -1432,7 +1424,11 @@ public:
std::vector<const sparse_set<Entity> *> selected(std::distance(first, last));
std::transform(first, last, selected.begin(), [this](const component ctype) {
return to_integer(ctype) < pools.size() ? pools[to_integer(ctype)].pool.get() : nullptr;
const auto it = std::find_if(pools.cbegin(), pools.cend(), [ctype](auto &&pdata) {
return pdata.id == to_integer(ctype);
});
return it == pools.cend() ? nullptr : it->pool.get();
});
return { std::move(selected) };
@@ -1480,7 +1476,7 @@ public:
if constexpr(sizeof...(Component) == 0) {
for(size_type pos{}; pos < pools.size(); ++pos) {
if(const auto &pdata = pools[pos]; pdata.assure && ((pos != to_integer(type<Exclude>())) && ...)) {
if(const auto &pdata = pools[pos]; pdata.assure && ((pdata.id != type_id_v<Exclude>) && ...)) {
pdata.assure(other, *pdata.pool);
}
}
@@ -1533,7 +1529,7 @@ public:
void stomp(const entity_type dst, const basic_registry &other, const entity_type src, exclude_t<Exclude...> = {}) {
if constexpr(sizeof...(Component) == 0) {
for(size_type pos{}; pos < other.pools.size(); ++pos) {
if(const auto &pdata = other.pools[pos]; pdata.stomp && ((pos != to_integer(type<Exclude>())) && ...) && pdata.pool->has(src)) {
if(const auto &pdata = other.pools[pos]; pdata.stomp && ((pdata.id != type_id_v<Exclude>) && ...) && pdata.pool->has(src)) {
pdata.stomp(*this, dst, *pdata.pool, src);
}
}
@@ -1629,14 +1625,9 @@ public:
*/
template<typename Type, typename... Args>
Type & set(Args &&... args) {
const auto vtype = context_family<std::decay_t<Type>>::type();
if(!(vtype < vars.size())) {
vars.resize(vtype+1);
}
vars[vtype] = std::make_unique<variable_handler<Type>>(std::forward<Args>(args)...);
return static_cast<variable_handler<Type> &>(*vars[vtype]).value;
unset<Type>();
vars.push_back(std::make_unique<variable_handler<Type>>(std::forward<Args>(args)...));
return static_cast<variable_handler<Type> &>(*vars.back()).value;
}
/**
@@ -1645,9 +1636,9 @@ public:
*/
template<typename Type>
void unset() {
if(const auto vtype = context_family<std::decay_t<Type>>::type(); vtype < vars.size()) {
vars[vtype].reset();
}
vars.erase(std::remove_if(vars.begin(), vars.end(), [](auto &&handler) {
return handler->id() == type_id_v<Type>;
}), vars.end());
}
/**
@@ -1675,8 +1666,11 @@ public:
*/
template<typename Type>
const Type * try_ctx() const {
const auto vtype = context_family<std::decay_t<Type>>::type();
return vtype < vars.size() && vars[vtype] ? &static_cast<variable_handler<Type> &>(*vars[vtype]).value : nullptr;
auto it = std::find_if(vars.cbegin(), vars.cend(), [](auto &&handler) {
return handler->id() == type_id_v<Type>;
});
return it == vars.cend() ? nullptr : &static_cast<const variable_handler<Type> &>(*it->get()).value;
}
/*! @copydoc try_ctx */

View File

@@ -87,7 +87,7 @@ class dispatcher {
if(!(index < pools.size()) || pools[index]->id() != type_id_v<Event>) {
index = std::find_if(pools.cbegin(), pools.cend(), [](auto &&cpool) {
return cpool->id() == type_id_v<Event>;
}) - pools.begin();
}) - pools.cbegin();
if(index == pools.size()) {
pools.push_back(std::make_unique<pool_handler<Event>>());

View File

@@ -126,7 +126,7 @@ class emitter {
if(!(index < pools.size()) || pools[index]->id() != type_id_v<Event>) {
index = std::find_if(pools.cbegin(), pools.cend(), [](auto &&cpool) {
return cpool->id() == type_id_v<Event>;
}) - pools.begin();
}) - pools.cbegin();
if(index == pools.size()) {
pools.push_back(std::make_unique<pool_handler<Event>>());

View File

@@ -4,6 +4,7 @@
#include <chrono>
#include <iterator>
#include <gtest/gtest.h>
#include <entt/core/type_info.hpp>
#include <entt/entity/registry.hpp>
struct position {
@@ -167,7 +168,7 @@ TEST(Benchmark, IterateSingleComponentRuntime1M) {
}
auto test = [&registry](auto func) {
entt::component types[] = { registry.type<position>() };
entt::component types[] = { entt::component{entt::type_id_v<position>} };
timer timer;
registry.runtime_view(std::begin(types), std::end(types)).each(func);
@@ -332,7 +333,7 @@ TEST(Benchmark, IterateTwoComponentsRuntime1M) {
}
auto test = [&registry](auto func) {
entt::component types[] = { registry.type<position>(), registry.type<velocity>() };
entt::component types[] = { entt::component{entt::type_id_v<position>}, entt::component{entt::type_id_v<velocity>} };
timer timer;
registry.runtime_view(std::begin(types), std::end(types)).each(func);
@@ -360,7 +361,7 @@ TEST(Benchmark, IterateTwoComponentsRuntime1MHalf) {
}
auto test = [&registry](auto func) {
entt::component types[] = { registry.type<position>(), registry.type<velocity>() };
entt::component types[] = { entt::component{entt::type_id_v<position>}, entt::component{entt::type_id_v<velocity>} };
timer timer;
registry.runtime_view(std::begin(types), std::end(types)).each(func);
@@ -388,7 +389,7 @@ TEST(Benchmark, IterateTwoComponentsRuntime1MOne) {
}
auto test = [&registry](auto func) {
entt::component types[] = { registry.type<position>(), registry.type<velocity>() };
entt::component types[] = { entt::component{entt::type_id_v<position>}, entt::component{entt::type_id_v<velocity>} };
timer timer;
registry.runtime_view(std::begin(types), std::end(types)).each(func);
@@ -561,7 +562,7 @@ TEST(Benchmark, IterateThreeComponentsRuntime1M) {
}
auto test = [&registry](auto func) {
entt::component types[] = { registry.type<position>(), registry.type<velocity>(), registry.type<comp<0>>() };
entt::component types[] = { entt::component{entt::type_id_v<position>}, entt::component{entt::type_id_v<velocity>}, entt::component{entt::type_id_v<comp<0>>} };
timer timer;
registry.runtime_view(std::begin(types), std::end(types)).each(func);
@@ -591,7 +592,7 @@ TEST(Benchmark, IterateThreeComponentsRuntime1MHalf) {
}
auto test = [&registry](auto func) {
entt::component types[] = { registry.type<position>(), registry.type<velocity>(), registry.type<comp<0>>() };
entt::component types[] = { entt::component{entt::type_id_v<position>}, entt::component{entt::type_id_v<velocity>}, entt::component{entt::type_id_v<comp<0>>} };
timer timer;
registry.runtime_view(std::begin(types), std::end(types)).each(func);
@@ -621,7 +622,7 @@ TEST(Benchmark, IterateThreeComponentsRuntime1MOne) {
}
auto test = [&registry](auto func) {
entt::component types[] = { registry.type<position>(), registry.type<velocity>(), registry.type<comp<0>>() };
entt::component types[] = { entt::component{entt::type_id_v<position>}, entt::component{entt::type_id_v<velocity>}, entt::component{entt::type_id_v<comp<0>>} };
timer timer;
registry.runtime_view(std::begin(types), std::end(types)).each(func);
@@ -836,11 +837,11 @@ TEST(Benchmark, IterateFiveComponentsRuntime1M) {
auto test = [&registry](auto func) {
entt::component types[] = {
registry.type<position>(),
registry.type<velocity>(),
registry.type<comp<0>>(),
registry.type<comp<1>>(),
registry.type<comp<2>>()
entt::component{entt::type_id_v<position>},
entt::component{entt::type_id_v<velocity>},
entt::component{entt::type_id_v<comp<0>>},
entt::component{entt::type_id_v<comp<1>>},
entt::component{entt::type_id_v<comp<2>>}
};
timer timer;
@@ -876,11 +877,11 @@ TEST(Benchmark, IterateFiveComponentsRuntime1MHalf) {
auto test = [&registry](auto func) {
entt::component types[] = {
registry.type<position>(),
registry.type<velocity>(),
registry.type<comp<0>>(),
registry.type<comp<1>>(),
registry.type<comp<2>>()
entt::component{entt::type_id_v<position>},
entt::component{entt::type_id_v<velocity>},
entt::component{entt::type_id_v<comp<0>>},
entt::component{entt::type_id_v<comp<1>>},
entt::component{entt::type_id_v<comp<2>>}
};
timer timer;
@@ -916,11 +917,11 @@ TEST(Benchmark, IterateFiveComponentsRuntime1MOne) {
auto test = [&registry](auto func) {
entt::component types[] = {
registry.type<position>(),
registry.type<velocity>(),
registry.type<comp<0>>(),
registry.type<comp<1>>(),
registry.type<comp<2>>()
entt::component{entt::type_id_v<position>},
entt::component{entt::type_id_v<velocity>},
entt::component{entt::type_id_v<comp<0>>},
entt::component{entt::type_id_v<comp<1>>},
entt::component{entt::type_id_v<comp<2>>}
};
timer timer;

View File

@@ -10,9 +10,8 @@ TEST(Helper, AsView) {
([](entt::view<entt::exclude_t<>, int>) {})(entt::as_view{registry});
([](entt::view<entt::exclude_t<int>, char, double>) {})(entt::as_view{registry});
([](entt::view<entt::exclude_t<const int>, char, double>) {})(entt::as_view{registry});
([](entt::view<entt::exclude_t<const int>, const char, double>) {})(entt::as_view{registry});
([](entt::view<entt::exclude_t<const int>, const char, const double>) {})(entt::as_view{registry});
([](entt::view<entt::exclude_t<int>, const char, double>) {})(entt::as_view{registry});
([](entt::view<entt::exclude_t<int>, const char, const double>) {})(entt::as_view{registry});
}
TEST(Helper, AsGroup) {
@@ -20,9 +19,8 @@ TEST(Helper, AsGroup) {
const entt::registry cregistry;
([](entt::group<entt::exclude_t<int>, entt::get_t<char>, double>) {})(entt::as_group{registry});
([](entt::group<entt::exclude_t<const int>, entt::get_t<char>, double>) {})(entt::as_group{registry});
([](entt::group<entt::exclude_t<const int>, entt::get_t<const char>, double>) {})(entt::as_group{registry});
([](entt::group<entt::exclude_t<const int>, entt::get_t<const char>, const double>) {})(entt::as_group{registry});
([](entt::group<entt::exclude_t<int>, entt::get_t<const char>, double>) {})(entt::as_group{registry});
([](entt::group<entt::exclude_t<int>, entt::get_t<const char>, const double>) {})(entt::as_group{registry});
}
TEST(Helper, Tag) {

View File

@@ -78,12 +78,6 @@ TEST(Registry, Context) {
ASSERT_EQ(registry.try_ctx<float>(), nullptr);
}
TEST(Registry, Types) {
entt::registry registry;
ASSERT_EQ(registry.type<int>(), registry.type<int>());
ASSERT_NE(registry.type<double>(), registry.type<int>());
}
TEST(Registry, Functionalities) {
entt::registry registry;
@@ -1540,9 +1534,7 @@ TEST(Registry, Constness) {
entt::registry registry;
ASSERT_TRUE((std::is_same_v<decltype(registry.assign<int>({})), int &>));
ASSERT_TRUE((std::is_same_v<decltype(registry.assign<const int>({})), int &>));
ASSERT_TRUE((std::is_same_v<decltype(registry.assign<empty_type>({})), empty_type>));
ASSERT_TRUE((std::is_same_v<decltype(registry.assign<const empty_type>({})), empty_type>));
ASSERT_TRUE((std::is_same_v<decltype(registry.get<int>({})), int &>));
ASSERT_TRUE((std::is_same_v<decltype(registry.get<int, char>({})), std::tuple<int &, char &>>));

View File

@@ -11,7 +11,7 @@ TEST(RuntimeView, Functionalities) {
registry.reserve<int>(0);
registry.reserve<char>(0);
entt::component types[] = { registry.type<int>(), registry.type<char>() };
entt::component types[] = { entt::component{entt::type_id_v<int>}, entt::component{entt::type_id_v<char>} };
auto view = registry.runtime_view(std::begin(types), std::end(types));
ASSERT_TRUE(view.empty());
@@ -54,7 +54,7 @@ TEST(RuntimeView, Iterator) {
registry.assign<int>(entity);
registry.assign<char>(entity);
entt::component types[] = { registry.type<int>(), registry.type<char>() };
entt::component types[] = { entt::component{entt::type_id_v<int>}, entt::component{entt::type_id_v<char>} };
auto view = registry.runtime_view(std::begin(types), std::end(types));
using iterator_type = typename decltype(view)::iterator_type;
@@ -90,7 +90,7 @@ TEST(RuntimeView, Contains) {
registry.destroy(e0);
entt::component types[] = { registry.type<int>(), registry.type<char>() };
entt::component types[] = { entt::component{entt::type_id_v<int>}, entt::component{entt::type_id_v<char>} };
auto view = registry.runtime_view(std::begin(types), std::end(types));
ASSERT_FALSE(view.contains(e0));
@@ -109,7 +109,7 @@ TEST(RuntimeView, Empty) {
registry.assign<char>(e1);
registry.assign<float>(e1);
entt::component types[] = { registry.type<char>(), registry.type<int>(), registry.type<float>() };
entt::component types[] = { entt::component{entt::type_id_v<int>}, entt::component{entt::type_id_v<char>}, entt::component{entt::type_id_v<float>} };
auto view = registry.runtime_view(std::begin(types), std::end(types));
view.each([](auto) { FAIL(); });
@@ -129,7 +129,7 @@ TEST(RuntimeView, Each) {
registry.assign<int>(e1);
registry.assign<char>(e1);
entt::component types[] = { registry.type<int>(), registry.type<char>() };
entt::component types[] = { entt::component{entt::type_id_v<int>}, entt::component{entt::type_id_v<char>} };
auto view = registry.runtime_view(std::begin(types), std::end(types));
std::size_t cnt = 0;
@@ -151,7 +151,7 @@ TEST(RuntimeView, EachWithHoles) {
registry.assign<int>(e0, 0);
registry.assign<int>(e2, 2);
entt::component types[] = { registry.type<int>(), registry.type<char>() };
entt::component types[] = { entt::component{entt::type_id_v<int>}, entt::component{entt::type_id_v<char>} };
auto view = registry.runtime_view(std::begin(types), std::end(types));
view.each([e0](auto entity) {
@@ -165,7 +165,7 @@ TEST(RuntimeView, MissingPool) {
const auto e0 = registry.create();
registry.assign<int>(e0);
entt::component types[] = { registry.type<int>(), registry.type<char>() };
entt::component types[] = { entt::component{entt::type_id_v<int>}, entt::component{entt::type_id_v<char>} };
auto view = registry.runtime_view(std::begin(types), std::end(types));
ASSERT_TRUE(view.empty());

View File

@@ -2,24 +2,6 @@
#include <entt/entity/registry.hpp>
#include "types.h"
ENTT_API entt::component int_type() {
entt::registry registry;
(void)registry.type<double>();
(void)registry.type<float>();
return registry.type<int>();
}
ENTT_API entt::component char_type() {
entt::registry registry;
(void)registry.type<double>();
(void)registry.type<float>();
return registry.type<char>();
}
ENTT_API void update_position(int delta, entt::registry &registry) {
registry.view<position, velocity>().each([delta](auto &pos, auto &vel) {
pos.x += delta * vel.dx;

View File

@@ -4,25 +4,9 @@
#include <entt/entity/registry.hpp>
#include "types.h"
ENTT_API entt::component int_type();
ENTT_API entt::component char_type();
ENTT_API void update_position(int, entt::registry &);
ENTT_API void assign_velocity(int, entt::registry &);
TEST(Lib, Types) {
entt::registry registry;
ASSERT_EQ(registry.type<int>(), registry.type<const int>());
ASSERT_EQ(registry.type<char>(), registry.type<const char>());
ASSERT_EQ(registry.type<int>(), int_type());
ASSERT_EQ(registry.type<char>(), char_type());
ASSERT_EQ(registry.type<const char>(), char_type());
ASSERT_EQ(registry.type<const int>(), int_type());
}
TEST(Lib, Registry) {
entt::registry registry;

View File

@@ -4,6 +4,7 @@
#include <string>
#include <duktape.h>
#include <gtest/gtest.h>
#include <entt/core/type_info.hpp>
#include <entt/entity/registry.hpp>
template<typename Type>
@@ -122,9 +123,6 @@ duk_ret_t get(duk_context *ctx, entt::registry &registry) {
}
class duktape_registry {
// I'm pretty sure I won't have more than 99 components in the example
static constexpr ENTT_ID_TYPE udef = 100;
struct func_map {
using func_type = duk_ret_t(*)(duk_context *, entt::registry &);
@@ -136,7 +134,7 @@ class duktape_registry {
template<typename... Comp>
void reg() {
((func[to_integer(registry.type<Comp>())] = {
((func[entt::type_id_v<Comp>] = {
&::set<Comp>,
&::unset<Comp>,
&::has<Comp>,
@@ -162,13 +160,11 @@ class duktape_registry {
auto &registry = dreg.registry;
auto type = duk_require_uint(ctx, 1);
if(type >= udef) {
type = to_integer(registry.type<duktape_runtime>());
}
const auto it = func.find(type);
assert(func.find(type) != func.cend());
return (func[type].*Op)(ctx, registry);
return (it == func.cend())
? (func[entt::type_id_v<duktape_runtime>].*Op)(ctx, registry)
: (it->second.*Op)(ctx, registry);
}
public:
@@ -179,7 +175,7 @@ public:
}
static duk_ret_t identifier(duk_context *ctx) {
static auto next = udef;
static ENTT_ID_TYPE next{};
duk_push_uint(ctx, next++);
return 1;
}
@@ -210,7 +206,6 @@ public:
static duk_ret_t entities(duk_context *ctx) {
const duk_idx_t nargs = duk_get_top(ctx);
auto &dreg = instance(ctx);
duk_uarridx_t pos = 0;
duk_push_array(ctx);
@@ -220,18 +215,19 @@ public:
for(duk_idx_t arg = 0; arg < nargs; arg++) {
auto type = duk_require_uint(ctx, arg);
if(type < udef) {
components.push_back(entt::component{type});
} else {
if(dreg.func.find(type) == dreg.func.cend()) {
if(runtime.empty()) {
components.push_back(dreg.registry.type<duktape_runtime>());
components.push_back(entt::component{entt::type_id_v<duktape_runtime>});
}
runtime.push_back(entt::component{type});
} else {
components.push_back(entt::component{type});
}
}
auto view = dreg.registry.runtime_view(components.cbegin(), components.cend());
duk_uarridx_t pos = 0;
for(const auto entity: view) {
if(runtime.empty()) {
@@ -269,15 +265,15 @@ const duk_function_list_entry js_duktape_registry_methods[] = {
{ nullptr, nullptr, 0 }
};
void export_types(duk_context *context, entt::registry &registry) {
auto export_type = [idx = duk_push_object(context)](auto *ctx, auto &reg, auto type, const auto *name) {
void export_types(duk_context *context) {
auto export_type = [idx = duk_push_object(context)](auto *ctx, auto type, const auto *name) {
duk_push_string(ctx, name);
duk_push_uint(ctx, to_integer(reg.template type<typename decltype(type)::type>()));
duk_push_uint(ctx, entt::type_id_v<typename decltype(type)::type>);
duk_def_prop(ctx, idx, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_CLEAR_WRITABLE);
};
export_type(context, registry, tag<position>{}, "position");
export_type(context, registry, tag<renderable>{}, "renderable");
export_type(context, tag<position>{}, "position");
export_type(context, tag<renderable>{}, "renderable");
duk_put_global_string(context, "Types");
}
@@ -302,7 +298,7 @@ TEST(Mod, Duktape) {
FAIL();
}
export_types(ctx, registry);
export_types(ctx);
export_duktape_registry(ctx, dreg);
const char *s0 = ""

View File

@@ -0,0 +1,33 @@
#define CR_HOST
#include <cr.h>
#include <gtest/gtest.h>
#include <entt/entity/registry.hpp>
#include "types.h"
TEST(Lib, Registry) {
entt::registry registry;
for(auto i = 0; i < 3; ++i) {
const auto entity = registry.create();
registry.assign<position>(entity, i, i+1);
}
ASSERT_FALSE(registry.empty<position>());
ASSERT_TRUE(registry.empty<velocity>());
cr_plugin ctx;
ctx.userdata = &registry;
cr_plugin_load(ctx, PLUGIN);
cr_plugin_update(ctx);
ASSERT_FALSE(registry.empty<position>());
ASSERT_FALSE(registry.empty<velocity>());
registry.view<position>().each([](auto entity, auto &position) {
ASSERT_EQ(position.x, entt::to_integer(entity) + 2);
ASSERT_EQ(position.y, entt::to_integer(entity) + 3);
});
cr_plugin_close(ctx);
}

View File

@@ -0,0 +1,30 @@
#include <cr.h>
#include <entt/entity/registry.hpp>
#include "types.h"
CR_EXPORT int cr_main(cr_plugin *ctx, cr_op operation) {
switch (operation) {
case CR_STEP:
[ctx]() {
auto *registry = static_cast<entt::registry *>(ctx->userdata);
registry->reset<velocity>();
for(auto entity: registry->view<position>()) {
registry->assign<velocity>(entity, 1, 1);
}
registry->view<position, velocity>().each([](auto &pos, auto &vel) {
pos.x += 2 * vel.dx;
pos.y += 2 * vel.dy;
});
}();
break;
case CR_LOAD:
case CR_UNLOAD:
case CR_CLOSE:
// nothing to do here, this is only a test.
break;
}
return 0;
}

View File

@@ -0,0 +1,14 @@
#ifndef ENTT_PLUGIN_REGISTRY_TYPES_H
#define ENTT_PLUGIN_REGISTRY_TYPES_H
struct position {
int x;
int y;
};
struct velocity {
int dx;
int dy;
};
#endif // ENTT_PLUGIN_REGISTRY_TYPES_H