BLI: Implement StringMap.add and StringMap.add_or_modify
This commit is contained in:
parent
fd10ac9aca
commit
62f6255b47
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue