Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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];
}
}
}