xo-arena: + DArenaHashMap::operator[] + utest
This commit is contained in:
parent
5565183495
commit
563f6b3ea4
3 changed files with 96 additions and 7 deletions
|
|
@ -98,8 +98,8 @@ namespace xo {
|
|||
* Replaces any previous value stored under the same key.
|
||||
*
|
||||
* Return pair retval with:
|
||||
* reval.first: true if size incremented;
|
||||
* retval.second: address of slots_[p] at which pair inserted/updated
|
||||
* retval.first: address of slots_[p] at which pair inserted/updated
|
||||
* retval.second: true if size incremented;
|
||||
*
|
||||
* When table is full retval.second will be nullptr,
|
||||
* with error captured in last_error_
|
||||
|
|
@ -119,6 +119,9 @@ namespace xo {
|
|||
**/
|
||||
iterator find(const key_type & key);
|
||||
|
||||
/** establish kv pair for @p key in this table; return address of value part **/
|
||||
mapped_type & operator[](const key_type & key);
|
||||
|
||||
private:
|
||||
/** insert @p kv_pair,
|
||||
* where key hashes to @p hash_value, into @p *store
|
||||
|
|
@ -169,7 +172,7 @@ namespace xo {
|
|||
bool debug_flag)
|
||||
: hash_{std::move(hash)},
|
||||
equal_{std::move(eq)},
|
||||
store_{lub_exp2(lub_group_mult(hint_max_capacity))},
|
||||
store_{"arenahashmap", lub_exp2(lub_group_mult(hint_max_capacity))},
|
||||
debug_flag_{debug_flag}
|
||||
{
|
||||
}
|
||||
|
|
@ -332,7 +335,8 @@ namespace xo {
|
|||
} else {
|
||||
log && log("duplicate-and-replace branch");
|
||||
|
||||
detail::HashMapStore<Key, Value> store_2x(std::make_pair(n_group_exponent_2x,
|
||||
detail::HashMapStore<Key, Value> store_2x("arenahashmap",
|
||||
std::make_pair(n_group_exponent_2x,
|
||||
n_group_2x));
|
||||
/* rehash everything in store_,
|
||||
* into store_2x
|
||||
|
|
@ -459,6 +463,42 @@ namespace xo {
|
|||
}
|
||||
}
|
||||
|
||||
template <typename Key,
|
||||
typename Value,
|
||||
typename Hash,
|
||||
typename Equal>
|
||||
auto
|
||||
DArenaHashMap<Key, Value, Hash, Equal>::operator[](const key_type & key) -> mapped_type &
|
||||
{
|
||||
{
|
||||
auto ix = this->find(key);
|
||||
|
||||
if (ix != this->end())
|
||||
return ix->second;
|
||||
}
|
||||
|
||||
// key-value pair
|
||||
value_type kv_pair = std::make_pair(key, mapped_type{});
|
||||
|
||||
auto [slot_addr, ins_flag] = this->try_insert(kv_pair);
|
||||
|
||||
if (slot_addr)
|
||||
return slot_addr->second;
|
||||
|
||||
if (!this->_try_grow()) {
|
||||
// we are out of room
|
||||
|
||||
throw std::runtime_error("DArenaHashMap::operator[]: table capacity exhausted");
|
||||
}
|
||||
|
||||
/* retry insert, now with bigger capacity */
|
||||
std::tie(slot_addr, ins_flag) = this->try_insert(kv_pair);
|
||||
|
||||
assert(slot_addr);
|
||||
|
||||
return slot_addr->second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify DArenaHashMap class invariants.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -22,14 +22,15 @@ namespace xo {
|
|||
|
||||
public:
|
||||
/** group_exp2: number of groups {x, 2^x} **/
|
||||
explicit HashMapStore(const std::pair<size_type,
|
||||
explicit HashMapStore(const std::string & name,
|
||||
const std::pair<size_type,
|
||||
size_type> & group_exp2)
|
||||
: size_{0},
|
||||
n_group_exponent_{group_exp2.first},
|
||||
n_group_{group_exp2.second},
|
||||
n_slot_{group_exp2.second * c_group_size},
|
||||
control_{control_vector_type::map(xo::mm::ArenaConfig{.size_ = control_size(n_slot_)})},
|
||||
slots_{slot_vector_type::map(xo::mm::ArenaConfig{.size_ = n_slot_ * sizeof(value_type)})}
|
||||
control_{control_vector_type::map(xo::mm::ArenaConfig{.name_ = name, .size_ = control_size(n_slot_)})},
|
||||
slots_{slot_vector_type::map(xo::mm::ArenaConfig{.name_ = name, .size_ = n_slot_ * sizeof(value_type)})}
|
||||
{
|
||||
/* here: arenas have allocated address range, but no committed memory yet */
|
||||
|
||||
|
|
|
|||
|
|
@ -226,6 +226,54 @@ namespace xo {
|
|||
}
|
||||
}
|
||||
|
||||
TEST_CASE("DArenaHashMap-operator-bracket", "[arena][DArenaHashMap]")
|
||||
{
|
||||
using HashMap = DArenaHashMap<int, int>;
|
||||
|
||||
HashMap map;
|
||||
|
||||
// insert via operator[]
|
||||
map[1] = 100;
|
||||
map[2] = 200;
|
||||
map[3] = 300;
|
||||
|
||||
REQUIRE(map.size() == 3);
|
||||
|
||||
// read back via operator[]
|
||||
REQUIRE(map[1] == 100);
|
||||
REQUIRE(map[2] == 200);
|
||||
REQUIRE(map[3] == 300);
|
||||
|
||||
// update via operator[]
|
||||
map[2] = 250;
|
||||
REQUIRE(map[2] == 250);
|
||||
REQUIRE(map.size() == 3); // size unchanged
|
||||
|
||||
// verify via find
|
||||
{
|
||||
auto it = map.find(1);
|
||||
REQUIRE(it != map.end());
|
||||
REQUIRE(it->second == 100);
|
||||
}
|
||||
{
|
||||
auto it = map.find(2);
|
||||
REQUIRE(it != map.end());
|
||||
REQUIRE(it->second == 250);
|
||||
}
|
||||
{
|
||||
auto it = map.find(3);
|
||||
REQUIRE(it != map.end());
|
||||
REQUIRE(it->second == 300);
|
||||
}
|
||||
|
||||
// operator[] on non-existent key creates default entry
|
||||
int & val = map[999];
|
||||
REQUIRE(map.size() == 4);
|
||||
REQUIRE(val == 0); // default-initialized
|
||||
val = 999;
|
||||
REQUIRE(map[999] == 999);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// - let's try getting lcov to work in xo-umbrella2
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue