|
@@ -27,63 +27,11 @@ namespace entt {
|
|
|
|
|
|
|
|
namespace internal {
|
|
namespace internal {
|
|
|
|
|
|
|
|
-template<typename Type, typename Allocator>
|
|
|
|
|
-struct dense_set_node final: Allocator {
|
|
|
|
|
- using allocator_type = Allocator;
|
|
|
|
|
-
|
|
|
|
|
- template<typename... Args>
|
|
|
|
|
- dense_set_node(const std::size_t pos, Args &&...args)
|
|
|
|
|
- : dense_set_node{std::allocator_arg, Allocator{}, pos, std::forward<Args>(args)...} {
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- template<typename... Args>
|
|
|
|
|
- dense_set_node(std::allocator_arg_t, const allocator_type &alloc, const std::size_t pos, Args &&...args)
|
|
|
|
|
- : Allocator{alloc},
|
|
|
|
|
- next{pos} {
|
|
|
|
|
- std::allocator_traits<allocator_type>::construct(*this, reinterpret_cast<Type *>(&instance), std::forward<Args>(args)...);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- dense_set_node(const dense_set_node &other)
|
|
|
|
|
- : dense_set_node{std::allocator_arg, Allocator{}, other} {
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- dense_set_node(std::allocator_arg_t, const allocator_type &alloc, const dense_set_node &other)
|
|
|
|
|
- : Allocator{alloc},
|
|
|
|
|
- next{other.next} {
|
|
|
|
|
- std::allocator_traits<allocator_type>::construct(*this, reinterpret_cast<Type *>(&instance), other.element());
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- dense_set_node(dense_set_node &&other)
|
|
|
|
|
- : dense_set_node{std::allocator_arg, Allocator{}, std::move(other)} {
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- dense_set_node(std::allocator_arg_t, const allocator_type &alloc, dense_set_node &&other)
|
|
|
|
|
- : Allocator{alloc},
|
|
|
|
|
- next{other.next} {
|
|
|
|
|
- std::allocator_traits<allocator_type>::construct(*this, reinterpret_cast<Type *>(&instance), std::move(other.element()));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- ~dense_set_node() {
|
|
|
|
|
- std::destroy_at(reinterpret_cast<const Type *>(&instance));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- const Type &element() const ENTT_NOEXCEPT {
|
|
|
|
|
- return *reinterpret_cast<const Type *>(&instance);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- Type &element() ENTT_NOEXCEPT {
|
|
|
|
|
- return *reinterpret_cast<Type *>(&instance);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- std::size_t next;
|
|
|
|
|
- std::aligned_storage_t<sizeof(Type)> instance;
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
template<typename It>
|
|
template<typename It>
|
|
|
class dense_set_iterator final {
|
|
class dense_set_iterator final {
|
|
|
friend dense_set_iterator<const std::remove_pointer_t<It> *>;
|
|
friend dense_set_iterator<const std::remove_pointer_t<It> *>;
|
|
|
|
|
|
|
|
- using iterator_traits = std::iterator_traits<decltype(std::addressof(std::as_const(std::declval<It>()->element())))>;
|
|
|
|
|
|
|
+ using iterator_traits = std::iterator_traits<decltype(std::addressof(std::as_const(std::declval<It>()->second)))>;
|
|
|
|
|
|
|
|
public:
|
|
public:
|
|
|
using value_type = typename iterator_traits::value_type;
|
|
using value_type = typename iterator_traits::value_type;
|
|
@@ -138,11 +86,11 @@ public:
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]] reference operator[](const difference_type value) const ENTT_NOEXCEPT {
|
|
[[nodiscard]] reference operator[](const difference_type value) const ENTT_NOEXCEPT {
|
|
|
- return it[value].element();
|
|
|
|
|
|
|
+ return it[value].second;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
|
|
[[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
|
|
|
- return std::addressof(it->element());
|
|
|
|
|
|
|
+ return std::addressof(it->second);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
|
|
[[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
|
|
@@ -201,7 +149,7 @@ template<typename It>
|
|
|
class dense_set_local_iterator final {
|
|
class dense_set_local_iterator final {
|
|
|
friend dense_set_local_iterator<const std::remove_pointer_t<It> *>;
|
|
friend dense_set_local_iterator<const std::remove_pointer_t<It> *>;
|
|
|
|
|
|
|
|
- using iterator_traits = std::iterator_traits<decltype(std::addressof(std::as_const(std::declval<It>()->element())))>;
|
|
|
|
|
|
|
+ using iterator_traits = std::iterator_traits<decltype(std::addressof(std::as_const(std::declval<It>()->second)))>;
|
|
|
|
|
|
|
|
public:
|
|
public:
|
|
|
using value_type = typename iterator_traits::value_type;
|
|
using value_type = typename iterator_traits::value_type;
|
|
@@ -222,7 +170,7 @@ public:
|
|
|
offset{other.offset} {}
|
|
offset{other.offset} {}
|
|
|
|
|
|
|
|
dense_set_local_iterator &operator++() ENTT_NOEXCEPT {
|
|
dense_set_local_iterator &operator++() ENTT_NOEXCEPT {
|
|
|
- return offset = it[offset].next, *this;
|
|
|
|
|
|
|
+ return offset = it[offset].first, *this;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
dense_set_local_iterator operator++(int) ENTT_NOEXCEPT {
|
|
dense_set_local_iterator operator++(int) ENTT_NOEXCEPT {
|
|
@@ -231,7 +179,7 @@ public:
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
|
|
[[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
|
|
|
- return std::addressof(it[offset].element());
|
|
|
|
|
|
|
+ return std::addressof(it[offset].second);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
|
|
[[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
|
|
@@ -284,7 +232,7 @@ class dense_set {
|
|
|
using alloc_traits = std::allocator_traits<Allocator>;
|
|
using alloc_traits = std::allocator_traits<Allocator>;
|
|
|
static_assert(std::is_same_v<typename alloc_traits::value_type, Type>);
|
|
static_assert(std::is_same_v<typename alloc_traits::value_type, Type>);
|
|
|
|
|
|
|
|
- using node_type = internal::dense_set_node<Type, Allocator>;
|
|
|
|
|
|
|
+ using node_type = std::pair<std::size_t, Type>;
|
|
|
using sparse_container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
|
|
using sparse_container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
|
|
|
using packed_container_type = std::vector<node_type, typename alloc_traits::template rebind_alloc<node_type>>;
|
|
using packed_container_type = std::vector<node_type, typename alloc_traits::template rebind_alloc<node_type>>;
|
|
|
|
|
|
|
@@ -316,10 +264,10 @@ class dense_set {
|
|
|
|
|
|
|
|
template<typename Other>
|
|
template<typename Other>
|
|
|
bool do_erase(const Other &value) {
|
|
bool do_erase(const Other &value) {
|
|
|
- for(size_type *curr = sparse.first().data() + bucket(value); *curr != std::numeric_limits<size_type>::max(); curr = &packed.first()[*curr].next) {
|
|
|
|
|
- if(packed.second()(packed.first()[*curr].element(), value)) {
|
|
|
|
|
|
|
+ for(size_type *curr = sparse.first().data() + bucket(value); *curr != std::numeric_limits<size_type>::max(); curr = &packed.first()[*curr].first) {
|
|
|
|
|
+ if(packed.second()(packed.first()[*curr].second, value)) {
|
|
|
const auto index = *curr;
|
|
const auto index = *curr;
|
|
|
- *curr = packed.first()[*curr].next;
|
|
|
|
|
|
|
+ *curr = packed.first()[*curr].first;
|
|
|
move_and_pop(index);
|
|
move_and_pop(index);
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
@@ -330,13 +278,13 @@ class dense_set {
|
|
|
|
|
|
|
|
void move_and_pop(const std::size_t pos) {
|
|
void move_and_pop(const std::size_t pos) {
|
|
|
if(const auto last = size() - 1u; pos != last) {
|
|
if(const auto last = size() - 1u; pos != last) {
|
|
|
- size_type *curr = sparse.first().data() + bucket(packed.first().back().element());
|
|
|
|
|
- for(; *curr != last; curr = &packed.first()[*curr].next) {}
|
|
|
|
|
|
|
+ size_type *curr = sparse.first().data() + bucket(packed.first().back().second);
|
|
|
|
|
+ for(; *curr != last; curr = &packed.first()[*curr].first) {}
|
|
|
*curr = pos;
|
|
*curr = pos;
|
|
|
|
|
|
|
|
// basic exception guarantees when value type has a throwing move constructor
|
|
// basic exception guarantees when value type has a throwing move constructor
|
|
|
- packed.first()[pos].element() = std::move(packed.first().back().element());
|
|
|
|
|
- packed.first()[pos].next = packed.first().back().next;
|
|
|
|
|
|
|
+ packed.first()[pos].second = std::move(packed.first().back().second);
|
|
|
|
|
+ packed.first()[pos].first = packed.first().back().first;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
packed.first().pop_back();
|
|
packed.first().pop_back();
|
|
@@ -591,21 +539,19 @@ public:
|
|
|
*/
|
|
*/
|
|
|
template<typename... Args>
|
|
template<typename... Args>
|
|
|
std::pair<iterator, bool> emplace(Args &&...args) {
|
|
std::pair<iterator, bool> emplace(Args &&...args) {
|
|
|
- auto &node = packed.first().emplace_back(packed.first().size(), std::forward<Args>(args)...);
|
|
|
|
|
- const auto hash = sparse.second()(node.element());
|
|
|
|
|
- auto index = hash_to_bucket(hash);
|
|
|
|
|
|
|
+ auto &node = packed.first().emplace_back(std::piecewise_construct, std::make_tuple(packed.first().size()), std::forward_as_tuple(std::forward<Args>(args)...));
|
|
|
|
|
+ const auto hash = sparse.second()(node.second);
|
|
|
|
|
+ const auto index = hash_to_bucket(hash);
|
|
|
|
|
|
|
|
- if(auto it = constrained_find(node.element(), index); it != end()) {
|
|
|
|
|
|
|
+ if(auto it = constrained_find(node.second, index); it != end()) {
|
|
|
packed.first().pop_back();
|
|
packed.first().pop_back();
|
|
|
return std::make_pair(it, false);
|
|
return std::make_pair(it, false);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // update goes after emplace to enforce exception guarantees
|
|
|
|
|
- node.next = std::exchange(sparse.first()[index], size() - 1u);
|
|
|
|
|
|
|
+ node.first = std::exchange(sparse.first()[index], size() - 1u);
|
|
|
|
|
|
|
|
- if(const auto count = size() + 1u; count > (bucket_count() * max_load_factor())) {
|
|
|
|
|
|
|
+ if(size() > (bucket_count() * max_load_factor())) {
|
|
|
rehash(bucket_count() * 2u);
|
|
rehash(bucket_count() * 2u);
|
|
|
- index = hash_to_bucket(hash);
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return std::make_pair(--end(), true);
|
|
return std::make_pair(--end(), true);
|
|
@@ -843,8 +789,8 @@ public:
|
|
|
std::fill(sparse.first().begin(), sparse.first().end(), std::numeric_limits<size_type>::max());
|
|
std::fill(sparse.first().begin(), sparse.first().end(), std::numeric_limits<size_type>::max());
|
|
|
|
|
|
|
|
for(size_type pos{}, last = size(); pos < last; ++pos) {
|
|
for(size_type pos{}, last = size(); pos < last; ++pos) {
|
|
|
- const auto index = bucket(packed.first()[pos].element());
|
|
|
|
|
- packed.first()[pos].next = std::exchange(sparse.first()[index], pos);
|
|
|
|
|
|
|
+ const auto index = bucket(packed.first()[pos].second);
|
|
|
|
|
+ packed.first()[pos].first = std::exchange(sparse.first()[index], pos);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|