xo-arena: move HashMapStore to dedicated file
This commit is contained in:
parent
cf5a8e9614
commit
93f64130b0
2 changed files with 133 additions and 116 deletions
|
|
@ -7,8 +7,7 @@
|
|||
|
||||
#include "DArenaVector.hpp"
|
||||
#include "hashmap/verify_policy.hpp"
|
||||
#include "hashmap/DArenaHashMapUtil.hpp"
|
||||
#include "hashmap/ControlGroup.hpp"
|
||||
#include "hashmap/HashMapStore.hpp"
|
||||
#include <xo/indentlog/scope.hpp>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
|
|
@ -27,120 +26,6 @@ namespace xo {
|
|||
#endif
|
||||
|
||||
namespace detail {
|
||||
template <typename Key,
|
||||
typename Value>
|
||||
struct HashMapStore : DArenaHashMapUtil {
|
||||
public:
|
||||
using value_type = std::pair<const Key, Value>;
|
||||
using group_type = detail::ControlGroup;
|
||||
|
||||
public:
|
||||
/** group_exp2: number of groups {x, 2^x} **/
|
||||
explicit HashMapStore(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_{DArenaVector<uint8_t>::map(ArenaConfig{.size_ = control_size(n_slot_)})},
|
||||
slots_{DArenaVector<value_type>::map(ArenaConfig{.size_ = n_slot_ * sizeof(value_type)})}
|
||||
{
|
||||
/* here: arenas have allocated address range, but no committed memory yet */
|
||||
|
||||
this->_init();
|
||||
}
|
||||
|
||||
size_type empty() const noexcept { return size_ == 0; }
|
||||
size_type capacity() const noexcept { return n_group_ * c_group_size; }
|
||||
float load_factor() const noexcept { return size_ / static_cast<float>(n_slot_); }
|
||||
|
||||
void resize_from_empty(const std::pair<size_type,
|
||||
size_type> & group_exp2)
|
||||
{
|
||||
assert(size_ == 0);
|
||||
|
||||
this->n_group_exponent_ = group_exp2.first;
|
||||
this->n_group_ = group_exp2.second;
|
||||
this->n_slot_ = group_exp2.second * c_group_size;
|
||||
|
||||
this->_init();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
/* remark: discontinuity in the sense that we lose n_group_ = 2 ^ n_group_epxonent_
|
||||
*
|
||||
* juice may not be worth the squeeze here,
|
||||
* since DArena doesn't yet (Jan 2026) unmap on clear
|
||||
*/
|
||||
|
||||
this->size_ = 0;
|
||||
this->n_group_exponent_ = 0;
|
||||
this->n_group_ = 0;
|
||||
this->n_slot_ = 0;
|
||||
this->control_.resize(0);
|
||||
this->slots_.resize(0);
|
||||
}
|
||||
|
||||
public:
|
||||
void _init() {
|
||||
this->control_.resize(control_size(n_slot_));
|
||||
|
||||
/* front stub: iterator bookend */
|
||||
std::fill(this->control_.begin(),
|
||||
this->control_.begin() + c_control_stub,
|
||||
c_iterator_bookend);
|
||||
|
||||
/* all slots marked empty initially */
|
||||
std::fill(this->control_.begin() + c_control_stub,
|
||||
this->control_.end() - c_control_stub,
|
||||
c_empty_slot);
|
||||
|
||||
/* end stub: iterator bookend */
|
||||
std::fill(this->control_.end() - c_control_stub,
|
||||
this->control_.end(),
|
||||
c_iterator_bookend);
|
||||
|
||||
this->slots_.resize(n_slot_);
|
||||
}
|
||||
|
||||
/** load control group for slot range [ix .. ix+c_group_size) **/
|
||||
group_type _load_group(size_type ix) {
|
||||
return group_type(&(control_[ix + c_control_stub]));
|
||||
}
|
||||
|
||||
/** update control group for slot number @p ix, replace with @p h2 **/
|
||||
void _update_control(size_type ix, uint8_t h2) {
|
||||
this->control_[ix + c_control_stub] = h2;
|
||||
|
||||
if (ix < c_group_size) {
|
||||
size_type N = this->capacity();
|
||||
|
||||
// refresh end-of-array copy
|
||||
std::memcpy(&(control_[N + c_control_stub]),
|
||||
&(control_[c_control_stub]),
|
||||
c_group_size);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/** number of pairs in this table **/
|
||||
size_type size_ = 0;
|
||||
/** base-2 logarithm of n_group_ **/
|
||||
size_type n_group_exponent_ = 0;
|
||||
/** table has capacity for this number of groups.
|
||||
* always an exact power of two.
|
||||
* number of slots is n_group_ * c_group_size
|
||||
**/
|
||||
size_type n_group_ = (1 << n_group_exponent_);
|
||||
/** table has capacity for this number of {key,value} pairs **/
|
||||
size_type n_slot_ = n_group_ * c_group_size;
|
||||
/** control_[] partitioned into groups of
|
||||
* c_group_size (16) consecutive elements
|
||||
**/
|
||||
DArenaVector<uint8_t> control_;
|
||||
/** slots_[] holds {key,value} pairs **/
|
||||
DArenaVector<value_type> slots_;
|
||||
};
|
||||
|
||||
template <typename Key,
|
||||
typename Value>
|
||||
|
|
|
|||
132
xo-arena/include/xo/arena/hashmap/HashMapStore.hpp
Normal file
132
xo-arena/include/xo/arena/hashmap/HashMapStore.hpp
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
/** @file HashMapStore.hpp
|
||||
*
|
||||
* @author Roland Conybeare, Jan 2026
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hashmap/DArenaHashMapUtil.hpp"
|
||||
#include "hashmap/ControlGroup.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace mm {
|
||||
namespace detail {
|
||||
template <typename Key,
|
||||
typename Value>
|
||||
struct HashMapStore : DArenaHashMapUtil {
|
||||
public:
|
||||
using value_type = std::pair<const Key, Value>;
|
||||
using group_type = detail::ControlGroup;
|
||||
|
||||
public:
|
||||
/** group_exp2: number of groups {x, 2^x} **/
|
||||
explicit HashMapStore(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_{DArenaVector<uint8_t>::map(ArenaConfig{.size_ = control_size(n_slot_)})},
|
||||
slots_{DArenaVector<value_type>::map(ArenaConfig{.size_ = n_slot_ * sizeof(value_type)})}
|
||||
{
|
||||
/* here: arenas have allocated address range, but no committed memory yet */
|
||||
|
||||
this->_init();
|
||||
}
|
||||
|
||||
size_type empty() const noexcept { return size_ == 0; }
|
||||
size_type capacity() const noexcept { return n_group_ * c_group_size; }
|
||||
float load_factor() const noexcept { return size_ / static_cast<float>(n_slot_); }
|
||||
|
||||
void resize_from_empty(const std::pair<size_type,
|
||||
size_type> & group_exp2)
|
||||
{
|
||||
assert(size_ == 0);
|
||||
|
||||
this->n_group_exponent_ = group_exp2.first;
|
||||
this->n_group_ = group_exp2.second;
|
||||
this->n_slot_ = group_exp2.second * c_group_size;
|
||||
|
||||
this->_init();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
/* remark: discontinuity in the sense that we lose n_group_ = 2 ^ n_group_epxonent_
|
||||
*
|
||||
* juice may not be worth the squeeze here,
|
||||
* since DArena doesn't yet (Jan 2026) unmap on clear
|
||||
*/
|
||||
|
||||
this->size_ = 0;
|
||||
this->n_group_exponent_ = 0;
|
||||
this->n_group_ = 0;
|
||||
this->n_slot_ = 0;
|
||||
this->control_.resize(0);
|
||||
this->slots_.resize(0);
|
||||
}
|
||||
|
||||
public:
|
||||
void _init() {
|
||||
this->control_.resize(control_size(n_slot_));
|
||||
|
||||
/* front stub: iterator bookend */
|
||||
std::fill(this->control_.begin(),
|
||||
this->control_.begin() + c_control_stub,
|
||||
c_iterator_bookend);
|
||||
|
||||
/* all slots marked empty initially */
|
||||
std::fill(this->control_.begin() + c_control_stub,
|
||||
this->control_.end() - c_control_stub,
|
||||
c_empty_slot);
|
||||
|
||||
/* end stub: iterator bookend */
|
||||
std::fill(this->control_.end() - c_control_stub,
|
||||
this->control_.end(),
|
||||
c_iterator_bookend);
|
||||
|
||||
this->slots_.resize(n_slot_);
|
||||
}
|
||||
|
||||
/** load control group for slot range [ix .. ix+c_group_size) **/
|
||||
group_type _load_group(size_type ix) {
|
||||
return group_type(&(control_[ix + c_control_stub]));
|
||||
}
|
||||
|
||||
/** update control group for slot number @p ix, replace with @p h2 **/
|
||||
void _update_control(size_type ix, uint8_t h2) {
|
||||
this->control_[ix + c_control_stub] = h2;
|
||||
|
||||
if (ix < c_group_size) {
|
||||
size_type N = this->capacity();
|
||||
|
||||
// refresh end-of-array copy
|
||||
std::memcpy(&(control_[N + c_control_stub]),
|
||||
&(control_[c_control_stub]),
|
||||
c_group_size);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/** number of pairs in this table **/
|
||||
size_type size_ = 0;
|
||||
/** base-2 logarithm of n_group_ **/
|
||||
size_type n_group_exponent_ = 0;
|
||||
/** table has capacity for this number of groups.
|
||||
* always an exact power of two.
|
||||
* number of slots is n_group_ * c_group_size
|
||||
**/
|
||||
size_type n_group_ = (1 << n_group_exponent_);
|
||||
/** table has capacity for this number of {key,value} pairs **/
|
||||
size_type n_slot_ = n_group_ * c_group_size;
|
||||
/** control_[] partitioned into groups of
|
||||
* c_group_size (16) consecutive elements
|
||||
**/
|
||||
DArenaVector<uint8_t> control_;
|
||||
/** slots_[] holds {key,value} pairs **/
|
||||
DArenaVector<value_type> slots_;
|
||||
};
|
||||
}
|
||||
} /*namespace mm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end HashMapStore.hpp */
|
||||
Loading…
Add table
Add a link
Reference in a new issue