Cleanup: Deduplicate custom VectorSet identifier hash and equality

Add `CustomIDVectorSet` for this purpose.
Based on code from Jacques in #133778.

Pull Request: https://projects.blender.org/blender/blender/pulls/133821
This commit is contained in:
Hans Goudey
2025-01-30 19:51:40 +01:00
committed by Hans Goudey
parent cc97c55515
commit c2fd4eb9cc
9 changed files with 111 additions and 195 deletions

View File

@@ -47,39 +47,19 @@ struct ReferenceLifetimesInfo;
namespace blender::bke {
struct NodeIDHash {
uint64_t operator()(const bNode *node) const
{
return node->identifier;
}
uint64_t operator()(const int32_t id) const
{
return id;
}
};
struct NodeIDEquality {
bool operator()(const bNode *a, const bNode *b) const
{
return a->identifier == b->identifier;
}
bool operator()(const bNode *a, const int32_t b) const
{
return a->identifier == b;
}
bool operator()(const int32_t a, const bNode *b) const
{
return this->operator()(b, a);
}
};
enum class FieldSocketState : int8_t {
RequiresSingle,
CanBeField,
IsField,
};
using NodeIDVectorSet = VectorSet<bNode *, DefaultProbingStrategy, NodeIDHash, NodeIDEquality>;
struct NodeIDGetter {
int32_t operator()(const bNode *value) const
{
return value->identifier;
}
};
using NodeIDVectorSet = CustomIDVectorSet<bNode *, NodeIDGetter>;
struct NodeLinkError {
std::string tooltip;

View File

@@ -1620,45 +1620,22 @@ void node_tree_set_type(const bContext *C, bNodeTree *ntree)
}
}
template<typename T> struct StructPointerIDNameHash {
uint64_t operator()(const T *value) const
template<typename T> struct NodeStructIDNameGetter {
StringRef operator()(const T *value) const
{
return get_default_hash(value->idname);
}
uint64_t operator()(const StringRef name) const
{
return get_default_hash(name);
}
};
template<typename T> struct StructPointerNameEqual {
bool operator()(const T *a, const T *b) const
{
return a->idname == b->idname;
}
bool operator()(const StringRef idname, const T *a) const
{
return a->idname == idname;
return StringRef(value->idname);
}
};
static auto &get_node_tree_type_map()
{
static VectorSet<bNodeTreeType *,
DefaultProbingStrategy,
StructPointerIDNameHash<bNodeTreeType>,
StructPointerNameEqual<bNodeTreeType>>
map;
static CustomIDVectorSet<bNodeTreeType *, NodeStructIDNameGetter<bNodeTreeType>> map;
return map;
}
static auto &get_node_type_map()
{
static VectorSet<bNodeType *,
DefaultProbingStrategy,
StructPointerIDNameHash<bNodeType>,
StructPointerNameEqual<bNodeType>>
map;
static CustomIDVectorSet<bNodeType *, NodeStructIDNameGetter<bNodeType>> map;
return map;
}
@@ -1670,11 +1647,7 @@ static auto &get_node_type_alias_map()
static auto &get_socket_type_map()
{
static VectorSet<bNodeSocketType *,
DefaultProbingStrategy,
StructPointerIDNameHash<bNodeSocketType>,
StructPointerNameEqual<bNodeSocketType>>
map;
static CustomIDVectorSet<bNodeSocketType *, NodeStructIDNameGetter<bNodeSocketType>> map;
return map;
}

View File

@@ -926,4 +926,45 @@ template<typename Key,
typename Slot = typename DefaultVectorSetSlot<Key>::type>
using RawVectorSet = VectorSet<Key, ProbingStrategy, Hash, IsEqual, Slot, RawAllocator>;
template<typename T, typename GetIDFn> struct CustomIDHash {
using CustomIDType = decltype(GetIDFn{}(std::declval<T>()));
uint64_t operator()(const T &value) const
{
return get_default_hash(GetIDFn{}(value));
}
uint64_t operator()(const CustomIDType &value) const
{
return get_default_hash(value);
}
};
template<typename T, typename GetIDFn> struct CustomIDEqual {
using CustomIDType = decltype(GetIDFn{}(std::declval<T>()));
bool operator()(const T &a, const T &b) const
{
return GetIDFn{}(a) == GetIDFn{}(b);
}
bool operator()(const CustomIDType &a, const T &b) const
{
return a == GetIDFn{}(b);
}
bool operator()(const T &a, const CustomIDType &b) const
{
return GetIDFn{}(a) == b;
}
};
/**
* Used for a set where the key itself isn't used for the hash or equality but some part of the
* key instead. For example the string identifiers of node types.
*
* #GetIDFn should have an implementation that returns a hashable and equality comparable type,
* i.e. `StringRef operator()(const bNode *value) { return value->idname; }`.
*/
template<typename T, typename GetIDFn>
using CustomIDVectorSet =
VectorSet<T, DefaultProbingStrategy, CustomIDHash<T, GetIDFn>, CustomIDEqual<T, GetIDFn>>;
} // namespace blender

View File

