Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce3a0157cb | ||
|
|
a146b06e4b | ||
|
|
dc78a3e56d | ||
|
|
86c524dade | ||
|
|
6889edcfc4 | ||
|
|
3cd5934bad | ||
|
|
064104f23a | ||
|
|
e80b1c264c |
@@ -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
2
TODO
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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++;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -69,45 +69,45 @@ class basic_registry {
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
decltype(auto) assign(basic_registry ®istry, 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 ®istry, 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, ®istry, 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 ®istry, 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 ®istry, 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 ®istry, 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)...);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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...>{});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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>>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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 &>);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -270,16 +270,14 @@ const duk_function_list_entry js_duktape_registry_methods[] = {
|
||||
};
|
||||
|
||||
void export_types(duk_context *context, entt::registry ®istry) {
|
||||
auto export_type = [](auto *ctx, auto ®, auto idx, auto type, const auto *name) {
|
||||
auto export_type = [idx = duk_push_object(context)](auto *ctx, auto ®, 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");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user