Просмотр исходного кода

dense_set: emplace always consumes its arguments

Michele Caini 4 лет назад
Родитель
Сommit
a4b8b93e7f
2 измененных файлов с 22 добавлено и 26 удалено
  1. 1 1
      TODO
  2. 21 25
      src/entt/container/dense_set.hpp

+ 1 - 1
TODO

@@ -4,7 +4,7 @@
 * add examples (and credits) from @alanjfs :)
 
 WIP:
-* dense map/set: support uses-allocator construction
+* dense map/set: support uses-allocator construction (single arg, multi-arg, key construction)
 * runtime events (emitter)
 * iterator based try_emplace vs try_insert for perf reasons
 * registry: remove reference to basic_sparse_set<E>

+ 21 - 25
src/entt/container/dense_set.hpp

@@ -273,27 +273,6 @@ class dense_set {
         return cend();
     }
 
-    template<typename Arg>
-    [[nodiscard]] auto get_or_emplace(Arg &&arg) {
-        const auto hash = sparse.second()(arg);
-        auto index = hash_to_bucket(hash);
-
-        if(auto it = constrained_find(arg, index); it != end()) {
-            return std::make_pair(it, false);
-        }
-
-        if(const auto count = size() + 1u; count > (bucket_count() * max_load_factor())) {
-            rehash(bucket_count() * 2u);
-            index = hash_to_bucket(hash);
-        }
-
-        packed.first().emplace_back(sparse.first()[index], std::forward<Arg>(arg));
-        // update goes after emplace to enforce exception guarantees
-        sparse.first()[index] = size() - 1u;
-
-        return std::make_pair(--end(), true);
-    }
-
     template<typename Other>
     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) {
@@ -557,6 +536,10 @@ public:
 
     /**
      * @brief Constructs an element in-place, if it does not exist.
+     *
+     * The element is also constructed when the container already has the key,
+     * in which case the newly constructed object is destroyed immediately.
+     *
      * @tparam Args Types of arguments to forward to the constructor of the
      * element.
      * @param args Arguments to forward to the constructor of the element.
@@ -566,11 +549,24 @@ public:
      */
     template<typename... Args>
     std::pair<iterator, bool> emplace(Args &&...args) {
-        if constexpr(((sizeof...(Args) == 1u) && ... && std::is_same_v<std::remove_const_t<std::remove_reference_t<Args>>, value_type>)) {
-            return get_or_emplace(std::forward<Args>(args)...);
-        } else {
-            return get_or_emplace(value_type{std::forward<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);
+
+        if(auto it = constrained_find(node.element, index); it != end()) {
+            packed.first().pop_back();
+            return std::make_pair(it, false);
+        }
+
+        // update goes after emplace to enforce exception guarantees
+        node.next = std::exchange(sparse.first()[index], size() - 1u);
+
+        if(const auto count = size() + 1u; count > (bucket_count() * max_load_factor())) {
+            rehash(bucket_count() * 2u);
+            index = hash_to_bucket(hash);
         }
+
+        return std::make_pair(--end(), true);
     }
 
     /**