@@ -317,4 +317,26 @@ TEST(vector_set, ExtractVectorEmpty)
EXPECT_TRUE(vec.is_empty());
}
TEST(vector_set, CustomIDVectorSet)
{
struct ThingWithID {
int a;
std::string b;
int c;
};
struct ThingGetter {
StringRef operator()(const ThingWithID &value) const
{
return value.b;
}
};
CustomIDVectorSet<ThingWithID, ThingGetter> set;
set.add_new(ThingWithID{0, "test", 54});
EXPECT_TRUE(set.contains_as("test"));
set.add_new(ThingWithID{4333, "other", 2});
EXPECT_EQ(set.size(), 2);
set.add(ThingWithID{3333, "test", 27});
EXPECT_EQ(set.size(), 2);
}
} // namespace blender::tests

View File

@@ -30,35 +30,15 @@
using blender::StringRef;
struct GizmoGroupTypePointerHash {
uint64_t operator()(const wmGizmoGroupType *value) const
{
return get_default_hash(StringRef(value->idname));
}
uint64_t operator()(const StringRef name) const
{
return get_default_hash(name);
}
};
struct GizmoGroupTypePointerNameEqual {
bool operator()(const wmGizmoGroupType *a, const wmGizmoGroupType *b) const
{
return STREQ(a->idname, b->idname);
}
bool operator()(const StringRef idname, const wmGizmoGroupType *a) const
{
return a->idname == idname;
}
};
static auto &get_gizmo_group_type_map()
{
static blender::VectorSet<wmGizmoGroupType *,
blender::DefaultProbingStrategy,
GizmoGroupTypePointerHash,
GizmoGroupTypePointerNameEqual>
map;
struct IDNameGetter {
StringRef operator()(const wmGizmoGroupType *value) const
{
return StringRef(value->idname);
}
};
static blender::CustomIDVectorSet<wmGizmoGroupType *, IDNameGetter> map;
return map;
}

View File

@@ -39,35 +39,15 @@
using blender::StringRef;
struct GizmoTypePointerHash {
uint64_t operator()(const wmGizmoType *value) const
{
return get_default_hash(StringRef(value->idname));
}
uint64_t operator()(const StringRef name) const
{
return get_default_hash(name);
}
};
struct GizmoTypePointerNameEqual {
bool operator()(const wmGizmoType *a, const wmGizmoType *b) const
{
return STREQ(a->idname, b->idname);
}
bool operator()(const StringRef idname, const wmGizmoType *a) const
{
return a->idname == idname;
}
};
static auto &get_gizmo_type_map()
{
static blender::VectorSet<wmGizmoType *,
blender::DefaultProbingStrategy,
GizmoTypePointerHash,
GizmoTypePointerNameEqual>
map;
struct IDNameGetter {
StringRef operator()(const wmGizmoType *value) const
{
return StringRef(value->idname);
}
};
static blender::CustomIDVectorSet<wmGizmoType *, IDNameGetter> map;
return map;
}

View File

@@ -28,35 +28,15 @@
using blender::StringRef;
struct MenuTypePointerHash {
uint64_t operator()(const MenuType *value) const
{
return get_default_hash(StringRef(value->idname));
}
uint64_t operator()(const StringRef name) const
{
return get_default_hash(name);
}
};
struct MenuTypePointerNameEqual {
bool operator()(const MenuType *a, const MenuType *b) const
{
return STREQ(a->idname, b->idname);
}
bool operator()(const StringRef idname, const MenuType *a) const
{
return a->idname == idname;
}
};
static auto &get_menu_type_map()
{
static blender::VectorSet<MenuType *,
blender::DefaultProbingStrategy,
MenuTypePointerHash,
MenuTypePointerNameEqual>
map;
struct IDNameGetter {
StringRef operator()(const MenuType *value) const
{
return StringRef(value->idname);
}
};
static blender::CustomIDVectorSet<MenuType *, IDNameGetter> map;
return map;
}

View File

@@ -25,35 +25,15 @@
using blender::StringRef;
struct PanelTypePointerHash {
uint64_t operator()(const PanelType *value) const
{
return get_default_hash(StringRef(value->idname));
}
uint64_t operator()(const StringRef name) const
{
return get_default_hash(name);
}
};
struct PanelTypePointerNameEqual {
bool operator()(const PanelType *a, const PanelType *b) const
{
return STREQ(a->idname, b->idname);
}
bool operator()(const StringRef idname, const PanelType *a) const
{
return a->idname == idname;
}
};
static auto &get_panel_type_map()
{
static blender::VectorSet<PanelType *,
blender::DefaultProbingStrategy,
PanelTypePointerHash,
PanelTypePointerNameEqual>
map;
struct IDNameGetter {
StringRef operator()(const PanelType *value) const
{
return StringRef(value->idname);
}
};
static blender::CustomIDVectorSet<PanelType *, IDNameGetter> map;
return map;
}

View File

@@ -32,35 +32,15 @@
using blender::StringRef;
struct ListTypePointerHash {
uint64_t operator()(const uiListType *value) const
{
return get_default_hash(StringRef(value->idname));
}
uint64_t operator()(const StringRef name) const
{
return get_default_hash(name);
}
};
struct ListTypePointerNameEqual {
bool operator()(const uiListType *a, const uiListType *b) const
{
return STREQ(a->idname, b->idname);
}
bool operator()(const StringRef idname, const uiListType *a) const
{
return a->idname == idname;
}
};
static auto &get_list_type_map()
{
static blender::VectorSet<uiListType *,
blender::DefaultProbingStrategy,
ListTypePointerHash,
ListTypePointerNameEqual>
map;
struct IDNameGetter {
StringRef operator()(const uiListType *value) const
{
return StringRef(value->idname);
}
};
static blender::CustomIDVectorSet<uiListType *, IDNameGetter> map;
return map;
}