From 6de86001e9f5b08f7601f96f87cbaa03223e95c4 Mon Sep 17 00:00:00 2001 From: Alex Shabalin Date: Mon, 26 Aug 2024 14:44:51 +0200 Subject: [PATCH] More compact maps format: pairs are lists of 2 elements --- doc/persist.rst | 8 +- .../persist/detail/cereal/compact_map.hpp | 83 +++ immer/extra/persist/detail/rbts/pool.hpp | 11 +- test/extra/persist/test_for_docs.cpp | 144 ++--- test/extra/persist/test_special_pool.cpp | 84 ++- test/extra/persist/test_special_pool_auto.cpp | 17 +- test/extra/persist/test_vectors.cpp | 588 +++++------------- 7 files changed, 356 insertions(+), 579 deletions(-) create mode 100644 immer/extra/persist/detail/cereal/compact_map.hpp diff --git a/doc/persist.rst b/doc/persist.rst index 13b88fa9..b6676d27 100644 --- a/doc/persist.rst +++ b/doc/persist.rst @@ -222,7 +222,7 @@ the ``new_value`` and inspect the JSON: :start-after: start-save-new_value :end-before: end-save-new_value -And indeed, we can see in the JSON that the node ``{"key": 2, "value": [10, 20]}`` is reused in both vectors. +And indeed, we can see in the JSON that the node ``[2, [10, 20]]`` is reused in both vectors. Transformation into a different type @@ -270,7 +270,7 @@ And serialize it with pools: :start-after: start-save-new_value-str :end-before: end-save-new_value-str -In the resulting JSON we can confirm that the node ``{"key": 2, "value": ["_1_", "_2_"]}`` is reused for both vectors. +In the resulting JSON we can confirm that the node ``[2, ["_1_", "_2_"]]`` is reused for both vectors. .. _transforming-hash-based-containers: @@ -459,7 +459,7 @@ The resulting JSON looks like: :start-after: start-nested-value-json :end-before: end-nested-value-json -Looking at the JSON we can confirm that the node ``{"key": 2, "value": [1, 2]}`` is reused. +Looking at the JSON we can confirm that the node ``[2, [1, 2]]`` is reused. Let's define a ``conversion_map`` like this: .. literalinclude:: ../test/extra/persist/test_for_docs.cpp @@ -497,7 +497,7 @@ And we can serialize it again to confirm that the structural sharing of the nest :start-after: start-verify-structural-sharing-of-nested :end-before: end-verify-structural-sharing-of-nested -We can see that the ``{"key": 2, "value": ["_1_", "_2_"]}`` node is still being reused in the two vectors. +We can see that the ``[2, ["_1_", "_2_"]]`` node is still being reused in the two vectors. Policy diff --git a/immer/extra/persist/detail/cereal/compact_map.hpp b/immer/extra/persist/detail/cereal/compact_map.hpp new file mode 100644 index 00000000..6a63d4a6 --- /dev/null +++ b/immer/extra/persist/detail/cereal/compact_map.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include + +#include + +namespace immer::persist::detail { + +template +struct compact_pair +{ + K key; + T value; +}; + +template +struct compact_map +{ + immer::map& map; +}; + +template +compact_map make_compact_map(immer::map& map) +{ + return compact_map{map}; +} + +} // namespace immer::persist::detail + +namespace cereal { + +template +void CEREAL_LOAD_FUNCTION_NAME(Archive& ar, + immer::persist::detail::compact_pair& m) +{ + size_type size; + ar(make_size_tag(size)); + if (size != 2) { + throw Exception{"A pair must be a list of 2 elements"}; + } + + ar(m.key); + ar(m.value); +} + +template +void CEREAL_SAVE_FUNCTION_NAME( + Archive& ar, const immer::persist::detail::compact_pair& m) +{ + ar(make_size_tag(static_cast(2))); + ar(m.key); + ar(m.value); +} + +template +void CEREAL_LOAD_FUNCTION_NAME(Archive& ar, + immer::persist::detail::compact_map& m) +{ + size_type size; + ar(make_size_tag(size)); + + for (auto i = size_type{}; i < size; ++i) { + auto pair = immer::persist::detail::compact_pair{}; + ar(pair); + + m.map = + std::move(m.map).set(std::move(pair.key), std::move(pair.value)); + } + if (size != m.map.size()) + throw Exception{"duplicate ids?"}; +} + +template +void CEREAL_SAVE_FUNCTION_NAME( + Archive& ar, const immer::persist::detail::compact_map& m) +{ + ar(make_size_tag(static_cast(m.map.size()))); + for (auto&& v : m.map) { + ar(immer::persist::detail::compact_pair{v.first, v.second}); + } +} + +} // namespace cereal diff --git a/immer/extra/persist/detail/rbts/pool.hpp b/immer/extra/persist/detail/rbts/pool.hpp index e827168f..829d7adc 100644 --- a/immer/extra/persist/detail/rbts/pool.hpp +++ b/immer/extra/persist/detail/rbts/pool.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -72,10 +73,12 @@ struct output_pool template void save(Archive& ar) const { + auto leaves_copy = leaves; + auto inners_copy = inners; ar(CEREAL_NVP(B), CEREAL_NVP(BL), - CEREAL_NVP(leaves), - CEREAL_NVP(inners), + cereal::make_nvp("leaves", detail::make_compact_map(leaves_copy)), + cereal::make_nvp("inners", detail::make_compact_map(inners_copy)), CEREAL_NVP(vectors)); } }; @@ -118,8 +121,8 @@ struct input_pool auto& BL = bits_leaf; ar(CEREAL_NVP(B), CEREAL_NVP(BL), - CEREAL_NVP(leaves), - CEREAL_NVP(inners), + cereal::make_nvp("leaves", detail::make_compact_map(leaves)), + cereal::make_nvp("inners", detail::make_compact_map(inners)), CEREAL_NVP(vectors)); } diff --git a/test/extra/persist/test_for_docs.cpp b/test/extra/persist/test_for_docs.cpp index 84b0004e..6a0cd1ec 100644 --- a/test/extra/persist/test_for_docs.cpp +++ b/test/extra/persist/test_for_docs.cpp @@ -118,20 +118,15 @@ TEST_CASE("Docs save with immer-persist", "[docs]") "B": 5, "BL": 1, "inners": [ - {"key": 0, "value": {"children": [2], "relaxed": false}}, - {"key": 3, "value": {"children": [2, 5], "relaxed": false}} - ], - "leaves": [ - {"key": 1, "value": [3]}, - {"key": 2, "value": [1, 2]}, - {"key": 4, "value": [5, 6]}, - {"key": 5, "value": [3, 4]} + [0, {"children": [2], "relaxed": false}], + [3, {"children": [2, 5], "relaxed": false}] ], + "leaves": [[1, [3]], [2, [1, 2]], [4, [5, 6]], [5, [3, 4]]], "vectors": [{"root": 0, "tail": 1}, {"root": 3, "tail": 4}] } } } - )"); + )"); // include:intro/end-persist-json REQUIRE(json_t::parse(str) == expected_json); @@ -227,29 +222,20 @@ TEST_CASE("Custom policy", "[docs]") "vector_of_ints": { "B": 5, "BL": 1, - "leaves": [ - {"key": 1, "value": [3]}, - {"key": 2, "value": [1, 2]}, - {"key": 4, "value": [5, 6]}, - {"key": 5, "value": [3, 4]} - ], + "leaves": [[1, [3]], [2, [1, 2]], [4, [5, 6]], [5, [3, 4]]], "inners": [ - {"key": 0, "value": {"children": [2], "relaxed": false}}, - {"key": 3, "value": {"children": [2, 5], "relaxed": false}} + [0, {"children": [2], "relaxed": false}], + [3, {"children": [2, 5], "relaxed": false}] ], "vectors": [{"root": 0, "tail": 1}, {"root": 3, "tail": 4}] }, "vector_of_strings": { "B": 5, "BL": 1, - "leaves": [ - {"key": 1, "value": ["one", "two"]}, - {"key": 3, "value": ["five"]}, - {"key": 4, "value": ["three", "four"]} - ], + "leaves": [[1, ["one", "two"]], [3, ["five"]], [4, ["three", "four"]]], "inners": [ - {"key": 0, "value": {"children": [], "relaxed": false}}, - {"key": 2, "value": {"children": [1, 4], "relaxed": false}} + [0, {"children": [], "relaxed": false}], + [2, {"children": [1, 4], "relaxed": false}] ], "vectors": [{"root": 0, "tail": 1}, {"root": 2, "tail": 3}] } @@ -330,27 +316,22 @@ TEST_CASE("Transformations", "[docs]") const auto str = immer::persist::cereal_save_with_pools(new_value, policy); const auto expected_json = json_t::parse(R"( - { - "pools": { - "ints": { - "B": 5, - "BL": 1, - "inners": [ - {"key": 0, "value": {"children": [2], "relaxed": false}}, - {"key": 3, "value": {"children": [2, 5], "relaxed": false}} - ], - "leaves": [ - {"key": 1, "value": [30]}, - {"key": 2, "value": [10, 20]}, - {"key": 4, "value": [50, 60]}, - {"key": 5, "value": [30, 40]} - ], - "vectors": [{"root": 0, "tail": 1}, {"root": 3, "tail": 4}] - } - }, - "value0": {"ints": 0, "ints2": 1} - } - )"); +{ + "pools": { + "ints": { + "B": 5, + "BL": 1, + "inners": [ + [0, {"children": [2], "relaxed": false}], + [3, {"children": [2, 5], "relaxed": false}] + ], + "leaves": [[1, [30]], [2, [10, 20]], [4, [50, 60]], [5, [30, 40]]], + "vectors": [{"root": 0, "tail": 1}, {"root": 3, "tail": 4}] + } + }, + "value0": {"ints": 0, "ints2": 1} +} + )"); REQUIRE(json_t::parse(str) == expected_json); // include:end-save-new_value } @@ -386,27 +367,27 @@ TEST_CASE("Transformations", "[docs]") const auto str = immer::persist::cereal_save_with_pools(new_value, policy); const auto expected_json = json_t::parse(R"( - { - "pools": { - "str": { - "B": 5, - "BL": 1, - "inners": [ - {"key": 0, "value": {"children": [2], "relaxed": false}}, - {"key": 3, "value": {"children": [2, 5], "relaxed": false}} - ], - "leaves": [ - {"key": 1, "value": ["_3_"]}, - {"key": 2, "value": ["_1_", "_2_"]}, - {"key": 4, "value": ["_5_", "_6_"]}, - {"key": 5, "value": ["_3_", "_4_"]} - ], - "vectors": [{"root": 0, "tail": 1}, {"root": 3, "tail": 4}] - } - }, - "value0": {"str": 0, "str2": 1} - } - )"); +{ + "pools": { + "str": { + "B": 5, + "BL": 1, + "inners": [ + [0, {"children": [2], "relaxed": false}], + [3, {"children": [2, 5], "relaxed": false}] + ], + "leaves": [ + [1, ["_3_"]], + [2, ["_1_", "_2_"]], + [4, ["_5_", "_6_"]], + [5, ["_3_", "_4_"]] + ], + "vectors": [{"root": 0, "tail": 1}, {"root": 3, "tail": 4}] + } + }, + "value0": {"str": 0, "str2": 1} +} + )"); REQUIRE(json_t::parse(str) == expected_json); // include:end-save-new_value-str } @@ -698,22 +679,17 @@ TEST_CASE("Transform nested containers", "[docs]") "B": 5, "BL": 1, "inners": [ - {"key": 0, "value": {"children": [2], "relaxed": false}}, - {"key": 3, "value": {"children": [2, 5], "relaxed": false}} - ], - "leaves": [ - {"key": 1, "value": [3]}, - {"key": 2, "value": [1, 2]}, - {"key": 4, "value": [5, 6]}, - {"key": 5, "value": [3, 4]} + [0, {"children": [2], "relaxed": false}], + [3, {"children": [2, 5], "relaxed": false}] ], + "leaves": [[1, [3]], [2, [1, 2]], [4, [5, 6]], [5, [3, 4]]], "vectors": [{"root": 0, "tail": 1}, {"root": 3, "tail": 4}] }, "nested": { "B": 5, "BL": 3, - "inners": [{"key": 0, "value": {"children": [], "relaxed": false}}], - "leaves": [{"key": 1, "value": [{"ints": 0}, {"ints": 1}]}], + "inners": [[0, {"children": [], "relaxed": false}]], + "leaves": [[1, [{"ints": 0}, {"ints": 1}]]], "vectors": [{"root": 0, "tail": 1}] } }, @@ -773,22 +749,22 @@ TEST_CASE("Transform nested containers", "[docs]") "nested": { "B": 5, "BL": 3, - "inners": [{"key": 0, "value": {"children": [], "relaxed": false}}], - "leaves": [{"key": 1, "value": [{"str": 0}, {"str": 1}]}], + "inners": [[0, {"children": [], "relaxed": false}]], + "leaves": [[1, [{"str": 0}, {"str": 1}]]], "vectors": [{"root": 0, "tail": 1}] }, "str": { "B": 5, "BL": 1, "inners": [ - {"key": 0, "value": {"children": [2], "relaxed": false}}, - {"key": 3, "value": {"children": [2, 5], "relaxed": false}} + [0, {"children": [2], "relaxed": false}], + [3, {"children": [2, 5], "relaxed": false}] ], "leaves": [ - {"key": 1, "value": ["_3_"]}, - {"key": 2, "value": ["_1_", "_2_"]}, - {"key": 4, "value": ["_5_", "_6_"]}, - {"key": 5, "value": ["_3_", "_4_"]} + [1, ["_3_"]], + [2, ["_1_", "_2_"]], + [4, ["_5_", "_6_"]], + [5, ["_3_", "_4_"]] ], "vectors": [{"root": 0, "tail": 1}, {"root": 3, "tail": 4}] } diff --git a/test/extra/persist/test_special_pool.cpp b/test/extra/persist/test_special_pool.cpp index 07640358..8438fb7f 100644 --- a/test/extra/persist/test_special_pool.cpp +++ b/test/extra/persist/test_special_pool.cpp @@ -429,7 +429,8 @@ TEST_CASE("Special pool loads empty test_data") // value); // REQUIRE(json_pool_str_ == ""); - const auto json_pool_str = R"({ + const auto json_pool_str = R"( +{ "value0": { "ints": 0, "strings": 0, @@ -445,51 +446,70 @@ TEST_CASE("Special pool loads empty test_data") "ints": { "B": 5, "BL": 1, - "leaves": [{"key": 1, "value": []}], - "inners": [{"key": 0, "value": {"children": [], "relaxed": false}}], + "leaves": [[1, []]], + "inners": [[0, {"children": [], "relaxed": false}]], "vectors": [{"root": 0, "tail": 1}] }, "strings": { "B": 5, "BL": 1, - "leaves": [{"key": 1, "value": []}], - "inners": [{"key": 0, "value": {"children": [], "relaxed": false}}], + "leaves": [[1, []]], + "inners": [[0, {"children": [], "relaxed": false}]], "vectors": [{"root": 0, "tail": 1}] }, "flex_ints": { "B": 5, "BL": 1, - "leaves": [{"key": 1, "value": []}], - "inners": [{"key": 0, "value": {"children": [], "relaxed": false}}], + "leaves": [[1, []]], + "inners": [[0, {"children": [], "relaxed": false}]], "vectors": [{"root": 0, "tail": 1}] }, "int_string_map": [ - {"values": [], "children": [], "nodemap": 0, "datamap": 0, "collisions": false} + { + "values": [], + "children": [], + "nodemap": 0, + "datamap": 0, + "collisions": false + } ], "metas": { "B": 5, "BL": 1, - "leaves": [{"key": 1, "value": []}], - "inners": [{"key": 0, "value": {"children": [], "relaxed": false}}], + "leaves": [[1, []]], + "inners": [[0, {"children": [], "relaxed": false}]], "vectors": [{"root": 0, "tail": 1}] }, "meta_metas": { "B": 5, "BL": 1, - "leaves": [{"key": 1, "value": []}], - "inners": [{"key": 0, "value": {"children": [], "relaxed": false}}], + "leaves": [[1, []]], + "inners": [[0, {"children": [], "relaxed": false}]], "vectors": [{"root": 0, "tail": 1}] }, "table_test_value": [], "int_meta_map": [ - {"values": [], "children": [], "nodemap": 0, "datamap": 0, "collisions": false} + { + "values": [], + "children": [], + "nodemap": 0, + "datamap": 0, + "collisions": false + } ], "int_vector_map": [ - {"values": [], "children": [], "nodemap": 0, "datamap": 0, "collisions": false} + { + "values": [], + "children": [], + "nodemap": 0, + "datamap": 0, + "collisions": false + } ], "string_box": [""] } -})"; +} + )"; { auto loaded = immer::persist::cereal_load_with_pools< @@ -507,7 +527,8 @@ TEST_CASE("Special pool throws cereal::Exception") // immer::persist::cereal_save_with_pools(value); // REQUIRE(json_pool_str == ""); - const auto json_pool_str = R"({ + const auto json_pool_str = R"( +{ "value0": { "ints": 99, "strings": 0, @@ -520,39 +541,45 @@ TEST_CASE("Special pool throws cereal::Exception") "ints": { "B": 5, "BL": 1, - "leaves": [{"key": 1, "value": []}], - "inners": [{"key": 0, "value": {"children": [], "relaxed": false}}], + "leaves": [[1, []]], + "inners": [[0, {"children": [], "relaxed": false}]], "vectors": [{"root": 0, "tail": 1}] }, "strings": { "B": 5, "BL": 1, - "leaves": [{"key": 1, "value": []}], - "inners": [{"key": 0, "value": {"children": [], "relaxed": false}}], + "leaves": [[1, []]], + "inners": [[0, {"children": [], "relaxed": false}]], "vectors": [{"root": 0, "tail": 1}] }, "flex_ints": { "B": 5, "BL": 1, - "leaves": [{"key": 1, "value": []}], - "inners": [{"key": 0, "value": {"children": [], "relaxed": false}}], + "leaves": [[1, []]], + "inners": [[0, {"children": [], "relaxed": false}]], "vectors": [{"root": 0, "tail": 1}] }, "int_string_map": [ - {"values": [], "children": [], "nodemap": 0, "datamap": 0, "collisions": false} + { + "values": [], + "children": [], + "nodemap": 0, + "datamap": 0, + "collisions": false + } ], "metas": { "B": 5, "BL": 1, - "leaves": [{"key": 1, "value": []}], - "inners": [{"key": 0, "value": {"children": [], "relaxed": false}}], + "leaves": [[1, []]], + "inners": [[0, {"children": [], "relaxed": false}]], "vectors": [{"root": 0, "tail": 1}] }, "meta_metas": { "B": 5, "BL": 1, - "leaves": [{"key": 1, "value": []}], - "inners": [{"key": 0, "value": {"children": [], "relaxed": false}}], + "leaves": [[1, []]], + "inners": [[0, {"children": [], "relaxed": false}]], "vectors": [{"root": 0, "tail": 1}] }, "table_test_value": [], @@ -560,7 +587,8 @@ TEST_CASE("Special pool throws cereal::Exception") "int_vector_map": [], "string_box": [] } -})"; +} + )"; const auto call = [&] { return immer::persist::cereal_load_with_pools( diff --git a/test/extra/persist/test_special_pool_auto.cpp b/test/extra/persist/test_special_pool_auto.cpp index 20324d52..400786de 100644 --- a/test/extra/persist/test_special_pool_auto.cpp +++ b/test/extra/persist/test_special_pool_auto.cpp @@ -497,21 +497,15 @@ TEST_CASE("Test loading broken table") "ones": { "B": 5, "BL": 1, - "leaves": [ - {"key": 1, "value": []}, - {"key": 2, "value": [{"twos": 1, "twos_table": 1}]} - ], - "inners": [{"key": 0, "value": {"children": [], "relaxed": false}}], + "leaves": [[1, []], [2, [{"twos": 1, "twos_table": 1}]]], + "inners": [[0, {"children": [], "relaxed": false}]], "vectors": [{"root": 0, "tail": 1}, {"root": 0, "tail": 2}] }, "twos": { "B": 5, "BL": 1, - "leaves": [ - {"key": 1, "value": [{"two": 0}, {"two": 1}]}, - {"key": 2, "value": []} - ], - "inners": [{"key": 0, "value": {"children": [], "relaxed": false}}], + "leaves": [[1, [{"two": 0}, {"two": 1}]], [2, []]], + "inners": [[0, {"children": [], "relaxed": false}]], "vectors": [{"root": 0, "tail": 1}, {"root": 0, "tail": 2}] }, "twos_table": [ @@ -531,7 +525,8 @@ TEST_CASE("Test loading broken table") } ] } -})"; +} + )"; using json_t = nlohmann::json; auto json = json_t::parse(expected_json_str); diff --git a/test/extra/persist/test_vectors.cpp b/test/extra/persist/test_vectors.cpp index 4496c8ee..a732dabd 100644 --- a/test/extra/persist/test_vectors.cpp +++ b/test/extra/persist/test_vectors.cpp @@ -480,276 +480,60 @@ TEST_CASE("Test saving and loading flex vectors of different lengths", "[slow]") TEST_CASE("A loop with 2 nodes") { - const auto json = std::string{R"({ + const auto json = std::string{R"( +{ "value0": { "B": 5, "BL": 1, "leaves": [ - { - "key": 32, - "value": [ - 58, - 59 - ] - }, - { - "key": 34, - "value": [ - 62, - 63 - ] - }, - { - "key": 3, - "value": [ - 0, - 1 - ] - }, - { - "key": 5, - "value": [ - 4, - 5 - ] - }, - { - "key": 6, - "value": [ - 6, - 7 - ] - }, - { - "key": 7, - "value": [ - 8, - 9 - ] - }, - { - "key": 8, - "value": [ - 10, - 11 - ] - }, - { - "key": 9, - "value": [ - 12, - 13 - ] - }, - { - "key": 10, - "value": [ - 14, - 15 - ] - }, - { - "key": 11, - "value": [ - 16, - 17 - ] - }, - { - "key": 12, - "value": [ - 18, - 19 - ] - }, - { - "key": 13, - "value": [ - 20, - 21 - ] - }, - { - "key": 14, - "value": [ - 22, - 23 - ] - }, - { - "key": 15, - "value": [ - 24, - 25 - ] - }, - { - "key": 16, - "value": [ - 26, - 27 - ] - }, - { - "key": 17, - "value": [ - 28, - 29 - ] - }, - { - "key": 18, - "value": [ - 30, - 31 - ] - }, - { - "key": 19, - "value": [ - 32, - 33 - ] - }, - { - "key": 20, - "value": [ - 34, - 35 - ] - }, - { - "key": 21, - "value": [ - 36, - 37 - ] - }, - { - "key": 22, - "value": [ - 38, - 39 - ] - }, - { - "key": 23, - "value": [ - 40, - 41 - ] - }, - { - "key": 24, - "value": [ - 42, - 43 - ] - }, - { - "key": 25, - "value": [ - 44, - 45 - ] - }, - { - "key": 26, - "value": [ - 46, - 47 - ] - }, - { - "key": 27, - "value": [ - 48, - 49 - ] - }, - { - "key": 28, - "value": [ - 50, - 51 - ] - }, - { - "key": 29, - "value": [ - 52, - 53 - ] - }, - { - "key": 30, - "value": [ - 54, - 55 - ] - }, - { - "key": 31, - "value": [ - 56, - 57 - ] - }, - { - "key": 1, - "value": [ - 66 - ] - }, - { - "key": 33, - "value": [ - 60, - 61 - ] - }, - { - "key": 4, - "value": [ - 2, - 3 - ] - }, - { - "key": 36, - "value": [ - 64, - 65 - ] - } + [32, [58, 59]], + [34, [62, 63]], + [3, [0, 1]], + [5, [4, 5]], + [6, [6, 7]], + [7, [8, 9]], + [8, [10, 11]], + [9, [12, 13]], + [10, [14, 15]], + [11, [16, 17]], + [12, [18, 19]], + [13, [20, 21]], + [14, [22, 23]], + [15, [24, 25]], + [16, [26, 27]], + [17, [28, 29]], + [18, [30, 31]], + [19, [32, 33]], + [20, [34, 35]], + [21, [36, 37]], + [22, [38, 39]], + [23, [40, 41]], + [24, [42, 43]], + [25, [44, 45]], + [26, [46, 47]], + [27, [48, 49]], + [28, [50, 51]], + [29, [52, 53]], + [30, [54, 55]], + [31, [56, 57]], + [1, [66]], + [33, [60, 61]], + [4, [2, 3]], + [36, [64, 65]] ], "inners": [ - { - "key": 0, - "value": { - "children": [ - 2, - 35 - ], - "relaxed": false - } - }, - { - "key": 35, - "value": { - "children": [ - 36, 0 - ], - "relaxed": false - } - }, - { - "key": 2, - "value": { - "children": [ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34 ], - "relaxed": false - } - } + [0, { + "children": [2, 35], + "relaxed": false + }], + [35, { + "children": [36, 0], + "relaxed": false + }], + [2, { + "children": [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], + "relaxed": false + }] ], "vectors": [ { @@ -863,32 +647,17 @@ TEST_CASE("Test modifying vector nodes") data["value0"]["B"] = 5; data["value0"]["BL"] = 1; data["value0"]["leaves"] = { - { - {"key", 1}, - {"value", {6}}, - }, - { - {"key", 2}, - {"value", {0, 1}}, - }, - { - {"key", 3}, - {"value", {2, 3}}, - }, - { - {"key", 4}, - {"value", {4, 5}}, - }, + {1, {6}}, + {2, {0, 1}}, + {3, {2, 3}}, + {4, {4, 5}}, }; data["value0"]["inners"] = { { - {"key", 0}, + 0, { - "value", - { - {"children", {2, 3, 4}}, - {"relaxed", false}, - }, + {"children", {2, 3, 4}}, + {"relaxed", false}, }, }, }; @@ -945,9 +714,9 @@ TEST_CASE("Test modifying vector nodes") SECTION("A leaf with too few elements") { auto& item = data["value0"]["leaves"][2]; - REQUIRE(item["key"] == 3); + REQUIRE(item[0] == 3); // Leaf #3 should have two elements, but it has only one. - item["value"] = {2}; + item[1] = {2}; REQUIRE_THROWS_AS(load_vec(data.dump(), 0), immer::persist::rbts::vector_corrupted_exception); } @@ -955,23 +724,23 @@ TEST_CASE("Test modifying vector nodes") SECTION("Mess with the tail") { auto& item = data["value0"]["leaves"][0]; - REQUIRE(item["key"] == 1); + REQUIRE(item[0] == 1); SECTION("Add to the tail") { - item["value"] = {6, 7}; + item[1] = {6, 7}; const auto vec = test::vector_one{0, 1, 2, 3, 4, 5, 6, 7}; REQUIRE(load_vec(data.dump(), 0) == vec); } SECTION("Remove from the tail") { - item["value"] = json_t::array(); + item[1] = json_t::array(); REQUIRE_THROWS_AS(load_vec(data.dump(), 0), immer::persist::rbts::vector_corrupted_exception); } SECTION("Add too many elements") { // Three elements can't be in a leaf - item["value"] = {6, 7, 8}; + item[1] = {6, 7, 8}; REQUIRE_THROWS_AS(load_vec(data.dump(), 0), immer::persist::invalid_children_count); } @@ -980,34 +749,34 @@ TEST_CASE("Test modifying vector nodes") SECTION("Modify children") { auto& item = data["value0"]["inners"][0]; - REQUIRE(item["key"] == 0); + REQUIRE(item[0] == 0); SECTION("Add too many") { - item["value"]["children"] = std::vector(33, 2); + item[1]["children"] = std::vector(33, 2); REQUIRE_THROWS_AS(load_vec(data.dump(), 0), immer::persist::invalid_children_count); } SECTION("Remove one") { - item["value"]["children"] = {2, 4}; - const auto vec = test::vector_one{0, 1, 4, 5, 6}; + item[1]["children"] = {2, 4}; + const auto vec = test::vector_one{0, 1, 4, 5, 6}; REQUIRE(load_vec(data.dump(), 0) == vec); } SECTION("Unknown child") { - item["value"]["children"] = {2, 4, 9}; + item[1]["children"] = {2, 4, 9}; REQUIRE_THROWS_AS(load_vec(data.dump(), 0), immer::persist::invalid_node_id); } SECTION("Node has itself as a child") { - item["value"]["children"] = {2, 0, 4}; + item[1]["children"] = {2, 0, 4}; REQUIRE_THROWS_AS(load_vec(data.dump(), 0), immer::persist::pool_has_cycles); } SECTION("Strict vector can not have relaxed nodes") { - item["value"]["relaxed"] = true; + item[1]["relaxed"] = true; REQUIRE_THROWS_AS( load_vec(data.dump(), 0), immer::persist::rbts::relaxed_node_not_allowed_exception); @@ -1021,48 +790,15 @@ TEST_CASE("Test modifying flex vector nodes") data["value0"]["B"] = 5; data["value0"]["BL"] = 1; data["value0"]["leaves"] = { - { - {"key", 1}, - {"value", {6, 99}}, - }, - { - {"key", 2}, - {"value", {0, 1}}, - }, - { - {"key", 3}, - {"value", {2, 3}}, - }, - { - {"key", 4}, - {"value", {4, 5}}, - }, - { - {"key", 5}, - {"value", {6}}, - }, + {1, {6, 99}}, + {2, {0, 1}}, + {3, {2, 3}}, + {4, {4, 5}}, + {5, {6}}, }; data["value0"]["inners"] = { - { - {"key", 0}, - { - "value", - { - {"children", {2, 3, 4, 5, 2, 3, 4}}, - {"relaxed", true}, - }, - }, - }, - { - {"key", 902}, - { - "value", - { - {"children", {2, 2, 3, 4}}, - {"relaxed", true}, - }, - }, - }, + {0, {{"children", {2, 3, 4, 5, 2, 3, 4}}, {"relaxed", true}}}, + {902, {{"children", {2, 2, 3, 4}}, {"relaxed", true}}}, }; data["value0"]["vectors"] = { { @@ -1091,10 +827,10 @@ TEST_CASE("Test modifying flex vector nodes") SECTION("Modify starting leaf") { auto& item = data["value0"]["leaves"][1]; - REQUIRE(item["key"] == 2); + REQUIRE(item[0] == 2); SECTION("One element") { - item["value"] = {0}; + item[1] = {0}; const auto vec_234 = test::flex_vector_one{0, 2, 3, 4, 5}; const auto leaf_1 = test::flex_vector_one{6, 99}; const auto leaf_5 = test::flex_vector_one{6}; @@ -1105,7 +841,7 @@ TEST_CASE("Test modifying flex vector nodes") // Empty starting leaf triggers a separate branch in the code, actually. SECTION("Empty leaf") { - item["value"] = json_t::array(); + item[1] = json_t::array(); const auto vec_234 = test::flex_vector_one{2, 3, 4, 5}; const auto leaf_1 = test::flex_vector_one{6, 99}; const auto leaf_5 = test::flex_vector_one{6}; @@ -1116,10 +852,10 @@ TEST_CASE("Test modifying flex vector nodes") SECTION("Modify second leaf") { auto& item = data["value0"]["leaves"][2]; - REQUIRE(item["key"] == 3); + REQUIRE(item[0] == 3); SECTION("One element") { - item["value"] = {2}; + item[1] = {2}; const auto vec_234 = test::flex_vector_one{0, 1, 2, 4, 5}; const auto leaf_1 = test::flex_vector_one{6, 99}; const auto leaf_5 = test::flex_vector_one{6}; @@ -1128,7 +864,7 @@ TEST_CASE("Test modifying flex vector nodes") } SECTION("Empty leaf") { - item["value"] = json_t::array(); + item[1] = json_t::array(); const auto vec_234 = test::flex_vector_one{0, 1, 4, 5}; const auto leaf_1 = test::flex_vector_one{6, 99}; const auto leaf_5 = test::flex_vector_one{6}; @@ -1139,10 +875,10 @@ TEST_CASE("Test modifying flex vector nodes") SECTION("Modify inner node") { auto& item = data["value0"]["inners"][0]; - REQUIRE(item["key"] == 0); + REQUIRE(item[0] == 0); SECTION("Mix leaves and inners as children") { - auto& children = item["value"]["children"]; + auto& children = item[1]["children"]; REQUIRE(children == json_t::array({2, 3, 4, 5, 2, 3, 4})); children = {2, 3, 4, 902, 4}; REQUIRE_THROWS_AS( @@ -1151,19 +887,19 @@ TEST_CASE("Test modifying flex vector nodes") } SECTION("No children") { - item["value"]["children"] = json_t::array(); + item[1]["children"] = json_t::array(); // There was a problem when an empty relaxed node triggered an // assert, while non-relaxed worked fine. - const auto is_relaxed = GENERATE(false, true); - item["value"]["relaxed"] = is_relaxed; - const auto leaf_1 = test::flex_vector_one{6, 99}; + const auto is_relaxed = GENERATE(false, true); + item[1]["relaxed"] = is_relaxed; + const auto leaf_1 = test::flex_vector_one{6, 99}; REQUIRE(load_flex_vec(data.dump(), 0) == leaf_1); } SECTION("Too many children") { - item["value"]["children"] = std::vector(40, 3); - const auto is_relaxed = GENERATE(false, true); - item["value"]["relaxed"] = is_relaxed; + item[1]["children"] = std::vector(40, 3); + const auto is_relaxed = GENERATE(false, true); + item[1]["relaxed"] = is_relaxed; REQUIRE_THROWS_AS(load_flex_vec(data.dump(), 0), immer::persist::invalid_children_count); } @@ -1171,10 +907,10 @@ TEST_CASE("Test modifying flex vector nodes") { SECTION("All leaves are full, non-relaxed works") { - item["value"]["children"] = {2, 3, 4, 2, 3, 4}; - const auto is_relaxed = GENERATE(false, true); - item["value"]["relaxed"] = is_relaxed; - const auto leaf_1 = test::flex_vector_one{6, 99}; + item[1]["children"] = {2, 3, 4, 2, 3, 4}; + const auto is_relaxed = GENERATE(false, true); + item[1]["relaxed"] = is_relaxed; + const auto leaf_1 = test::flex_vector_one{6, 99}; const auto vec_234 = test::flex_vector_one{0, 1, 2, 3, 4, 5}; const auto vec = vec_234 + vec_234 + leaf_1; @@ -1182,10 +918,10 @@ TEST_CASE("Test modifying flex vector nodes") } SECTION("Relaxed leaf") { - item["value"]["children"] = {2, 3, 5, 3}; + item[1]["children"] = {2, 3, 5, 3}; SECTION("Non-relaxed breaks") { - item["value"]["relaxed"] = false; + item[1]["relaxed"] = false; REQUIRE_THROWS_AS( load_flex_vec(data.dump(), 0), immer::persist::rbts::vector_corrupted_exception); @@ -1230,33 +966,24 @@ TEST_CASE("Test more inner nodes") data["value0"]["B"] = 5; data["value0"]["BL"] = 1; data["value0"]["leaves"] = { - {{"key", 32}, {"value", {58, 59}}}, {{"key", 34}, {"value", {62, 63}}}, - {{"key", 3}, {"value", {0, 1}}}, {{"key", 5}, {"value", {4, 5}}}, - {{"key", 6}, {"value", {6, 7}}}, {{"key", 7}, {"value", {8, 9}}}, - {{"key", 8}, {"value", {10, 11}}}, {{"key", 9}, {"value", {12, 13}}}, - {{"key", 10}, {"value", {14, 15}}}, {{"key", 11}, {"value", {16, 17}}}, - {{"key", 12}, {"value", {18, 19}}}, {{"key", 13}, {"value", {20, 21}}}, - {{"key", 14}, {"value", {22, 23}}}, {{"key", 15}, {"value", {24, 25}}}, - {{"key", 16}, {"value", {26, 27}}}, {{"key", 17}, {"value", {28, 29}}}, - {{"key", 18}, {"value", {30, 31}}}, {{"key", 19}, {"value", {32, 33}}}, - {{"key", 20}, {"value", {34, 35}}}, {{"key", 21}, {"value", {36, 37}}}, - {{"key", 22}, {"value", {38, 39}}}, {{"key", 23}, {"value", {40, 41}}}, - {{"key", 24}, {"value", {42, 43}}}, {{"key", 25}, {"value", {44, 45}}}, - {{"key", 26}, {"value", {46, 47}}}, {{"key", 27}, {"value", {48, 49}}}, - {{"key", 28}, {"value", {50, 51}}}, {{"key", 29}, {"value", {52, 53}}}, - {{"key", 30}, {"value", {54, 55}}}, {{"key", 31}, {"value", {56, 57}}}, - {{"key", 1}, {"value", {66}}}, {{"key", 33}, {"value", {60, 61}}}, - {{"key", 4}, {"value", {2, 3}}}, {{"key", 36}, {"value", {64, 65}}}, + {32, {58, 59}}, {34, {62, 63}}, {3, {0, 1}}, {5, {4, 5}}, + {6, {6, 7}}, {7, {8, 9}}, {8, {10, 11}}, {9, {12, 13}}, + {10, {14, 15}}, {11, {16, 17}}, {12, {18, 19}}, {13, {20, 21}}, + {14, {22, 23}}, {15, {24, 25}}, {16, {26, 27}}, {17, {28, 29}}, + {18, {30, 31}}, {19, {32, 33}}, {20, {34, 35}}, {21, {36, 37}}, + {22, {38, 39}}, {23, {40, 41}}, {24, {42, 43}}, {25, {44, 45}}, + {26, {46, 47}}, {27, {48, 49}}, {28, {50, 51}}, {29, {52, 53}}, + {30, {54, 55}}, {31, {56, 57}}, {1, {66}}, {33, {60, 61}}, + {4, {2, 3}}, {36, {64, 65}}, }; data["value0"]["inners"] = { - {{"key", 0}, {"value", {{"children", {2, 35}}, {"relaxed", false}}}}, - {{"key", 2}, - {"value", - {{"children", - {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34}}, - {"relaxed", false}}}}, - {{"key", 35}, {"value", {{"children", {36}}, {"relaxed", false}}}}, + {0, {{"children", {2, 35}}, {"relaxed", false}}}, + {2, + {{"children", + {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34}}, + {"relaxed", false}}}, + {35, {{"children", {36}}, {"relaxed", false}}}, }; data["value0"]["vectors"] = { { @@ -1273,16 +1000,14 @@ TEST_CASE("Test more inner nodes") SECTION("Throw in some empty nodes") { // Empty leaf #205 - data["value0"]["leaves"].push_back( - {{"key", 205}, {"value", json_t::array()}}); + data["value0"]["leaves"].push_back({205, json_t::array()}); // Inner node #560 referencing the empty leaf data["value0"]["inners"].push_back( - {{"key", 560}, - {"value", {{"children", {205}}, {"relaxed", false}}}}); + {560, {{"children", {205}}, {"relaxed", false}}}); auto& item = data["value0"]["inners"][0]; SECTION("Three nodes") { - item["value"]["children"] = {2, 560, 35}; + item[1]["children"] = {2, 560, 35}; REQUIRE(load_vec(data.dump(), 0) == gen(example_vector{}, 67)); } @@ -1293,7 +1018,7 @@ TEST_CASE("Test more inner nodes") // SECTION("Empty first") // { // FAIL("Fix this test"); - // item["value"]["children"] = {560, 35}; + // item[1]["children"] = {560, 35}; // REQUIRE_NOTHROW(load_vec(data.dump(), 0)); // for (auto i : load_vec(data.dump(), 0)) { // SPDLOG_INFO(i); @@ -1305,13 +1030,13 @@ TEST_CASE("Test more inner nodes") // SECTION("Empty last") // { // FAIL("Fix this test"); - // item["value"]["children"] = {35, 560}; + // item[1]["children"] = {35, 560}; // REQUIRE(load_vec(data.dump(), 0) == example_vector{64, 65, 66}); // } } SECTION("Mix leaves and inners as children") { - auto& children = data["value0"]["inners"][0]["value"]["children"]; + auto& children = data["value0"]["inners"][0][1]["children"]; REQUIRE(children == json_t::array({2, 35})); children = {2, 28}; REQUIRE_THROWS_AS(load_vec(data.dump(), 0), @@ -1322,7 +1047,7 @@ TEST_CASE("Test more inner nodes") SECTION("Relaxed root, 0") { auto& inners = data["value0"]["inners"]; - auto& item = inners[0]["value"]; + auto& item = inners[0][1]; REQUIRE_FALSE(item["relaxed"]); item["relaxed"] = true; REQUIRE_THROWS_AS( @@ -1332,7 +1057,7 @@ TEST_CASE("Test more inner nodes") SECTION("Relaxed non-root") { auto& inners = data["value0"]["inners"]; - auto& item = inners[1]["value"]; + auto& item = inners[1][1]; REQUIRE_FALSE(item["relaxed"]); item["relaxed"] = true; REQUIRE_THROWS_AS( @@ -1347,22 +1072,22 @@ TEST_CASE("Test more inner nodes") auto& inners = data["value0"]["inners"]; SECTION("Relaxed 0 can contain non-relaxed") { - auto& item = inners[0]["value"]; + auto& item = inners[0][1]; REQUIRE_FALSE(item["relaxed"]); item["relaxed"] = true; REQUIRE(load_flex_vec(data.dump(), 0) == gen(example_vector{}, 67)); SECTION("Relaxed 0 can contain relaxed 2") { - inners[1]["value"]["relaxed"] = true; + inners[1][1]["relaxed"] = true; REQUIRE(load_flex_vec(data.dump(), 0) == gen(example_vector{}, 67)); } } SECTION("Strict 0 can't contain relaxed 2") { - inners[1]["value"]["relaxed"] = true; - inners[1]["value"]["children"] = {3, 4, 5}; + inners[1][1]["relaxed"] = true; + inners[1][1]["children"] = {3, 4, 5}; REQUIRE_THROWS_AS( load_flex_vec(data.dump(), 0), immer::persist::rbts::relaxed_node_not_allowed_exception); @@ -1377,48 +1102,15 @@ TEST_CASE("Exception while loading children") data["value0"]["B"] = 5; data["value0"]["BL"] = 1; data["value0"]["leaves"] = { - { - {"key", 1}, - {"value", {6, 99}}, - }, - { - {"key", 2}, - {"value", {0, 1}}, - }, - { - {"key", 3}, - {"value", {2, 3}}, - }, - { - {"key", 4}, - {"value", {4, 5}}, - }, - { - {"key", 5}, - {"value", {6}}, - }, + {1, {6, 99}}, + {2, {0, 1}}, + {3, {2, 3}}, + {4, {4, 5}}, + {5, {6}}, }; data["value0"]["inners"] = { - { - {"key", 0}, - { - "value", - { - {"children", {2, 3, 4, 5, 2, 3, 4}}, - {"relaxed", true}, - }, - }, - }, - { - {"key", 902}, - { - "value", - { - {"children", {5}}, - {"relaxed", true}, - }, - }, - }, + {0, {{"children", {2, 3, 4, 5, 2, 3, 4}}, {"relaxed", true}}}, + {902, {{"children", {5}}, {"relaxed", true}}}, }; data["value0"]["vectors"] = { { @@ -1427,7 +1119,7 @@ TEST_CASE("Exception while loading children") }, }; - auto& children = data["value0"]["inners"][0]["value"]["children"]; + auto& children = data["value0"]["inners"][0][1]["children"]; REQUIRE(children == json_t::array({2, 3, 4, 5, 2, 3, 4})); children = {2, 3, 4, 902, 4}; REQUIRE_THROWS_AS(load_flex_vec(data.dump(), 0), @@ -1440,12 +1132,12 @@ TEST_CASE("Test flex vector with a weird shape relaxed") data["value0"]["B"] = 5; data["value0"]["BL"] = 1; data["value0"]["leaves"] = { - {{"key", 1}, {"value", {66}}}, - {{"key", 36}, {"value", {64, 65}}}, + {1, {66}}, + {36, {64, 65}}, }; data["value0"]["inners"] = { - {{"key", 0}, {"value", {{"children", {35}}, {"relaxed", true}}}}, - {{"key", 35}, {"value", {{"children", {36}}, {"relaxed", true}}}}, + {0, {{"children", {35}}, {"relaxed", true}}}, + {35, {{"children", {36}}, {"relaxed", true}}}, }; data["value0"]["vectors"] = { { @@ -1480,12 +1172,12 @@ TEST_CASE("Test flex vector with a weird shape strict", "[.broken]") data["value0"]["B"] = 5; data["value0"]["BL"] = 1; data["value0"]["leaves"] = { - {{"key", 1}, {"value", {66}}}, - {{"key", 36}, {"value", {64, 65}}}, + {1, {66}}, + {36, {64, 65}}, }; data["value0"]["inners"] = { - {{"key", 0}, {"value", {{"children", {35}}, {"relaxed", false}}}}, - {{"key", 35}, {"value", {{"children", {36}}, {"relaxed", false}}}}, + {0, {{"children", {35}}, {"relaxed", false}}}, + {35, {{"children", {36}}, {"relaxed", false}}}, }; data["value0"]["vectors"] = { {{"root", 0}, {"tail", 1}},