sparse_set: turn head into a size (position/length)
This commit is contained in:
@@ -132,11 +132,6 @@ template<typename Container>
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
auto policy_to_head(const Type mask, const deletion_policy mode) noexcept {
|
||||
return mask * (mode != deletion_policy::swap_only);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
|
||||
@@ -167,6 +162,12 @@ class basic_sparse_set {
|
||||
using packed_container_type = std::vector<Entity, Allocator>;
|
||||
using underlying_type = typename entt_traits<Entity>::entity_type;
|
||||
|
||||
static constexpr auto max_size = static_cast<std::size_t>(typename entt_traits<Entity>::to_entity(null));
|
||||
|
||||
[[nodiscard]] auto policy_to_head() const noexcept {
|
||||
return static_cast<size_type>(max_size * (mode != deletion_policy::swap_only));
|
||||
}
|
||||
|
||||
[[nodiscard]] auto sparse_ptr(const Entity entt) const {
|
||||
const auto pos = static_cast<size_type>(traits_type::to_entity(entt));
|
||||
const auto page = pos / traits_type::page_size;
|
||||
@@ -229,7 +230,7 @@ private:
|
||||
}
|
||||
|
||||
virtual void swap_or_move([[maybe_unused]] const std::size_t lhs, [[maybe_unused]] const std::size_t rhs) {
|
||||
ENTT_ASSERT((mode != deletion_policy::swap_only) || ((lhs < static_cast<const std::size_t>(head)) == (rhs < static_cast<const std::size_t>(head))), "Cross swapping is not supported");
|
||||
ENTT_ASSERT((mode != deletion_policy::swap_only) || ((lhs < head) == (rhs < head)), "Cross swapping is not supported");
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -242,9 +243,9 @@ protected:
|
||||
*/
|
||||
void swap_only(const basic_iterator it) {
|
||||
ENTT_ASSERT(mode == deletion_policy::swap_only, "Deletion policy mismatch");
|
||||
const auto pos = static_cast<underlying_type>(index(*it));
|
||||
const auto pos = index(*it);
|
||||
bump(traits_type::next(*it));
|
||||
swap_at(pos, static_cast<size_type>(head -= (pos < head)));
|
||||
swap_at(pos, head -= (pos < head));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -270,8 +271,8 @@ protected:
|
||||
*/
|
||||
void in_place_pop(const basic_iterator it) {
|
||||
ENTT_ASSERT(mode == deletion_policy::in_place, "Deletion policy mismatch");
|
||||
const auto entt = traits_type::to_entity(std::exchange(sparse_ref(*it), null));
|
||||
packed[static_cast<size_type>(entt)] = traits_type::combine(std::exchange(head, entt), tombstone);
|
||||
const auto pos = static_cast<size_type>(traits_type::to_entity(std::exchange(sparse_ref(*it), null)));
|
||||
packed[pos] = traits_type::combine(static_cast<underlying_type>(std::exchange(head, pos)), tombstone);
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -304,7 +305,7 @@ protected:
|
||||
virtual void pop_all() {
|
||||
switch(mode) {
|
||||
case deletion_policy::in_place:
|
||||
if(head != traits_type::to_entity(null)) {
|
||||
if(head != max_size) {
|
||||
for(auto first = begin(); !(first.index() < 0); ++first) {
|
||||
if(*first != tombstone) {
|
||||
sparse_ref(*first) = null;
|
||||
@@ -321,7 +322,7 @@ protected:
|
||||
break;
|
||||
}
|
||||
|
||||
head = internal::policy_to_head(traits_type::entity_mask, mode);
|
||||
head = policy_to_head();
|
||||
packed.clear();
|
||||
}
|
||||
|
||||
@@ -338,11 +339,11 @@ protected:
|
||||
|
||||
switch(mode) {
|
||||
case deletion_policy::in_place:
|
||||
if(head != traits_type::to_entity(null) && !force_back) {
|
||||
pos = static_cast<size_type>(head);
|
||||
if(head != max_size && !force_back) {
|
||||
pos = head;
|
||||
ENTT_ASSERT(elem == null, "Slot not available");
|
||||
elem = traits_type::combine(head, traits_type::to_integral(entt));
|
||||
head = traits_type::to_entity(std::exchange(packed[pos], entt));
|
||||
elem = traits_type::combine(static_cast<underlying_type>(head), traits_type::to_integral(entt));
|
||||
head = static_cast<size_type>(traits_type::to_entity(std::exchange(packed[pos], entt)));
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
@@ -356,11 +357,11 @@ protected:
|
||||
packed.push_back(entt);
|
||||
elem = traits_type::combine(static_cast<underlying_type>(packed.size() - 1u), traits_type::to_integral(entt));
|
||||
} else {
|
||||
ENTT_ASSERT(!(traits_type::to_entity(elem) < head), "Slot not available");
|
||||
ENTT_ASSERT(!(static_cast<size_type>(traits_type::to_entity(elem)) < head), "Slot not available");
|
||||
bump(entt);
|
||||
}
|
||||
|
||||
pos = static_cast<size_type>(head++);
|
||||
pos = head++;
|
||||
swap_at(static_cast<size_type>(traits_type::to_entity(elem)), pos);
|
||||
break;
|
||||
}
|
||||
@@ -421,7 +422,7 @@ public:
|
||||
packed{allocator},
|
||||
info{&elem},
|
||||
mode{pol},
|
||||
head{internal::policy_to_head(traits_type::entity_mask, mode)} {
|
||||
head{policy_to_head()} {
|
||||
ENTT_ASSERT(traits_type::version_mask || mode != deletion_policy::in_place, "Policy does not support zero-sized versions");
|
||||
}
|
||||
|
||||
@@ -434,7 +435,7 @@ public:
|
||||
packed{std::move(other.packed)},
|
||||
info{other.info},
|
||||
mode{other.mode},
|
||||
head{std::exchange(other.head, internal::policy_to_head(traits_type::entity_mask, mode))} {}
|
||||
head{std::exchange(other.head, policy_to_head())} {}
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended move constructor.
|
||||
@@ -446,7 +447,7 @@ public:
|
||||
packed{std::move(other.packed), allocator},
|
||||
info{other.info},
|
||||
mode{other.mode},
|
||||
head{std::exchange(other.head, internal::policy_to_head(traits_type::entity_mask, mode))} {
|
||||
head{std::exchange(other.head, policy_to_head())} {
|
||||
ENTT_ASSERT(alloc_traits::is_always_equal::value || packed.get_allocator() == other.packed.get_allocator(), "Copying a sparse set is not allowed");
|
||||
}
|
||||
|
||||
@@ -468,7 +469,7 @@ public:
|
||||
packed = std::move(other.packed);
|
||||
info = other.info;
|
||||
mode = other.mode;
|
||||
head = std::exchange(other.head, internal::policy_to_head(traits_type::entity_mask, mode));
|
||||
head = std::exchange(other.head, policy_to_head());
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -506,7 +507,7 @@ public:
|
||||
* @return The head of the free list.
|
||||
*/
|
||||
[[nodiscard]] size_type free_list() const noexcept {
|
||||
return static_cast<size_type>(head);
|
||||
return head;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -515,7 +516,7 @@ public:
|
||||
*/
|
||||
void free_list(const size_type len) noexcept {
|
||||
ENTT_ASSERT((mode == deletion_policy::swap_only) && !(len > packed.size()), "Invalid value");
|
||||
head = static_cast<underlying_type>(len);
|
||||
head = len;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -585,7 +586,7 @@ public:
|
||||
* @return True if the sparse set is fully packed, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool contiguous() const noexcept {
|
||||
return (mode != deletion_policy::in_place) || (head == traits_type::to_entity(null));
|
||||
return (mode != deletion_policy::in_place) || (head == max_size);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -916,11 +917,12 @@ public:
|
||||
void compact() {
|
||||
if(mode == deletion_policy::in_place) {
|
||||
size_type from = packed.size();
|
||||
for(; from && packed[from - 1u] == tombstone; --from) {}
|
||||
underlying_type pos = std::exchange(head, traits_type::entity_mask);
|
||||
size_type pos = std::exchange(head, max_size);
|
||||
|
||||
while(pos != traits_type::to_entity(null)) {
|
||||
if(const auto to = static_cast<size_type>(std::exchange(pos, traits_type::to_entity(packed[pos]))); to < from) {
|
||||
for(; from && packed[from - 1u] == tombstone; --from) {}
|
||||
|
||||
while(pos != max_size) {
|
||||
if(const auto to = std::exchange(pos, static_cast<size_type>(traits_type::to_entity(packed[pos]))); to < from) {
|
||||
--from;
|
||||
swap_or_move(from, to);
|
||||
|
||||
@@ -990,7 +992,7 @@ public:
|
||||
*/
|
||||
template<typename Compare, typename Sort = std_sort, typename... Args>
|
||||
void sort_n(const size_type length, Compare compare, Sort algo = Sort{}, Args &&...args) {
|
||||
ENTT_ASSERT((mode != deletion_policy::in_place) || (head == traits_type::to_entity(null)), "Sorting with tombstones not allowed");
|
||||
ENTT_ASSERT((mode != deletion_policy::in_place) || (head == max_size), "Sorting with tombstones not allowed");
|
||||
ENTT_ASSERT(!(length > packed.size()), "Length exceeds the number of elements");
|
||||
|
||||
algo(packed.rend() - length, packed.rend(), std::move(compare), std::forward<Args>(args)...);
|
||||
@@ -1043,7 +1045,7 @@ public:
|
||||
*/
|
||||
template<typename It>
|
||||
iterator sort_as(It first, It last) {
|
||||
ENTT_ASSERT((mode != deletion_policy::in_place) || (head == traits_type::to_entity(null)), "Sorting with tombstones not allowed");
|
||||
ENTT_ASSERT((mode != deletion_policy::in_place) || (head == max_size), "Sorting with tombstones not allowed");
|
||||
auto it = begin(0);
|
||||
|
||||
for(const auto other = end(0); (it != other) && (first != last); ++first) {
|
||||
@@ -1065,7 +1067,7 @@ public:
|
||||
pop_all();
|
||||
// sanity check to avoid subtle issues due to storage classes
|
||||
ENTT_ASSERT((compact(), size()) == 0u, "Non-empty set");
|
||||
head = internal::policy_to_head(traits_type::entity_mask, mode);
|
||||
head = policy_to_head();
|
||||
packed.clear();
|
||||
}
|
||||
|
||||
@@ -1085,7 +1087,7 @@ private:
|
||||
packed_container_type packed;
|
||||
const type_info *info;
|
||||
deletion_policy mode;
|
||||
underlying_type head;
|
||||
size_type head;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
Reference in New Issue
Block a user