Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

store extra information in iterator needed to find base of allocation #190

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
44 changes: 42 additions & 2 deletions immer/detail/hamts/champ_iterator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,32 @@ namespace immer {
namespace detail {
namespace hamts {

template <bool Enabled, bits_t B>
struct relocation_info_t
{
void reset() {}
void increment() {}
void step_right(count_t) {}
void step_down(count_t) {}
};

template <bits_t B>
struct relocation_info_t<true, B>
{
count_t cur_off_;
std::uint8_t path_off_[max_depth<B>] = {
0,
};

void reset() { cur_off_ = 0; }

void increment() { cur_off_++; }

void step_right(count_t depth) { ++path_off_[depth - 1]; }

void step_down(count_t depth) { path_off_[depth - 1] = 0; }
};

template <typename T, typename Hash, typename Eq, typename MP, bits_t B>
struct champ_iterator
: iterator_facade<champ_iterator<T, Hash, Eq, MP, B>,
Expand All @@ -32,6 +58,7 @@ struct champ_iterator

champ_iterator(const tree_t& v)
: depth_{0}
, relocation_info_{}
{
if (v.root->datamap()) {
cur_ = v.root->values();
Expand All @@ -47,6 +74,7 @@ struct champ_iterator
: cur_{nullptr}
, end_{nullptr}
, depth_{0}
, relocation_info_{}
{
path_[0] = &v.root;
}
Expand All @@ -55,10 +83,13 @@ struct champ_iterator
: cur_{other.cur_}
, end_{other.end_}
, depth_{other.depth_}
, relocation_info_{other.relocation_info_}
{
std::copy(other.path_, other.path_ + depth_ + 1, path_);
}

auto relocation_info() const { return relocation_info_; }

private:
friend iterator_core_access;

Expand All @@ -68,10 +99,12 @@ struct champ_iterator
node_t* const* path_[max_depth<B> + 1] = {
0,
};
relocation_info_t<MP::track_base_offset_of_pointers, B> relocation_info_;

void increment()
{
++cur_;
relocation_info_.increment();
ensure_valid_();
}

Expand All @@ -83,16 +116,19 @@ struct champ_iterator
if (parent->nodemap()) {
++depth_;
path_[depth_] = parent->children();
auto child = *path_[depth_];
relocation_info_.step_down(depth_);
auto child = *path_[depth_];
assert(child);
if (depth_ < max_depth<B>) {
if (child->datamap()) {
cur_ = child->values();
end_ = cur_ + child->data_count();
relocation_info_.reset();
}
} else {
cur_ = child->collisions();
end_ = cur_ + child->collision_count();
relocation_info_.reset();
}
return true;
}
Expand All @@ -108,16 +144,19 @@ struct champ_iterator
auto next = path_[depth_] + 1;
if (next < last) {
path_[depth_] = next;
auto child = *path_[depth_];
relocation_info_.step_right(depth_);
auto child = *path_[depth_];
assert(child);
if (depth_ < max_depth<B>) {
if (child->datamap()) {
cur_ = child->values();
end_ = cur_ + child->data_count();
relocation_info_.reset();
}
} else {
cur_ = child->collisions();
end_ = cur_ + child->collision_count();
relocation_info_.reset();
}
return true;
}
Expand All @@ -136,6 +175,7 @@ struct champ_iterator
// end of sequence
assert(depth_ == 0);
cur_ = end_ = nullptr;
relocation_info_.reset();
return;
}
}
Expand Down
6 changes: 5 additions & 1 deletion immer/memory_policy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ template <typename HeapPolicy,
bool PreferFewerBiggerObjects =
get_prefer_fewer_bigger_objects_v<HeapPolicy>,
bool UseTransientRValues =
get_use_transient_rvalues_v<RefcountPolicy>>
get_use_transient_rvalues_v<RefcountPolicy>,
bool TrackBaseOffsetOfPointers = false>
struct memory_policy
{
using heap = HeapPolicy;
Expand All @@ -103,6 +104,9 @@ struct memory_policy

static constexpr bool use_transient_rvalues = UseTransientRValues;

static constexpr bool track_base_offset_of_pointers =
TrackBaseOffsetOfPointers;

using transience_t = typename transience::template apply<heap>::type;
};

Expand Down
53 changes: 53 additions & 0 deletions test/set/relocation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// immer: immutable data structures for C++
// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
//
// This software is distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
//

#include <catch.hpp>
#include <immer/set.hpp>

using relocation_memory = immer::memory_policy<immer::default_heap_policy,
immer::default_refcount_policy,
immer::default_lock_policy,
immer::no_transience_policy,
true,
false,
true>;

template <typename T,
typename Hash = std::hash<T>,
typename Eq = std::equal_to<T>>
using test_set_t = immer::set<T, Hash, Eq, relocation_memory, 3u>;

TEST_CASE("relocation info")
{
auto v = test_set_t<unsigned>{};
for (auto i = 0u; i < 512u; ++i)
v = v.insert(i);
auto iter = v.begin();
test_set_t<unsigned>::iterator::node_t *node = v.impl().root,
*parent = nullptr;
unsigned depth = 0;

while (node->nodemap()) {
parent = node;
node = node->children()[0];
++depth;
}
CHECK(depth >= 2);
for (auto i = 0u; i < parent->children_count(); ++i) {
for (auto j = 0u; j < node->data_count(); ++j) {
CHECK(iter.relocation_info().cur_off_ == j);
CHECK(iter.relocation_info().path_off_[depth] == 0);
CHECK(iter.relocation_info().path_off_[depth - 1] == i);
CHECK(iter.relocation_info().path_off_[depth - 2] == 0);
++iter;
}
if (i + 1 < parent->children_count()) {
node = parent->children()[i + 1];
}
}
}