Skip to content

Commit

Permalink
Support hash size that's not std::size_t
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-sparus committed Sep 18, 2024
1 parent efbbbf3 commit 552d20b
Show file tree
Hide file tree
Showing 11 changed files with 241 additions and 92 deletions.
9 changes: 4 additions & 5 deletions immer/detail/hamts/bits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ namespace detail {
namespace hamts {

using size_t = std::size_t;
using hash_t = std::size_t;
using bits_t = std::uint32_t;
using count_t = std::uint32_t;
using shift_t = std::uint32_t;
Expand Down Expand Up @@ -53,14 +52,14 @@ struct get_bitmap_type<4u>
template <bits_t B, typename T = count_t>
constexpr T branches = T{1u} << B;

template <bits_t B, typename T = size_t>
template <typename T, bits_t B>
constexpr T mask = branches<B, T> - 1u;

template <bits_t B, typename T = count_t>
template <typename hash_t, bits_t B, typename T = count_t>
constexpr T max_depth = (sizeof(hash_t) * 8u + B - 1u) / B;

template <bits_t B, typename T = count_t>
constexpr T max_shift = max_depth<B, count_t> * B;
template <typename hash_t, bits_t B, typename T = count_t>
constexpr T max_shift = max_depth<hash_t, B, count_t> * B;

#define IMMER_HAS_BUILTIN_POPCOUNT 1

Expand Down
51 changes: 26 additions & 25 deletions immer/detail/hamts/champ.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ struct champ
using edit_t = typename MemoryPolicy::transience_t::edit;
using owner_t = typename MemoryPolicy::transience_t::owner;
using bitmap_t = typename get_bitmap_type<B>::type;
using hash_t = node_t::hash_t;

static_assert(branches<B> <= sizeof(bitmap_t) * 8, "");

Expand Down Expand Up @@ -202,7 +203,7 @@ struct champ
size_t hash_mask) const
{
auto result = std::size_t{};
if (depth < max_depth<B>) {
if (depth < max_depth<hash_t, B>) {
auto nodemap = node->nodemap();
if (nodemap) {
auto fst = node->children();
Expand All @@ -213,7 +214,7 @@ struct champ
do_check_champ(child,
depth + 1,
path_hash | (idx << (B * depth)),
(hash_mask << B) | mask<B>);
(hash_mask << B) | mask<hash_t, B>);
}
}
}
Expand Down Expand Up @@ -248,7 +249,7 @@ struct champ
// due some value being moved out of the champ when it should have not.
bool check_champ() const
{
auto r = do_check_champ(root, 0, 0, mask<B>);
auto r = do_check_champ(root, 0, 0, mask<hash_t, B>);
// assert(r == size);
return r == size;
}
Expand All @@ -258,7 +259,7 @@ struct champ
node_t* node,
count_t depth) const
{
if (depth < max_depth<B>) {
if (depth < max_depth<hash_t, B>) {
++stats.inner_node_count;
stats.inner_node_w_value_count += node->data_count() > 0;
stats.inner_node_w_child_count += node->children_count() > 0;
Expand Down Expand Up @@ -317,7 +318,7 @@ struct champ
void
for_each_chunk_traversal(const node_t* node, count_t depth, Fn&& fn) const
{
if (depth < max_depth<B>) {
if (depth < max_depth<hash_t, B>) {
auto datamap = node->datamap();
if (datamap)
fn(node->values(), node->values() + node->data_count());
Expand Down Expand Up @@ -348,7 +349,7 @@ struct champ
{
if (old_node == new_node)
return;
if (depth < max_depth<B>) {
if (depth < max_depth<hash_t, B>) {
auto old_nodemap = old_node->nodemap();
auto new_nodemap = new_node->nodemap();
auto old_datamap = old_node->datamap();
Expand Down Expand Up @@ -537,8 +538,8 @@ struct champ
{
auto node = root;
auto hash = Hash{}(k);
for (auto i = count_t{}; i < max_depth<B>; ++i) {
auto bit = bitmap_t{1u} << (hash & mask<B>);
for (auto i = count_t{}; i < max_depth<hash_t, B>; ++i) {
auto bit = bitmap_t{1u} << (hash & mask<hash_t, B>);
if (node->nodemap() & bit) {
auto offset = node->children_count(bit);
node = node->children()[offset];
Expand Down Expand Up @@ -571,7 +572,7 @@ struct champ
add_result do_add(node_t* node, T v, hash_t hash, shift_t shift) const
{
assert(node);
if (shift == max_shift<B>) {
if (shift == max_shift<hash_t, B>) {
auto fst = node->collisions();
auto lst = fst + node->collision_count();
for (; fst != lst; ++fst)
Expand All @@ -581,7 +582,7 @@ struct champ
false};
return {node_t::copy_collision_insert(node, std::move(v)), true};
} else {
auto idx = (hash & (mask<B> << shift)) >> shift;
auto idx = (hash & (mask<hash_t, B> << shift)) >> shift;
auto bit = bitmap_t{1u} << idx;
if (node->nodemap() & bit) {
auto offset = node->children_count(bit);
Expand Down Expand Up @@ -644,7 +645,7 @@ struct champ
do_add_mut(edit_t e, node_t* node, T v, hash_t hash, shift_t shift) const
{
assert(node);
if (shift == max_shift<B>) {
if (shift == max_shift<hash_t, B>) {
auto fst = node->collisions();
auto lst = fst + node->collision_count();
for (; fst != lst; ++fst)
Expand All @@ -663,7 +664,7 @@ struct champ
: node_t::copy_collision_insert(node, std::move(v));
return {node_t::owned(r, e), true, mutate};
} else {
auto idx = (hash & (mask<B> << shift)) >> shift;
auto idx = (hash & (mask<hash_t, B> << shift)) >> shift;
auto bit = bitmap_t{1u} << idx;
if (node->nodemap() & bit) {
auto offset = node->children_count(bit);
Expand Down Expand Up @@ -756,7 +757,7 @@ struct champ
update_result
do_update(node_t* node, K&& k, Fn&& fn, hash_t hash, shift_t shift) const
{
if (shift == max_shift<B>) {
if (shift == max_shift<hash_t, B>) {
auto fst = node->collisions();
auto lst = fst + node->collision_count();
for (; fst != lst; ++fst)
Expand All @@ -774,7 +775,7 @@ struct champ
std::forward<Fn>(fn)(Default{}()))),
true};
} else {
auto idx = (hash & (mask<B> << shift)) >> shift;
auto idx = (hash & (mask<hash_t, B> << shift)) >> shift;
auto bit = bitmap_t{1u} << idx;
if (node->nodemap() & bit) {
auto offset = node->children_count(bit);
Expand Down Expand Up @@ -851,7 +852,7 @@ struct champ
node_t* do_update_if_exists(
node_t* node, K&& k, Fn&& fn, hash_t hash, shift_t shift) const
{
if (shift == max_shift<B>) {
if (shift == max_shift<hash_t, B>) {
auto fst = node->collisions();
auto lst = fst + node->collision_count();
for (; fst != lst; ++fst)
Expand All @@ -864,7 +865,7 @@ struct champ
Project{}(detail::as_const(*fst)))));
return nullptr;
} else {
auto idx = (hash & (mask<B> << shift)) >> shift;
auto idx = (hash & (mask<hash_t, B> << shift)) >> shift;
auto bit = bitmap_t{1u} << idx;
if (node->nodemap() & bit) {
auto offset = node->children_count(bit);
Expand Down Expand Up @@ -929,7 +930,7 @@ struct champ
hash_t hash,
shift_t shift) const
{
if (shift == max_shift<B>) {
if (shift == max_shift<hash_t, B>) {
auto fst = node->collisions();
auto lst = fst + node->collision_count();
for (; fst != lst; ++fst)
Expand All @@ -956,7 +957,7 @@ struct champ
: node_t::copy_collision_insert(node, std::move(v));
return {node_t::owned(r, e), true, mutate};
} else {
auto idx = (hash & (mask<B> << shift)) >> shift;
auto idx = (hash & (mask<hash_t, B> << shift)) >> shift;
auto bit = bitmap_t{1u} << idx;
if (node->nodemap() & bit) {
auto offset = node->children_count(bit);
Expand Down Expand Up @@ -1068,7 +1069,7 @@ struct champ
hash_t hash,
shift_t shift) const
{
if (shift == max_shift<B>) {
if (shift == max_shift<hash_t, B>) {
auto fst = node->collisions();
auto lst = fst + node->collision_count();
for (; fst != lst; ++fst)
Expand All @@ -1090,7 +1091,7 @@ struct champ
}
return {nullptr, false};
} else {
auto idx = (hash & (mask<B> << shift)) >> shift;
auto idx = (hash & (mask<hash_t, B> << shift)) >> shift;
auto bit = bitmap_t{1u} << idx;
if (node->nodemap() & bit) {
auto offset = node->children_count(bit);
Expand Down Expand Up @@ -1204,7 +1205,7 @@ struct champ
sub_result
do_sub(node_t* node, const K& k, hash_t hash, shift_t shift) const
{
if (shift == max_shift<B>) {
if (shift == max_shift<hash_t, B>) {
auto fst = node->collisions();
auto lst = fst + node->collision_count();
for (auto cur = fst; cur != lst; ++cur)
Expand All @@ -1227,7 +1228,7 @@ struct champ
#endif
#endif
} else {
auto idx = (hash & (mask<B> << shift)) >> shift;
auto idx = (hash & (mask<hash_t, B> << shift)) >> shift;
auto bit = bitmap_t{1u} << idx;
if (node->nodemap() & bit) {
auto offset = node->children_count(bit);
Expand Down Expand Up @@ -1350,7 +1351,7 @@ struct champ
void* store) const
{
auto mutate = node->can_mutate(e);
if (shift == max_shift<B>) {
if (shift == max_shift<hash_t, B>) {
auto fst = node->collisions();
auto lst = fst + node->collision_count();
for (auto cur = fst; cur != lst; ++cur) {
Expand All @@ -1374,7 +1375,7 @@ struct champ
}
return {};
} else {
auto idx = (hash & (mask<B> << shift)) >> shift;
auto idx = (hash & (mask<hash_t, B> << shift)) >> shift;
auto bit = bitmap_t{1u} << idx;
if (node->nodemap() & bit) {
auto offset = node->children_count(bit);
Expand Down Expand Up @@ -1511,7 +1512,7 @@ struct champ
{
if (a == b)
return true;
else if (depth == max_depth<B>) {
else if (depth == max_depth<hash_t, B>) {
auto nv = a->collision_count();
return nv == b->collision_count() &&
equals_collisions<Eq>(a->collisions(), b->collisions(), nv);
Expand Down
9 changes: 5 additions & 4 deletions immer/detail/hamts/champ_iterator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct champ_iterator
{
using tree_t = champ<T, Hash, Eq, MP, B>;
using node_t = typename tree_t::node_t;
using hash_t = node_t::hash_t;

champ_iterator() = default;

Expand Down Expand Up @@ -67,7 +68,7 @@ struct champ_iterator
T* cur_;
T* end_;
count_t depth_;
node_t* const* path_[max_depth<B> + 1] = {
node_t* const* path_[max_depth<hash_t, B> + 1] = {
0,
};

Expand All @@ -79,15 +80,15 @@ struct champ_iterator

bool step_down()
{
if (depth_ < max_depth<B>) {
if (depth_ < max_depth<hash_t, B>) {
auto parent = *path_[depth_];
assert(parent);
if (parent->nodemap()) {
++depth_;
path_[depth_] = parent->children();
auto child = *path_[depth_];
assert(child);
if (depth_ < max_depth<B>) {
if (depth_ < max_depth<hash_t, B>) {
if (child->datamap()) {
cur_ = child->values();
end_ = cur_ + child->data_count();
Expand All @@ -112,7 +113,7 @@ struct champ_iterator
path_[depth_] = next;
auto child = *path_[depth_];
assert(child);
if (depth_ < max_depth<B>) {
if (depth_ < max_depth<hash_t, B>) {
if (child->datamap()) {
cur_ = child->values();
end_ = cur_ + child->data_count();
Expand Down
17 changes: 9 additions & 8 deletions immer/detail/hamts/node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ struct node
using edit_t = typename transience::edit;
using value_t = T;
using bitmap_t = typename get_bitmap_type<B>::type;
using hash_t = decltype(Hash{}(std::declval<const T&>()));

enum class kind_t
{
Expand Down Expand Up @@ -991,9 +992,9 @@ struct node
static node_t*
make_merged(shift_t shift, T v1, hash_t hash1, T v2, hash_t hash2)
{
if (shift < max_shift<B>) {
auto idx1 = hash1 & (mask<B> << shift);
auto idx2 = hash2 & (mask<B> << shift);
if (shift < max_shift<hash_t, B>) {
auto idx1 = hash1 & (mask<hash_t, B> << shift);
auto idx2 = hash2 & (mask<hash_t, B> << shift);
if (idx1 == idx2) {
auto merged = make_merged(
shift + B, std::move(v1), hash1, std::move(v2), hash2);
Expand All @@ -1020,9 +1021,9 @@ struct node
static node_t* make_merged_e(
edit_t e, shift_t shift, T v1, hash_t hash1, T v2, hash_t hash2)
{
if (shift < max_shift<B>) {
auto idx1 = hash1 & (mask<B> << shift);
auto idx2 = hash2 & (mask<B> << shift);
if (shift < max_shift<hash_t, B>) {
auto idx1 = hash1 & (mask<hash_t, B> << shift);
auto idx2 = hash2 & (mask<hash_t, B> << shift);
if (idx1 == idx2) {
auto merged = make_merged_e(
e, shift + B, std::move(v1), hash1, std::move(v2), hash2);
Expand Down Expand Up @@ -1097,7 +1098,7 @@ struct node

static void delete_deep(node_t* p, shift_t s)
{
if (s == max_depth<B>)
if (s == max_depth<hash_t, B>)
delete_collision(p);
else {
auto fst = p->children();
Expand All @@ -1111,7 +1112,7 @@ struct node

static void delete_deep_shift(node_t* p, shift_t s)
{
if (s == max_shift<B>)
if (s == max_shift<hash_t, B>)
delete_collision(p);
else {
auto fst = p->children();
Expand Down
3 changes: 2 additions & 1 deletion immer/extra/persist/detail/champ/output.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ struct output_pool_builder
void visit(const Node* node, immer::detail::hamts::count_t depth)
{
using immer::detail::hamts::max_depth;
using hash_t = Node::hash_t;

if (depth < max_depth<B>) {
if (depth < max_depth<hash_t, B>) {
visit_inner(node, depth);
} else {
visit_collision(node);
Expand Down
Loading

0 comments on commit 552d20b

Please sign in to comment.