xo-arena: DArenaHashMap [WIP]
This commit is contained in:
parent
d00fb57671
commit
0e6ab862d1
5 changed files with 180 additions and 1 deletions
150
xo-arena/include/xo/arena/DArenaHashMap.hpp
Normal file
150
xo-arena/include/xo/arena/DArenaHashMap.hpp
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
/** @file DArenaHashMap.hpp
|
||||
*
|
||||
* @author Roland Conybeare, Jan 2026
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DArenaVector.hpp"
|
||||
#include <utility>
|
||||
|
||||
namespace xo {
|
||||
namespace mm {
|
||||
/** @brief flat hash map of key-value pairs using dedicated DArenas for storage
|
||||
*
|
||||
* Replicates (to the extent feasible) std::unordered_map<K,V>
|
||||
*
|
||||
* @tparam K key type.
|
||||
* @tparam V value type.
|
||||
**/
|
||||
template <typename Key,
|
||||
typename Value,
|
||||
typename Hash = std::hash<Key>,
|
||||
typename Equal = std::equal_to<void>>
|
||||
struct DArenaHashMap {
|
||||
public:
|
||||
using size_type = std::size_t;
|
||||
using key_type = Key;
|
||||
using mapped_type = Value;
|
||||
using value_type = std::pair<const Key, Value>;
|
||||
using key_hash = Hash;
|
||||
using key_equal = Equal;
|
||||
using byte = std::byte;
|
||||
|
||||
/** create hash map **/
|
||||
DArenaHashMap(size_type hint_max_capacity,
|
||||
bool debug_flag = false);
|
||||
DArenaHashMap(Hash && hash = Hash(),
|
||||
Equal && eq = Equal(),
|
||||
size_type hint_max_capacity = 0,
|
||||
bool debug_flag = false);
|
||||
|
||||
/** find smallest x such that 2^x >= n. Return {x, 2^x} **/
|
||||
static std::pair<size_type, size_type> lub_exp2(size_t n);
|
||||
static constexpr size_type group_size() { return c_group_size; }
|
||||
#ifdef NOT_YET
|
||||
static size_type min_groups();
|
||||
static size_type min_size() { return min_groups() * c_group_size; }
|
||||
#endif
|
||||
|
||||
size_type empty() const noexcept { return size_ == 0; }
|
||||
size_type capacity() const noexcept { return n_group_ * c_group_size; }
|
||||
|
||||
#ifdef NOT_YET
|
||||
// TODO: std::pair<iterator, bool>
|
||||
void
|
||||
insert(std::pair<const Key, Value> & kv_pair) {
|
||||
uint64_t h = hash_(kv_pair.first);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
/** group size **/
|
||||
static constexpr std::size_t c_group_size = 16;
|
||||
|
||||
/** hash function **/
|
||||
key_hash hash_;
|
||||
/** key equal **/
|
||||
key_equal equal_;
|
||||
/** number of pairs in this table **/
|
||||
std::size_t size_ = 0;
|
||||
/** base-2 logarithm of n_group_ **/
|
||||
std::size_t 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
|
||||
**/
|
||||
std::size_t n_group_ = 1 << n_group_exponent_;
|
||||
/** control_[] partitioned into groups of c_group_size (16) consecutive elements **/
|
||||
DArenaVector<byte> control_;
|
||||
/** slots_[] holds {key,value} pairs **/
|
||||
DArenaVector<value_type> slots_;
|
||||
/** true to enable debug logging **/
|
||||
bool debug_flag_ = false;
|
||||
};
|
||||
|
||||
template <typename Key, typename Value, typename Hash, typename Equal>
|
||||
DArenaHashMap<Key, Value, Hash, Equal>::DArenaHashMap(size_type hint_max_capacity,
|
||||
bool debug_flag)
|
||||
: DArenaHashMap(Hash(), Equal(), hint_max_capacity, debug_flag)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Key, typename Value, typename Hash, typename Equal>
|
||||
DArenaHashMap<Key, Value, Hash, Equal>::DArenaHashMap(Hash && hash,
|
||||
Equal && eq,
|
||||
size_type hint_max_capacity,
|
||||
bool debug_flag)
|
||||
: hash_{std::move(hash)},
|
||||
equal_{std::move(eq)},
|
||||
size_{0},
|
||||
n_group_exponent_{lub_exp2(hint_max_capacity).first},
|
||||
n_group_{lub_exp2(hint_max_capacity).second},
|
||||
control_{DArenaVector<byte>::map(ArenaConfig{.size_ = n_group_})},
|
||||
slots_{DArenaVector<value_type>::map(ArenaConfig{.size_ = n_group_ * sizeof(value_type)})},
|
||||
debug_flag_{debug_flag}
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Key, typename Value, typename Hash, typename Equal>
|
||||
auto
|
||||
DArenaHashMap<Key, Value, Hash, Equal>::lub_exp2(size_t n) -> std::pair<size_type, size_type>
|
||||
|
||||
{
|
||||
size_type ngx = 0;
|
||||
size_type ng = 1;
|
||||
|
||||
while (ng < n) {
|
||||
++ngx;
|
||||
ng *= 2;
|
||||
}
|
||||
|
||||
return std::make_pair(ngx, ng);;
|
||||
}
|
||||
|
||||
#ifdef NOT_YET
|
||||
template <typename Key, typename Value, typename Hash, typename Equal>
|
||||
auto
|
||||
DArenaHashMap<Key, Value, Hash, Equal>::min_groups() -> size_type
|
||||
{
|
||||
size_type page_z = getpagesize();
|
||||
|
||||
// 1 page of slots
|
||||
size_type n_slot = page_z / sizeof(value_type);
|
||||
|
||||
// 1 page of groups
|
||||
size_type n_group = n_slot / c_group_size;
|
||||
|
||||
// glb power of 2, but at least 1
|
||||
size_type ng = 1;
|
||||
|
||||
while (2 * ng < n_group)
|
||||
ng *= 2;
|
||||
|
||||
return ng;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end DArenaHashMap.hpp */
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
* @author Roland Conybeare, Jan 2026
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DArena.hpp"
|
||||
#include <stdexcept>
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ set(UTEST_SRCS
|
|||
# objectmodel.test.cpp
|
||||
DArena.test.cpp
|
||||
DArenaVector.test.cpp
|
||||
DArenaHashMap.test.cpp
|
||||
# DArenaIterator.test.cpp
|
||||
# Collector.test.cpp
|
||||
# DX1CollectorIterator.test.cpp
|
||||
|
|
|
|||
26
xo-arena/utest/DArenaHashMap.test.cpp
Normal file
26
xo-arena/utest/DArenaHashMap.test.cpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/** @file DArenaHashMap.test.cpp
|
||||
*
|
||||
* @author Roland Conybeare, Jan 2026
|
||||
**/
|
||||
|
||||
#include "DArenaHashMap.hpp"
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
namespace xo {
|
||||
using xo::mm::DArenaHashMap;
|
||||
//using xo::mM::ArenaConfig;
|
||||
|
||||
namespace ut {
|
||||
TEST_CASE("DArenaHashMap-ctor", "[arena][DArenaHashMap]")
|
||||
{
|
||||
using HashMap = DArenaHashMap<int, int>;
|
||||
|
||||
HashMap map;
|
||||
|
||||
REQUIRE(map.empty());
|
||||
REQUIRE(map.capacity() == HashMap::group_size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* end DArenaHashMap.test.cpp */
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* @author Roland Conybeare, Jan 2026
|
||||
**/
|
||||
|
||||
#include "xo/arena/DArenaVector.hpp"
|
||||
#include "DArenaVector.hpp"
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
namespace xo {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue