[Bf-blender-cvs] [62f6255b476] master: BLI: Implement StringMap.add and StringMap.add_or_modify

Jacques Lucke noreply at git.blender.org
Fri Apr 24 22:34:47 CEST 2020


Commit: 62f6255b476a9fbd2c85b8fc7466734da912fa34
Author: Jacques Lucke
Date:   Fri Apr 24 22:33:48 2020 +0200
Branches: master
https://developer.blender.org/rB62f6255b476a9fbd2c85b8fc7466734da912fa34

BLI: Implement StringMap.add and StringMap.add_or_modify

===================================================================

M	source/blender/blenlib/BLI_map.hh
M	source/blender/blenlib/BLI_string_map.hh
M	tests/gtests/blenlib/BLI_string_map_test.cc

===================================================================

diff --git a/source/blender/blenlib/BLI_map.hh b/source/blender/blenlib/BLI_map.hh
index 4e8c9f67338..553175b0395 100644
--- a/source/blender/blenlib/BLI_map.hh
+++ b/source/blender/blenlib/BLI_map.hh
@@ -149,9 +149,7 @@ class Map {
     template<typename ForwardKeyT, typename ForwardValueT>
     void store(uint offset, ForwardKeyT &&key, ForwardValueT &&value)
     {
-      BLI_assert(m_status[offset] != IS_SET);
-      m_status[offset] = IS_SET;
-      new (this->key(offset)) KeyT(std::forward<ForwardKeyT>(key));
+      this->store_without_value(offset, std::forward<ForwardKeyT>(key));
       new (this->value(offset)) ValueT(std::forward<ForwardValueT>(value));
     }
 
diff --git a/source/blender/blenlib/BLI_string_map.hh b/source/blender/blenlib/BLI_string_map.hh
index d47f57c8bcc..ed23ea3aaa0 100644
--- a/source/blender/blenlib/BLI_string_map.hh
+++ b/source/blender/blenlib/BLI_string_map.hh
@@ -155,11 +155,16 @@ template<typename T, typename Allocator = GuardedAllocator> class StringMap {
 
     template<typename ForwardT>
     void store(uint offset, uint32_t hash, uint32_t index, ForwardT &&value)
+    {
+      this->store_without_value(offset, hash, index);
+      new (this->value(offset)) T(std::forward<ForwardT>(value));
+    }
+
+    void store_without_value(uint offset, uint32_t hash, uint32_t index)
     {
       BLI_assert(!this->is_set(offset));
       m_hashes[offset] = hash;
       m_indices[offset] = index;
-      new (this->value(offset)) T(std::forward<ForwardT>(value));
     }
   };
 
@@ -195,15 +200,51 @@ template<typename T, typename Allocator = GuardedAllocator> class StringMap {
    */
   void add(StringRef key, const T &value)
   {
-    if (!this->contains(key)) {
-      this->add_new(key, value);
-    }
+    this->add__impl(key, value);
   }
   void add(StringRef key, T &&value)
   {
-    if (!this->contains(key)) {
-      this->add_new(key, std::move(value));
+    this->add__impl(key, std::move(value));
+  }
+
+  /**
+   * First, checks if the key exists in the map.
+   * If it does exist, call the modify function with a pointer to the corresponding value.
+   * If it does not exist, call the create function with a pointer to where the value should be
+   * created.
+   *
+   * Returns whatever is returned from one of the callback functions. Both callbacks have to return
+   * the same type.
+   *
+   * CreateValueF: Takes a pointer to where the value should be created.
+   * ModifyValueF: Takes a pointer to the value that should be modified.
+   */
+  template<typename CreateValueF, typename ModifyValueF>
+  auto add_or_modify(StringRef key,
+                     const CreateValueF &create_value,
+                     const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
+  {
+    using CreateReturnT = decltype(create_value(nullptr));
+    using ModifyReturnT = decltype(modify_value(nullptr));
+    BLI_STATIC_ASSERT((std::is_same<CreateReturnT, ModifyReturnT>::value),
+                      "Both callbacks should return the same type.");
+
+    this->ensure_can_add();
+    uint32_t hash = this->compute_string_hash(key);
+    ITER_SLOTS_BEGIN (hash, m_array, , item, offset) {
+      if (item.is_empty(offset)) {
+        m_array.update__empty_to_set();
+        uint32_t index = this->save_key_in_array(key);
+        item.store_without_value(offset, hash, index);
+        T *value_ptr = item.value(offset);
+        return create_value(value_ptr);
+      }
+      else if (item.has_hash(offset, hash) && item.has_exact_key(offset, key, m_chars)) {
+        T *value_ptr = item.value(offset);
+        return modify_value(value_ptr);
+      }
     }
+    ITER_SLOTS_END(offset);
   }
 
   /**
@@ -435,6 +476,24 @@ template<typename T, typename Allocator = GuardedAllocator> class StringMap {
     ITER_SLOTS_END(offset);
   }
 
+  template<typename ForwardT> bool add__impl(StringRef key, ForwardT &&value)
+  {
+    this->ensure_can_add();
+    uint32_t hash = this->compute_string_hash(key);
+    ITER_SLOTS_BEGIN (hash, m_array, , item, offset) {
+      if (item.is_empty(offset)) {
+        uint32_t index = this->save_key_in_array(key);
+        item.store(offset, hash, index, std::forward<ForwardT>(value));
+        m_array.update__empty_to_set();
+        return true;
+      }
+      else if (item.has_hash(offset, hash) && item.has_exact_key(offset, key, m_chars)) {
+        return false;
+      }
+    }
+    ITER_SLOTS_END(offset);
+  }
+
   template<typename ForwardT> void add_new__impl(StringRef key, ForwardT &&value)
   {
     BLI_assert(!this->contains(key));
diff --git a/tests/gtests/blenlib/BLI_string_map_test.cc b/tests/gtests/blenlib/BLI_string_map_test.cc
index 5e671da86c7..41cda920a89 100644
--- a/tests/gtests/blenlib/BLI_string_map_test.cc
+++ b/tests/gtests/blenlib/BLI_string_map_test.cc
@@ -232,3 +232,20 @@ TEST(string_map, UniquePtrValues)
   std::unique_ptr<int> *b = map.lookup_ptr("A");
   EXPECT_EQ(a.get(), b->get());
 }
+
+TEST(string_map, AddOrModify)
+{
+  StringMap<int> map;
+  auto create_func = [](int *value) {
+    *value = 10;
+    return true;
+  };
+  auto modify_func = [](int *value) {
+    *value += 5;
+    return false;
+  };
+  EXPECT_TRUE(map.add_or_modify("Hello", create_func, modify_func));
+  EXPECT_EQ(map.lookup("Hello"), 10);
+  EXPECT_FALSE(map.add_or_modify("Hello", create_func, modify_func));
+  EXPECT_EQ(map.lookup("Hello"), 15);
+}



More information about the Bf-blender-cvs mailing list