xo-arena: + DArenaHashMap::operator[] + utest
This commit is contained in:
parent
c65819d3eb
commit
3711ab21a4
3 changed files with 96 additions and 7 deletions
|
|
@ -98,8 +98,8 @@ namespace xo {
|
||||||
* Replaces any previous value stored under the same key.
|
* Replaces any previous value stored under the same key.
|
||||||
*
|
*
|
||||||
* Return pair retval with:
|
* Return pair retval with:
|
||||||
* reval.first: true if size incremented;
|
* retval.first: address of slots_[p] at which pair inserted/updated
|
||||||
* retval.second: address of slots_[p] at which pair inserted/updated
|
* retval.second: true if size incremented;
|
||||||
*
|
*
|
||||||
* When table is full retval.second will be nullptr,
|
* When table is full retval.second will be nullptr,
|
||||||
* with error captured in last_error_
|
* with error captured in last_error_
|
||||||
|
|
@ -119,6 +119,9 @@ namespace xo {
|
||||||
**/
|
**/
|
||||||
iterator find(const key_type & key);
|
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:
|
private:
|
||||||
/** insert @p kv_pair,
|
/** insert @p kv_pair,
|
||||||
* where key hashes to @p hash_value, into @p *store
|
* where key hashes to @p hash_value, into @p *store
|
||||||
|
|
@ -169,7 +172,7 @@ namespace xo {
|
||||||
bool debug_flag)
|
bool debug_flag)
|
||||||
: hash_{std::move(hash)},
|
: hash_{std::move(hash)},
|
||||||
equal_{std::move(eq)},
|
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}
|
debug_flag_{debug_flag}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -332,7 +335,8 @@ namespace xo {
|
||||||
} else {
|
} else {
|
||||||
log && log("duplicate-and-replace branch");
|
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));
|
n_group_2x));
|
||||||
/* rehash everything in store_,
|
/* rehash everything in store_,
|
||||||
* into store_2x
|
* 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.
|
* Verify DArenaHashMap class invariants.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -22,14 +22,15 @@ namespace xo {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** group_exp2: number of groups {x, 2^x} **/
|
/** 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_type> & group_exp2)
|
||||||
: size_{0},
|
: size_{0},
|
||||||
n_group_exponent_{group_exp2.first},
|
n_group_exponent_{group_exp2.first},
|
||||||
n_group_{group_exp2.second},
|
n_group_{group_exp2.second},
|
||||||
n_slot_{group_exp2.second * c_group_size},
|
n_slot_{group_exp2.second * c_group_size},
|
||||||
control_{control_vector_type::map(xo::mm::ArenaConfig{.size_ = control_size(n_slot_)})},
|
control_{control_vector_type::map(xo::mm::ArenaConfig{.name_ = name, .size_ = control_size(n_slot_)})},
|
||||||
slots_{slot_vector_type::map(xo::mm::ArenaConfig{.size_ = n_slot_ * sizeof(value_type)})}
|
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 */
|
/* 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:
|
// TODO:
|
||||||
// - let's try getting lcov to work in xo-umbrella2
|
// - let's try getting lcov to work in xo-umbrella2
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue