Compare commits

..

8 Commits

Author SHA1 Message Date
Michele Caini
ce3a0157cb updated version.h to v3.2.1 2019-11-26 11:20:54 +01:00
Michele Caini
a146b06e4b updated single include file to v3.2.1 (close #366) 2019-11-26 11:18:41 +01:00
Michele Caini
dc78a3e56d version: 3.2.1 2019-11-26 11:17:13 +01:00
Michele Caini
86c524dade fix: sorting empty types (close #365) 2019-11-26 11:16:02 +01:00
Innokentiy Alaytsev
6889edcfc4 meta, fix: meta_prop::next lazy initialization 2019-11-26 11:11:42 +01:00
Michele Caini
3cd5934bad typo 2019-11-26 11:11:26 +01:00
Michele Caini
064104f23a suppress **all** shadow warnings (close #346) 2019-11-26 11:11:19 +01:00
Michele Caini
e80b1c264c family: it no longer dacays types 2019-11-26 11:11:13 +01:00
19 changed files with 6958 additions and 5503 deletions

View File

@@ -16,7 +16,7 @@ endif()
# Project configuration
#
project(EnTT VERSION 3.2.0 LANGUAGES CXX)
project(EnTT VERSION 3.2.1 LANGUAGES CXX)
include(GNUInstallDirs)

2
TODO
View File

@@ -36,3 +36,5 @@
* null support for entt::component
* add ENTT_CUSTOM_NAMED_TYPE for custom names
* Make another attempt to overcome named types
* meta: members+class as fake functions, is it possible?
* named types: almost-stable index optimization for direct access to pools, no more linear searches

View File

@@ -1672,7 +1672,15 @@ only the entities to which it's assigned are made available. All the iterators
as well as the `get` member functions of the registry, the views and the groups
will return temporary objects. Similarly, some functions such as `try_get` or
the raw access to the list of components aren't available for this kind of
types.<br/>
types. Finally, the `sort` functionality accepts only callbacks that require to
return entities rather than components:
```cpp
registry.sort<empty_type>([](const entt::entity lhs, const entt::entity rhs) {
return entt::registry::entity(lhs) < entt::registry::entity(rhs);
});
```
On the other hand, iterations are faster because only the entities to which the
type is assigned are considered. Moreover, less memory is used, since there
doesn't exist any instance of the component, no matter how many entities it is

File diff suppressed because it is too large Load Diff

View File

@@ -2,10 +2,10 @@
#define ENTT_CONFIG_VERSION_H
#define ENTT_VERSION "3.2.0"
#define ENTT_VERSION "3.2.1"
#define ENTT_VERSION_MAJOR 3
#define ENTT_VERSION_MINOR 2
#define ENTT_VERSION_PATCH 0
#define ENTT_VERSION_PATCH 1
#endif // ENTT_CONFIG_VERSION_H

View File

@@ -20,10 +20,6 @@ template<typename...>
class family {
inline static ENTT_MAYBE_ATOMIC(ENTT_ID_TYPE) identifier{};
template<typename...>
// clang (since version 9) started to complain if auto is used instead of ENTT_ID_TYPE
inline static const ENTT_ID_TYPE inner = identifier++;
public:
/*! @brief Unsigned integer type. */
using family_type = ENTT_ID_TYPE;
@@ -31,7 +27,7 @@ public:
/*! @brief Statically generated unique identifier for the given type. */
template<typename... Type>
// at the time I'm writing, clang crashes during compilation if auto is used instead of family_type
inline static const family_type type = inner<std::decay_t<Type>...>;
inline static const family_type type = identifier++;
};

View File

@@ -74,9 +74,9 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>> {
using pool_type = std::conditional_t<std::is_const_v<Component>, const storage<Entity, std::remove_const_t<Component>>, storage<Entity, Component>>;
// we could use pool_type<Type> *..., but vs complains about it and refuses to compile for unknown reasons (most likely a bug)
basic_group(sparse_set<Entity> *ref, storage<Entity, std::remove_const_t<Get>> *... get) ENTT_NOEXCEPT
basic_group(sparse_set<Entity> *ref, storage<Entity, std::remove_const_t<Get>> *... gpool) ENTT_NOEXCEPT
: handler{ref},
pools{get...}
pools{gpool...}
{}
template<typename Func, typename... Weak>
@@ -491,28 +491,28 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...> {
using component_iterator_type = decltype(std::declval<pool_type<Component>>().begin());
// we could use pool_type<Type> *..., but vs complains about it and refuses to compile for unknown reasons (most likely a bug)
basic_group(const std::size_t *ref, const std::size_t *extent, storage<Entity, std::remove_const_t<Owned>> *... owned, storage<Entity, std::remove_const_t<Get>> *... get) ENTT_NOEXCEPT
: pools{owned..., get...},
basic_group(const std::size_t *ref, const std::size_t *extent, storage<Entity, std::remove_const_t<Owned>> *... opool, storage<Entity, std::remove_const_t<Get>> *... gpool) ENTT_NOEXCEPT
: pools{opool..., gpool...},
length{extent},
super{ref}
{}
template<typename Func, typename... Strong, typename... Weak>
void traverse(Func func, type_list<Strong...>, type_list<Weak...>) const {
[[maybe_unused]] auto raw = std::make_tuple((std::get<pool_type<Strong> *>(pools)->end() - *length)...);
[[maybe_unused]] auto it = std::make_tuple((std::get<pool_type<Strong> *>(pools)->end() - *length)...);
[[maybe_unused]] auto data = std::get<0>(pools)->sparse_set<entity_type>::end() - *length;
for(auto next = *length; next; --next) {
if constexpr(std::is_invocable_v<Func, decltype(get<Strong>({}))..., decltype(get<Weak>({}))...>) {
if constexpr(sizeof...(Weak) == 0) {
func(*(std::get<component_iterator_type<Strong>>(raw)++)...);
func(*(std::get<component_iterator_type<Strong>>(it)++)...);
} else {
const auto entt = *(data++);
func(*(std::get<component_iterator_type<Strong>>(raw)++)..., std::get<pool_type<Weak> *>(pools)->get(entt)...);
func(*(std::get<component_iterator_type<Strong>>(it)++)..., std::get<pool_type<Weak> *>(pools)->get(entt)...);
}
} else {
const auto entt = *(data++);
func(entt, *(std::get<component_iterator_type<Strong>>(raw)++)..., std::get<pool_type<Weak> *>(pools)->get(entt)...);
func(entt, *(std::get<component_iterator_type<Strong>>(it)++)..., std::get<pool_type<Weak> *>(pools)->get(entt)...);
}
}
}
@@ -837,13 +837,13 @@ public:
}, std::move(algo), std::forward<Args>(args)...);
}
[](std::size_t length, auto *cpool, auto *... other) {
for(auto next = length; next; --next) {
[this](auto *head, auto *... other) {
for(auto next = *length; next; --next) {
const auto pos = next - 1;
[[maybe_unused]] const auto entt = cpool->data()[pos];
[[maybe_unused]] const auto entt = head->data()[pos];
(other->swap(other->data()[pos], entt), ...);
}
}(*length, std::get<pool_type<Owned> *>(pools)...);
}(std::get<pool_type<Owned> *>(pools)...);
}
private:

View File

@@ -69,45 +69,45 @@ class basic_registry {
}
template<typename... Args>
decltype(auto) assign(basic_registry &registry, const Entity entt, Args &&... args) {
decltype(auto) assign(basic_registry &owner, const Entity entt, Args &&... args) {
if constexpr(ENTT_ENABLE_ETO(Component)) {
storage<Entity, Component>::construct(entt);
construction.publish(entt, registry, Component{});
construction.publish(entt, owner, Component{});
return Component{std::forward<Args>(args)...};
} else {
auto &component = storage<Entity, Component>::construct(entt, std::forward<Args>(args)...);
construction.publish(entt, registry, component);
construction.publish(entt, owner, component);
return component;
}
}
template<typename It, typename... Args>
auto batch(basic_registry &registry, It first, It last, Args &&... args) {
auto batch(basic_registry &owner, It first, It last, Args &&... args) {
auto it = storage<Entity, Component>::batch(first, last, std::forward<Args>(args)...);
if(!construction.empty()) {
std::for_each(first, last, [this, &registry, it](const auto entt) mutable {
construction.publish(entt, registry, *(it++));
std::for_each(first, last, [this, &owner, it](const auto entt) mutable {
construction.publish(entt, owner, *(it++));
});
}
return it;
}
void remove(basic_registry &registry, const Entity entt) {
destruction.publish(entt, registry);
void remove(basic_registry &owner, const Entity entt) {
destruction.publish(entt, owner);
storage<Entity, Component>::destroy(entt);
}
template<typename... Args>
decltype(auto) replace(basic_registry &registry, const Entity entt, Args &&... args) {
decltype(auto) replace(basic_registry &owner, const Entity entt, Args &&... args) {
if constexpr(ENTT_ENABLE_ETO(Component)) {
ENTT_ASSERT((storage<Entity, Component>::has(entt)));
update.publish(entt, registry, Component{});
update.publish(entt, owner, Component{});
return Component{std::forward<Args>(args)...};
} else {
Component component{std::forward<Args>(args)...};
update.publish(entt, registry, component);
update.publish(entt, owner, component);
return (storage<Entity, Component>::get(entt) = std::move(component));
}
}
@@ -218,7 +218,7 @@ class basic_registry {
if constexpr(is_named_type_v<Type>) {
return named_type_traits_v<Type>;
} else {
return Family::template type<Type>;
return Family::template type<std::decay_t<Type>>;
}
}
@@ -276,8 +276,8 @@ class basic_registry {
pdata->runtime_type = ctype;
pdata->pool = std::make_unique<pool_type<Component>>();
pdata->remove = [](sparse_set<Entity> &cpool, basic_registry &registry, const Entity entt) {
static_cast<pool_type<Component> &>(cpool).remove(registry, entt);
pdata->remove = [](sparse_set<Entity> &cpool, basic_registry &owner, const Entity entt) {
static_cast<pool_type<Component> &>(cpool).remove(owner, entt);
};
if constexpr(std::is_copy_constructible_v<std::decay_t<Component>>) {
@@ -699,8 +699,8 @@ public:
* @sa destroy
*
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range to generate.
* @param last An iterator past the last element of the range to generate.
* @param first An iterator to the first element of the range to destroy.
* @param last An iterator past the last element of the range to destroy.
*/
template<typename It>
void destroy(It first, It last) {
@@ -1351,7 +1351,7 @@ public:
[[maybe_unused]] constexpr auto size = sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude);
const auto cpools = std::make_tuple(assure<Owned>()..., assure<Get>()..., assure<Exclude>()...);
const std::size_t extent[3]{sizeof...(Owned), sizeof...(Get), sizeof...(Exclude)};
handler_type *curr = nullptr;
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))
@@ -1360,10 +1360,10 @@ public:
&& (gdata.exclude(type<Exclude>()) && ...);
}); it != groups.cend())
{
curr = static_cast<handler_type *>(it->group.get());
handler = static_cast<handler_type *>(it->group.get());
}
if(!curr) {
if(!handler) {
const void *maybe_valid_if = nullptr;
const void *discard_if = nullptr;
@@ -1376,36 +1376,36 @@ public:
};
if constexpr(sizeof...(Owned) == 0) {
curr = static_cast<handler_type *>(groups.emplace_back(std::move(gdata)).group.get());
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 &gdata) {
const std::size_t diff[3]{ (0u + ... + gdata.owned(type<Owned>())), (0u + ... + gdata.get(type<Get>())), (0u + ... + gdata.exclude(type<Exclude>())) };
return !diff[0] || ((std::equal(std::begin(diff), std::end(diff), extent) || std::equal(std::begin(diff), std::end(diff), gdata.extent)));
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>())) };
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 &gdata) {
const std::size_t diff = (0u + ... + gdata.owned(type<Owned>()));
return !diff || (size > (gdata.extent[0] + gdata.extent[1] + gdata.extent[2]));
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>()));
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 &gdata) {
return (0u + ... + gdata.owned(type<Owned>()));
const auto prev = std::find_if(std::make_reverse_iterator(next), groups.crend(), [](const auto &curr) {
return (0u + ... + curr.owned(type<Owned>()));
});
maybe_valid_if = (next == groups.cend() ? maybe_valid_if : next->group.get());
discard_if = (prev == groups.crend() ? discard_if : prev->group.get());
curr = static_cast<handler_type *>(groups.insert(next, std::move(gdata))->group.get());
handler = static_cast<handler_type *>(groups.insert(next, std::move(gdata))->group.get());
}
((std::get<pool_type<Owned> *>(cpools)->super = std::max(std::get<pool_type<Owned> *>(cpools)->super, size)), ...);
(std::get<pool_type<Owned> *>(cpools)->on_construct().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<Owned>>(*curr), ...);
(std::get<pool_type<Get> *>(cpools)->on_construct().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<Get>>(*curr), ...);
(std::get<pool_type<Exclude> *>(cpools)->on_destroy().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<Exclude>>(*curr), ...);
(std::get<pool_type<Owned> *>(cpools)->on_construct().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<Owned>>(*handler), ...);
(std::get<pool_type<Get> *>(cpools)->on_construct().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<Get>>(*handler), ...);
(std::get<pool_type<Exclude> *>(cpools)->on_destroy().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if<Exclude>>(*handler), ...);
(std::get<pool_type<Owned> *>(cpools)->on_destroy().before(discard_if).template connect<&handler_type::discard_if>(*curr), ...);
(std::get<pool_type<Get> *>(cpools)->on_destroy().before(discard_if).template connect<&handler_type::discard_if>(*curr), ...);
(std::get<pool_type<Exclude> *>(cpools)->on_construct().before(discard_if).template connect<&handler_type::discard_if>(*curr), ...);
(std::get<pool_type<Owned> *>(cpools)->on_destroy().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...);
(std::get<pool_type<Get> *>(cpools)->on_destroy().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...);
(std::get<pool_type<Exclude> *>(cpools)->on_construct().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...);
const auto *cpool = std::min({
static_cast<sparse_set<Entity> *>(std::get<pool_type<Owned> *>(cpools))...,
@@ -1415,16 +1415,16 @@ public:
});
// we cannot iterate backwards because we want to leave behind valid entities in case of owned types
std::for_each(cpool->data(), cpool->data() + cpool->size(), [cpools, curr](const auto entity) {
std::for_each(cpool->data(), cpool->data() + cpool->size(), [cpools, handler](const auto entity) {
if((std::get<pool_type<Owned> *>(cpools)->has(entity) && ...)
&& (std::get<pool_type<Get> *>(cpools)->has(entity) && ...)
&& !(std::get<pool_type<Exclude> *>(cpools)->has(entity) || ...))
{
if constexpr(sizeof...(Owned) == 0) {
curr->set.construct(entity);
handler->set.construct(entity);
} else {
if(!(std::get<0>(cpools)->index(entity) < curr->owned)) {
const auto pos = curr->owned++;
if(!(std::get<0>(cpools)->index(entity) < handler->owned)) {
const auto pos = handler->owned++;
(std::get<pool_type<Owned> *>(cpools)->swap(std::get<pool_type<Owned> *>(cpools)->data()[pos], entity), ...);
}
}
@@ -1433,9 +1433,9 @@ public:
}
if constexpr(sizeof...(Owned) == 0) {
return { &curr->set, std::get<pool_type<Get> *>(cpools)... };
return { &handler->set, std::get<pool_type<Get> *>(cpools)... };
} else {
return { &std::get<0>(cpools)->super, &curr->owned, std::get<pool_type<Owned> *>(cpools)... , std::get<pool_type<Get> *>(cpools)... };
return { &std::get<0>(cpools)->super, &handler->owned, std::get<pool_type<Owned> *>(cpools)... , std::get<pool_type<Get> *>(cpools)... };
}
}
@@ -1506,9 +1506,9 @@ public:
*/
template<typename It>
entt::basic_runtime_view<Entity> runtime_view(It first, It last) const {
std::vector<const sparse_set<Entity> *> set(std::distance(first, last));
std::vector<const sparse_set<Entity> *> selected(std::distance(first, last));
std::transform(first, last, set.begin(), [this](const component ctype) {
std::transform(first, last, selected.begin(), [this](const component ctype) {
auto it = std::find_if(pools.begin(), pools.end(), [ctype = to_integer(ctype)](const auto &pdata) {
return pdata.pool && pdata.runtime_type == ctype;
});
@@ -1516,7 +1516,7 @@ public:
return it != pools.cend() && it->pool ? it->pool.get() : nullptr;
});
return { std::move(set) };
return { std::move(selected) };
}
/**
@@ -1785,8 +1785,8 @@ public:
*/
template<typename Type, typename... Args>
Type & ctx_or_set(Args &&... args) {
auto *type = try_ctx<Type>();
return type ? *type : set<Type>(std::forward<Args>(args)...);
auto *value = try_ctx<Type>();
return value ? *value : set<Type>(std::forward<Args>(args)...);
}
/**

View File

@@ -431,6 +431,11 @@ public:
* either `data` or `raw` gives no guarantees on the order, even though
* `sort` has been invoked.
*
* @warning
* Empty types are never instantiated. Therefore, only comparison function
* objects that require to return entities rather than components are
* accepted.
*
* @tparam Compare Type of comparison function object.
* @tparam Sort Type of sort function object.
* @tparam Args Types of arguments to forward to the sort function object.
@@ -673,6 +678,18 @@ public:
underlying_type::batch(first, last);
return begin();
}
/*! @copydoc storage::sort */
template<typename Compare, typename Sort = std_sort, typename... Args>
void sort(iterator_type first, iterator_type last, Compare compare, Sort algo = Sort{}, Args &&... args) {
ENTT_ASSERT(!(last < first));
ENTT_ASSERT(!(last > end()));
const auto from = underlying_type::begin() + std::distance(begin(), first);
const auto to = from + std::distance(first, last);
underlying_type::sort(from, to, std::move(compare), std::move(algo), std::forward<Args>(args)...);
}
};
/*! @copydoc basic_storage */

View File

@@ -85,11 +85,11 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> {
class iterator {
friend class basic_view<Entity, exclude_t<Exclude...>, Component...>;
iterator(underlying_iterator_type first, underlying_iterator_type last, unchecked_type other, filter_type exclude) ENTT_NOEXCEPT
iterator(underlying_iterator_type first, underlying_iterator_type last, unchecked_type other, filter_type ignore) ENTT_NOEXCEPT
: begin{first},
end{last},
unchecked{other},
filter{exclude}
filter{ignore}
{
if(begin != end && !valid()) {
++(*this);
@@ -143,9 +143,9 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> {
};
// we could use pool_type<Component> *..., but vs complains about it and refuses to compile for unknown reasons (likely a bug)
basic_view(storage<Entity, std::remove_const_t<Component>> *... component, storage<Entity, std::remove_const_t<Exclude>> *... exclude) ENTT_NOEXCEPT
basic_view(storage<Entity, std::remove_const_t<Component>> *... component, storage<Entity, std::remove_const_t<Exclude>> *... epool) ENTT_NOEXCEPT
: pools{component...},
filter{exclude...}
filter{epool...}
{}
const sparse_set<Entity> * candidate() const ENTT_NOEXCEPT {
@@ -304,8 +304,8 @@ public:
*/
iterator_type begin() const ENTT_NOEXCEPT {
const auto *view = candidate();
const filter_type exclude{std::get<pool_type<Exclude> *>(filter)...};
return iterator_type{view->begin(), view->end(), unchecked(view), exclude};
const filter_type ignore{std::get<pool_type<Exclude> *>(filter)...};
return iterator_type{view->begin(), view->end(), unchecked(view), ignore};
}
/**
@@ -325,8 +325,8 @@ public:
*/
iterator_type end() const ENTT_NOEXCEPT {
const auto *view = candidate();
const filter_type exclude{std::get<pool_type<Exclude> *>(filter)...};
return iterator_type{view->end(), view->end(), unchecked(view), exclude};
const filter_type ignore{std::get<pool_type<Exclude> *>(filter)...};
return iterator_type{view->end(), view->end(), unchecked(view), ignore};
}
/**
@@ -337,8 +337,8 @@ public:
*/
iterator_type find(const entity_type entt) const ENTT_NOEXCEPT {
const auto *view = candidate();
const filter_type exclude{std::get<pool_type<Exclude> *>(filter)...};
iterator_type it{view->find(entt), view->end(), unchecked(view), exclude};
const filter_type ignore{std::get<pool_type<Exclude> *>(filter)...};
iterator_type it{view->find(entt), view->end(), unchecked(view), ignore};
return (it != end() && *it == entt) ? it : end();
}

View File

@@ -196,15 +196,15 @@ template<typename Type, auto Candidate, typename Policy, std::size_t... Indexes>
meta_any invoke([[maybe_unused]] meta_handle handle, meta_any *args, std::index_sequence<Indexes...>) {
using helper_type = meta_function_helper_t<decltype(Candidate)>;
auto dispatch = [](auto *... args) {
auto dispatch = [](auto *... params) {
if constexpr(std::is_void_v<typename helper_type::return_type> || std::is_same_v<Policy, as_void_t>) {
std::invoke(Candidate, *args...);
std::invoke(Candidate, *params...);
return meta_any{std::in_place_type<void>};
} else if constexpr(std::is_same_v<Policy, as_alias_t>) {
return meta_any{std::ref(std::invoke(Candidate, *args...))};
return meta_any{std::ref(std::invoke(Candidate, *params...))};
} else {
static_assert(std::is_same_v<Policy, as_is_t>);
return meta_any{std::invoke(Candidate, *args...)};
return meta_any{std::invoke(Candidate, *params...)};
}
};
@@ -718,8 +718,8 @@ class extended_meta_factory: public meta_factory<Type> {
}
template<std::size_t Step = 0, typename Func, typename... Other>
void unroll(choice_t<0>, Func &&func, Other &&... other) {
unroll<Step>(choice<3>, std::forward<Func>(func)(), std::forward<Other>(other)...);
void unroll(choice_t<0>, Func &&invocable, Other &&... other) {
unroll<Step>(choice<3>, std::forward<Func>(invocable)(), std::forward<Other>(other)...);
}
template<std::size_t>
@@ -730,7 +730,7 @@ class extended_meta_factory: public meta_factory<Type> {
static auto property{std::make_tuple(std::forward<Key>(key), std::forward<Value>(value)...)};
static internal::meta_prop_node node{
*curr,
nullptr,
[]() -> meta_any {
return std::get<0>(property);
},
@@ -744,6 +744,7 @@ class extended_meta_factory: public meta_factory<Type> {
};
ENTT_ASSERT(!duplicate(node.key(), *curr));
node.next = *curr;
*curr = &node;
}

View File

@@ -209,23 +209,23 @@ struct meta_node<Type> {
static void reset() ENTT_NOEXCEPT {
auto * const node = resolve();
auto **curr = meta_node<>::global;
auto **it = meta_node<>::global;
while(*curr && *curr != node) {
curr = &(*curr)->next;
while(*it && *it != node) {
it = &(*it)->next;
}
if(*curr) {
*curr = (*curr)->next;
if(*it) {
*it = (*it)->next;
}
const auto unregister_all = y_combinator{
[](auto &&self, auto **node, auto... member) {
while(*node) {
auto *curr = *node;
(self(&(curr->*member)), ...);
*node = curr->next;
curr->next = nullptr;
[](auto &&self, auto **curr, auto... member) {
while(*curr) {
auto *prev = *curr;
(self(&(prev->*member)), ...);
*curr = prev->next;
prev->next = nullptr;
}
}
};
@@ -269,8 +269,8 @@ struct meta_node<Type> {
};
if constexpr(is_named_type_v<Type>) {
auto *candidate = internal::find_if([](auto *candidate) {
return candidate->identifier == named_type_traits_v<Type>;
auto *candidate = internal::find_if([](auto *curr) {
return curr->identifier == named_type_traits_v<Type>;
}, *meta_node<>::global);
return candidate ? candidate : &node;
@@ -1355,11 +1355,11 @@ inline bool operator!=(const meta_func &lhs, const meta_func &rhs) ENTT_NOEXCEPT
/*! @brief Opaque container for meta types. */
class meta_type {
template<typename... Args, std::size_t... Indexes>
auto ctor(std::index_sequence<Indexes...>, const internal::meta_type_node *node) const ENTT_NOEXCEPT {
auto ctor(std::index_sequence<Indexes...>) const ENTT_NOEXCEPT {
return internal::find_if([](auto *candidate) {
return candidate->size == sizeof...(Args) && ([](auto *from, auto *to) {
return (from == to) || internal::find_if<&internal::meta_type_node::base>([to](auto *node) { return node->type() == to; }, from)
|| internal::find_if<&internal::meta_type_node::conv>([to](auto *node) { return node->type() == to; }, from);
return (from == to) || internal::find_if<&internal::meta_type_node::base>([to](auto *curr) { return curr->type() == to; }, from)
|| internal::find_if<&internal::meta_type_node::conv>([to](auto *curr) { return curr->type() == to; }, from);
}(internal::meta_info<Args>::resolve(), candidate->arg(Indexes)) && ...);
}, node->ctor);
}
@@ -1583,7 +1583,7 @@ public:
*/
template<typename... Args>
meta_ctor ctor() const ENTT_NOEXCEPT {
return ctor<Args...>(std::index_sequence_for<Args...>{}, node);
return ctor<Args...>(std::index_sequence_for<Args...>{});
}
/**

View File

@@ -90,7 +90,7 @@ class dispatcher {
if constexpr(is_named_type_v<Event>) {
return named_type_traits_v<Event>;
} else {
return event_family::type<Event>;
return event_family::type<std::decay_t<Event>>;
}
}

View File

@@ -125,7 +125,7 @@ class emitter {
if constexpr(is_named_type_v<Event>) {
return named_type_traits_v<Event>;
} else {
return handler_family::type<Event>;
return handler_family::type<std::decay_t<Event>>;
}
}

View File

@@ -9,8 +9,8 @@ macro(SETUP_LIBRARY_TARGET LIB_TARGET)
set_target_properties(${LIB_TARGET} PROPERTIES CXX_EXTENSIONS OFF)
target_compile_definitions(${LIB_TARGET} PRIVATE $<TARGET_PROPERTY:EnTT,INTERFACE_COMPILE_DEFINITIONS>)
target_compile_features(${LIB_TARGET} PRIVATE $<TARGET_PROPERTY:EnTT,INTERFACE_COMPILE_FEATURES>)
target_compile_options(${LIB_TARGET} PRIVATE $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-pedantic -Wall>)
target_compile_options(${LIB_TARGET} PRIVATE $<$<CXX_COMPILER_ID:MSVC>:/EHsc>)
target_compile_options(${LIB_TARGET} PRIVATE $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-pedantic -Wall -Wshadow>)
target_compile_options(${LIB_TARGET} PRIVATE $<$<CXX_COMPILER_ID:MSVC>:/EHsc /W2>)
endmacro()
add_library(odr OBJECT odr.cpp)
@@ -22,8 +22,8 @@ macro(SETUP_AND_ADD_TEST TEST_NAME TEST_SOURCE)
target_link_libraries(${TEST_NAME} PRIVATE EnTT GTest::Main Threads::Threads)
target_compile_definitions(${TEST_NAME} PRIVATE $<TARGET_PROPERTY:EnTT,INTERFACE_COMPILE_DEFINITIONS>)
target_compile_features(${TEST_NAME} PRIVATE $<TARGET_PROPERTY:EnTT,INTERFACE_COMPILE_FEATURES>)
target_compile_options(${TEST_NAME} PRIVATE $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-pedantic -Wall>)
target_compile_options(${TEST_NAME} PRIVATE $<$<CXX_COMPILER_ID:MSVC>:/EHsc>)
target_compile_options(${TEST_NAME} PRIVATE $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-pedantic -Wall -Wshadow>)
target_compile_options(${TEST_NAME} PRIVATE $<$<CXX_COMPILER_ID:MSVC>:/EHsc /W2>)
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})
endmacro()

View File

@@ -16,7 +16,7 @@ TEST(Family, Functionalities) {
}
TEST(Family, Uniqueness) {
ASSERT_EQ(a_family::type<int>, a_family::type<int &>);
ASSERT_EQ(a_family::type<int>, a_family::type<int &&>);
ASSERT_EQ(a_family::type<int>, a_family::type<const int &>);
ASSERT_NE(a_family::type<int>, a_family::type<int &>);
ASSERT_NE(a_family::type<int>, a_family::type<int &&>);
ASSERT_NE(a_family::type<int>, a_family::type<const int &>);
}

View File

@@ -825,6 +825,22 @@ TEST(Registry, SortMulti) {
}
}
TEST(Registry, SortEmpty) {
entt::registry registry;
registry.assign<empty_type>(registry.create());
registry.assign<empty_type>(registry.create());
registry.assign<empty_type>(registry.create());
ASSERT_LT(registry.data<empty_type>()[0], registry.data<empty_type>()[1]);
ASSERT_LT(registry.data<empty_type>()[1], registry.data<empty_type>()[2]);
registry.sort<empty_type>(std::less<entt::entity>{});
ASSERT_GT(registry.data<empty_type>()[0], registry.data<empty_type>()[1]);
ASSERT_GT(registry.data<empty_type>()[1], registry.data<empty_type>()[2]);
}
TEST(Registry, ComponentsWithTypesFromStandardTemplateLibrary) {
// see #37 - the test shouldn't crash, that's all
entt::registry registry;

View File

@@ -255,6 +255,11 @@ struct Meta: ::testing::Test {
static void SetUpAfterUnregistration() {
entt::meta<double>().conv<float>();
entt::meta<props>()
.data<props::prop_bool>("prop_bool"_hs)
.prop(props::prop_int, 0)
.prop(props::prop_value, 3);
entt::meta<derived_type>()
.type("my_type"_hs)
.prop(props::prop_bool, false)
@@ -2094,3 +2099,18 @@ TEST_F(Meta, Reset) {
ASSERT_TRUE(entt::resolve("your_type"_hs).func("a_member_function"_hs));
ASSERT_FALSE(entt::resolve("your_type"_hs).func("another_member_function"_hs));
}
TEST_F(Meta, ReRegistrationAfterReset) {
ASSERT_TRUE(entt::resolve<props>().data("prop_bool"_hs).prop(props::prop_int));
ASSERT_TRUE(entt::resolve<props>().data("prop_bool"_hs).prop(props::prop_value));
entt::meta<double>().reset();
entt::meta<props>().reset();
entt::meta<derived_type>().reset();
entt::meta<another_abstract_type>().reset();
Meta::SetUpAfterUnregistration();
ASSERT_TRUE(entt::resolve<props>().data("prop_bool"_hs).prop(props::prop_int));
ASSERT_TRUE(entt::resolve<props>().data("prop_bool"_hs).prop(props::prop_value));
}

View File

@@ -270,16 +270,14 @@ const duk_function_list_entry js_duktape_registry_methods[] = {
};
void export_types(duk_context *context, entt::registry &registry) {
auto export_type = [](auto *ctx, auto &reg, auto idx, auto type, const auto *name) {
auto export_type = [idx = duk_push_object(context)](auto *ctx, auto &reg, auto type, const auto *name) {
duk_push_string(ctx, name);
duk_push_uint(ctx, to_integer(reg.template type<typename decltype(type)::type>()));
duk_def_prop(ctx, idx, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_CLEAR_WRITABLE);
};
auto idx = duk_push_object(context);
export_type(context, registry, idx, tag<position>{}, "position");
export_type(context, registry, idx, tag<renderable>{}, "renderable");
export_type(context, registry, tag<position>{}, "position");
export_type(context, registry, tag<renderable>{}, "renderable");
duk_put_global_string(context, "Types");
}