[Bf-blender-cvs] [cc48610d2c5] master: BLI: improve support for using vectors as hash table keys
Jacques Lucke
noreply at git.blender.org
Thu Dec 29 15:01:31 CET 2022
Commit: cc48610d2c55a001bcd3af57ad11f7951602936d
Author: Jacques Lucke
Date: Thu Dec 29 14:59:48 2022 +0100
Branches: master
https://developer.blender.org/rBcc48610d2c55a001bcd3af57ad11f7951602936d
BLI: improve support for using vectors as hash table keys
To support this, I had to add comparison and hashing functions for
vectors or sequences more generally.
===================================================================
M source/blender/blenlib/BLI_hash_tables.hh
M source/blender/blenlib/BLI_span.hh
M source/blender/blenlib/BLI_vector.hh
M source/blender/blenlib/tests/BLI_map_test.cc
===================================================================
diff --git a/source/blender/blenlib/BLI_hash_tables.hh b/source/blender/blenlib/BLI_hash_tables.hh
index fff2411f94c..6e453820ec9 100644
--- a/source/blender/blenlib/BLI_hash_tables.hh
+++ b/source/blender/blenlib/BLI_hash_tables.hh
@@ -353,4 +353,22 @@ template<typename T> struct DefaultEquality<std::unique_ptr<T>> : public Pointer
template<typename T> struct DefaultEquality<std::shared_ptr<T>> : public PointerComparison {
};
+struct SequenceComparison {
+ template<typename T1, typename T2> bool operator()(const T1 &a, const T2 &b) const
+ {
+ const auto a_begin = a.begin();
+ const auto a_end = a.end();
+ const auto b_begin = b.begin();
+ const auto b_end = b.end();
+ if (a_end - a_begin != b_end - b_begin) {
+ return false;
+ }
+ return std::equal(a_begin, a_end, b_begin);
+ }
+};
+
+template<typename T, int64_t InlineBufferCapacity, typename Allocator>
+struct DefaultEquality<Vector<T, InlineBufferCapacity, Allocator>> : public SequenceComparison {
+};
+
} // namespace blender
diff --git a/source/blender/blenlib/BLI_span.hh b/source/blender/blenlib/BLI_span.hh
index 84a5c87d423..a276bbd8f68 100644
--- a/source/blender/blenlib/BLI_span.hh
+++ b/source/blender/blenlib/BLI_span.hh
@@ -66,6 +66,8 @@
namespace blender {
+template<typename T> uint64_t get_default_hash(const T &v);
+
/**
* References an array of type T that is owned by someone else. The data in the array cannot be
* modified.
@@ -418,6 +420,15 @@ template<typename T> class Span {
return IndexRange(size_);
}
+ constexpr uint64_t hash() const
+ {
+ uint64_t hash = 0;
+ for (const T &value : *this) {
+ hash = hash * 33 ^ get_default_hash(value);
+ }
+ return hash;
+ }
+
/**
* Returns a new Span to the same underlying memory buffer. No conversions are done.
*/
diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh
index 8860bb05127..09486b32480 100644
--- a/source/blender/blenlib/BLI_vector.hh
+++ b/source/blender/blenlib/BLI_vector.hh
@@ -157,6 +157,12 @@ class Vector {
this->increase_size_by_unchecked(size);
}
+ template<typename U, BLI_ENABLE_IF((std::is_convertible_v<U, T>))>
+ explicit Vector(MutableSpan<U> values, Allocator allocator = {})
+ : Vector(values.as_span(), allocator)
+ {
+ }
+
/**
* Create a vector that contains copies of the values in the initialized list.
*
@@ -937,6 +943,16 @@ class Vector {
return IndexRange(this->size());
}
+ uint64_t hash() const
+ {
+ return this->as_span().hash();
+ }
+
+ static uint64_t hash_as(const Span<T> values)
+ {
+ return values.hash();
+ }
+
friend bool operator==(const Vector &a, const Vector &b)
{
return a.as_span() == b.as_span();
diff --git a/source/blender/blenlib/tests/BLI_map_test.cc b/source/blender/blenlib/tests/BLI_map_test.cc
index 69ae82d6f05..2662d547ee9 100644
--- a/source/blender/blenlib/tests/BLI_map_test.cc
+++ b/source/blender/blenlib/tests/BLI_map_test.cc
@@ -671,6 +671,24 @@ TEST(map, LookupKey)
EXPECT_EQ(map.lookup_key_ptr("a"), map.lookup_key_ptr_as("a"));
}
+TEST(map, VectorKey)
+{
+ Map<Vector<int>, int> map;
+ map.add({1, 2, 3}, 100);
+ map.add({3, 2, 1}, 200);
+
+ EXPECT_EQ(map.size(), 2);
+ EXPECT_EQ(map.lookup({1, 2, 3}), 100);
+ EXPECT_EQ(map.lookup({3, 2, 1}), 200);
+ EXPECT_FALSE(map.contains({1, 2}));
+
+ std::array<int, 3> array = {1, 2, 3};
+ EXPECT_EQ(map.lookup_as(array), 100);
+
+ map.remove_as(Vector<int>({1, 2, 3}).as_mutable_span());
+ EXPECT_EQ(map.size(), 1);
+}
+
/**
* Set this to 1 to activate the benchmark. It is disabled by default, because it prints a lot.
*/
More information about the Bf-blender-cvs
mailing list