Skip to content

Commit

Permalink
wip: nested groups
Browse files Browse the repository at this point in the history
  • Loading branch information
skypjack committed Sep 20, 2019
1 parent b043b48 commit fe173da
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 233 deletions.
1 change: 1 addition & 0 deletions TODO
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ TODO
* range based registry::remove and some others?
* nested groups: AB/ABC/ABCD/... (hints: sort, check functions)
- sink::before and ordered calls
- doc, test
* ::size_type - c'mon
96 changes: 53 additions & 43 deletions src/entt/entity/group.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,21 +63,20 @@ class basic_group;
*
* @tparam Entity A valid entity type (see entt_traits for more details).
* @tparam Exclude Types of components used to filter the group.
* @tparam Get Type of component observed by the group.
* @tparam Other Other types of components observed by the group.
* @tparam Get Type of components observed by the group.
*/
template<typename Entity, typename... Exclude, typename Get, typename... Other>
class basic_group<Entity, exclude_t<Exclude...>, get_t<Get, Other...>> {
template<typename Entity, typename... Exclude, typename... Get>
class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>> {
/*! @brief A registry is allowed to create groups. */
friend class basic_registry<Entity>;

template<typename Component>
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, storage<Entity, std::remove_const_t<Other>> *... other) ENTT_NOEXCEPT
basic_group(sparse_set<Entity> *ref, storage<Entity, std::remove_const_t<Get>> *... get) ENTT_NOEXCEPT
: handler{ref},
pools{get, other...}
pools{get...}
{}

template<typename Func, typename... Weak>
Expand All @@ -93,9 +92,9 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get, Other...>> {

public:
/*! @brief Underlying entity identifier. */
using entity_type = typename sparse_set<Entity>::entity_type;
using entity_type = Entity;
/*! @brief Unsigned integer type. */
using size_type = typename sparse_set<Entity>::size_type;
using size_type = std::size_t;
/*! @brief Input iterator type. */
using iterator_type = typename sparse_set<Entity>::iterator_type;

Expand Down Expand Up @@ -306,8 +305,8 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get, Other...>> {
* forms:
*
* @code{.cpp}
* void(const entity_type, Get &, Other &...);
* void(Get &, Other &...);
* void(const entity_type, Get &...);
* void(Get &...);
* @endcode
*
* @note
Expand All @@ -320,7 +319,7 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get, Other...>> {
*/
template<typename Func>
void each(Func func) const {
traverse(std::move(func), type_list<Get, Other...>{});
traverse(std::move(func), type_list<Get...>{});
}

/**
Expand All @@ -345,9 +344,8 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get, Other...>> {
*/
template<typename Func>
void less(Func func) const {
using get_type_list = std::conditional_t<std::is_empty_v<Get>, type_list<>, type_list<Get>>;
using other_type_list = type_list_cat_t<std::conditional_t<std::is_empty_v<Other>, type_list<>, type_list<Other>>...>;
traverse(std::move(func), type_list_cat_t<get_type_list, other_type_list>{});
using get_type_list = type_list_cat_t<std::conditional_t<std::is_empty_v<Get>, type_list<>, type_list<Get>>...>;
traverse(std::move(func), get_type_list{});
}

/**
Expand Down Expand Up @@ -430,7 +428,7 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get, Other...>> {

private:
sparse_set<entity_type> *handler;
const std::tuple<pool_type<Get> *, pool_type<Other> *...> pools;
const std::tuple<pool_type<Get> *...> pools;
};


Expand Down Expand Up @@ -479,11 +477,10 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get, Other...>> {
* @tparam Entity A valid entity type (see entt_traits for more details).
* @tparam Exclude Types of components used to filter the group.
* @tparam Get Types of components observed by the group.
* @tparam Owned Type of component owned by the group.
* @tparam Other Other types of components owned by the group.
* @tparam Owned Types of components owned by the group.
*/
template<typename Entity, typename... Exclude, typename... Get, typename Owned, typename... Other>
class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned, Other...> {
template<typename Entity, typename... Exclude, typename... Get, typename... Owned>
class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...> {
/*! @brief A registry is allowed to create groups. */
friend class basic_registry<Entity>;

Expand All @@ -494,15 +491,16 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned, Other...>
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 typename basic_registry<Entity>::size_type *sz, storage<Entity, std::remove_const_t<Owned>> *owned, storage<Entity, std::remove_const_t<Other>> *... other, storage<Entity, std::remove_const_t<Get>> *... get) ENTT_NOEXCEPT
: length{sz},
pools{owned, other..., get...}
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...},
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 data = std::get<pool_type<Owned> *>(pools)->sparse_set<entity_type>::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>({}))...>) {
Expand All @@ -521,9 +519,9 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned, Other...>

public:
/*! @brief Underlying entity identifier. */
using entity_type = typename sparse_set<Entity>::entity_type;
using entity_type = Entity;
/*! @brief Unsigned integer type. */
using size_type = typename sparse_set<Entity>::size_type;
using size_type = std::size_t;
/*! @brief Input iterator type. */
using iterator_type = typename sparse_set<Entity>::iterator_type;

Expand Down Expand Up @@ -618,7 +616,7 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned, Other...>
* @return A pointer to the array of entities.
*/
const entity_type * data() const ENTT_NOEXCEPT {
return std::get<pool_type<Owned> *>(pools)->data();
return std::get<0>(pools)->data();
}

/**
Expand All @@ -636,7 +634,7 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned, Other...>
* @return An iterator to the first entity that has the given components.
*/
iterator_type begin() const ENTT_NOEXCEPT {
return std::get<pool_type<Owned> *>(pools)->sparse_set<entity_type>::end() - *length;
return std::get<0>(pools)->sparse_set<entity_type>::end() - *length;
}

/**
Expand All @@ -655,7 +653,7 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned, Other...>
* given components.
*/
iterator_type end() const ENTT_NOEXCEPT {
return std::get<pool_type<Owned> *>(pools)->sparse_set<entity_type>::end();
return std::get<0>(pools)->sparse_set<entity_type>::end();
}

/**
Expand All @@ -665,7 +663,7 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned, Other...>
* iterator otherwise.
*/
iterator_type find(const entity_type entt) const ENTT_NOEXCEPT {
const auto it = std::get<pool_type<Owned> *>(pools)->find(entt);
const auto it = std::get<0>(pools)->find(entt);
return it != end() && it >= begin() && *it == entt ? it : end();
}

Expand Down Expand Up @@ -726,8 +724,8 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned, Other...>
* forms:
*
* @code{.cpp}
* void(const entity_type, Owned &, Other &..., Get &...);
* void(Owned &, Other &..., Get &...);
* void(const entity_type, Owned &..., Get &...);
* void(Owned &..., Get &...);
* @endcode
*
* @note
Expand All @@ -740,7 +738,7 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned, Other...>
*/
template<typename Func>
void each(Func func) const {
traverse(std::move(func), type_list<Owned, Other...>{}, type_list<Get...>{});
traverse(std::move(func), type_list<Owned...>{}, type_list<Get...>{});
}

/**
Expand All @@ -765,10 +763,18 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned, Other...>
*/
template<typename Func>
void less(Func func) const {
using owned_type_list = std::conditional_t<std::is_empty_v<Owned>, type_list<>, type_list<Owned>>;
using other_type_list = type_list_cat_t<std::conditional_t<std::is_empty_v<Other>, type_list<>, type_list<Other>>...>;
using owned_type_list = type_list_cat_t<std::conditional_t<std::is_empty_v<Owned>, type_list<>, type_list<Owned>>...>;
using get_type_list = type_list_cat_t<std::conditional_t<std::is_empty_v<Get>, type_list<>, type_list<Get>>...>;
traverse(std::move(func), type_list_cat_t<owned_type_list, other_type_list>{}, get_type_list{});
traverse(std::move(func), owned_type_list{}, get_type_list{});
}

/**
* @brief Checks whether the group can be sorted.
* @return True if the group can be sorted, false otherwise.
*/
bool sortable() const ENTT_NOEXCEPT {
constexpr auto size = sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude);
return *super == size;
}

/**
Expand Down Expand Up @@ -815,7 +821,8 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned, Other...>
*/
template<typename... Component, typename Compare, typename Sort = std_sort, typename... Args>
void sort(Compare compare, Sort algo = Sort{}, Args &&... args) {
auto *cpool = std::get<pool_type<Owned> *>(pools);
ENTT_ASSERT(sortable());
auto *cpool = std::get<0>(pools);

if constexpr(sizeof...(Component) == 0) {
static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>);
Expand All @@ -830,16 +837,19 @@ class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned, Other...>
}, std::move(algo), std::forward<Args>(args)...);
}

