diff --git a/immer/detail/hamts/champ.hpp b/immer/detail/hamts/champ.hpp index 64a8cb82..9a145f17 100644 --- a/immer/detail/hamts/champ.hpp +++ b/immer/detail/hamts/champ.hpp @@ -12,6 +12,8 @@ #include #include +#include +#include namespace immer { namespace detail { @@ -328,6 +330,61 @@ struct champ } } + template + bool for_each_chunk_p(Fn&& fn) const + { + struct State + { + const node_t* const* fst{}; + const node_t* const* lst{}; + }; + + std::array + 1> stack{}; + stack[0] = {&root, &root + 1}; + size_t depth = 0; + + while (true) { + auto fst = stack[depth].fst; + auto lst = stack[depth].lst; + + if (fst == lst) { + if (!depth) + return true; + + depth--; + continue; + } + + const node_t* node = *fst; + + if (depth < max_depth) { + auto datamap = node->datamap(); + if (datamap && + !fn(node->values(), node->values() + node->data_count())) { + return false; + } + + auto nodemap = node->nodemap(); + stack[depth].fst++; + + if (nodemap) { + auto childFst = node->children(); + depth++; + stack[depth].fst = childFst; + stack[depth].lst = childFst + node->children_count(); + } + continue; + } + + if (!fn(node->collisions(), + node->collisions() + node->collision_count())) { + return false; + } + --depth; + } + return true; + } + template void diff(const champ& new_champ, Differ&& differ) const { diff --git a/test/algorithm.cpp b/test/algorithm.cpp index 6a785dbd..001cfc6b 100644 --- a/test/algorithm.cpp +++ b/test/algorithm.cpp @@ -110,10 +110,9 @@ TEST_CASE("all_of") do_check(immer::vector{}); do_check(immer::flex_vector{}); do_check(immer::array{}); - // not supported - // do_check(immer::map{}); - // do_check(immer::set{}); - // do_check(immer::table{}); + do_check(immer::map{}); + do_check(immer::set{}); + do_check(immer::table{}); } TEST_CASE("update vectors") diff --git a/test/map/generic.ipp b/test/map/generic.ipp index e9b6cf58..14153c87 100644 --- a/test/map/generic.ipp +++ b/test/map/generic.ipp @@ -263,6 +263,55 @@ TEST_CASE("accumulate") } } +TEST_CASE("all_of") +{ + static const auto n = 666u; + auto v = make_test_map(n); + + static const auto all_identity = [](const auto& keyval) { + return keyval.first == keyval.second; + }; + static const auto all_less_n = [](const auto& keyval) { + return keyval.second < n; + }; + static const auto all_less_n2 = [](const auto& keyval) { + return keyval.second < n / 2; + }; + + SECTION("All identity (true)") + { + bool result = immer::all_of(v, all_identity); + CHECK(result); + } + + SECTION("Empty (true)") + { + bool result = immer::all_of(make_test_map(0), all_identity); + CHECK(result); + } + + SECTION("All less n/2 (false)") + { + bool result = immer::all_of(v, all_less_n2); + CHECK(!result); + } + + SECTION("All less n w/ collisions (true)") + { + auto vals = make_values_with_collisions(n); + auto s = make_test_map(vals); + bool result = immer::all_of(v, all_less_n); + CHECK(result); + } + SECTION("All less n/2 w/ collisions (false)") + { + auto vals = make_values_with_collisions(n); + auto s = make_test_map(vals); + bool result = immer::all_of(v, all_less_n2); + CHECK(!result); + } +} + TEST_CASE("update a lot") { auto v = make_test_map(666u);