BLI: make Map.add_or_modify more powerful
The function now allows custom return types defined by the callbacks. This can be useful when a user of the data structure has to implement some custom behavior.
This commit is contained in:
@@ -151,6 +151,13 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
|
|||||||
new (this->value(offset)) ValueT(std::forward<ForwardValueT>(value));
|
new (this->value(offset)) ValueT(std::forward<ForwardValueT>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename ForwardKeyT> void store_without_value(uint offset, ForwardKeyT &&key)
|
||||||
|
{
|
||||||
|
BLI_assert(m_status[offset] != IS_SET);
|
||||||
|
m_status[offset] = IS_SET;
|
||||||
|
new (this->key(offset)) KeyT(std::forward<ForwardKeyT>(key));
|
||||||
|
}
|
||||||
|
|
||||||
void set_dummy(uint offset)
|
void set_dummy(uint offset)
|
||||||
{
|
{
|
||||||
BLI_assert(m_status[offset] == IS_SET);
|
BLI_assert(m_status[offset] == IS_SET);
|
||||||
@@ -280,22 +287,28 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the key exists in the map.
|
* First, checks if the key exists in the map.
|
||||||
* If it does exist, call the modify function with a reference to the corresponding value.
|
* If it does exist, call the modify function with a pointer to the corresponding value.
|
||||||
* If it does not exist, call the create function and insert a new key-value-pair.
|
* If it does not exist, call the create function with a pointer to where the value should be
|
||||||
* Returns true when a new pair was inserted, otherwise false.
|
* 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>
|
template<typename CreateValueF, typename ModifyValueF>
|
||||||
bool add_or_modify(const KeyT &key,
|
auto add_or_modify(const KeyT &key,
|
||||||
const CreateValueF &create_value,
|
const CreateValueF &create_value,
|
||||||
const ModifyValueF &modify_value)
|
const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
|
||||||
{
|
{
|
||||||
return this->add_or_modify__impl(key, create_value, modify_value);
|
return this->add_or_modify__impl(key, create_value, modify_value);
|
||||||
}
|
}
|
||||||
template<typename CreateValueF, typename ModifyValueF>
|
template<typename CreateValueF, typename ModifyValueF>
|
||||||
bool add_or_modify(KeyT &&key,
|
auto add_or_modify(KeyT &&key,
|
||||||
const CreateValueF &create_value,
|
const CreateValueF &create_value,
|
||||||
const ModifyValueF &modify_value)
|
const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
|
||||||
{
|
{
|
||||||
return this->add_or_modify__impl(std::move(key), create_value, modify_value);
|
return this->add_or_modify__impl(std::move(key), create_value, modify_value);
|
||||||
}
|
}
|
||||||
@@ -611,10 +624,15 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
|
|||||||
template<typename ForwardKeyT, typename ForwardValueT>
|
template<typename ForwardKeyT, typename ForwardValueT>
|
||||||
bool add_override__impl(ForwardKeyT &&key, ForwardValueT &&value)
|
bool add_override__impl(ForwardKeyT &&key, ForwardValueT &&value)
|
||||||
{
|
{
|
||||||
return this->add_or_modify(
|
return this->add_or_modify(std::forward<ForwardKeyT>(key),
|
||||||
std::forward<ForwardKeyT>(key),
|
[&](ValueT *dst) {
|
||||||
[&]() { return std::forward<ForwardValueT>(value); },
|
new (dst) ValueT(std::forward<ForwardValueT>(value));
|
||||||
[&](ValueT &old_value) { old_value = std::forward<ForwardValueT>(value); });
|
return true;
|
||||||
|
},
|
||||||
|
[&](ValueT *old_value) {
|
||||||
|
*old_value = std::forward<ForwardValueT>(value);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ForwardKeyT, typename ForwardValueT>
|
template<typename ForwardKeyT, typename ForwardValueT>
|
||||||
@@ -652,21 +670,27 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename ForwardKeyT, typename CreateValueF, typename ModifyValueF>
|
template<typename ForwardKeyT, typename CreateValueF, typename ModifyValueF>
|
||||||
bool add_or_modify__impl(ForwardKeyT &&key,
|
auto add_or_modify__impl(ForwardKeyT &&key,
|
||||||
const CreateValueF &create_value,
|
const CreateValueF &create_value,
|
||||||
const ModifyValueF &modify_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();
|
this->ensure_can_add();
|
||||||
|
|
||||||
ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
|
ITER_SLOTS_BEGIN (key, m_array, , item, offset) {
|
||||||
if (item.is_empty(offset)) {
|
if (item.is_empty(offset)) {
|
||||||
item.store(offset, std::forward<ForwardKeyT>(key), create_value());
|
|
||||||
m_array.update__empty_to_set();
|
m_array.update__empty_to_set();
|
||||||
return true;
|
item.store_without_value(offset, std::forward<ForwardKeyT>(key));
|
||||||
|
ValueT *value_ptr = item.value(offset);
|
||||||
|
return create_value(value_ptr);
|
||||||
}
|
}
|
||||||
else if (item.has_key(offset, key)) {
|
else if (item.has_key(offset, key)) {
|
||||||
modify_value(*item.value(offset));
|
ValueT *value_ptr = item.value(offset);
|
||||||
return false;
|
return modify_value(value_ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ITER_SLOTS_END(offset);
|
ITER_SLOTS_END(offset);
|
||||||
|
@@ -180,11 +180,17 @@ TEST(map, LookupOrAdd_Lambdas)
|
|||||||
EXPECT_EQ(map.lookup_or_add(1, lambda1), 20.0f);
|
EXPECT_EQ(map.lookup_or_add(1, lambda1), 20.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(map, InsertOrModify)
|
TEST(map, AddOrModify)
|
||||||
{
|
{
|
||||||
IntFloatMap map;
|
IntFloatMap map;
|
||||||
auto create_func = []() { return 10.0f; };
|
auto create_func = [](float *value) {
|
||||||
auto modify_func = [](float &value) { value += 5; };
|
*value = 10.0f;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
auto modify_func = [](float *value) {
|
||||||
|
*value += 5;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
EXPECT_TRUE(map.add_or_modify(1, create_func, modify_func));
|
EXPECT_TRUE(map.add_or_modify(1, create_func, modify_func));
|
||||||
EXPECT_EQ(map.lookup(1), 10.0f);
|
EXPECT_EQ(map.lookup(1), 10.0f);
|
||||||
EXPECT_FALSE(map.add_or_modify(1, create_func, modify_func));
|
EXPECT_FALSE(map.add_or_modify(1, create_func, modify_func));
|
||||||
|
Reference in New Issue
Block a user