BLI: support multiple arguments for value in *_as methods of Map

This allows us to build more complex values in-place in the map.
Before those values had to be build separately and then moved into the map.

Existing calls to the Map API remain unchanged.
This commit is contained in:
2021-04-17 18:39:35 +02:00
parent 5cf6f570c6
commit d0d85742fc
3 changed files with 56 additions and 45 deletions

View File

@@ -247,11 +247,11 @@ class Map {
{
this->add_new_as(std::move(key), std::move(value));
}
template<typename ForwardKey, typename ForwardValue>
void add_new_as(ForwardKey &&key, ForwardValue &&value)
template<typename ForwardKey, typename... ForwardValue>
void add_new_as(ForwardKey &&key, ForwardValue &&... value)
{
this->add_new__impl(
std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash_(key));
std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
}
/**
@@ -277,11 +277,11 @@ class Map {
{
return this->add_as(std::move(key), std::move(value));
}
template<typename ForwardKey, typename ForwardValue>
bool add_as(ForwardKey &&key, ForwardValue &&value)
template<typename ForwardKey, typename... ForwardValue>
bool add_as(ForwardKey &&key, ForwardValue &&... value)
{
return this->add__impl(
std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash_(key));
std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
}
/**
@@ -307,11 +307,11 @@ class Map {
{
return this->add_overwrite_as(std::move(key), std::move(value));
}
template<typename ForwardKey, typename ForwardValue>
bool add_overwrite_as(ForwardKey &&key, ForwardValue &&value)
template<typename ForwardKey, typename... ForwardValue>
bool add_overwrite_as(ForwardKey &&key, ForwardValue &&... value)
{
return this->add_overwrite__impl(
std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash_(key));
std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
}
/**
@@ -413,12 +413,12 @@ class Map {
{
return this->pop_default_as(key, std::move(default_value));
}
template<typename ForwardKey, typename ForwardValue>
Value pop_default_as(const ForwardKey &key, ForwardValue &&default_value)
template<typename ForwardKey, typename... ForwardValue>
Value pop_default_as(const ForwardKey &key, ForwardValue &&... default_value)
{
Slot *slot = this->lookup_slot_ptr(key, hash_(key));
if (slot == nullptr) {
return std::forward<ForwardValue>(default_value);
return Value(std::forward<ForwardValue>(default_value)...);
}
Value value = std::move(*slot->value());
slot->remove();
@@ -525,15 +525,15 @@ class Map {
{
return this->lookup_default_as(key, default_value);
}
template<typename ForwardKey, typename ForwardValue>
Value lookup_default_as(const ForwardKey &key, ForwardValue &&default_value) const
template<typename ForwardKey, typename... ForwardValue>
Value lookup_default_as(const ForwardKey &key, ForwardValue &&... default_value) const
{
const Value *ptr = this->lookup_ptr_as(key);
if (ptr != nullptr) {
return *ptr;
}
else {
return std::forward<ForwardValue>(default_value);
return Value(std::forward<ForwardValue>(default_value)...);
}
}
@@ -557,11 +557,11 @@ class Map {
{
return this->lookup_or_add_as(std::move(key), std::move(value));
}
template<typename ForwardKey, typename ForwardValue>
Value &lookup_or_add_as(ForwardKey &&key, ForwardValue &&value)
template<typename ForwardKey, typename... ForwardValue>
Value &lookup_or_add_as(ForwardKey &&key, ForwardValue &&... value)
{
return this->lookup_or_add__impl(
std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash_(key));
std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
}
/**
@@ -982,7 +982,7 @@ class Map {
SLOT_PROBING_BEGIN (ProbingStrategy, hash, new_slot_mask, slot_index) {
Slot &slot = new_slots[slot_index];
if (slot.is_empty()) {
slot.occupy(std::move(*old_slot.key()), std::move(*old_slot.value()), hash);
slot.occupy(std::move(*old_slot.key()), hash, std::move(*old_slot.value()));
return;
}
}
@@ -996,8 +996,8 @@ class Map {
new (this) Map(NoExceptConstructor(), allocator);
}
template<typename ForwardKey, typename ForwardValue>
void add_new__impl(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
template<typename ForwardKey, typename... ForwardValue>
void add_new__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
{
BLI_assert(!this->contains_as(key));
@@ -1005,7 +1005,7 @@ class Map {
MAP_SLOT_PROBING_BEGIN (hash, slot) {
if (slot.is_empty()) {
slot.occupy(std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash);
slot.occupy(std::forward<ForwardKey>(key), hash, std::forward<ForwardValue>(value)...);
occupied_and_removed_slots_++;
return;
}
@@ -1013,14 +1013,14 @@ class Map {
MAP_SLOT_PROBING_END();
}
template<typename ForwardKey, typename ForwardValue>
bool add__impl(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
template<typename ForwardKey, typename... ForwardValue>
bool add__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
{
this->ensure_can_add();
MAP_SLOT_PROBING_BEGIN (hash, slot) {
if (slot.is_empty()) {
slot.occupy(std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash);
slot.occupy(std::forward<ForwardKey>(key), hash, std::forward<ForwardValue>(value)...);
occupied_and_removed_slots_++;
return true;
}
@@ -1075,7 +1075,7 @@ class Map {
MAP_SLOT_PROBING_BEGIN (hash, slot) {
if (slot.is_empty()) {
slot.occupy(std::forward<ForwardKey>(key), create_value(), hash);
slot.occupy(std::forward<ForwardKey>(key), hash, create_value());
occupied_and_removed_slots_++;
return *slot.value();
}
@@ -1086,14 +1086,14 @@ class Map {
MAP_SLOT_PROBING_END();
}
template<typename ForwardKey, typename ForwardValue>
Value &lookup_or_add__impl(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
template<typename ForwardKey, typename... ForwardValue>
Value &lookup_or_add__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
{
this->ensure_can_add();
MAP_SLOT_PROBING_BEGIN (hash, slot) {
if (slot.is_empty()) {
slot.occupy(std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash);
slot.occupy(std::forward<ForwardKey>(key), hash, std::forward<ForwardValue>(value)...);
occupied_and_removed_slots_++;
return *slot.value();
}
@@ -1104,15 +1104,15 @@ class Map {
MAP_SLOT_PROBING_END();
}
template<typename ForwardKey, typename ForwardValue>
bool add_overwrite__impl(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
template<typename ForwardKey, typename... ForwardValue>
bool add_overwrite__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
{
auto create_func = [&](Value *ptr) {
new (static_cast<void *>(ptr)) Value(std::forward<ForwardValue>(value));
new (static_cast<void *>(ptr)) Value(std::forward<ForwardValue>(value)...);
return true;
};
auto modify_func = [&](Value *ptr) {
*ptr = std::forward<ForwardValue>(value);
*ptr = Value(std::forward<ForwardValue>(value)...);
return false;
};
return this->add_or_modify__impl(
@@ -1221,16 +1221,18 @@ template<typename Key, typename Value> class StdUnorderedMapWrapper {
map_.reserve(n);
}
template<typename ForwardKey, typename ForwardValue>
void add_new(ForwardKey &&key, ForwardValue &&value)
template<typename ForwardKey, typename... ForwardValue>
void add_new(ForwardKey &&key, ForwardValue &&... value)
{
map_.insert({std::forward<ForwardKey>(key), std::forward<ForwardValue>(value)});
map_.insert({std::forward<ForwardKey>(key), Value(std::forward<ForwardValue>(value)...)});
}
template<typename ForwardKey, typename ForwardValue>
bool add(ForwardKey &&key, ForwardValue &&value)
template<typename ForwardKey, typename... ForwardValue>
bool add(ForwardKey &&key, ForwardValue &&... value)
{
return map_.insert({std::forward<ForwardKey>(key), std::forward<ForwardValue>(value)}).second;
return map_
.insert({std::forward<ForwardKey>(key), Value(std::forward<ForwardValue>(value)...)})
.second;
}
bool contains(const Key &key) const

View File

@@ -195,11 +195,11 @@ template<typename Key, typename Value> class SimpleMapSlot {
* Change the state of this slot from empty/removed to occupied. The key/value has to be
* constructed by calling the constructor with the given key/value as parameter.
*/
template<typename ForwardKey, typename ForwardValue>
void occupy(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
template<typename ForwardKey, typename... ForwardValue>
void occupy(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
{
BLI_assert(!this->is_occupied());
new (&value_buffer_) Value(std::forward<ForwardValue>(value));
new (&value_buffer_) Value(std::forward<ForwardValue>(value)...);
this->occupy_no_value(std::forward<ForwardKey>(key), hash);
state_ = Occupied;
}
@@ -315,12 +315,12 @@ template<typename Key, typename Value, typename KeyInfo> class IntrusiveMapSlot
return is_equal(key, key_);
}
template<typename ForwardKey, typename ForwardValue>
void occupy(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
template<typename ForwardKey, typename... ForwardValue>
void occupy(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
{
BLI_assert(!this->is_occupied());
BLI_assert(KeyInfo::is_not_empty_or_removed(key));
new (&value_buffer_) Value(std::forward<ForwardValue>(value));
new (&value_buffer_) Value(std::forward<ForwardValue>(value)...);
this->occupy_no_value(std::forward<ForwardKey>(key), hash);
}

View File

@@ -604,6 +604,15 @@ TEST(map, GenericAlgorithms)
EXPECT_EQ(std::count(map.keys().begin(), map.keys().end(), 7), 1);
}
TEST(map, AddAsVariadic)
{
Map<int, StringRef> map;
map.add_as(3, "hello", 2);
map.add_as(2, "test", 1);
EXPECT_EQ(map.lookup(3), "he");
EXPECT_EQ(map.lookup(2), "t");
}
/**
* Set this to 1 to activate the benchmark. It is disabled by default, because it prints a lot.
*/