for(auto next = *length; next; --next) {
const auto pos = next - 1;
[[maybe_unused]] const auto entt = cpool->data()[pos];
(std::get<pool_type<Other> *>(pools)->swap(std::get<pool_type<Other> *>(pools)->data()[pos], entt), ...);
}
[](std::size_t length, auto *cpool, auto *... other) {
for(auto next = length; next; --next) {
const auto pos = next - 1;
[[maybe_unused]] const auto entt = cpool->data()[pos];
(other->swap(other->data()[pos], entt), ...);
}
}(*length, std::get<pool_type<Owned> *>(pools)...);
}

private:
const typename basic_registry<Entity>::size_type *length;
const std::tuple<pool_type<Owned> *, pool_type<Other> *..., pool_type<Get> *...> pools;
const std::tuple<pool_type<Owned> *..., pool_type<Get> *...> pools;
const size_type *length;
const size_type *super;
};


Expand Down
48 changes: 21 additions & 27 deletions src/entt/entity/registry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class basic_registry {

template<typename Component>
struct pool_handler: storage<Entity, Component> {
std::size_t *owned;
std::size_t super{};

pool_handler() ENTT_NOEXCEPT = default;

Expand Down Expand Up @@ -323,7 +323,7 @@ class basic_registry {
/*! @brief Underlying version type. */
using version_type = typename traits_type::version_type;
/*! @brief Unsigned integer type. */
using size_type = typename sparse_set<Entity>::size_type;
using size_type = std::size_t;

/*! @brief Default constructor. */
basic_registry() ENTT_NOEXCEPT = default;
Expand Down Expand Up @@ -1088,12 +1088,9 @@ class basic_registry {
*/
template<typename Component, typename Compare, typename Sort = std_sort, typename... Args>
void sort(Compare compare, Sort algo = Sort{}, Args &&... args) {
if(auto *cpool = assure<Component>(); cpool->owned) {
const auto last = cpool->end() - *cpool->owned;
cpool->sort(cpool->begin(), last, std::move(compare), std::move(algo), std::forward<Args>(args)...);
} else {
cpool->sort(cpool->begin(), cpool->end(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
}
auto *cpool = assure<Component>();
ENTT_ASSERT(!cpool->super);
cpool->sort(cpool->begin(), cpool->end(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
}

/**
Expand Down Expand Up @@ -1133,8 +1130,9 @@ class basic_registry {
*/
template<typename To, typename From>
void sort() {
ENTT_ASSERT(!owned<To>());
assure<To>()->respect(*assure<From>());
auto *cpool = assure<To>();
ENTT_ASSERT(!cpool->super);
cpool->respect(*assure<From>());
}

/**
Expand Down Expand Up @@ -1322,17 +1320,6 @@ class basic_registry {
return const_cast<basic_registry *>(this)->view<Component...>(exclude<Exclude...>);
}

/**
* @brief Checks whether a given component belongs to a group.
* @tparam Component Type of component in which one is interested.
* @return True if the component belongs to a group, false otherwise.
*/
template<typename Component>
bool owned() const ENTT_NOEXCEPT {
const auto *cpool = pool<Component>();
return cpool && cpool->owned;
}

/**
* @brief Returns a group for the given components.
*
Expand Down Expand Up @@ -1366,6 +1353,8 @@ class basic_registry {
static_assert(sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude) > 1);

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 std::size_t extent[3]{sizeof...(Owned), sizeof...(Get), sizeof...(Exclude)};
handler_type *curr = nullptr;
Expand All @@ -1381,6 +1370,11 @@ class basic_registry {
}

if(!curr) {
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)));
}));

groups.push_back(group_data{
{ sizeof...(Owned), sizeof...(Get), sizeof...(Exclude) },
decltype(group_data::group){new handler_type{cpools}, [](void *gptr) { delete static_cast<handler_type *>(gptr); }},
Expand All @@ -1391,9 +1385,7 @@ class basic_registry {

curr = static_cast<handler_type *>(groups.back().group.get());

ENTT_ASSERT((!std::get<pool_type<Owned> *>(cpools)->owned && ...));
((std::get<pool_type<Owned> *>(cpools)->owned = &curr->owned), ...);

((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().template connect<&handler_type::template maybe_valid_if<Owned>>(*curr), ...);
(std::get<pool_type<Owned> *>(cpools)->on_destroy().template connect<&handler_type::discard_if>(*curr), ...);

Expand All @@ -1419,8 +1411,10 @@ class basic_registry {
if constexpr(sizeof...(Owned) == 0) {
curr->set.construct(entity);
} else {
const auto pos = curr->owned++;
(std::get<pool_type<Owned> *>(cpools)->swap(std::get<pool_type<Owned> *>(cpools)->data()[pos], entity), ...);
if(!(std::get<0>(cpools)->index(entity) < curr->owned)) {
const auto pos = curr->owned++;
(std::get<pool_type<Owned> *>(cpools)->swap(std::get<pool_type<Owned> *>(cpools)->data()[pos], entity), ...);
}
}
}
});
Expand All @@ -1429,7 +1423,7 @@ class basic_registry {
if constexpr(sizeof...(Owned) == 0) {
return { &curr->set, std::get<pool_type<Get> *>(cpools)... };
} else {
return { &curr->owned, std::get<pool_type<Owned> *>(cpools)... , std::get<pool_type<Get> *>(cpools)... };
return { &std::get<0>(cpools)->super, &curr->owned, std::get<pool_type<Owned> *>(cpools)... , std::get<pool_type<Get> *>(cpools)... };
}
}

Expand Down
Loading

0 comments on commit fe173da

Please sign in to comment.