diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e318162..a95f9bef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ option(ENABLE_GUILE "enable building guile module" off) option(ENABLE_BOOST_COROUTINE "run benchmarks with boost coroutine" off) option(immer_BUILD_TESTS "Build tests" ON) -option(immer_BUILD_ARCHIVE_TESTS "Build experimental archive tests" off) +option(immer_BUILD_PERSIST_TESTS "Build experimental persist tests" off) option(immer_BUILD_EXAMPLES "Build examples" ON) option(immer_BUILD_DOCS "Build docs" ON) option(immer_BUILD_EXTRAS "Build extras" ON) diff --git a/extra/fuzzer/CMakeLists.txt b/extra/fuzzer/CMakeLists.txt index ed9fe716..7aea77e0 100644 --- a/extra/fuzzer/CMakeLists.txt +++ b/extra/fuzzer/CMakeLists.txt @@ -14,7 +14,7 @@ endif() file(GLOB_RECURSE immer_fuzzers "*.cpp") foreach(TMP_PATH ${immer_fuzzers}) - string(FIND ${TMP_PATH} archive EXCLUDE_DIR_FOUND) + string(FIND ${TMP_PATH} persist EXCLUDE_DIR_FOUND) if(NOT ${EXCLUDE_DIR_FOUND} EQUAL -1) list(REMOVE_ITEM immer_fuzzers ${TMP_PATH}) endif() @@ -36,6 +36,6 @@ foreach(_file IN LISTS immer_fuzzers) endif() endforeach() -if(immer_BUILD_ARCHIVE_TESTS) - add_subdirectory(archive) +if(immer_BUILD_PERSIST_TESTS) + add_subdirectory(persist) endif() diff --git a/extra/fuzzer/archive/CMakeLists.txt b/extra/fuzzer/persist/CMakeLists.txt similarity index 100% rename from extra/fuzzer/archive/CMakeLists.txt rename to extra/fuzzer/persist/CMakeLists.txt diff --git a/extra/fuzzer/archive/flex-vector.cpp b/extra/fuzzer/persist/flex-vector.cpp similarity index 93% rename from extra/fuzzer/archive/flex-vector.cpp rename to extra/fuzzer/persist/flex-vector.cpp index 530398c6..aef8d472 100644 --- a/extra/fuzzer/archive/flex-vector.cpp +++ b/extra/fuzzer/persist/flex-vector.cpp @@ -12,8 +12,8 @@ #include #include -#include -#include +#include +#include #include @@ -38,13 +38,12 @@ extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, using size_t = std::uint8_t; const auto check_save_and_load = [&](const auto& vec) { - auto ar = immer::archive::rbts::make_save_archive_for(vec); - auto vector_id = immer::archive::container_id{}; - std::tie(ar, vector_id) = - immer::archive::rbts::save_to_archive(vec, ar); + auto ar = immer::persist::rbts::make_input_pool_for(vec); + auto vector_id = immer::persist::container_id{}; + std::tie(ar, vector_id) = immer::persist::rbts::add_to_pool(vec, ar); auto loader = - immer::archive::rbts::make_loader_for(vec, to_load_archive(ar)); + immer::persist::rbts::make_loader_for(vec, to_output_pool(ar)); auto loaded = loader.load(vector_id); require_eq(vec, loaded); }; diff --git a/extra/fuzzer/archive/fuzz-set.cpp b/extra/fuzzer/persist/fuzz-set.cpp similarity index 85% rename from extra/fuzzer/archive/fuzz-set.cpp rename to extra/fuzzer/persist/fuzz-set.cpp index 942e175b..e432f2ac 100644 --- a/extra/fuzzer/archive/fuzz-set.cpp +++ b/extra/fuzzer/persist/fuzz-set.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include #include @@ -77,21 +77,20 @@ extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, case op_check: { const auto bitset = std::bitset(read(in)); auto ids = - std::vector>{}; - auto archive = - immer::archive::champ::container_archive_save{}; + std::vector>{}; + auto archive = immer::persist::champ::container_input_pool{}; for (auto index = std::size_t{}; index < var_count; ++index) { if (bitset[index]) { - auto set_id = immer::archive::node_id{}; + auto set_id = immer::persist::node_id{}; std::tie(archive, set_id) = - immer::archive::champ::save_to_archive(vars[index], - archive); + immer::persist::champ::add_to_pool(vars[index], + archive); ids.emplace_back(index, set_id); } } - auto loader = immer::archive::champ::container_loader{ - to_load_archive(archive)}; + auto loader = immer::persist::champ::container_loader{ + to_output_pool(archive)}; for (const auto& [index, set_id] : ids) { const auto& set = vars[index]; diff --git a/flake.nix b/flake.nix index 470c6baa..6262608b 100644 --- a/flake.nix +++ b/flake.nix @@ -48,7 +48,7 @@ arximboldi-cereal = pkgs.callPackage ./nix/cereal.nix {inherit arximboldi-cereal-src;}; - archive-inputs = with pkgs; [ + persist-inputs = with pkgs; [ spdlog arximboldi-cereal xxHash @@ -79,8 +79,8 @@ checkPhase = '' ctest -D ExperimentalMemCheck valgrind --quiet --error-exitcode=99 --leak-check=full --errors-for-leak-kinds=all \ - --suppressions=./test/extra/archive/valgrind.supp \ - ./test/extra/archive/archive-tests + --suppressions=./test/extra/persist/valgrind.supp \ + ./test/extra/persist/persist-tests ''; }); }; @@ -103,7 +103,7 @@ fzf starship ] - ++ archive-inputs; + ++ persist-inputs; shellHook = self.checks.${system}.pre-commit-check.shellHook @@ -147,7 +147,7 @@ unit-tests = (withLLVM self.packages.${system}.immer).overrideAttrs (prev: { name = "immer-unit-tests"; - buildInputs = with pkgs; [catch2_3 boehmgc boost fmt] ++ archive-inputs; + buildInputs = with pkgs; [catch2_3 boehmgc boost fmt] ++ persist-inputs; nativeBuildInputs = with pkgs; [cmake ninja]; dontBuild = false; doCheck = true; @@ -159,7 +159,7 @@ cmakeFlags = [ "-DCMAKE_BUILD_TYPE=Debug" "-Dimmer_BUILD_TESTS=ON" - "-Dimmer_BUILD_ARCHIVE_TESTS=ON" + "-Dimmer_BUILD_PERSIST_TESTS=ON" "-Dimmer_BUILD_EXAMPLES=OFF" "-DCXX_STANDARD=20" ]; diff --git a/immer/extra/archive/errors.hpp b/immer/extra/archive/errors.hpp deleted file mode 100644 index 8f0899dc..00000000 --- a/immer/extra/archive/errors.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include - -#include - -#include - -namespace immer::archive { - -class archive_exception : public std::invalid_argument -{ -public: - using invalid_argument::invalid_argument; -}; - -class archive_has_cycles : public archive_exception -{ -public: - explicit archive_has_cycles(node_id id) - : archive_exception{fmt::format("Cycle detected with node ID {}", id)} - { - } -}; - -class invalid_node_id : public archive_exception -{ -public: - explicit invalid_node_id(node_id id) - : archive_exception{fmt::format("Node ID {} is not found", id)} - { - } -}; - -class invalid_container_id : public archive_exception -{ -public: - explicit invalid_container_id(container_id id) - : archive_exception{fmt::format("Container ID {} is not found", id)} - { - } -}; - -class invalid_children_count : public archive_exception -{ -public: - explicit invalid_children_count(node_id id) - : archive_exception{ - fmt::format("Node ID {} has more children than allowed", id)} - { - } -}; - -} // namespace immer::archive diff --git a/immer/extra/archive/json/json_with_archive_auto.hpp b/immer/extra/archive/json/json_with_archive_auto.hpp deleted file mode 100644 index 6387eb94..00000000 --- a/immer/extra/archive/json/json_with_archive_auto.hpp +++ /dev/null @@ -1,384 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include -#include -#include - -namespace immer::archive { - -template -struct is_auto_ignored_type : boost::hana::false_ -{}; - -template -struct is_auto_ignored_type>> - : boost::hana::true_ -{}; - -template -struct is_auto_ignored_type>> - : boost::hana::true_ -{}; - -template <> -struct is_auto_ignored_type> - : boost::hana::true_ -{}; - -template <> -struct is_auto_ignored_type> : boost::hana::true_ -{}; - -template <> -struct is_auto_ignored_type> : boost::hana::true_ -{}; - -/** - * This wrapper is used to load a given container via archivable. - */ -template -struct archivable_loader_wrapper -{ - Container& value; - - template - typename container_traits::container_id::rep_t - save_minimal(const Archive&) const - { - throw std::logic_error{ - "Should never be called. archivable_loader_wrapper::save_minimal"}; - } - - template - void load_minimal( - const Archive& ar, - const typename container_traits::container_id::rep_t& - container_id) - { - archivable arch; - immer::archive::load_minimal(ar.previous, arch, container_id); - value = std::move(arch).container; - } -}; - -constexpr auto is_archivable = boost::hana::is_valid( - [](auto&& obj) -> - typename container_traits>::save_archive_t {}); - -constexpr auto is_auto_ignored = [](const auto& value) { - return is_auto_ignored_type>{}; -}; - -/** - * Make a function that operates conditionally on its single argument, based on - * the given predicate. If the predicate is not satisfied, the function forwards - * its argument unchanged. - */ -constexpr auto make_conditional_func = [](auto pred, auto func) { - return [pred, func](auto&& value) -> decltype(auto) { - return boost::hana::if_(pred(value), func, boost::hana::id)( - std::forward(value)); - }; -}; - -// We must not try to archive types that are actually the archive itself, -// for example, `immer::map> leaves` etc. -constexpr auto exclude_internal_archive_types = [](auto wrap) { - namespace hana = boost::hana; - return make_conditional_func(hana::compose(hana::not_, is_auto_ignored), - wrap); -}; - -constexpr auto to_archivable = [](const auto& x) { - return archivable>(x); -}; - -constexpr auto to_archivable_loader = [](auto& value) { - using V = std::decay_t; - return archivable_loader_wrapper{value}; -}; - -/** - * This function will wrap a value in archivable if possible or will return a - * reference to its argument. - */ -constexpr auto wrap_for_saving = exclude_internal_archive_types( - make_conditional_func(is_archivable, to_archivable)); - -constexpr auto wrap_for_loading = exclude_internal_archive_types( - make_conditional_func(is_archivable, to_archivable_loader)); - -/** - * Generate a hana map of archivable members for a given type T. - * Where key is a type (archivable immer container) and value is a name for that - * archive (using the member name from the given struct). - * Example: [(type_c>, "tracks")] - */ -template -auto get_auto_archives_types(const T& value) -{ - namespace hana = boost::hana; - static_assert(hana::Struct::value, - "get_auto_archives_types works only with types that " - "implement hana::Struct concept"); - - constexpr auto is_archivable_key = [](auto key) { - return is_archivable(hana::at_key(T{}, key)); - }; - - // A list of pairs like (hana::type_c, "member_name") - auto pairs = hana::transform( - hana::filter(hana::keys(value), is_archivable_key), [&](auto key) { - const auto& member = hana::at_key(value, key); - return hana::make_pair(hana::typeid_(member), key); - }); - - return hana::unpack(pairs, hana::make_map); -} - -/** - * Generate a hana map of archivable members for the given types and apply - * manual overrides for names. - * manual_overrides is a map of manual overrides. - */ -auto get_archives_for_types(auto types, - auto manual_overrides = boost::hana::make_map()) -{ - namespace hana = boost::hana; - // Automatically generate names and archives - const auto names = - hana::fold_left(hana::transform(types, - [](auto t) { - using T = - typename decltype(t)::type; - return get_auto_archives_types(T{}); - }), - hana::make_map(), - hana::union_); - // Apply the overrides - return hana::union_(names, manual_overrides); -} - -template > -auto to_json_with_auto_archive(const T& serializable, - const ArchivesTypes& archives_types, - const WrapF& wrap = wrap_for_saving) -{ - namespace hana = boost::hana; - - // In the future, wrap function may ignore certain user-provided types that - // should not be archived. - static_assert( - std::is_same_v())), - const std::string&>, - "wrap must return a reference when it's not wrapping the type"); - static_assert( - std::is_same_v{})), - archivable>>, - "and a value when it's wrapping"); - - auto archives = detail::generate_archives_save(archives_types); - using Archives = std::decay_t; - - const auto save_archive = [wrap](auto archives) { - auto previous = - json_immer_output_archive{ - archives}; - auto ar = json_immer_auto_output_archive{previous, wrap}; - - ar(archives); - return std::move(previous).get_output_archives(); - }; - - auto os = std::ostringstream{}; - { - auto previous = - json_immer_output_archive{os}; - auto ar = json_immer_auto_output_archive{previous, wrap}; - // value0 because that's now cereal saves the unnamed object by default, - // maybe change later. - ar(cereal::make_nvp("value0", serializable)); - if constexpr (!is_archive_empty()) { - save_archives_impl(previous, save_archive); - ar.finalize(); - } - archives = std::move(previous).get_output_archives(); - } - return std::make_pair(os.str(), std::move(archives)); -} - -// Same as to_json_with_auto_archive but we don't generate any JSON. -template > -auto get_auto_archive(const T& serializable, - const ArchivesTypes& archives_types, - const WrapF& wrap = wrap_for_saving) -{ - namespace hana = boost::hana; - - // In the future, wrap function may ignore certain user-provided types that - // should not be archived. - static_assert( - std::is_same_v())), - const std::string&>, - "wrap must return a reference when it's not wrapping the type"); - static_assert( - std::is_same_v{})), - archivable>>, - "and a value when it's wrapping"); - - auto archives = detail::generate_archives_save(archives_types); - using Archives = std::decay_t; - - const auto save_archive = [wrap](auto archives) { - auto previous = - json_immer_output_archive{ - archives}; - auto ar = json_immer_auto_output_archive{previous, wrap}; - ar(archives); - return std::move(previous).get_output_archives(); - }; - - { - auto previous = - json_immer_output_archive{}; - auto ar = json_immer_auto_output_archive{previous, wrap}; - // value0 because that's now cereal saves the unnamed object by default, - // maybe change later. - ar(cereal::make_nvp("value0", serializable)); - if constexpr (!is_archive_empty()) { - save_archives_impl(previous, save_archive); - ar.finalize(); - } - archives = std::move(previous).get_output_archives(); - } - return archives; -} - -template -auto load_initial_auto_archives(std::istream& is, WrapF wrap) -{ - auto archives = Archives{}; - if constexpr (is_archive_empty()) { - return archives; - } - - auto restore = util::istream_snapshot{is}; - auto previous = cereal::JSONInputArchive{is}; - auto ar = json_immer_auto_input_archive{previous, wrap}; - ar(CEREAL_NVP(archives)); - return archives; -} - -constexpr auto reload_archive_auto = [](auto wrap) { - return [wrap](std::istream& is, - auto archives, - bool ignore_archive_exceptions) { - using Archives = std::decay_t; - auto restore = util::istream_snapshot{is}; - archives.ignore_archive_exceptions = ignore_archive_exceptions; - auto previous = - json_immer_input_archive{ - std::move(archives), is}; - auto ar = json_immer_auto_input_archive{previous, wrap}; - /** - * NOTE: Critical to clear the archives before loading into it - * again. I hit a bug when archives contained a vector and every - * load would append to it, instead of replacing the contents. - */ - archives = {}; - ar(CEREAL_NVP(archives)); - return archives; - }; -}; - -template -T from_json_with_auto_archive(std::istream& is, - const ArchivesTypes& archives_types) -{ - namespace hana = boost::hana; - constexpr auto wrap = wrap_for_loading; - - using Archives = - std::decay_t; - - auto archives = - load_archives(is, - load_initial_auto_archives(is, wrap), - reload_archive_auto(wrap)); - - auto previous = - json_immer_input_archive{ - std::move(archives), is}; - auto ar = json_immer_auto_input_archive{previous, wrap}; - // value0 because that's now cereal saves the unnamed object by default, - // maybe change later. - auto value0 = T{}; - ar(CEREAL_NVP(value0)); - return value0; -} - -template -T from_json_with_auto_archive(const std::string& input, - const ArchivesTypes& archives_types) -{ - auto is = std::istringstream{input}; - return from_json_with_auto_archive(is, archives_types); -} - -template -T from_json_with_auto_archive_with_conversion( - std::istream& is, - const ConversionsMap& map, - const ArchivesTypes& archives_types) -{ - constexpr auto wrap = wrap_for_loading; - - // Load the archives part for the old type - using OldArchives = - std::decay_t; - auto archives_old = - load_archives(is, - load_initial_auto_archives(is, wrap), - reload_archive_auto(wrap)); - - auto archives = archives_old.transform(map); - using Archives = decltype(archives); - - auto previous = - json_immer_input_archive{ - std::move(archives), is}; - auto ar = json_immer_auto_input_archive{previous, wrap}; - auto r = T{}; - ar(r); - return r; -} - -template -T from_json_with_auto_archive_with_conversion( - const std::string& input, - const ConversionsMap& map, - const ArchivesTypes& archives_types) -{ - auto is = std::istringstream{input}; - return from_json_with_auto_archive_with_conversion( - is, map, archives_types); -} - -} // namespace immer::archive diff --git a/immer/extra/archive/rbts/save.hpp b/immer/extra/archive/rbts/save.hpp deleted file mode 100644 index 34eadbcb..00000000 --- a/immer/extra/archive/rbts/save.hpp +++ /dev/null @@ -1,221 +0,0 @@ -#pragma once - -#include - -namespace immer::archive::rbts { - -namespace detail { - -template -std::pair, node_id> -get_node_id(archive_save ar, - const immer::detail::rbts::node* ptr) -{ - auto* ptr_void = static_cast(ptr); - if (auto* maybe_id = ar.node_ptr_to_id.find(ptr_void)) { - auto id = *maybe_id; - return {std::move(ar), id}; - } - - const auto id = node_id{ar.node_ptr_to_id.size()}; - ar.node_ptr_to_id = std::move(ar.node_ptr_to_id).set(ptr_void, id); - return {std::move(ar), id}; -} - -template -struct archive_builder -{ - archive_save ar; - - template - void operator()(regular_pos_tag, Pos& pos, auto&& visit) - { - auto id = get_node_id(pos.node()); - if (ar.inners.count(id)) { - return; - } - - auto node_info = inner_node{}; - // Explicit this-> call to workaround an "unused this" warning. - pos.each(visitor_helper{}, - [&node_info, &visit, this]( - auto any_tag, auto& child_pos, auto&&) mutable { - node_info.children = - std::move(node_info.children) - .push_back(this->get_node_id(child_pos.node())); - visit(child_pos); - }); - ar.inners = std::move(ar.inners).set(id, node_info); - } - - template - void operator()(relaxed_pos_tag, Pos& pos, auto&& visit) - { - auto id = get_node_id(pos.node()); - if (ar.inners.count(id)) { - return; - } - - auto node_info = inner_node{ - .relaxed = true, - }; - - pos.each(visitor_helper{}, [&](auto any_tag, auto& child_pos, auto&&) { - node_info.children = std::move(node_info.children) - .push_back(get_node_id(child_pos.node())); - - visit(child_pos); - }); - - assert(node_info.children.size() == pos.node()->relaxed()->d.count); - - ar.inners = std::move(ar.inners).set(id, node_info); - } - - template - void operator()(leaf_pos_tag, Pos& pos, auto&& visit) - { - T* first = pos.node()->leaf(); - auto id = get_node_id(pos.node()); - if (ar.leaves.count(id)) { - return; - } - - auto info = values_save{ - .begin = first, - .end = first + pos.count(), - }; - ar.leaves = std::move(ar.leaves).set(id, std::move(info)); - } - - node_id get_node_id(immer::detail::rbts::node* ptr) - { - auto [ar2, id] = - immer::archive::rbts::detail::get_node_id(std::move(ar), ptr); - ar = std::move(ar2); - return id; - } -}; - -template -auto save_nodes(const immer::detail::rbts::rbtree& tree, - Archive ar) -{ - auto save = archive_builder{ - .ar = std::move(ar), - }; - tree.traverse(visitor_helper{}, save); - return std::move(save.ar); -} - -template -auto save_nodes( - const immer::detail::rbts::rrbtree& tree, - Archive ar) -{ - auto save = archive_builder{ - .ar = std::move(ar), - }; - tree.traverse(visitor_helper{}, save); - return std::move(save.ar); -} - -} // namespace detail - -template -std::pair, container_id> -save_to_archive(immer::vector vec, - archive_save archive) -{ - const auto& impl = vec.impl(); - auto root_id = node_id{}; - auto tail_id = node_id{}; - std::tie(archive, root_id) = - detail::get_node_id(std::move(archive), impl.root); - std::tie(archive, tail_id) = - detail::get_node_id(std::move(archive), impl.tail); - const auto tree_id = rbts_info{ - .root = root_id, - .tail = tail_id, - }; - - if (auto* p = archive.rbts_to_id.find(tree_id)) { - // Already been saved - auto vector_id = *p; - return {std::move(archive), vector_id}; - } - - archive = detail::save_nodes(impl, std::move(archive)); - - assert(archive.inners.count(root_id)); - assert(archive.leaves.count(tail_id)); - - const auto vector_id = container_id{archive.vectors.size()}; - - archive.rbts_to_id = std::move(archive.rbts_to_id).set(tree_id, vector_id); - archive.vectors = std::move(archive.vectors).push_back(tree_id); - archive.saved_vectors = - std::move(archive.saved_vectors).push_back(std::move(vec)); - - return {std::move(archive), vector_id}; -} - -template -std::pair, container_id> -save_to_archive(immer::flex_vector vec, - archive_save archive) -{ - const auto& impl = vec.impl(); - auto root_id = node_id{}; - auto tail_id = node_id{}; - std::tie(archive, root_id) = - detail::get_node_id(std::move(archive), impl.root); - std::tie(archive, tail_id) = - detail::get_node_id(std::move(archive), impl.tail); - const auto tree_id = rbts_info{ - .root = root_id, - .tail = tail_id, - }; - - if (auto* p = archive.rbts_to_id.find(tree_id)) { - // Already been saved - auto vector_id = *p; - return {std::move(archive), vector_id}; - } - - archive = detail::save_nodes(impl, std::move(archive)); - - assert(archive.inners.count(root_id)); - assert(archive.leaves.count(tail_id)); - - const auto vector_id = container_id{archive.vectors.size()}; - - archive.rbts_to_id = std::move(archive.rbts_to_id).set(tree_id, vector_id); - archive.vectors = std::move(archive.vectors).push_back(tree_id); - archive.saved_flex_vectors = - std::move(archive.saved_flex_vectors).push_back(std::move(vec)); - - return {std::move(archive), vector_id}; -} - -} // namespace immer::archive::rbts diff --git a/immer/extra/archive/alias.hpp b/immer/extra/persist/alias.hpp similarity index 77% rename from immer/extra/archive/alias.hpp rename to immer/extra/persist/alias.hpp index bd05ae77..68a18e76 100644 --- a/immer/extra/archive/alias.hpp +++ b/immer/extra/persist/alias.hpp @@ -2,7 +2,7 @@ #include -namespace immer::archive { +namespace immer::persist { template struct type_alias @@ -41,16 +41,16 @@ struct type_alias } }; -} // namespace immer::archive +} // namespace immer::persist /** * Have to use this for fmt v9. */ template -struct fmt::formatter> : formatter +struct fmt::formatter> : formatter { template - auto format(const immer::archive::type_alias& value, + auto format(const immer::persist::type_alias& value, FormatContext& ctx) const { return formatter::format(value.value, ctx); @@ -58,9 +58,9 @@ struct fmt::formatter> : formatter }; template -struct std::hash> +struct std::hash> { - auto operator()(const immer::archive::type_alias& x) const + auto operator()(const immer::persist::type_alias& x) const { return hash{}(x.value); } diff --git a/immer/extra/archive/box/archive.hpp b/immer/extra/persist/box/pool.hpp similarity index 60% rename from immer/extra/archive/box/archive.hpp rename to immer/extra/persist/box/pool.hpp index df290500..5237fd5c 100644 --- a/immer/extra/archive/box/archive.hpp +++ b/immer/extra/persist/box/pool.hpp @@ -1,8 +1,8 @@ #pragma once -#include -#include -#include +#include +#include +#include #include #include @@ -12,16 +12,16 @@ #include -namespace immer::archive::box { +namespace immer::persist::box { template -struct archive_save +struct input_pool { immer::map> boxes; immer::map ids; - friend bool operator==(const archive_save& left, const archive_save& right) + friend bool operator==(const input_pool& left, const input_pool& right) { return left.boxes == right.boxes; } @@ -45,8 +45,8 @@ struct archive_save }; template -std::pair, container_id> -get_box_id(archive_save ar, +std::pair, container_id> +get_box_id(input_pool ar, const immer::box& box) { auto* ptr_void = static_cast(box.impl()); @@ -60,17 +60,17 @@ get_box_id(archive_save ar, } template -inline auto make_save_archive_for(const immer::box&) +inline auto make_input_pool_for(const immer::box&) { - return archive_save{}; + return input_pool{}; } template -struct archive_load +struct output_pool { immer::vector> boxes; - friend bool operator==(const archive_load& left, const archive_load& right) + friend bool operator==(const output_pool& left, const output_pool& right) { return left.boxes == right.boxes; } @@ -90,86 +90,85 @@ struct archive_load }; template -archive_load -to_load_archive(const archive_save& archive) +output_pool +to_output_pool(const input_pool& pool) { - auto result = archive_load{}; - archive.for_each_ordered([&](const auto& box) { + auto result = output_pool{}; + pool.for_each_ordered([&](const auto& box) { result.boxes = std::move(result.boxes).push_back(box); }); return result; } template -std::pair, container_id> -save_to_archive(immer::box box, - archive_save archive) +std::pair, container_id> +add_to_pool(immer::box box, input_pool pool) { - auto id = container_id{}; - std::tie(archive, id) = get_box_id(std::move(archive), box); + auto id = container_id{}; + std::tie(pool, id) = get_box_id(std::move(pool), box); - if (archive.boxes.count(id)) { + if (pool.boxes.count(id)) { // Already been saved - return {std::move(archive), id}; + return {std::move(pool), id}; } - archive.boxes = std::move(archive.boxes).set(id, std::move(box)); - return {std::move(archive), id}; + pool.boxes = std::move(pool.boxes).set(id, std::move(box)); + return {std::move(pool), id}; } template , + typename Pool = output_pool, typename TransformF = boost::hana::id_t> class loader { public: - explicit loader(Archive ar) + explicit loader(Pool pool) requires std::is_same_v - : ar_{std::move(ar)} + : pool_{std::move(pool)} { } - explicit loader(Archive ar, TransformF transform) - : ar_{std::move(ar)} + explicit loader(Pool pool, TransformF transform) + : pool_{std::move(pool)} , transform_{std::move(transform)} { } immer::box load(container_id id) { - if (id.value >= ar_.boxes.size()) { + if (id.value >= pool_.boxes.size()) { throw invalid_container_id{id}; } if constexpr (std::is_same_v) { - return ar_.boxes[id.value]; + return pool_.boxes[id.value]; } else { - if (auto* b = boxes.find(id)) { + if (auto* b = boxes_.find(id)) { return *b; } - const auto& old_box = ar_.boxes[id.value]; + const auto& old_box = pool_.boxes[id.value]; auto new_box = immer::box{transform_(old_box.get())}; - boxes = std::move(boxes).set(id, new_box); + boxes_ = std::move(boxes_).set(id, new_box); return new_box; } } private: - const Archive ar_; + const Pool pool_; const TransformF transform_; - immer::map> boxes; + immer::map> boxes_; }; template loader make_loader_for(const immer::box&, - archive_load ar) + output_pool ar) { return loader{std::move(ar)}; } template -auto transform_archive(const archive_load& ar, F&& func) +auto transform_pool(const output_pool& ar, F&& func) { using U = std::decay_t()))>; auto boxes = immer::vector>{}; @@ -177,26 +176,26 @@ auto transform_archive(const archive_load& ar, F&& func) boxes = std::move(boxes).push_back(func(item.get())); } - return archive_load{ + return output_pool{ .boxes = std::move(boxes), }; } -} // namespace immer::archive::box +} // namespace immer::persist::box -namespace immer::archive { +namespace immer::persist { template struct container_traits> { - using save_archive_t = box::archive_save; - using load_archive_t = box::archive_load; + using input_pool_t = box::input_pool; + using output_pool_t = box::output_pool; - template - using loader_t = box::loader; + using loader_t = box::loader; - using container_id = immer::archive::container_id; + using container_id = immer::persist::container_id; template static auto transform(F&& func) @@ -206,4 +205,4 @@ struct container_traits> } }; -} // namespace immer::archive +} // namespace immer::persist diff --git a/immer/extra/archive/cereal/immer_map.hpp b/immer/extra/persist/cereal/immer_map.hpp similarity index 100% rename from immer/extra/archive/cereal/immer_map.hpp rename to immer/extra/persist/cereal/immer_map.hpp diff --git a/immer/extra/archive/cereal/immer_vector.hpp b/immer/extra/persist/cereal/immer_vector.hpp similarity index 100% rename from immer/extra/archive/cereal/immer_vector.hpp rename to immer/extra/persist/cereal/immer_vector.hpp diff --git a/immer/extra/archive/champ/champ.hpp b/immer/extra/persist/champ/champ.hpp similarity index 73% rename from immer/extra/archive/champ/champ.hpp rename to immer/extra/persist/champ/champ.hpp index cc7831f3..c721fe36 100644 --- a/immer/extra/archive/champ/champ.hpp +++ b/immer/extra/persist/champ/champ.hpp @@ -1,12 +1,12 @@ #pragma once -#include "archive.hpp" -#include "load.hpp" -#include "save.hpp" +#include "input.hpp" +#include "output.hpp" +#include "pool.hpp" #include -namespace immer::archive { +namespace immer::persist { namespace champ { template @@ -34,13 +34,13 @@ struct node_traits static constexpr auto bits = impl::bits; }; -class hash_validation_failed_exception : public archive_exception +class hash_validation_failed_exception : public pool_exception { public: explicit hash_validation_failed_exception(const std::string& msg) - : archive_exception{"Hash validation failed, likely different hash " - "algos are used for saving and loading, " + - msg} + : pool_exception{"Hash validation failed, likely different hash " + "algos are used for saving and loading, " + + msg} { } }; @@ -55,8 +55,8 @@ class hash_validation_failed_exception : public archive_exception * function that handles the target_container_type_request. */ template , - typename TransformF = boost::hana::id_t, + typename Pool = container_output_pool, + typename TransformF = boost::hana::id_t, bool enable_incompatible_hash_mode = false> class container_loader { @@ -64,7 +64,7 @@ class container_loader using node_t = typename champ_t::node_t; using value_t = typename node_t::value_t; using traits = node_traits; - using nodes_load = std::decay_t().nodes)>; + using nodes_load = std::decay_t().nodes)>; struct project_value_ptr { @@ -75,22 +75,22 @@ class container_loader }; public: - explicit container_loader(Archive archive) + explicit container_loader(Pool pool) requires std::is_same_v - : archive_{std::move(archive)} - , nodes_{archive_.nodes} + : pool_{std::move(pool)} + , nodes_{pool_.nodes} { } - explicit container_loader(Archive archive, TransformF transform) - : archive_{std::move(archive)} - , nodes_{archive_.nodes, std::move(transform)} + explicit container_loader(Pool pool, TransformF transform) + : pool_{std::move(pool)} + , nodes_{pool_.nodes, std::move(transform)} { } Container load(node_id root_id) { - if (root_id.value >= archive_.nodes.size()) { + if (root_id.value >= pool_.nodes.size()) { throw invalid_node_id{root_id}; } @@ -146,7 +146,7 @@ class container_loader } private: - const Archive archive_; + const Pool pool_; nodes_loader -container_loader(container_archive_load archive) +container_loader(container_output_pool pool) -> container_loader; template -std::pair, node_id> -save_to_archive(Container container, container_archive_save archive) +std::pair, node_id> +add_to_pool(Container container, container_input_pool pool) { const auto& impl = container.impl(); auto root_id = node_id{}; - std::tie(archive.nodes, root_id) = - get_node_id(std::move(archive.nodes), impl.root); + std::tie(pool.nodes, root_id) = + get_node_id(std::move(pool.nodes), impl.root); - if (archive.nodes.inners.count(root_id)) { + if (pool.nodes.inners.count(root_id)) { // Already been saved - return {std::move(archive), root_id}; + return {std::move(pool), root_id}; } - archive.nodes = save_nodes(impl, std::move(archive.nodes)); - assert(archive.nodes.inners.count(root_id)); + pool.nodes = save_nodes(impl, std::move(pool.nodes)); + assert(pool.nodes.inners.count(root_id)); - archive.containers = - std::move(archive.containers).push_back(std::move(container)); + pool.containers = + std::move(pool.containers).push_back(std::move(container)); - return {std::move(archive), root_id}; + return {std::move(pool), root_id}; } } // namespace champ -} // namespace immer::archive +} // namespace immer::persist diff --git a/immer/extra/archive/champ/save.hpp b/immer/extra/persist/champ/input.hpp similarity index 62% rename from immer/extra/archive/champ/save.hpp rename to immer/extra/persist/champ/input.hpp index 860f8a3b..8d8134c5 100644 --- a/immer/extra/archive/champ/save.hpp +++ b/immer/extra/persist/champ/input.hpp @@ -1,21 +1,21 @@ #pragma once -#include +#include #include -namespace immer::archive { +namespace immer::persist { namespace champ { template -struct nodes_archive_builder +struct input_pool_builder { - nodes_save ar; + nodes_save pool; void visit_inner(const auto* node, auto depth) { auto id = get_node_id(node); - if (ar.inners.count(id)) { + if (pool.inners.count(id)) { return; } @@ -38,23 +38,24 @@ struct nodes_archive_builder } } - ar.inners = std::move(ar.inners).set(id, node_info); + pool.inners = std::move(pool.inners).set(id, node_info); } void visit_collision(const auto* node) { auto id = get_node_id(node); - if (ar.inners.count(id)) { + if (pool.inners.count(id)) { return; } - ar.inners = std::move(ar.inners).set( - id, - inner_node_save{ - .values = {node->collisions(), - node->collisions() + node->collision_count()}, - .collisions = true, - }); + pool.inners = std::move(pool.inners) + .set(id, + inner_node_save{ + .values = {node->collisions(), + node->collisions() + + node->collision_count()}, + .collisions = true, + }); } void visit(const auto* node, immer::detail::hamts::count_t depth) @@ -70,8 +71,9 @@ struct nodes_archive_builder node_id get_node_id(auto* ptr) { - auto [ar2, id] = immer::archive::champ::get_node_id(std::move(ar), ptr); - ar = std::move(ar2); + auto [pool2, id] = + immer::persist::champ::get_node_id(std::move(pool), ptr); + pool = std::move(pool2); return id; } }; @@ -81,21 +83,21 @@ template + class Pool> auto save_nodes( const immer::detail::hamts::champ& champ, - Archive ar) + Pool pool) { using champ_t = std::decay_t; using node_t = typename champ_t::node_t; - auto save = nodes_archive_builder{ - .ar = std::move(ar), + auto save = input_pool_builder{ + .pool = std::move(pool), }; save.visit(champ.root, 0); - return std::move(save.ar); + return std::move(save.pool); } } // namespace champ -} // namespace immer::archive +} // namespace immer::persist diff --git a/immer/extra/archive/champ/load.hpp b/immer/extra/persist/champ/output.hpp similarity index 83% rename from immer/extra/archive/champ/load.hpp rename to immer/extra/persist/champ/output.hpp index ca358ba9..08ef4c0e 100644 --- a/immer/extra/archive/champ/load.hpp +++ b/immer/extra/persist/champ/output.hpp @@ -1,8 +1,8 @@ #pragma once -#include -#include -#include +#include +#include +#include #include @@ -11,17 +11,17 @@ #include -namespace immer::archive { +namespace immer::persist { namespace champ { -class children_count_corrupted_exception : public archive_exception +class children_count_corrupted_exception : public pool_exception { public: children_count_corrupted_exception(node_id id, std::uint64_t nodemap, std::size_t expected_count, std::size_t real_count) - : archive_exception{fmt::format( + : pool_exception{fmt::format( "Loaded container is corrupted. Inner " "node ID {} has nodemap {} which means it should have {} " "children but it has {}", @@ -33,14 +33,14 @@ class children_count_corrupted_exception : public archive_exception } }; -class data_count_corrupted_exception : public archive_exception +class data_count_corrupted_exception : public pool_exception { public: data_count_corrupted_exception(node_id id, std::uint64_t datamap, std::size_t expected_count, std::size_t real_count) - : archive_exception{fmt::format( + : pool_exception{fmt::format( "Loaded container is corrupted. Inner " "node ID {} has datamap {} which means it should contain {} " "values but it has {}", @@ -53,30 +53,30 @@ class data_count_corrupted_exception : public archive_exception }; template , - typename Equal = std::equal_to, - typename MemoryPolicy = immer::default_memory_policy, - immer::detail::hamts::bits_t B = immer::default_bits, - typename NodesLoad = nodes_load, - typename TransformF = boost::hana::id_t> + typename Hash, + typename Equal, + typename MemoryPolicy, + immer::detail::hamts::bits_t B, + typename NodesLoad = nodes_load, + typename TransformF = boost::hana::id_t> class nodes_loader { public: using champ_t = immer::detail::hamts::champ; using node_t = typename champ_t::node_t; - using node_ptr = immer::archive::node_ptr; + using node_ptr = immer::persist::node_ptr; using values_t = immer::flex_vector>; - explicit nodes_loader(NodesLoad archive) + explicit nodes_loader(NodesLoad pool) requires std::is_same_v - : archive_{std::move(archive)} + : pool_{std::move(pool)} { } - explicit nodes_loader(NodesLoad archive, TransformF transform) - : archive_{std::move(archive)} + explicit nodes_loader(NodesLoad pool, TransformF transform) + : pool_{std::move(pool)} , transform_{std::move(transform)} { } @@ -87,11 +87,11 @@ class nodes_loader return *p; } - if (id.value >= archive_.size()) { + if (id.value >= pool_.size()) { throw invalid_node_id{id}; } - const auto& node_info = archive_[id.value]; + const auto& node_info = pool_[id.value]; const auto values = get_values(node_info.values.data); const auto n = values.size(); @@ -110,11 +110,11 @@ class nodes_loader return *p; } - if (id.value >= archive_.size()) { + if (id.value >= pool_.size()) { throw invalid_node_id{id}; } - const auto& node_info = archive_[id.value]; + const auto& node_info = pool_[id.value]; const auto children_count = node_info.children.size(); const auto values_count = node_info.values.data.size(); @@ -196,11 +196,11 @@ class nodes_loader std::pair load_some_node(node_id id) { - if (id.value >= archive_.size()) { + if (id.value >= pool_.size()) { throw invalid_node_id{id}; } - if (archive_[id.value].collisions) { + if (pool_[id.value].collisions) { return load_collision(id); } else { return load_inner(id); @@ -215,7 +215,7 @@ class nodes_loader for (const auto& child_node_id : children_ids) { auto [child, child_values] = load_some_node(child_node_id); if (!child) { - throw archive_exception{ + throw pool_exception{ fmt::format("Failed to load node ID {}", child_node_id)}; } @@ -244,11 +244,11 @@ class nodes_loader } private: - const NodesLoad archive_; + const NodesLoad pool_; const TransformF transform_; immer::map> collisions_; immer::map> inners_; }; } // namespace champ -} // namespace immer::archive +} // namespace immer::persist diff --git a/immer/extra/archive/champ/archive.hpp b/immer/extra/persist/champ/pool.hpp similarity index 88% rename from immer/extra/archive/champ/archive.hpp rename to immer/extra/persist/champ/pool.hpp index 2083e840..c7db7046 100644 --- a/immer/extra/archive/champ/archive.hpp +++ b/immer/extra/persist/champ/pool.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include @@ -8,11 +8,11 @@ #include #include -#include +#include #include -namespace immer::archive::champ { +namespace immer::persist::champ { template struct inner_node_save @@ -153,19 +153,19 @@ linearize_map(const immer::map>& inners) * Container is a champ-based container. */ template -struct container_archive_save +struct container_input_pool { using champ_t = std::decay_t().impl())>; using T = typename champ_t::node_t::value_t; nodes_save nodes; - // Saving the archived container, so that no mutations are allowed to - // happen. + // Saving the persisted container, so that no mutations are allowed to + // happen . immer::vector containers; - friend bool operator==(const container_archive_save& left, - const container_archive_save& right) + friend bool operator==(const container_input_pool& left, + const container_input_pool& right) { return left.nodes == right.nodes; } @@ -181,15 +181,15 @@ struct container_archive_save }; template -struct container_archive_load +struct container_output_pool { using champ_t = std::decay_t().impl())>; using T = typename champ_t::node_t::value_t; nodes_load nodes; - friend bool operator==(const container_archive_load& left, - const container_archive_load& right) + friend bool operator==(const container_output_pool& left, + const container_output_pool& right) { return left.nodes == right.nodes; } @@ -203,12 +203,12 @@ struct container_archive_load }; template -container_archive_load -to_load_archive(const container_archive_save& archive) +container_output_pool +to_output_pool(const container_input_pool& pool) { return { - .nodes = linearize_map(archive.nodes.inners), + .nodes = linearize_map(pool.nodes.inners), }; } -} // namespace immer::archive::champ +} // namespace immer::persist::champ diff --git a/immer/extra/archive/champ/traits.hpp b/immer/extra/persist/champ/traits.hpp similarity index 76% rename from immer/extra/archive/champ/traits.hpp rename to immer/extra/persist/champ/traits.hpp index e0faf05d..c5a54f68 100644 --- a/immer/extra/archive/champ/traits.hpp +++ b/immer/extra/persist/champ/traits.hpp @@ -1,12 +1,12 @@ #pragma once -#include -#include -#include +#include +#include +#include #include -namespace immer::archive { +namespace immer::persist { /** * A bit of a hack but currently this is the simplest way to request a type of @@ -20,16 +20,15 @@ struct target_container_type_request template struct champ_traits { - using save_archive_t = - immer::archive::champ::container_archive_save; - using load_archive_t = - immer::archive::champ::container_archive_load; - using container_id = immer::archive::node_id; + using input_pool_t = immer::persist::champ::container_input_pool; + using output_pool_t = + immer::persist::champ::container_output_pool; + using container_id = immer::persist::node_id; - template using loader_t = - immer::archive::champ::container_loader; + immer::persist::champ::container_loader; template static auto transform(F&& func) @@ -75,10 +74,10 @@ struct container_traits> namespace champ { template -auto transform_archive(const container_archive_load& ar, F&& func) +auto transform_pool(const container_output_pool& ar, F&& func) { using NewContainer = decltype(container_traits::transform(func)); - return container_archive_load{ + return container_output_pool{ .nodes = transform(ar.nodes, func), }; } @@ -103,13 +102,13 @@ struct container_traits> // the loader to do something special. static constexpr bool enable_incompatible_hash_mode = true; - template using loader_t = - immer::archive::champ::container_loader; }; -} // namespace immer::archive +} // namespace immer::persist diff --git a/immer/extra/archive/common/archive.hpp b/immer/extra/persist/common/pool.hpp similarity index 95% rename from immer/extra/archive/common/archive.hpp rename to immer/extra/persist/common/pool.hpp index 4fac89e1..2b8a487c 100644 --- a/immer/extra/archive/common/archive.hpp +++ b/immer/extra/persist/common/pool.hpp @@ -1,13 +1,13 @@ #pragma once -#include +#include #include #include #include -namespace immer::archive { +namespace immer::persist { struct node_id_tag; using node_id = type_alias; @@ -93,4 +93,4 @@ auto transform(const immer::map>& map, F&& func) return result; } -} // namespace immer::archive +} // namespace immer::persist diff --git a/immer/extra/persist/errors.hpp b/immer/extra/persist/errors.hpp new file mode 100644 index 00000000..b858792a --- /dev/null +++ b/immer/extra/persist/errors.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include + +#include + +#include + +namespace immer::persist { + +class pool_exception : public std::invalid_argument +{ +public: + using invalid_argument::invalid_argument; +}; + +class pool_has_cycles : public pool_exception +{ +public: + explicit pool_has_cycles(node_id id) + : pool_exception{fmt::format("Cycle detected with node ID {}", id)} + { + } +}; + +class invalid_node_id : public pool_exception +{ +public: + explicit invalid_node_id(node_id id) + : pool_exception{fmt::format("Node ID {} is not found", id)} + { + } +}; + +class invalid_container_id : public pool_exception +{ +public: + explicit invalid_container_id(container_id id) + : pool_exception{fmt::format("Container ID {} is not found", id)} + { + } +}; + +class invalid_children_count : public pool_exception +{ +public: + explicit invalid_children_count(node_id id) + : pool_exception{ + fmt::format("Node ID {} has more children than allowed", id)} + { + } +}; + +} // namespace immer::persist diff --git a/immer/extra/archive/json/json_immer.hpp b/immer/extra/persist/json/json_immer.hpp similarity index 57% rename from immer/extra/archive/json/json_immer.hpp rename to immer/extra/persist/json/json_immer.hpp index 2f58e895..65a7442b 100644 --- a/immer/extra/archive/json/json_immer.hpp +++ b/immer/extra/persist/json/json_immer.hpp @@ -4,10 +4,10 @@ /** * Special types of archives, working with JSON, that support providing extra - * context (ImmerArchives) to serialize immer data structures. + * context (Pools) to serialize immer data structures. */ -namespace immer::archive { +namespace immer::persist { struct blackhole_output_archive { @@ -27,27 +27,26 @@ struct blackhole_output_archive * Adapted from cereal/archives/adapters.hpp */ -template +template class json_immer_output_archive - : public cereal::OutputArchive< - json_immer_output_archive> + : public cereal::OutputArchive> , public cereal::traits::TextArchive { public: template explicit json_immer_output_archive(Args&&... args) : cereal::OutputArchive< - json_immer_output_archive>{this} + json_immer_output_archive>{this} , previous{std::forward(args)...} { } template - json_immer_output_archive(ImmerArchives archives, Args&&... args) + json_immer_output_archive(Pools pools_, Args&&... args) : cereal::OutputArchive< - json_immer_output_archive>{this} + json_immer_output_archive>{this} , previous{std::forward(args)...} - , archives{std::move(archives)} + , pools{std::move(pools_)} { } @@ -65,34 +64,32 @@ class json_immer_output_archive previous.saveValue(value); } - ImmerArchives& get_output_archives() & { return archives; } + Pools& get_input_pools() & { return pools; } - ImmerArchives&& get_output_archives() && { return std::move(archives); } + Pools&& get_input_pools() && { return std::move(pools); } void finalize() { auto& self = *this; - self(CEREAL_NVP(archives)); + self(CEREAL_NVP(pools)); } private: Previous previous; - ImmerArchives archives; + Pools pools; }; -template +template class json_immer_input_archive - : public cereal::InputArchive< - json_immer_input_archive> + : public cereal::InputArchive> , public cereal::traits::TextArchive { public: template - json_immer_input_archive(ImmerArchives archives_, Args&&... args) - : cereal::InputArchive< - json_immer_input_archive>{this} + json_immer_input_archive(Pools pools_, Args&&... args) + : cereal::InputArchive>{this} , previous{std::forward(args)...} - , archives{std::move(archives_)} + , pools{std::move(pools_)} { } @@ -108,22 +105,22 @@ class json_immer_input_archive previous.loadValue(value); } - ImmerArchives& get_input_archives() { return archives; } - const ImmerArchives& get_input_archives() const { return archives; } + Pools& get_output_pools() { return pools; } + const Pools& get_output_pools() const { return pools; } private: Previous previous; - ImmerArchives archives; + Pools pools; }; /** * NOTE: All of the following is needed, ultimately, to enable specializing * serializing functions specifically for this type of archive that provides - * access to the immer-related archive. + * access to the immer-related pools. * - * template - * void load(json_immer_input_archive& ar, - * vector_one_archivable& value) + * template + * void load(json_immer_input_archive& ar, + * vector_one_persistable& value) */ // ###################################################################### @@ -133,15 +130,15 @@ class json_immer_input_archive // ###################################################################### //! Prologue for NVPs for JSON archives /*! NVPs do not start or finish nodes - they just set up the names */ -template -inline void prologue(json_immer_output_archive&, +template +inline void prologue(json_immer_output_archive&, cereal::NameValuePair const&) { } //! Prologue for NVPs for JSON archives -template -inline void prologue(json_immer_input_archive&, +template +inline void prologue(json_immer_input_archive&, cereal::NameValuePair const&) { } @@ -149,16 +146,16 @@ inline void prologue(json_immer_input_archive&, // ###################################################################### //! Epilogue for NVPs for JSON archives /*! NVPs do not start or finish nodes - they just set up the names */ -template -inline void epilogue(json_immer_output_archive&, +template +inline void epilogue(json_immer_output_archive&, cereal::NameValuePair const&) { } //! Epilogue for NVPs for JSON archives /*! NVPs do not start or finish nodes - they just set up the names */ -template -inline void epilogue(json_immer_input_archive&, +template +inline void epilogue(json_immer_input_archive&, cereal::NameValuePair const&) { } @@ -166,15 +163,15 @@ inline void epilogue(json_immer_input_archive&, // ###################################################################### //! Prologue for deferred data for JSON archives /*! Do nothing for the defer wrapper */ -template -inline void prologue(json_immer_output_archive&, +template +inline void prologue(json_immer_output_archive&, cereal::DeferredData const&) { } //! Prologue for deferred data for JSON archives -template -inline void prologue(json_immer_input_archive&, +template +inline void prologue(json_immer_input_archive&, cereal::DeferredData const&) { } @@ -182,16 +179,16 @@ inline void prologue(json_immer_input_archive&, // ###################################################################### //! Epilogue for deferred for JSON archives /*! NVPs do not start or finish nodes - they just set up the names */ -template -inline void epilogue(json_immer_output_archive&, +template +inline void epilogue(json_immer_output_archive&, cereal::DeferredData const&) { } //! Epilogue for deferred for JSON archives /*! Do nothing for the defer wrapper */ -template -inline void epilogue(json_immer_input_archive&, +template +inline void epilogue(json_immer_input_archive&, cereal::DeferredData const&) { } @@ -200,16 +197,16 @@ inline void epilogue(json_immer_input_archive&, //! Prologue for SizeTags for JSON archives /*! SizeTags are strictly ignored for JSON, they just indicate that the current node should be made into an array */ -template -inline void prologue(json_immer_output_archive& ar, +template +inline void prologue(json_immer_output_archive& ar, cereal::SizeTag const&) { ar.makeArray(); } //! Prologue for SizeTags for JSON archives -template -inline void prologue(json_immer_input_archive&, +template +inline void prologue(json_immer_input_archive&, cereal::SizeTag const&) { } @@ -217,15 +214,15 @@ inline void prologue(json_immer_input_archive&, // ###################################################################### //! Epilogue for SizeTags for JSON archives /*! SizeTags are strictly ignored for JSON */ -template -inline void epilogue(json_immer_output_archive&, +template +inline void epilogue(json_immer_output_archive&, cereal::SizeTag const&) { } //! Epilogue for SizeTags for JSON archives -template -inline void epilogue(json_immer_input_archive&, +template +inline void epilogue(json_immer_input_archive&, cereal::SizeTag const&) { } @@ -237,40 +234,38 @@ inline void epilogue(json_immer_input_archive&, Minimal types do not start or finish nodes */ template ::value, !cereal::traits::has_minimal_base_class_serialization< T, cereal::traits::has_minimal_output_serialization, - json_immer_output_archive>::value, + json_immer_output_archive>::value, !cereal::traits::has_minimal_output_serialization< T, - json_immer_output_archive>::value> = + json_immer_output_archive>::value> = cereal::traits::sfinae> -inline void prologue(json_immer_output_archive& ar, - T const&) +inline void prologue(json_immer_output_archive& ar, T const&) { ar.startNode(); } //! Prologue for all other types for JSON archives template ::value, !cereal::traits::has_minimal_base_class_serialization< T, cereal::traits::has_minimal_input_serialization, - json_immer_input_archive>::value, + json_immer_input_archive>::value, !cereal::traits::has_minimal_input_serialization< T, - json_immer_input_archive>::value> = + json_immer_input_archive>::value> = cereal::traits::sfinae> -inline void prologue(json_immer_input_archive& ar, - T const&) +inline void prologue(json_immer_input_archive& ar, T const&) { ar.startNode(); } @@ -281,71 +276,69 @@ inline void prologue(json_immer_input_archive& ar, Minimal types do not start or finish nodes */ template ::value, !cereal::traits::has_minimal_base_class_serialization< T, cereal::traits::has_minimal_output_serialization, - json_immer_output_archive>::value, + json_immer_output_archive>::value, !cereal::traits::has_minimal_output_serialization< T, - json_immer_output_archive>::value> = + json_immer_output_archive>::value> = cereal::traits::sfinae> -inline void epilogue(json_immer_output_archive& ar, - T const&) +inline void epilogue(json_immer_output_archive& ar, T const&) { ar.finishNode(); } //! Epilogue for all other types other for JSON archives template ::value, !cereal::traits::has_minimal_base_class_serialization< T, cereal::traits::has_minimal_input_serialization, - json_immer_input_archive>::value, + json_immer_input_archive>::value, !cereal::traits::has_minimal_input_serialization< T, - json_immer_input_archive>::value> = + json_immer_input_archive>::value> = cereal::traits::sfinae> -inline void epilogue(json_immer_input_archive& ar, - T const&) +inline void epilogue(json_immer_input_archive& ar, T const&) { ar.finishNode(); } // ###################################################################### //! Prologue for arithmetic types for JSON archives -template -inline void prologue(json_immer_output_archive& ar, +template +inline void prologue(json_immer_output_archive& ar, std::nullptr_t const&) { ar.writeName(); } //! Prologue for arithmetic types for JSON archives -template -inline void prologue(json_immer_input_archive&, +template +inline void prologue(json_immer_input_archive&, std::nullptr_t const&) { } // ###################################################################### //! Epilogue for arithmetic types for JSON archives -template -inline void epilogue(json_immer_output_archive&, +template +inline void epilogue(json_immer_output_archive&, std::nullptr_t const&) { } //! Epilogue for arithmetic types for JSON archives -template -inline void epilogue(json_immer_input_archive&, +template +inline void epilogue(json_immer_input_archive&, std::nullptr_t const&) { } @@ -353,93 +346,73 @@ inline void epilogue(json_immer_input_archive&, // ###################################################################### //! Prologue for arithmetic types for JSON archives template ::value> = cereal::traits::sfinae> -inline void prologue(json_immer_output_archive& ar, - T const&) +inline void prologue(json_immer_output_archive& ar, T const&) { ar.writeName(); } //! Prologue for arithmetic types for JSON archives template ::value> = cereal::traits::sfinae> -inline void prologue(json_immer_input_archive&, - T const&) +inline void prologue(json_immer_input_archive&, T const&) { } // ###################################################################### //! Epilogue for arithmetic types for JSON archives template ::value> = cereal::traits::sfinae> -inline void epilogue(json_immer_output_archive&, - T const&) +inline void epilogue(json_immer_output_archive&, T const&) { } //! Epilogue for arithmetic types for JSON archives template ::value> = cereal::traits::sfinae> -inline void epilogue(json_immer_input_archive&, - T const&) +inline void epilogue(json_immer_input_archive&, T const&) { } // ###################################################################### //! Prologue for strings for JSON archives -template -inline void prologue(json_immer_output_archive& ar, +template +inline void prologue(json_immer_output_archive& ar, std::basic_string const&) { ar.writeName(); } //! Prologue for strings for JSON archives -template -inline void prologue(json_immer_input_archive&, +template +inline void prologue(json_immer_input_archive&, std::basic_string const&) { } // ###################################################################### //! Epilogue for strings for JSON archives -template -inline void epilogue(json_immer_output_archive&, +template +inline void epilogue(json_immer_output_archive&, std::basic_string const&) { } //! Epilogue for strings for JSON archives -template -inline void epilogue(json_immer_input_archive&, +template +inline void epilogue(json_immer_input_archive&, std::basic_string const&) { } @@ -448,18 +421,18 @@ inline void epilogue(json_immer_input_archive&, // Common JSONArchive serialization functions // ###################################################################### //! Serializing NVP types to JSON -template -inline void CEREAL_SAVE_FUNCTION_NAME( - json_immer_output_archive& ar, - cereal::NameValuePair const& t) +template +inline void +CEREAL_SAVE_FUNCTION_NAME(json_immer_output_archive& ar, + cereal::NameValuePair const& t) { ar.setNextName(t.name); ar(t.value); } -template +template inline void -CEREAL_LOAD_FUNCTION_NAME(json_immer_input_archive& ar, +CEREAL_LOAD_FUNCTION_NAME(json_immer_input_archive& ar, cereal::NameValuePair& t) { ar.setNextName(t.name); @@ -467,18 +440,18 @@ CEREAL_LOAD_FUNCTION_NAME(json_immer_input_archive& ar, } //! Saving for nullptr to JSON -template -inline void CEREAL_SAVE_FUNCTION_NAME( - json_immer_output_archive& ar, - std::nullptr_t const& t) +template +inline void +CEREAL_SAVE_FUNCTION_NAME(json_immer_output_archive& ar, + std::nullptr_t const& t) { ar.saveValue(t); } //! Loading arithmetic from JSON -template +template inline void -CEREAL_LOAD_FUNCTION_NAME(json_immer_input_archive& ar, +CEREAL_LOAD_FUNCTION_NAME(json_immer_input_archive& ar, std::nullptr_t& t) { ar.loadValue(t); @@ -486,50 +459,42 @@ CEREAL_LOAD_FUNCTION_NAME(json_immer_input_archive& ar, //! Saving for arithmetic to JSON template ::value> = cereal::traits::sfinae> -inline void CEREAL_SAVE_FUNCTION_NAME( - json_immer_output_archive& ar, T const& t) +inline void +CEREAL_SAVE_FUNCTION_NAME(json_immer_output_archive& ar, + T const& t) { ar.saveValue(t); } //! Loading arithmetic from JSON template ::value> = cereal::traits::sfinae> inline void -CEREAL_LOAD_FUNCTION_NAME(json_immer_input_archive& ar, - T& t) +CEREAL_LOAD_FUNCTION_NAME(json_immer_input_archive& ar, T& t) { ar.loadValue(t); } //! saving string to JSON -template -inline void CEREAL_SAVE_FUNCTION_NAME( - json_immer_output_archive& ar, - std::basic_string const& str) +template +inline void +CEREAL_SAVE_FUNCTION_NAME(json_immer_output_archive& ar, + std::basic_string const& str) { ar.saveValue(str); } //! loading string from JSON -template +template inline void -CEREAL_LOAD_FUNCTION_NAME(json_immer_input_archive& ar, +CEREAL_LOAD_FUNCTION_NAME(json_immer_input_archive& ar, std::basic_string& str) { ar.loadValue(str); @@ -537,42 +502,40 @@ CEREAL_LOAD_FUNCTION_NAME(json_immer_input_archive& ar, // ###################################################################### //! Saving SizeTags to JSON -template +template inline void -CEREAL_SAVE_FUNCTION_NAME(json_immer_output_archive&, +CEREAL_SAVE_FUNCTION_NAME(json_immer_output_archive&, cereal::SizeTag const&) { // nothing to do here, we don't explicitly save the size } //! Loading SizeTags from JSON -template +template inline void -CEREAL_LOAD_FUNCTION_NAME(json_immer_input_archive& ar, +CEREAL_LOAD_FUNCTION_NAME(json_immer_input_archive& ar, cereal::SizeTag& st) { ar.loadSize(st.size); } -} // namespace immer::archive +} // namespace immer::persist // tie input and output archives together namespace cereal { namespace traits { namespace detail { -template +template struct get_output_from_input< - immer::archive::json_immer_input_archive> + immer::persist::json_immer_input_archive> { - using type = - immer::archive::json_immer_output_archive; + using type = immer::persist::json_immer_output_archive; }; -template +template struct get_input_from_output< - immer::archive::json_immer_output_archive> + immer::persist::json_immer_output_archive> { - using type = - immer::archive::json_immer_input_archive; + using type = immer::persist::json_immer_input_archive; }; } // namespace detail } // namespace traits diff --git a/immer/extra/archive/json/json_immer_auto.hpp b/immer/extra/persist/json/json_immer_auto.hpp similarity index 95% rename from immer/extra/archive/json/json_immer_auto.hpp rename to immer/extra/persist/json/json_immer_auto.hpp index 911de150..84576242 100644 --- a/immer/extra/archive/json/json_immer_auto.hpp +++ b/immer/extra/persist/json/json_immer_auto.hpp @@ -4,11 +4,12 @@ /** * This cereal archive automatically wraps values into - * immer::archive::archivable whenever possible and forwards into the "previous" - * archive (which normally would be `json_immer_[out|in]put_archive`). + * immer::persist::persistable whenever possible and forwards into the + * "previous" archive (which normally would be + * `json_immer_[out|in]put_archive`). */ -namespace immer::archive { +namespace immer::persist { /** * Adapted from cereal/archives/adapters.hpp @@ -46,7 +47,7 @@ class json_immer_auto_output_archive void finalize() { auto& self = *this; - self(cereal::make_nvp("archives", previous.get_output_archives())); + self(cereal::make_nvp("pools", previous.get_input_pools())); } Previous& previous; @@ -77,8 +78,8 @@ class json_immer_auto_input_archive template void loadValue(T& value) { - // if value is a ref to something non-immer-archivable, just return the - // reference to it directly. Otherwise, wrap it in archivable. + // if value is a ref to something non-immer-persistable, just return the + // reference to it directly. Otherwise, wrap it in persistable. auto& wrapped = wrapF(value); previous.loadValue(wrapped); } @@ -90,11 +91,11 @@ class json_immer_auto_input_archive /** * NOTE: All of the following is needed, ultimately, to enable specializing * serializing functions specifically for this type of archive that provides - * access to the immer-related archive. + * access to the immer-related pools. * * template * void load(json_immer_auto_input_archive& ar, - * vector_one_archivable& value) + * vector_one_persistable& value) */ // ###################################################################### @@ -500,23 +501,23 @@ CEREAL_LOAD_FUNCTION_NAME(json_immer_auto_input_archive& ar, ar.loadSize(st.size); } -} // namespace immer::archive +} // namespace immer::persist // tie input and output archives together namespace cereal::traits::detail { template struct get_output_from_input< - immer::archive::json_immer_auto_input_archive> + immer::persist::json_immer_auto_input_archive> { using type = - immer::archive::json_immer_auto_output_archive; + immer::persist::json_immer_auto_output_archive; }; template struct get_input_from_output< - immer::archive::json_immer_auto_output_archive> + immer::persist::json_immer_auto_output_archive> { - using type = immer::archive::json_immer_auto_input_archive; + using type = immer::persist::json_immer_auto_input_archive; }; } // namespace cereal::traits::detail diff --git a/immer/extra/archive/json/json_with_archive.hpp b/immer/extra/persist/json/json_with_pool.hpp similarity index 59% rename from immer/extra/archive/json/json_with_archive.hpp rename to immer/extra/persist/json/json_with_pool.hpp index 6245c269..b1e3d6de 100644 --- a/immer/extra/archive/json/json_with_archive.hpp +++ b/immer/extra/persist/json/json_with_pool.hpp @@ -1,18 +1,18 @@ #pragma once -#include -#include #include +#include +#include #include #include /** - * to_json_with_archive + * to_json_with_pool */ -namespace immer::archive { +namespace immer::persist { namespace detail { @@ -23,13 +23,13 @@ namespace hana = boost::hana; * is. */ template -class error_no_archive_for_the_given_type_check_get_archives_types_function; +class error_no_pool_for_the_given_type_check_get_pools_types_function; template -class error_duplicate_archive_name_found; +class error_duplicate_pool_name_found; template -class error_missing_archive_for_type; +class error_missing_pool_for_type; template struct storage_holder @@ -62,17 +62,17 @@ auto make_shared_storage_holder(std::shared_ptr ptr) } /** - * Archives and functions to serialize types that contain archivable data + * Pools and functions to serialize types that contain persistable data * structures. */ template -struct archives_save +struct input_pools { using names_t = Names; Storage storage_; - // To aling the interface with archives_load + // To aling the interface with output_pools Storage& storage() { return storage_; } const Storage& storage() const { return storage_; } @@ -87,74 +87,73 @@ struct archives_save } template - auto& get_save_archive() + auto& get_input_pool() { using Contains = decltype(hana::contains(storage(), hana::type_c)); if constexpr (!Contains::value) { auto err = - error_no_archive_for_the_given_type_check_get_archives_types_function< + error_no_pool_for_the_given_type_check_get_pools_types_function< T>{}; } return storage()[hana::type_c]; } template - const auto& get_save_archive() const + const auto& get_input_pool() const { using Contains = decltype(hana::contains(storage(), hana::type_c)); if constexpr (!Contains::value) { auto err = - error_no_archive_for_the_given_type_check_get_archives_types_function< + error_no_pool_for_the_given_type_check_get_pools_types_function< T>{}; } return storage()[hana::type_c]; } - friend bool operator==(const archives_save& left, - const archives_save& right) + friend bool operator==(const input_pools& left, const input_pools& right) { return left.storage() == right.storage(); } }; template ::load_archive_t, + class Pool = typename container_traits::output_pool_t, class TransformF = boost::hana::id_t, class OldContainerType = boost::hana::id_t> -struct archive_type_load +struct output_pool { using container_t = Container; using old_container_t = OldContainerType; - Archive archive = {}; + Pool pool = {}; TransformF transform; std::optional::template loader_t> + Container>::template loader_t> loader; - archive_type_load() = default; + output_pool() = default; - explicit archive_type_load(Archive archive_) + explicit output_pool(Pool pool_) requires std::is_same_v - : archive{std::move(archive_)} + : pool{std::move(pool_)} { } - explicit archive_type_load(Archive archive_, TransformF transform_) - : archive{std::move(archive_)} + explicit output_pool(Pool pool_, TransformF transform_) + : pool{std::move(pool_)} , transform{std::move(transform_)} { } - archive_type_load(const archive_type_load& other) - : archive{other.archive} + output_pool(const output_pool& other) + : pool{other.pool} , transform{other.transform} { } - archive_type_load& operator=(const archive_type_load& other) + output_pool& operator=(const output_pool& other) { - archive = other.archive; + pool = other.pool; transform = other.transform; return *this; } @@ -162,7 +161,7 @@ struct archive_type_load auto& get_loader() { if (!loader) { - loader.emplace(archive, transform); + loader.emplace(pool, transform); } return *loader; } @@ -178,14 +177,13 @@ struct archive_type_load func))>; using TransF = std::function; // the transform function must be filled in later - return archive_type_load{ - archive, TransF{}}; + return output_pool{pool, + TransF{}}; } - friend bool operator==(const archive_type_load& left, - const archive_type_load& right) + friend bool operator==(const output_pool& left, const output_pool& right) { - return left.archive == right.archive; + return left.pool == right.pool; } }; @@ -210,7 +208,7 @@ constexpr auto inject_argument = [](auto arg, auto func) { }; template -class archives_load +class output_pools { private: StorageF storage_; @@ -218,19 +216,19 @@ class archives_load public: using names_t = Names; - archives_load() = default; + output_pools() = default; - explicit archives_load(StorageF storage) + explicit output_pools(StorageF storage) : storage_{std::move(storage)} { } - archives_load(StorageF storage, Names) + output_pools(StorageF storage, Names) : storage_{std::move(storage)} { } - bool ignore_archive_exceptions = false; + bool ignore_pool_exceptions = false; auto& storage() { return storage_(); } const auto& storage() const { return storage_(); } @@ -241,7 +239,7 @@ class archives_load using Contains = decltype(hana::contains(storage(), hana::type_c)); if constexpr (!Contains::value) { - auto err = error_missing_archive_for_type{}; + auto err = error_missing_pool_for_type{}; } return storage()[hana::type_c].get_loader(); } @@ -259,7 +257,7 @@ class archives_load using Key = decltype(find_key(storage())); using IsJust = decltype(hana::is_just(Key{})); if constexpr (!IsJust::value) { - auto err = error_missing_archive_for_type{}; + auto err = error_missing_pool_for_type{}; } return storage()[Key{}.value()].get_loader(); } @@ -270,19 +268,18 @@ class archives_load constexpr auto keys = hana::keys(names_t{}); hana::for_each(keys, [&](auto key) { constexpr auto name = names_t{}[key]; - ar(cereal::make_nvp(name.c_str(), storage()[key].archive)); + ar(cereal::make_nvp(name.c_str(), storage()[key].pool)); }); } - friend bool operator==(const archives_load& left, - const archives_load& right) + friend bool operator==(const output_pools& left, const output_pools& right) { return left.storage() == right.storage(); } /** - * Return a new archives_load after applying the described transformations - * to each archive type. + * Return a new output_pools after applying the described transformations + * to each pool type. */ template auto transform(const ConversionMap& map) const @@ -293,20 +290,20 @@ class archives_load using Contains = decltype(hana::contains(map, hana::first(pair))); if constexpr (Contains::value) { // Look up the conversion function by the type from the original - // archive. - const auto& func = map[hana::first(pair)]; - const auto& archive = hana::second(pair).archive; + // pool. + const auto& func = map[hana::first(pair)]; + const auto& pool = hana::second(pair).pool; - // Each archive defines the transform_archive function that + // Each pool defines the transform_pool function that // transforms its leaves with the given function. - auto new_archive = transform_archive(archive, func); + auto new_pool = transform_pool(pool, func); using Container = typename decltype(+hana::first(pair))::type; using NewContainer = std::decay_t< decltype(container_traits::transform(func))>; return hana::make_pair( hana::type_c, - archive_type_load{std::move(new_archive)}); + output_pool{std::move(new_pool)}); } else { return pair; } @@ -319,13 +316,13 @@ class archives_load return hana::insert(map, transform_pair(pair)); }); auto holder = make_storage_holder(std::move(new_storage)); - return archives_load{std::move(holder)}; + return output_pools{std::move(holder)}; } /** * ConversionMap is a map where keys are types of the original container * (hana::type_c>) and the values are converting - * functions that are used to convert the archives. + * functions that are used to convert the pools. * * The main feature is that the converting function can also take the second * argument, a function get_loader, which can be called with a container @@ -333,7 +330,7 @@ class archives_load * return a reference to a loader that can be used to load other containers * that have already been converted. * - * @see test/extra/archive/test_conversion.cpp + * @see test/extra/persist/test_conversion.cpp */ template auto transform_recursive(const ConversionMap& conversion_map, @@ -357,7 +354,7 @@ class archives_load decltype(hana::contains(conversion_map, hana::first(pair))); if constexpr (Contains::value) { // Look up the conversion function by the type from the - // original archive. + // original pool. const auto& func = inject_argument( fake_convert_container, conversion_map[hana::first(pair)]); auto type_load = @@ -393,7 +390,7 @@ class archives_load const auto id = get_id(old_container); using Contains = decltype(hana::contains(get_data(), new_type)); if constexpr (!Contains::value) { - auto err = error_missing_archive_for_type< + auto err = error_missing_pool_for_type< typename decltype(new_type)::type>{}; } auto& loader = get_data()[new_type].get_loader(); @@ -427,11 +424,11 @@ class archives_load }); auto holder = make_shared_storage_holder(std::move(shared_storage)); - return archives_load{std::move(holder)}; + return output_pools{std::move(holder)}; } }; -inline auto generate_archives_save(auto type_names) +inline auto generate_input_pools(auto type_names) { auto storage = hana::fold_left(type_names, hana::make_map(), [](auto map, auto pair) { @@ -440,12 +437,12 @@ inline auto generate_archives_save(auto type_names) map, hana::make_pair( hana::first(pair), - typename container_traits::save_archive_t{})); + typename container_traits::input_pool_t{})); }); using Storage = decltype(storage); using Names = decltype(type_names); - return archives_save{storage}; + return input_pools{storage}; } inline auto are_type_names_unique(auto type_names) @@ -455,7 +452,7 @@ inline auto are_type_names_unique(auto type_names) return hana::if_( hana::contains(set, hana::second(pair)), [](auto pair) { - return error_duplicate_archive_name_found< + return error_duplicate_pool_name_found< decltype(hana::second(pair))>{}; }, [&set](auto pair) { @@ -465,249 +462,226 @@ inline auto are_type_names_unique(auto type_names) return hana::length(type_names) == hana::length(names_set); } -inline auto generate_archives_load(auto type_names) +inline auto generate_output_pools(auto type_names) { auto storage = hana::fold_left(type_names, hana::make_map(), [](auto map, auto pair) { using Type = typename decltype(+hana::first(pair))::type; return hana::insert( - map, - hana::make_pair(hana::first(pair), archive_type_load{})); + map, hana::make_pair(hana::first(pair), output_pool{})); }); auto storage_f = detail::make_storage_holder(std::move(storage)); - return archives_load{std::move(storage_f), type_names}; + return output_pools{std::move(storage_f), type_names}; } template -inline auto to_load_archives(const archives_save& save_archive) +inline auto to_output_pools(const input_pools& input_pool) { - auto archives = generate_archives_load(Names{}); - boost::hana::for_each(boost::hana::keys(archives.storage()), [&](auto key) { - archives.storage()[key].archive = - to_load_archive(save_archive.storage()[key]); + auto pool = generate_output_pools(Names{}); + boost::hana::for_each(boost::hana::keys(pool.storage()), [&](auto key) { + pool.storage()[key].pool = to_output_pool(input_pool.storage()[key]); }); - return archives; + return pool; } } // namespace detail template -auto get_archives_types(const T&) +auto get_pools_types(const T&) { return boost::hana::make_map(); } -template -constexpr bool is_archive_empty() +template +constexpr bool is_pool_empty() { - using Result = decltype(boost::hana::is_empty( - boost::hana::keys(Archives{}.storage()))); + using Result = + decltype(boost::hana::is_empty(boost::hana::keys(Pools{}.storage()))); return Result::value; } -// Recursively serializes the archives but not calling finalize -template -void save_archives_impl(json_immer_output_archive& ar, - const SaveArchiveF& save_archive) +// Recursively serializes the pools but not calling finalize +template +void save_pools_impl(json_immer_output_archive& ar, + const SavePoolF& save_pool) { - using Names = typename Archives::names_t; + using Names = typename Pools::names_t; using IsUnique = decltype(detail::are_type_names_unique(Names{})); - static_assert(IsUnique::value, - "Archive names for each type must be unique"); + static_assert(IsUnique::value, "Pool names for each type must be unique"); - auto& archives = ar.get_output_archives(); + auto& pools = ar.get_input_pools(); - auto prev = archives; + auto prev = pools; while (true) { - // Keep saving archives until everything is saved. - archives = save_archive(std::move(archives)); - if (prev == archives) { + // Keep saving pools until everything is saved. + pools = save_pool(std::move(pools)); + if (prev == pools) { break; } - prev = archives; + prev = pools; } } /** - * Type T must provide a callable free function get_archives_types(const T&). + * Type T must provide a callable free function get_pools_types(const T&). */ template -auto to_json_with_archive(const T& serializable) +auto to_json_with_pool(const T& serializable) { - auto archives = - detail::generate_archives_save(get_archives_types(serializable)); - using Archives = std::decay_t; + auto pools = detail::generate_input_pools(get_pools_types(serializable)); + using Pools = std::decay_t; - const auto save_archive = [](auto archives) { + const auto save_pool = [](auto pools) { auto ar2 = - json_immer_output_archive{ - archives}; - ar2(archives); - return std::move(ar2).get_output_archives(); + json_immer_output_archive{pools}; + ar2(pools); + return std::move(ar2).get_input_pools(); }; auto os = std::ostringstream{}; { auto ar = - immer::archive::json_immer_output_archive{os}; + immer::persist::json_immer_output_archive{os}; ar(serializable); - if constexpr (!is_archive_empty()) { - save_archives_impl(ar, save_archive); + if constexpr (!is_pool_empty()) { + save_pools_impl(ar, save_pool); ar.finalize(); } - archives = std::move(ar).get_output_archives(); + pools = std::move(ar).get_input_pools(); } - return std::make_pair(os.str(), std::move(archives)); + return std::make_pair(os.str(), std::move(pools)); } -template -auto load_initial_archives(std::istream& is) +template +auto load_pools(std::istream& is, const ReloadPoolF& reload_pool) { - auto archives = Archives{}; - if constexpr (is_archive_empty()) { - return archives; + auto pools = Pools{}; + if constexpr (is_pool_empty()) { + return pools; } - auto restore = util::istream_snapshot{is}; - auto ar = cereal::JSONInputArchive{is}; - ar(CEREAL_NVP(archives)); - return archives; -} - -template -auto load_archives(std::istream& is, - Archives archives, - const ReloadArchiveF& reload_archive) -{ - if constexpr (is_archive_empty()) { - return archives; - } - - auto prev = archives; + auto prev = pools; while (true) { // Keep reloading until everything is loaded. - // Reloading of the archive might trigger validation of some containers + // Reloading of the pool might trigger validation of some containers // (hash-based, for example) because the elements actually come from - // other archives that are not yet loaded. - constexpr bool ignore_archive_exceptions = true; - archives = - reload_archive(is, std::move(archives), ignore_archive_exceptions); - if (prev == archives) { + // other pools that are not yet loaded. + constexpr bool ignore_pool_exceptions = true; + pools = reload_pool(is, std::move(pools), ignore_pool_exceptions); + if (prev == pools) { // Looks like we're done, reload one more time but do not ignore the // exceptions, for the final validation. - archives = reload_archive(is, std::move(archives), false); + pools = reload_pool(is, std::move(pools), false); break; } - prev = archives; + prev = pools; } - return archives; + return pools; } -constexpr auto reload_archive = - [](std::istream& is, auto archives, bool ignore_archive_exceptions) { - using Archives = std::decay_t; - auto restore = util::istream_snapshot{is}; - archives.ignore_archive_exceptions = ignore_archive_exceptions; - auto ar = json_immer_input_archive{ - std::move(archives), is}; +constexpr auto reload_pool = + [](std::istream& is, auto pools, bool ignore_pool_exceptions) { + using Pools = std::decay_t; + auto restore = util::istream_snapshot{is}; + pools.ignore_pool_exceptions = ignore_pool_exceptions; + auto ar = json_immer_input_archive{ + std::move(pools), is}; /** - * NOTE: Critical to clear the archives before loading into it - * again. I hit a bug when archives contained a vector and every + * NOTE: Critical to clear the pools before loading into it + * again. I hit a bug when pools contained a vector and every * load would append to it, instead of replacing the contents. */ - archives = {}; - ar(CEREAL_NVP(archives)); - return archives; + pools = {}; + ar(CEREAL_NVP(pools)); + return pools; }; template -T from_json_with_archive(std::istream& is) +T from_json_with_pool(std::istream& is) { - using Archives = std::decay_t())))>; - auto archives = - load_archives(is, load_initial_archives(is), reload_archive); - - auto ar = immer::archive::json_immer_input_archive{ - std::move(archives), is}; + using Pools = std::decay_t())))>; + auto pools = load_pools(is, reload_pool); + + auto ar = + immer::persist::json_immer_input_archive{std::move(pools), is}; auto r = T{}; ar(r); return r; } template -T from_json_with_archive(const std::string& input) +T from_json_with_pool(const std::string& input) { auto is = std::istringstream{input}; - return from_json_with_archive(is); + return from_json_with_pool(is); } template -T from_json_with_archive_with_conversion(std::istream& is, - const ConversionsMap& map) +T from_json_with_pool_with_conversion(std::istream& is, + const ConversionsMap& map) { - // Load the archives part for the old type - using OldArchives = std::decay_t())))>; - auto archives_old = load_archives( - is, load_initial_archives(is), reload_archive); - auto archives = archives_old.transform(map); - using Archives = decltype(archives); - - auto ar = immer::archive::json_immer_input_archive{ - std::move(archives), is}; + // Load the pools part for the old type + using OldPools = std::decay_t())))>; + auto pools_old = load_pools(is, reload_pool); + auto pools = pools_old.transform(map); + using Pools = decltype(pools); + + auto ar = + immer::persist::json_immer_input_archive{std::move(pools), is}; auto r = T{}; ar(r); return r; } template -T from_json_with_archive_with_conversion(const std::string& input, - const ConversionsMap& map) +T from_json_with_pool_with_conversion(const std::string& input, + const ConversionsMap& map) { auto is = std::istringstream{input}; - return from_json_with_archive_with_conversion(is, map); + return from_json_with_pool_with_conversion(is, map); } template -auto get_container_id(const detail::archives_save& archives, +auto get_container_id(const detail::input_pools& pools, const Container& container) { - const auto& old_archive = - archives.template get_save_archive>(); - const auto [new_archive, id] = save_to_archive(container, old_archive); - if (!(new_archive == old_archive)) { + const auto& old_pool = + pools.template get_input_pool>(); + const auto [new_pool, id] = add_to_pool(container, old_pool); + if (!(new_pool == old_pool)) { throw std::logic_error{ - "Expecting that the container has already been archived"}; + "Expecting that the container has already been poold"}; } return id; } /** - * Given an archives_save and a map of transformations, produce a new type of - * load archive with those transformations applied + * Given an input_pools and a map of transformations, produce a new type of + * load pool with those transformations applied */ template -inline auto transform_save_archive( - const detail::archives_save& old_archives, - const ConversionMap& conversion_map) +inline auto +transform_input_pool(const detail::input_pools& old_pools, + const ConversionMap& conversion_map) { - const auto old_load_archives = to_load_archives(old_archives); - // NOTE: We have to copy old_archives here because the get_id function will + const auto old_load_pools = to_output_pools(old_pools); + // NOTE: We have to copy old_pools here because the get_id function will // be called later, as the conversion process is lazy. - const auto get_id = [old_archives](const auto& immer_container) { - return get_container_id(old_archives, immer_container); + const auto get_id = [old_pools](const auto& immer_container) { + return get_container_id(old_pools, immer_container); }; - return old_load_archives.transform_recursive(conversion_map, get_id); + return old_load_pools.transform_recursive(conversion_map, get_id); } /** - * Given an old save archives and a new (transformed) load archives, effectively + * Given an old save pools and a new (transformed) load pools, effectively * convert the given container. */ template auto convert_container( - const detail::archives_save& old_save_archives, - detail::archives_load& new_load_archives, + const detail::input_pools& old_save_pools, + detail::output_pools& new_load_pools, const Container& container) { - const auto container_id = get_container_id(old_save_archives, container); + const auto container_id = get_container_id(old_save_pools, container); auto& loader = - new_load_archives + new_load_pools .template get_loader_by_old_container>(); auto result = loader.load(container_id); - // return std::make_pair(std::move(result), std::move(new_load_archives)); + // return std::make_pair(std::move(result), std::move(new_load_pools)); return result; } -} // namespace immer::archive +} // namespace immer::persist diff --git a/immer/extra/persist/json/json_with_pool_auto.hpp b/immer/extra/persist/json/json_with_pool_auto.hpp new file mode 100644 index 00000000..6de479e1 --- /dev/null +++ b/immer/extra/persist/json/json_with_pool_auto.hpp @@ -0,0 +1,353 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +namespace immer::persist { + +template +struct is_auto_ignored_type : boost::hana::false_ +{}; + +template +struct is_auto_ignored_type>> + : boost::hana::true_ +{}; + +template +struct is_auto_ignored_type>> + : boost::hana::true_ +{}; + +template <> +struct is_auto_ignored_type> + : boost::hana::true_ +{}; + +template <> +struct is_auto_ignored_type> : boost::hana::true_ +{}; + +template <> +struct is_auto_ignored_type> : boost::hana::true_ +{}; + +/** + * This wrapper is used to load a given container via persistable. + */ +template +struct persistable_loader_wrapper +{ + Container& value; + + template + typename container_traits::container_id::rep_t + save_minimal(const Archive&) const + { + throw std::logic_error{ + "Should never be called. persistable_loader_wrapper::save_minimal"}; + } + + template + void load_minimal( + const Archive& ar, + const typename container_traits::container_id::rep_t& + container_id) + { + persistable arch; + immer::persist::load_minimal(ar.previous, arch, container_id); + value = std::move(arch).container; + } +}; + +constexpr auto is_persistable = boost::hana::is_valid( + [](auto&& obj) -> + typename container_traits>::input_pool_t {}); + +constexpr auto is_auto_ignored = [](const auto& value) { + return is_auto_ignored_type>{}; +}; + +/** + * Make a function that operates conditionally on its single argument, based on + * the given predicate. If the predicate is not satisfied, the function forwards + * its argument unchanged. + */ +constexpr auto make_conditional_func = [](auto pred, auto func) { + return [pred, func](auto&& value) -> decltype(auto) { + return boost::hana::if_(pred(value), func, boost::hana::id)( + std::forward(value)); + }; +}; + +// We must not try to persist types that are actually the pool itself, +// for example, `immer::map> leaves` etc. +constexpr auto exclude_internal_pool_types = [](auto wrap) { + namespace hana = boost::hana; + return make_conditional_func(hana::compose(hana::not_, is_auto_ignored), + wrap); +}; + +constexpr auto to_persistable = [](const auto& x) { + return persistable>(x); +}; + +constexpr auto to_persistable_loader = [](auto& value) { + using V = std::decay_t; + return persistable_loader_wrapper{value}; +}; + +/** + * This function will wrap a value in persistable if possible or will return a + * reference to its argument. + */ +constexpr auto wrap_for_saving = exclude_internal_pool_types( + make_conditional_func(is_persistable, to_persistable)); + +constexpr auto wrap_for_loading = exclude_internal_pool_types( + make_conditional_func(is_persistable, to_persistable_loader)); + +/** + * Generate a hana map of persistable members for a given type T. + * Where key is a type (persistable immer container) and value is a name for + * that pool (using the member name from the given struct). Example: + * [(type_c>, "tracks")] + */ +template +auto get_auto_pools_types(const T& value) +{ + namespace hana = boost::hana; + static_assert(hana::Struct::value, + "get_auto_pools_types works only with types that " + "implement hana::Struct concept"); + + constexpr auto is_persistable_key = [](auto key) { + return is_persistable(hana::at_key(T{}, key)); + }; + + // A list of pairs like (hana::type_c, "member_name") + auto pairs = hana::transform( + hana::filter(hana::keys(value), is_persistable_key), [&](auto key) { + const auto& member = hana::at_key(value, key); + return hana::make_pair(hana::typeid_(member), key); + }); + + return hana::unpack(pairs, hana::make_map); +} + +/** + * Generate a hana map of persistable members for the given types and apply + * manual overrides for names. + * manual_overrides is a map of manual overrides. + */ +auto get_pools_for_types(auto types, + auto manual_overrides = boost::hana::make_map()) +{ + namespace hana = boost::hana; + // Automatically generate names and pools + const auto names = + hana::fold_left(hana::transform(types, + [](auto t) { + using T = + typename decltype(t)::type; + return get_auto_pools_types(T{}); + }), + hana::make_map(), + hana::union_); + // Apply the overrides + return hana::union_(names, manual_overrides); +} + +template > +auto to_json_with_auto_pool(const T& serializable, + const PoolsTypes& pools_types, + const WrapF& wrap = wrap_for_saving) +{ + namespace hana = boost::hana; + + // In the future, wrap function may ignore certain user-provided types that + // should not be persisted. + static_assert( + std::is_same_v())), + const std::string&>, + "wrap must return a reference when it's not wrapping the type"); + static_assert( + std::is_same_v{})), + persistable>>, + "and a value when it's wrapping"); + + auto pools = detail::generate_input_pools(pools_types); + using Pools = std::decay_t; + + const auto save_pool = [wrap](auto pools) { + auto previous = + json_immer_output_archive{pools}; + auto ar = json_immer_auto_output_archive{previous, wrap}; + ar(pools); + return std::move(previous).get_input_pools(); + }; + + auto os = std::ostringstream{}; + { + auto previous = + json_immer_output_archive{os}; + auto ar = json_immer_auto_output_archive{previous, wrap}; + // value0 because that's now cereal saves the unnamed object by default, + // maybe change later. + ar(cereal::make_nvp("value0", serializable)); + if constexpr (!is_pool_empty()) { + save_pools_impl(previous, save_pool); + ar.finalize(); + } + pools = std::move(previous).get_input_pools(); + } + return std::make_pair(os.str(), std::move(pools)); +} + +// Same as to_json_with_auto_pool but we don't generate any JSON. +template > +auto get_auto_pool(const T& serializable, + const PoolsTypes& pools_types, + const WrapF& wrap = wrap_for_saving) +{ + namespace hana = boost::hana; + + // In the future, wrap function may ignore certain user-provided types that + // should not be persisted. + static_assert( + std::is_same_v())), + const std::string&>, + "wrap must return a reference when it's not wrapping the type"); + static_assert( + std::is_same_v{})), + persistable>>, + "and a value when it's wrapping"); + + auto pools = detail::generate_input_pools(pools_types); + using Pools = std::decay_t; + + const auto save_pool = [wrap](auto pools) { + auto previous = + json_immer_output_archive{pools}; + auto ar = json_immer_auto_output_archive{previous, wrap}; + ar(pools); + return std::move(previous).get_input_pools(); + }; + + { + auto previous = + json_immer_output_archive{}; + auto ar = json_immer_auto_output_archive{previous, wrap}; + // value0 because that's now cereal saves the unnamed object by default, + // maybe change later. + ar(cereal::make_nvp("value0", serializable)); + if constexpr (!is_pool_empty()) { + save_pools_impl(previous, save_pool); + ar.finalize(); + } + pools = std::move(previous).get_input_pools(); + } + return pools; +} + +constexpr auto reload_pool_auto = [](auto wrap) { + return [wrap](std::istream& is, auto pools, bool ignore_pool_exceptions) { + using Pools = std::decay_t; + auto restore = util::istream_snapshot{is}; + pools.ignore_pool_exceptions = ignore_pool_exceptions; + auto previous = + json_immer_input_archive{ + std::move(pools), is}; + auto ar = json_immer_auto_input_archive{previous, wrap}; + /** + * NOTE: Critical to clear the pools before loading into it + * again. I hit a bug when pools contained a vector and every + * load would append to it, instead of replacing the contents. + */ + pools = {}; + ar(CEREAL_NVP(pools)); + return pools; + }; +}; + +template +T from_json_with_auto_pool(std::istream& is, const PoolsTypes& pools_types) +{ + namespace hana = boost::hana; + constexpr auto wrap = wrap_for_loading; + + using Pools = + std::decay_t; + + auto pools = load_pools(is, reload_pool_auto(wrap)); + + auto previous = json_immer_input_archive{ + std::move(pools), is}; + auto ar = json_immer_auto_input_archive{previous, wrap}; + // value0 because that's now cereal saves the unnamed object by default, + // maybe change later. + auto value0 = T{}; + ar(CEREAL_NVP(value0)); + return value0; +} + +template +T from_json_with_auto_pool(const std::string& input, + const PoolsTypes& pools_types) +{ + auto is = std::istringstream{input}; + return from_json_with_auto_pool(is, pools_types); +} + +template +T from_json_with_auto_pool_with_conversion(std::istream& is, + const ConversionsMap& map, + const PoolsTypes& pools_types) +{ + constexpr auto wrap = wrap_for_loading; + + // Load the pools part for the old type + using OldPools = + std::decay_t; + auto pools_old = load_pools(is, reload_pool_auto(wrap)); + + auto pools = pools_old.transform(map); + using Pools = decltype(pools); + + auto previous = json_immer_input_archive{ + std::move(pools), is}; + auto ar = json_immer_auto_input_archive{previous, wrap}; + auto r = T{}; + ar(r); + return r; +} + +template +T from_json_with_auto_pool_with_conversion(const std::string& input, + const ConversionsMap& map, + const PoolsTypes& pools_types) +{ + auto is = std::istringstream{input}; + return from_json_with_auto_pool_with_conversion( + is, map, pools_types); +} + +} // namespace immer::persist diff --git a/immer/extra/archive/json/archivable.hpp b/immer/extra/persist/json/persistable.hpp similarity index 63% rename from immer/extra/archive/json/archivable.hpp rename to immer/extra/persist/json/persistable.hpp index decc815e..554b327a 100644 --- a/immer/extra/archive/json/archivable.hpp +++ b/immer/extra/persist/json/persistable.hpp @@ -1,16 +1,16 @@ #pragma once -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include -namespace immer::archive { +namespace immer::persist { namespace detail { template @@ -35,50 +35,50 @@ auto get_iterator_type() } // namespace detail template -struct archivable +struct persistable { Container container; - archivable() = default; + persistable() = default; - archivable(std::initializer_list values) + persistable(std::initializer_list values) : container{std::move(values)} { } - archivable(Container container_) + persistable(Container container_) : container{std::move(container_)} { } - archivable(const archivable& other) + persistable(const persistable& other) : container{other.container} { } - archivable& operator=(const archivable&) = default; + persistable& operator=(const persistable&) = default; - archivable(archivable&& other) + persistable(persistable&& other) : container{std::move(other.container)} { } - archivable& operator=(archivable&&) = default; + persistable& operator=(persistable&&) = default; - friend bool operator==(const archivable& left, const archivable& right) + friend bool operator==(const persistable& left, const persistable& right) { return left.container == right.container; } // template , bool> = true> - // friend auto begin(const archivable& value) + // friend auto begin(const persistable& value) // { // return value.container.begin(); // } // friend std::enable_if_t, // decltype(std::declval().end())> - // end(const archivable& value) + // end(const persistable& value) // { // return value.container.end(); // } @@ -87,25 +87,23 @@ struct archivable template auto save_minimal( const json_immer_output_archive>& ar, - const archivable& value) + detail::input_pools>& ar, + const persistable& value) { - auto& save_archive = + auto& pool = const_cast< json_immer_output_archive>&>( - ar) - .get_output_archives() - .template get_save_archive(); - auto [archive, id] = - save_to_archive(value.container, std::move(save_archive)); - save_archive = std::move(archive); + detail::input_pools>&>(ar) + .get_input_pools() + .template get_input_pool(); + auto [pool2, id] = add_to_pool(value.container, std::move(pool)); + pool = std::move(pool2); return id.value; } -template -auto save_minimal(const json_immer_auto_output_archive& ar, - const archivable& value) +template +auto save_minimal(const json_immer_auto_output_archive& ar, + const persistable& value) { return save_minimal(ar.previous, value); } @@ -115,8 +113,8 @@ auto save_minimal(const json_immer_auto_output_archive& ar, template auto save_minimal( const json_immer_output_archive>& ar, - const archivable& value) -> + detail::output_pools>& ar, + const persistable& value) -> typename container_traits::container_id::rep_t { throw std::logic_error{"Should never be called"}; @@ -125,12 +123,12 @@ auto save_minimal( template void load_minimal( const json_immer_input_archive& ar, - archivable& value, + persistable& value, const typename container_traits::container_id::rep_t& id) { auto& loader = const_cast&>(ar) - .get_input_archives() + .get_output_pools() .template get_loader(); // Have to be specific because for vectors container_id is different from @@ -140,10 +138,10 @@ void load_minimal( try { value.container = loader.load(container_id_{id}); - } catch (const archive_exception& ex) { - if (!ar.get_input_archives().ignore_archive_exceptions) { + } catch (const pool_exception& ex) { + if (!ar.get_output_pools().ignore_pool_exceptions) { throw ::cereal::Exception{fmt::format( - "Failed to load a container ID {} from the archive of {}: {}", + "Failed to load a container ID {} from the pool of {}: {}", id, boost::core::demangle(typeid(Container).name()), ex.what())}; @@ -154,7 +152,7 @@ void load_minimal( // This function must exist because cereal does some checks and it's not // possible to have only load_minimal for a type without having save_minimal. template -auto save_minimal(const Archive& ar, const archivable& value) -> +auto save_minimal(const Archive& ar, const persistable& value) -> typename container_traits::container_id::rep_t { throw std::logic_error{ @@ -164,11 +162,11 @@ auto save_minimal(const Archive& ar, const archivable& value) -> template void load_minimal( const Archive& ar, - archivable& value, + persistable& value, const typename container_traits::container_id::rep_t& id) { // This one is actually called while loading with not-yet-fully-loaded - // archive. + // pool. } -} // namespace immer::archive +} // namespace immer::persist diff --git a/immer/extra/archive/node_ptr.hpp b/immer/extra/persist/node_ptr.hpp similarity index 97% rename from immer/extra/archive/node_ptr.hpp rename to immer/extra/persist/node_ptr.hpp index 916607bd..a657eb74 100644 --- a/immer/extra/archive/node_ptr.hpp +++ b/immer/extra/persist/node_ptr.hpp @@ -4,7 +4,7 @@ #include -namespace immer::archive { +namespace immer::persist { template struct ptr_with_deleter @@ -120,4 +120,4 @@ class node_ptr ptr_with_deleter ptr; }; -} // namespace immer::archive +} // namespace immer::persist diff --git a/immer/extra/persist/rbts/input.hpp b/immer/extra/persist/rbts/input.hpp new file mode 100644 index 00000000..49fa82a3 --- /dev/null +++ b/immer/extra/persist/rbts/input.hpp @@ -0,0 +1,216 @@ +#pragma once + +#include + +namespace immer::persist::rbts { + +namespace detail { + +template +std::pair, node_id> +get_node_id(input_pool pool, + const immer::detail::rbts::node* ptr) +{ + auto* ptr_void = static_cast(ptr); + if (auto* maybe_id = pool.node_ptr_to_id.find(ptr_void)) { + auto id = *maybe_id; + return {std::move(pool), id}; + } + + const auto id = node_id{pool.node_ptr_to_id.size()}; + pool.node_ptr_to_id = std::move(pool.node_ptr_to_id).set(ptr_void, id); + return {std::move(pool), id}; +} + +template +struct pool_builder +{ + input_pool pool; + + template + void operator()(regular_pos_tag, Pos& pos, auto&& visit) + { + auto id = get_node_id(pos.node()); + if (pool.inners.count(id)) { + return; + } + + auto node_info = inner_node{}; + // Explicit this-> call to workaround an "unused this" warning. + pos.each(visitor_helper{}, + [&node_info, &visit, this]( + auto any_tag, auto& child_pos, auto&&) mutable { + node_info.children = + std::move(node_info.children) + .push_back(this->get_node_id(child_pos.node())); + visit(child_pos); + }); + pool.inners = std::move(pool.inners).set(id, node_info); + } + + template + void operator()(relaxed_pos_tag, Pos& pos, auto&& visit) + { + auto id = get_node_id(pos.node()); + if (pool.inners.count(id)) { + return; + } + + auto node_info = inner_node{ + .relaxed = true, + }; + + pos.each(visitor_helper{}, [&](auto any_tag, auto& child_pos, auto&&) { + node_info.children = std::move(node_info.children) + .push_back(get_node_id(child_pos.node())); + + visit(child_pos); + }); + + assert(node_info.children.size() == pos.node()->relaxed()->d.count); + + pool.inners = std::move(pool.inners).set(id, node_info); + } + + template + void operator()(leaf_pos_tag, Pos& pos, auto&& visit) + { + T* first = pos.node()->leaf(); + auto id = get_node_id(pos.node()); + if (pool.leaves.count(id)) { + return; + } + + auto info = values_save{ + .begin = first, + .end = first + pos.count(), + }; + pool.leaves = std::move(pool.leaves).set(id, std::move(info)); + } + + node_id get_node_id(immer::detail::rbts::node* ptr) + { + auto [pool2, id] = + immer::persist::rbts::detail::get_node_id(std::move(pool), ptr); + pool = std::move(pool2); + return id; + } +}; + +template +auto save_nodes(const immer::detail::rbts::rbtree& tree, + Pool pool) +{ + auto save = pool_builder{ + .pool = std::move(pool), + }; + tree.traverse(visitor_helper{}, save); + return std::move(save.pool); +} + +template +auto save_nodes( + const immer::detail::rbts::rrbtree& tree, Pool pool) +{ + auto save = pool_builder{ + .pool = std::move(pool), + }; + tree.traverse(visitor_helper{}, save); + return std::move(save.pool); +} + +} // namespace detail + +template +std::pair, container_id> +add_to_pool(immer::vector vec, + input_pool pool) +{ + const auto& impl = vec.impl(); + auto root_id = node_id{}; + auto tail_id = node_id{}; + std::tie(pool, root_id) = detail::get_node_id(std::move(pool), impl.root); + std::tie(pool, tail_id) = detail::get_node_id(std::move(pool), impl.tail); + const auto tree_id = rbts_info{ + .root = root_id, + .tail = tail_id, + }; + + if (auto* p = pool.rbts_to_id.find(tree_id)) { + // Already been saved + auto vector_id = *p; + return {std::move(pool), vector_id}; + } + + pool = detail::save_nodes(impl, std::move(pool)); + + assert(pool.inners.count(root_id)); + assert(pool.leaves.count(tail_id)); + + const auto vector_id = container_id{pool.vectors.size()}; + + pool.rbts_to_id = std::move(pool.rbts_to_id).set(tree_id, vector_id); + pool.vectors = std::move(pool.vectors).push_back(tree_id); + pool.saved_vectors = + std::move(pool.saved_vectors).push_back(std::move(vec)); + + return {std::move(pool), vector_id}; +} + +template +std::pair, container_id> +add_to_pool(immer::flex_vector vec, + input_pool pool) +{ + const auto& impl = vec.impl(); + auto root_id = node_id{}; + auto tail_id = node_id{}; + std::tie(pool, root_id) = detail::get_node_id(std::move(pool), impl.root); + std::tie(pool, tail_id) = detail::get_node_id(std::move(pool), impl.tail); + const auto tree_id = rbts_info{ + .root = root_id, + .tail = tail_id, + }; + + if (auto* p = pool.rbts_to_id.find(tree_id)) { + // Already been saved + auto vector_id = *p; + return {std::move(pool), vector_id}; + } + + pool = detail::save_nodes(impl, std::move(pool)); + + assert(pool.inners.count(root_id)); + assert(pool.leaves.count(tail_id)); + + const auto vector_id = container_id{pool.vectors.size()}; + + pool.rbts_to_id = std::move(pool.rbts_to_id).set(tree_id, vector_id); + pool.vectors = std::move(pool.vectors).push_back(tree_id); + pool.saved_flex_vectors = + std::move(pool.saved_flex_vectors).push_back(std::move(vec)); + + return {std::move(pool), vector_id}; +} + +} // namespace immer::persist::rbts diff --git a/immer/extra/archive/rbts/load.hpp b/immer/extra/persist/rbts/output.hpp similarity index 86% rename from immer/extra/archive/rbts/load.hpp rename to immer/extra/persist/rbts/output.hpp index 93d5a26d..99fad006 100644 --- a/immer/extra/archive/rbts/load.hpp +++ b/immer/extra/persist/rbts/output.hpp @@ -1,9 +1,9 @@ #pragma once -#include -#include -#include -#include +#include +#include +#include +#include #include #include @@ -13,7 +13,7 @@ #include -namespace immer::archive::rbts { +namespace immer::persist::rbts { inline constexpr auto get_shift_for_depth(immer::detail::rbts::bits_t b, immer::detail::rbts::bits_t bl, @@ -24,18 +24,18 @@ inline constexpr auto get_shift_for_depth(immer::detail::rbts::bits_t b, return bits_leaf + bits * (immer::detail::rbts::shift_t{depth} - 1); } -class vector_corrupted_exception : public archive_exception +class vector_corrupted_exception : public pool_exception { public: vector_corrupted_exception(node_id id_, std::size_t expected_count_, std::size_t real_count_) - : archive_exception{fmt::format("Loaded vector is corrupted. Inner " - "node ID {} should " - "have {} children but it has {}", - id_, - expected_count_, - real_count_)} + : pool_exception{fmt::format("Loaded vector is corrupted. Inner " + "node ID {} should " + "have {} children but it has {}", + id_, + expected_count_, + real_count_)} , id{id_} , expected_count{expected_count_} , real_count{real_count_} @@ -47,12 +47,11 @@ class vector_corrupted_exception : public archive_exception std::size_t real_count; }; -class relaxed_node_not_allowed_exception : public archive_exception +class relaxed_node_not_allowed_exception : public pool_exception { public: relaxed_node_not_allowed_exception(node_id id_) - : archive_exception{fmt::format("Node ID {} can't be a relaxed node", - id_)} + : pool_exception{fmt::format("Node ID {} can't be a relaxed node", id_)} , id{id_} { } @@ -60,14 +59,14 @@ class relaxed_node_not_allowed_exception : public archive_exception node_id id; }; -class same_depth_children_exception : public archive_exception +class same_depth_children_exception : public pool_exception { public: same_depth_children_exception(node_id id, std::size_t expected_depth, node_id child_id, std::size_t real_depth) - : archive_exception{ + : pool_exception{ fmt::format("All children of node {} must have the same depth " "{}, but the child {} has depth {}", id, @@ -82,7 +81,7 @@ template , + class Pool = output_pool, class TransformF = boost::hana::id_t> class loader { @@ -93,25 +92,25 @@ class loader using node_ptr = node_ptr; using nodes_set_t = immer::set; - explicit loader(Archive ar) + explicit loader(Pool pool) requires std::is_same_v - : ar_{std::move(ar)} + : pool_{std::move(pool)} { } - explicit loader(Archive ar, TransformF transform) - : ar_{std::move(ar)} + explicit loader(Pool pool, TransformF transform) + : pool_{std::move(pool)} , transform_{std::move(transform)} { } immer::vector load_vector(container_id id) { - if (id.value >= ar_.vectors.size()) { + if (id.value >= pool_.vectors.size()) { throw invalid_container_id{id}; } - const auto& info = ar_.vectors[id.value]; + const auto& info = pool_.vectors[id.value]; const auto relaxed_allowed = false; auto root = load_inner(info.root, {}, relaxed_allowed); @@ -133,11 +132,11 @@ class loader immer::flex_vector load_flex_vector(container_id id) { - if (id.value >= ar_.vectors.size()) { + if (id.value >= pool_.vectors.size()) { throw invalid_container_id{id}; } - const auto& info = ar_.vectors[id.value]; + const auto& info = pool_.vectors[id.value]; const auto relaxed_allowed = true; auto root = load_inner(info.root, {}, relaxed_allowed); @@ -165,7 +164,7 @@ class loader return *p; } - auto* node_info = ar_.leaves.find(id); + auto* node_info = pool_.leaves.find(id); if (!node_info) { throw invalid_node_id{id}; } @@ -206,14 +205,14 @@ class loader load_inner(node_id id, nodes_set_t loading_nodes, bool relaxed_allowed) { if (loading_nodes.count(id)) { - throw archive_has_cycles{id}; + throw pool_has_cycles{id}; } if (auto* p = inners_.find(id)) { return *p; } - auto* node_info = ar_.inners.find(id); + auto* node_info = pool_.inners.find(id); if (!node_info) { throw invalid_node_id{id}; } @@ -306,10 +305,10 @@ class loader load_some_node(node_id id, nodes_set_t loading_nodes, bool relaxed_allowed) { // Unknown type: leaf, inner or relaxed - if (ar_.leaves.count(id)) { + if (pool_.leaves.count(id)) { return load_leaf(id); } - if (ar_.inners.count(id)) { + if (pool_.inners.count(id)) { return load_inner(id, std::move(loading_nodes), relaxed_allowed); } throw invalid_node_id{id}; @@ -334,15 +333,15 @@ class loader return *p; } auto size = [&] { - if (auto* p = ar_.leaves.find(id)) { + if (auto* p = pool_.leaves.find(id)) { return p->data.size(); } - if (auto* p = ar_.inners.find(id)) { + if (auto* p = pool_.inners.find(id)) { auto result = std::size_t{}; loading_nodes = std::move(loading_nodes).insert(id); for (const auto& child_id : p->children) { if (loading_nodes.count(child_id)) { - throw archive_has_cycles{child_id}; + throw pool_has_cycles{child_id}; } result += get_node_size(child_id, loading_nodes); } @@ -360,10 +359,10 @@ class loader return *p; } auto depth = [&]() -> immer::detail::rbts::count_t { - if (auto* p = ar_.leaves.find(id)) { + if (auto* p = pool_.leaves.find(id)) { return 0; } - if (auto* p = ar_.inners.find(id)) { + if (auto* p = pool_.inners.find(id)) { if (p->children.empty()) { return 1; } else { @@ -419,7 +418,7 @@ class loader throw std::logic_error{"Inner node of a freshly loaded " "vector is unknown"}; } - const auto* info = ar_.inners.find(*id); + const auto* info = pool_.inners.find(*id); assert(info); if (!info) { throw std::logic_error{ @@ -471,7 +470,7 @@ class loader throw std::logic_error{ "Leaf of a freshly loaded vector is unknown"}; } - const auto* info = ar_.leaves.find(*id); + const auto* info = pool_.leaves.find(*id); assert(info); if (!info) { throw std::logic_error{ @@ -488,7 +487,7 @@ class loader } private: - const Archive ar_; + const Pool pool_; const TransformF transform_; immer::map leaves_; immer::map inners_; @@ -502,26 +501,26 @@ template , + class Pool = output_pool, class TransformF = boost::hana::id_t> class vector_loader { public: - explicit vector_loader(Archive ar) + explicit vector_loader(Pool pool) requires std::is_same_v - : loader{std::move(ar)} + : loader{std::move(pool)} { } - explicit vector_loader(Archive ar, TransformF transform) - : loader{std::move(ar), std::move(transform)} + explicit vector_loader(Pool pool, TransformF transform) + : loader{std::move(pool), std::move(transform)} { } auto load(container_id id) { return loader.load_vector(id); } private: - loader loader; + loader loader; }; template vector_loader make_loader_for(const immer::vector&, - archive_load ar) + output_pool pool) { - return vector_loader{std::move(ar)}; + return vector_loader{std::move(pool)}; } template , + class Pool = output_pool, class TransformF = boost::hana::id_t> class flex_vector_loader { public: - explicit flex_vector_loader(Archive ar) + explicit flex_vector_loader(Pool pool) requires std::is_same_v - : loader{std::move(ar)} + : loader{std::move(pool)} { } - explicit flex_vector_loader(Archive ar, TransformF transform) - : loader{std::move(ar), std::move(transform)} + explicit flex_vector_loader(Pool pool, TransformF transform) + : loader{std::move(pool), std::move(transform)} { } auto load(container_id id) { return loader.load_flex_vector(id); } private: - loader loader; + loader loader; }; template flex_vector_loader make_loader_for(const immer::flex_vector&, - archive_load ar) + output_pool pool) { - return flex_vector_loader{std::move(ar)}; + return flex_vector_loader{std::move(pool)}; } -} // namespace immer::archive::rbts +} // namespace immer::persist::rbts diff --git a/immer/extra/archive/rbts/archive.hpp b/immer/extra/persist/rbts/pool.hpp similarity index 66% rename from immer/extra/archive/rbts/archive.hpp rename to immer/extra/persist/rbts/pool.hpp index eb60843a..d0f76d6f 100644 --- a/immer/extra/archive/rbts/archive.hpp +++ b/immer/extra/persist/rbts/pool.hpp @@ -1,9 +1,9 @@ #pragma once -#include -#include -#include -#include +#include +#include +#include +#include #include #include @@ -12,7 +12,7 @@ #include -namespace immer::archive::rbts { +namespace immer::persist::rbts { struct inner_node { @@ -48,7 +48,7 @@ template -struct archive_save +struct input_pool { immer::map> leaves; immer::map inners; @@ -57,14 +57,14 @@ struct archive_save immer::map rbts_to_id; immer::map node_ptr_to_id; - // Saving the archived vectors, so that no mutations are allowed to happen. + // Saving the persisted vectors, so that no mutations are allowed to happen. immer::vector> saved_vectors; immer::vector> saved_flex_vectors; auto tie() const { return std::tie(leaves, inners, vectors); } - friend bool operator==(const archive_save& left, const archive_save& right) + friend bool operator==(const input_pool& left, const input_pool& right) { return left.tie() == right.tie(); } @@ -80,9 +80,9 @@ template -inline auto make_save_archive_for(const immer::vector&) +inline auto make_input_pool_for(const immer::vector&) { - return archive_save{}; + return input_pool{}; } template inline auto -make_save_archive_for(const immer::flex_vector&) +make_input_pool_for(const immer::flex_vector&) { - return archive_save{}; + return input_pool{}; } template -struct archive_load +struct output_pool { immer::map> leaves; immer::map inners; immer::vector vectors; - friend bool operator==(const archive_load& left, - const archive_load& right) = default; + friend bool operator==(const output_pool& left, + const output_pool& right) = default; template void load(Archive& ar) @@ -112,13 +112,13 @@ struct archive_load } }; -// This is needed to be able to use the archive that was not read from JSON +// This is needed to be able to use the pool that was not read from JSON // because .data is set only while reading from JSON. template -archive_load to_load_archive(archive_save ar) +output_pool to_output_pool(input_pool ar) { auto leaves = immer::map>{}; for (const auto& item : ar.leaves) { @@ -133,28 +133,28 @@ archive_load to_load_archive(archive_save ar) } /** - * Given a transformation function from T to U, transform an archive into - * archive. This allows to preserve structural sharing while loading. + * Given a transformation function from T to U, transform an output_pool into + * output_pool. This allows to preserve structural sharing while loading. */ template -auto transform_archive(const archive_load& ar, F&& func) +auto transform_pool(const output_pool& pool, F&& func) { using U = std::decay_t()))>; - return archive_load{ - .leaves = transform(ar.leaves, func), - .inners = ar.inners, - .vectors = ar.vectors, + return output_pool{ + .leaves = transform(pool.leaves, func), + .inners = pool.inners, + .vectors = pool.vectors, }; } -} // namespace immer::archive::rbts +} // namespace immer::persist::rbts namespace std { template <> -struct hash +struct hash { - auto operator()(const immer::archive::rbts::rbts_info& x) const + auto operator()(const immer::persist::rbts::rbts_info& x) const { const auto boost_combine = [](std::size_t& seed, std::size_t hash) { seed ^= hash + 0x9e3779b9 + (seed << 6) + (seed >> 2); @@ -162,9 +162,9 @@ struct hash auto seed = std::size_t{}; boost_combine(seed, - hash{}(x.root.value)); + hash{}(x.root.value)); boost_combine(seed, - hash{}(x.tail.value)); + hash{}(x.tail.value)); return seed; } }; diff --git a/immer/extra/archive/rbts/traits.hpp b/immer/extra/persist/rbts/traits.hpp similarity index 57% rename from immer/extra/archive/rbts/traits.hpp rename to immer/extra/persist/rbts/traits.hpp index 2f22cb6c..cef13d40 100644 --- a/immer/extra/archive/rbts/traits.hpp +++ b/immer/extra/persist/rbts/traits.hpp @@ -1,10 +1,10 @@ #pragma once -#include -#include -#include +#include +#include +#include -namespace immer::archive { +namespace immer::persist { template struct container_traits> { - using save_archive_t = rbts::archive_save; - using load_archive_t = rbts::archive_load; - using container_id = immer::archive::container_id; + using input_pool_t = rbts::input_pool; + using output_pool_t = rbts::output_pool; + using container_id = immer::persist::container_id; - template using loader_t = - rbts::vector_loader; + rbts::vector_loader; // This function is used to determine the type of the container after // applying some transformation. @@ -37,14 +37,14 @@ template struct container_traits> { - using save_archive_t = rbts::archive_save; - using load_archive_t = rbts::archive_load; - using container_id = immer::archive::container_id; + using input_pool_t = rbts::input_pool; + using output_pool_t = rbts::output_pool; + using container_id = immer::persist::container_id; - template using loader_t = - rbts::flex_vector_loader; + rbts::flex_vector_loader; template static auto transform(F&& func) @@ -54,4 +54,4 @@ struct container_traits> } }; -} // namespace immer::archive +} // namespace immer::persist diff --git a/immer/extra/archive/rbts/traverse.hpp b/immer/extra/persist/rbts/traverse.hpp similarity index 94% rename from immer/extra/archive/rbts/traverse.hpp rename to immer/extra/persist/rbts/traverse.hpp index fe9e69ba..ecda01a5 100644 --- a/immer/extra/archive/rbts/traverse.hpp +++ b/immer/extra/persist/rbts/traverse.hpp @@ -1,10 +1,10 @@ #pragma once -#include +#include #include -namespace immer::archive::rbts::detail { +namespace immer::persist::rbts::detail { struct regular_pos_tag {}; @@ -96,4 +96,4 @@ struct visitor_helper } }; -} // namespace immer::archive::rbts::detail +} // namespace immer::persist::rbts::detail diff --git a/immer/extra/archive/traits.hpp b/immer/extra/persist/traits.hpp similarity index 60% rename from immer/extra/archive/traits.hpp rename to immer/extra/persist/traits.hpp index d2a6a691..26e22387 100644 --- a/immer/extra/archive/traits.hpp +++ b/immer/extra/persist/traits.hpp @@ -1,13 +1,13 @@ #pragma once -namespace immer::archive { +namespace immer::persist { /** - * Define these traits to connect a type (vector_one) to its archive - * (archive_save). + * Define these traits to connect a type (vector_one) to its pool + * (input_pool). */ template struct container_traits {}; -} // namespace immer::archive +} // namespace immer::persist diff --git a/immer/extra/archive/xxhash/xxhash.hpp b/immer/extra/persist/xxhash/xxhash.hpp similarity index 89% rename from immer/extra/archive/xxhash/xxhash.hpp rename to immer/extra/persist/xxhash/xxhash.hpp index 962c78b2..c476a294 100644 --- a/immer/extra/archive/xxhash/xxhash.hpp +++ b/immer/extra/persist/xxhash/xxhash.hpp @@ -2,7 +2,7 @@ #include -namespace immer::archive { +namespace immer::persist { template struct xx_hash; @@ -24,4 +24,4 @@ struct xx_hash std::size_t operator()(const T& val) const { return xx_hash_value(val); } }; -} // namespace immer::archive +} // namespace immer::persist diff --git a/immer/extra/archive/xxhash/xxhash_64.cpp b/immer/extra/persist/xxhash/xxhash_64.cpp similarity index 82% rename from immer/extra/archive/xxhash/xxhash_64.cpp rename to immer/extra/persist/xxhash/xxhash_64.cpp index cf1c87a5..8111b310 100644 --- a/immer/extra/archive/xxhash/xxhash_64.cpp +++ b/immer/extra/persist/xxhash/xxhash_64.cpp @@ -2,7 +2,7 @@ #include -namespace immer::archive { +namespace immer::persist { static_assert(sizeof(std::size_t) == 8); // 64 bits static_assert(sizeof(XXH64_hash_t) == sizeof(std::size_t)); @@ -12,4 +12,4 @@ std::size_t xx_hash_value_string(const std::string& str) return XXH3_64bits(str.c_str(), str.size()); } -} // namespace immer::archive +} // namespace immer::persist diff --git a/justfile b/justfile index 6351625a..e2f8cd92 100644 --- a/justfile +++ b/justfile @@ -10,23 +10,23 @@ build-valgrind-path := "build-valgrind-" + os() + "-" + arch() # Create a build directory for a Debug build without ASAN, so that valgrind can work mk-build-valgrind: (_mk-dir build-valgrind-path) - cd {{ build-valgrind-path }} ; cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Debug -Dimmer_BUILD_TESTS=ON -Dimmer_BUILD_ARCHIVE_TESTS=ON -Dimmer_BUILD_EXAMPLES=OFF -DCXX_STANDARD=20 + cd {{ build-valgrind-path }} ; cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Debug -Dimmer_BUILD_TESTS=ON -Dimmer_BUILD_PERSIST_TESTS=ON -Dimmer_BUILD_EXAMPLES=OFF -DCXX_STANDARD=20 [linux] run-valgrind: cd {{ build-valgrind-path }} ; ninja tests && ctest -D ExperimentalMemCheck [linux] -run-valgrind-archive: - cd {{ build-valgrind-path }} ; ninja archive-tests && valgrind --quiet --error-exitcode=99 --leak-check=full --errors-for-leak-kinds=all \ - --suppressions=../test/extra/archive/valgrind.supp \ - ./test/extra/archive/archive-tests +run-valgrind-persist: + cd {{ build-valgrind-path }} ; ninja persist-tests && valgrind --quiet --error-exitcode=99 --leak-check=full --errors-for-leak-kinds=all \ + --suppressions=../test/extra/persist/valgrind.supp \ + ./test/extra/persist/persist-tests build-asan-path := "build-asan-" + os() + "-" + arch() # Create a build directory for a Debug build with ASAN enabled mk-build-asan: (_mk-dir build-asan-path) - cd {{ build-asan-path }} ; cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Debug -DENABLE_ASAN=ON -Dimmer_BUILD_TESTS=ON -Dimmer_BUILD_ARCHIVE_TESTS=ON -Dimmer_BUILD_EXAMPLES=OFF -DCXX_STANDARD=20 + cd {{ build-asan-path }} ; cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Debug -DENABLE_ASAN=ON -Dimmer_BUILD_TESTS=ON -Dimmer_BUILD_PERSIST_TESTS=ON -Dimmer_BUILD_EXAMPLES=OFF -DCXX_STANDARD=20 run-tests-asan: cd {{ build-asan-path }} ; ninja tests && ninja test diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2661f043..afe96306 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -11,13 +11,13 @@ set(MEMORYCHECK_SUPPRESSIONS_FILE "${PROJECT_SOURCE_DIR}/test/valgrind_suppress.txt" CACHE FILEPATH "") set(VALGRIND_COMMAND_OPTIONS - "--suppressions=${PROJECT_SOURCE_DIR}/test/extra/archive/valgrind.supp") + "--suppressions=${PROJECT_SOURCE_DIR}/test/extra/persist/valgrind.supp") find_package(Catch2 REQUIRED) include(CTest) file(GLOB_RECURSE immer_unit_tests "*.cpp") foreach(TMP_PATH ${immer_unit_tests}) - string(FIND ${TMP_PATH} archive EXCLUDE_DIR_FOUND) + string(FIND ${TMP_PATH} persist EXCLUDE_DIR_FOUND) if(NOT ${EXCLUDE_DIR_FOUND} EQUAL -1) list(REMOVE_ITEM immer_unit_tests ${TMP_PATH}) endif() @@ -37,6 +37,6 @@ foreach(_file IN LISTS immer_unit_tests) add_test("test/${_output}" ${_output}) endforeach() -if(immer_BUILD_ARCHIVE_TESTS) - add_subdirectory(extra/archive) +if(immer_BUILD_PERSIST_TESTS) + add_subdirectory(extra/persist) endif() diff --git a/test/extra/archive/CMakeLists.txt b/test/extra/archive/CMakeLists.txt deleted file mode 100644 index 4ab1fdfa..00000000 --- a/test/extra/archive/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -find_package(spdlog REQUIRED) -find_package(cereal REQUIRED) -find_package(xxHash 0.8 CONFIG REQUIRED) - -if(${CXX_STANDARD} LESS 20) - # Maybe no particular reason, but we're not targeting older compilers anyway. - message(FATAL_ERROR "archive requires C++20") -endif() - -include(CTest) - -add_executable( - archive-tests EXCLUDE_FROM_ALL - test_vectors.cpp - test_special_archive.cpp - test_special_archive_auto.cpp - test_champ.cpp - test_xxhash.cpp - test_box.cpp - test_conversion.cpp - test_circular_dependency_conversion.cpp - ${PROJECT_SOURCE_DIR}/immer/extra/archive/xxhash/xxhash_64.cpp) -target_precompile_headers(archive-tests PRIVATE - ) -add_dependencies(tests archive-tests) -add_test("test/archive-tests" archive-tests) -target_include_directories(archive-tests PRIVATE ${CMAKE_SOURCE_DIR}) -target_link_libraries( - archive-tests PRIVATE spdlog::spdlog Catch2::Catch2WithMain xxHash::xxhash) - -target_compile_options(archive-tests PRIVATE -O1 -fno-optimize-sibling-calls -g - -fno-omit-frame-pointer) -target_compile_options(archive-tests PRIVATE -Wno-unused-function) - -if(ENABLE_ASAN) - target_compile_options( - archive-tests PRIVATE -fsanitize-coverage=trace-pc-guard -fsanitize=address) - target_link_options(archive-tests PRIVATE -fsanitize=address) -endif() -target_compile_definitions(archive-tests PRIVATE BOOST_USE_ASAN=1) -target_compile_definitions( - archive-tests PRIVATE SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_TRACE - IMMER_NO_FREE_LIST=1) - -install(TARGETS archive-tests DESTINATION bin) -install(FILES valgrind.supp DESTINATION bin) diff --git a/test/extra/persist/CMakeLists.txt b/test/extra/persist/CMakeLists.txt new file mode 100644 index 00000000..d02238d7 --- /dev/null +++ b/test/extra/persist/CMakeLists.txt @@ -0,0 +1,46 @@ +find_package(spdlog REQUIRED) +find_package(cereal REQUIRED) +find_package(xxHash 0.8 CONFIG REQUIRED) + +if(${CXX_STANDARD} LESS 20) + # Maybe no particular reason, but we're not targeting older compilers anyway. + message(FATAL_ERROR "persist requires C++20") +endif() + +include(CTest) + +add_executable( + persist-tests EXCLUDE_FROM_ALL + test_vectors.cpp + test_special_archive.cpp + test_special_archive_auto.cpp + test_champ.cpp + test_xxhash.cpp + test_box.cpp + test_conversion.cpp + test_circular_dependency_conversion.cpp + ${PROJECT_SOURCE_DIR}/immer/extra/persist/xxhash/xxhash_64.cpp) +target_precompile_headers(persist-tests PRIVATE + ) +add_dependencies(tests persist-tests) +add_test("test/persist-tests" persist-tests) +target_include_directories(persist-tests PRIVATE ${CMAKE_SOURCE_DIR}) +target_link_libraries( + persist-tests PRIVATE spdlog::spdlog Catch2::Catch2WithMain xxHash::xxhash) + +target_compile_options(persist-tests PRIVATE -O1 -fno-optimize-sibling-calls -g + -fno-omit-frame-pointer) +target_compile_options(persist-tests PRIVATE -Wno-unused-function) + +if(ENABLE_ASAN) + target_compile_options( + persist-tests PRIVATE -fsanitize-coverage=trace-pc-guard -fsanitize=address) + target_link_options(persist-tests PRIVATE -fsanitize=address) +endif() +target_compile_definitions(persist-tests PRIVATE BOOST_USE_ASAN=1) +target_compile_definitions( + persist-tests PRIVATE SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_TRACE + IMMER_NO_FREE_LIST=1) + +install(TARGETS persist-tests DESTINATION bin) +install(FILES valgrind.supp DESTINATION bin) diff --git a/test/extra/archive/cereal/immer_box.hpp b/test/extra/persist/cereal/immer_box.hpp similarity index 100% rename from test/extra/archive/cereal/immer_box.hpp rename to test/extra/persist/cereal/immer_box.hpp diff --git a/test/extra/archive/cereal/immer_set.hpp b/test/extra/persist/cereal/immer_set.hpp similarity index 100% rename from test/extra/archive/cereal/immer_set.hpp rename to test/extra/persist/cereal/immer_set.hpp diff --git a/test/extra/archive/cereal/immer_table.hpp b/test/extra/persist/cereal/immer_table.hpp similarity index 100% rename from test/extra/archive/cereal/immer_table.hpp rename to test/extra/persist/cereal/immer_table.hpp diff --git a/test/extra/archive/suppr.txt b/test/extra/persist/suppr.txt similarity index 100% rename from test/extra/archive/suppr.txt rename to test/extra/persist/suppr.txt diff --git a/test/extra/archive/test_box.cpp b/test/extra/persist/test_box.cpp similarity index 66% rename from test/extra/archive/test_box.cpp rename to test/extra/persist/test_box.cpp index 5044c1d2..414b69ee 100644 --- a/test/extra/archive/test_box.cpp +++ b/test/extra/persist/test_box.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include "utils.hpp" @@ -14,18 +14,18 @@ TEST_CASE("Test saving a box") const auto test1 = Container{"hello"}; const auto test2 = Container{"world"}; - auto ar = immer::archive::box::make_save_archive_for(test1); + auto ar = immer::persist::box::make_input_pool_for(test1); - auto id1 = immer::archive::container_id{}; - std::tie(ar, id1) = immer::archive::box::save_to_archive(test1, ar); + auto id1 = immer::persist::container_id{}; + std::tie(ar, id1) = immer::persist::box::add_to_pool(test1, ar); - auto id2 = immer::archive::container_id{}; - std::tie(ar, id2) = immer::archive::box::save_to_archive(test2, ar); + auto id2 = immer::persist::container_id{}; + std::tie(ar, id2) = immer::persist::box::add_to_pool(test2, ar); SECTION("Save again, same id") { - auto id3 = immer::archive::container_id{}; - std::tie(ar, id3) = immer::archive::box::save_to_archive(test2, ar); + auto id3 = immer::persist::container_id{}; + std::tie(ar, id3) = immer::persist::box::add_to_pool(test2, ar); REQUIRE(id3 == id2); } @@ -35,11 +35,11 @@ TEST_CASE("Test saving a box") SECTION("Via JSON") { const auto archive = - from_json>( + from_json>( ar_str); auto loader = - immer::archive::box::make_loader_for(Container{}, archive); + immer::persist::box::make_loader_for(Container{}, archive); const auto loaded1 = loader.load(id1); REQUIRE(loaded1 == test1); @@ -52,8 +52,8 @@ TEST_CASE("Test saving a box") SECTION("Via archive transformation") { - auto loader = immer::archive::box::make_loader_for(Container{}, - to_load_archive(ar)); + auto loader = immer::persist::box::make_loader_for(Container{}, + to_output_pool(ar)); const auto loaded1 = loader.load(id1); REQUIRE(loaded1 == test1); @@ -68,20 +68,20 @@ TEST_CASE("Test saving and mutating a box") using Container = immer::box; auto test1 = Container{"hello"}; - auto ar = immer::archive::box::make_save_archive_for(test1); + auto ar = immer::persist::box::make_input_pool_for(test1); - auto id1 = immer::archive::container_id{}; - std::tie(ar, id1) = immer::archive::box::save_to_archive(test1, ar); + auto id1 = immer::persist::container_id{}; + std::tie(ar, id1) = immer::persist::box::add_to_pool(test1, ar); test1 = std::move(test1).update([](auto str) { return str + " world"; }); - auto id2 = immer::archive::container_id{}; - std::tie(ar, id2) = immer::archive::box::save_to_archive(test1, ar); + auto id2 = immer::persist::container_id{}; + std::tie(ar, id2) = immer::persist::box::add_to_pool(test1, ar); REQUIRE(id1 != id2); auto loader = - immer::archive::box::make_loader_for(Container{}, to_load_archive(ar)); + immer::persist::box::make_loader_for(Container{}, to_output_pool(ar)); const auto loaded1 = loader.load(id1); REQUIRE(loaded1.get() == "hello"); @@ -110,10 +110,9 @@ TEST_CASE("Test box with a fwd declared type") TEST_CASE("Box: converting loader can handle exceptions") { - const auto box = immer::box{123}; - const auto [ar_save, box_id] = - immer::archive::box::save_to_archive(box, {}); - const auto ar_load = to_load_archive(ar_save); + const auto box = immer::box{123}; + const auto [ar_save, box_id] = immer::persist::box::add_to_pool(box, {}); + const auto ar_load = to_output_pool(ar_save); using Archive = std::decay_t; @@ -124,7 +123,7 @@ TEST_CASE("Box: converting loader can handle exceptions") }; using TransformF = std::decay_t; - using Loader = immer::archive::box::loader; @@ -141,7 +140,7 @@ TEST_CASE("Box: converting loader can handle exceptions") }; using TransformF = std::decay_t; - using Loader = immer::archive::box::loader; diff --git a/test/extra/archive/test_champ.cpp b/test/extra/persist/test_champ.cpp similarity index 88% rename from test/extra/archive/test_champ.cpp rename to test/extra/persist/test_champ.cpp index 40dfcf99..1d13ae96 100644 --- a/test/extra/archive/test_champ.cpp +++ b/test/extra/persist/test_champ.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include "utils.hpp" @@ -10,7 +10,7 @@ using namespace test; using json_t = nlohmann::json; -using immer::archive::node_id; +using immer::persist::node_id; namespace { @@ -62,7 +62,7 @@ struct broken_hash if ("10" < str && str < "19") { return 123; } - return immer::archive::xx_hash{}(str); + return immer::persist::xx_hash{}(str); } std::size_t operator()(int map_key) const @@ -81,17 +81,17 @@ TEST_CASE("Test saving a set") using Container = immer::set; const auto set = gen_set(Container{}, 200); - const auto [ar, set_id] = immer::archive::champ::save_to_archive(set, {}); + const auto [ar, set_id] = immer::persist::champ::add_to_pool(set, {}); const auto ar_str = to_json(ar); // REQUIRE(ar_str == ""); SECTION("Load with the correct hash") { const auto loaded_archive = - from_json>( + from_json>( ar_str); - auto loader = immer::archive::champ::container_loader{loaded_archive}; + auto loader = immer::persist::champ::container_loader{loaded_archive}; const auto loaded = loader.load(set_id); REQUIRE(into_set(set).size() == set.size()); for (const auto& item : set) { @@ -106,33 +106,33 @@ TEST_CASE("Test saving a set") { using WrongContainer = immer::set; const auto loaded_archive = from_json< - immer::archive::champ::container_archive_load>( + immer::persist::champ::container_output_pool>( ar_str); - auto loader = immer::archive::champ::container_loader{loaded_archive}; + auto loader = immer::persist::champ::container_loader{loaded_archive}; REQUIRE_THROWS_AS( loader.load(set_id), - immer::archive::champ::hash_validation_failed_exception); + immer::persist::champ::hash_validation_failed_exception); } } TEST_CASE("Test set with xxHash") { using Container = - immer::set>; + immer::set>; const auto set = gen_set(Container{}, 200); - const auto [ar, set_id] = immer::archive::champ::save_to_archive(set, {}); + const auto [ar, set_id] = immer::persist::champ::add_to_pool(set, {}); const auto ar_str = to_json(ar); // REQUIRE(ar_str == ""); SECTION("Load with the correct hash") { const auto loaded_archive = - from_json>( + from_json>( ar_str); - auto loader = immer::archive::champ::container_loader{loaded_archive}; + auto loader = immer::persist::champ::container_loader{loaded_archive}; const auto loaded = loader.load(set_id); REQUIRE(into_set(set).size() == set.size()); for (const auto& item : set) { @@ -150,11 +150,11 @@ TEST_CASE("Test archive conversion, no json") const auto set = gen_set(Container{}, 200); const auto set2 = gen_set(set, 300); - auto [ar, set_id] = immer::archive::champ::save_to_archive(set, {}); - auto set2_id = immer::archive::node_id{}; - std::tie(ar, set2_id) = immer::archive::champ::save_to_archive(set2, ar); + auto [ar, set_id] = immer::persist::champ::add_to_pool(set, {}); + auto set2_id = immer::persist::node_id{}; + std::tie(ar, set2_id) = immer::persist::champ::add_to_pool(set2, ar); - auto loader = immer::archive::champ::container_loader{to_load_archive(ar)}; + auto loader = immer::persist::champ::container_loader{to_output_pool(ar)}; const auto check_set = [&loader](auto id, const auto& expected) { const auto loaded = loader.load(id); @@ -180,11 +180,11 @@ TEST_CASE("Test save mutated set") using Container = immer::set; auto set = gen_set(Container{}, 200); - auto [ar, set_id] = immer::archive::champ::save_to_archive(set, {}); + auto [ar, set_id] = immer::persist::champ::add_to_pool(set, {}); set = std::move(set).insert("435"); - auto set_id2 = immer::archive::node_id{}; - std::tie(ar, set_id2) = immer::archive::champ::save_to_archive(set, ar); + auto set_id2 = immer::persist::node_id{}; + std::tie(ar, set_id2) = immer::persist::champ::add_to_pool(set, ar); REQUIRE(set_id != set_id2); } @@ -194,17 +194,17 @@ TEST_CASE("Test saving a map") using Container = immer::map; const auto map = gen_map(Container{}, 200); - const auto [ar, map_id] = immer::archive::champ::save_to_archive(map, {}); + const auto [ar, map_id] = immer::persist::champ::add_to_pool(map, {}); const auto ar_str = to_json(ar); // REQUIRE(ar_str == ""); SECTION("Load with the correct hash") { const auto loaded_archive = - from_json>( + from_json>( ar_str); - auto loader = immer::archive::champ::container_loader{loaded_archive}; + auto loader = immer::persist::champ::container_loader{loaded_archive}; const auto loaded = loader.load(map_id); REQUIRE(into_map(map).size() == map.size()); for (const auto& [key, value] : map) { @@ -220,13 +220,13 @@ TEST_CASE("Test saving a map") { using WrongContainer = immer::map; const auto loaded_archive = from_json< - immer::archive::champ::container_archive_load>( + immer::persist::champ::container_output_pool>( ar_str); - auto loader = immer::archive::champ::container_loader{loaded_archive}; + auto loader = immer::persist::champ::container_loader{loaded_archive}; REQUIRE_THROWS_AS( loader.load(map_id), - immer::archive::champ::hash_validation_failed_exception); + immer::persist::champ::hash_validation_failed_exception); } } @@ -236,11 +236,11 @@ TEST_CASE("Test map archive conversion, no json") const auto map = gen_map(Container{}, 200); const auto map2 = gen_map(map, 300); - auto [ar, map_id] = immer::archive::champ::save_to_archive(map, {}); - auto map2_id = immer::archive::node_id{}; - std::tie(ar, map2_id) = immer::archive::champ::save_to_archive(map2, ar); + auto [ar, map_id] = immer::persist::champ::add_to_pool(map, {}); + auto map2_id = immer::persist::node_id{}; + std::tie(ar, map2_id) = immer::persist::champ::add_to_pool(map2, ar); - auto loader = immer::archive::champ::container_loader{to_load_archive(ar)}; + auto loader = immer::persist::champ::container_loader{to_output_pool(ar)}; const auto check_map = [&loader](auto id, const auto& expected) { const auto loaded = loader.load(id); @@ -266,11 +266,11 @@ TEST_CASE("Test map archive conversion, no json") TEST_CASE("Test save mutated map") { auto map = gen_map(immer::map{}, 200); - auto [ar, map_id] = immer::archive::champ::save_to_archive(map, {}); + auto [ar, map_id] = immer::persist::champ::add_to_pool(map, {}); map = std::move(map).set(999, "435"); - auto map_id2 = immer::archive::node_id{}; - std::tie(ar, map_id2) = immer::archive::champ::save_to_archive(map, ar); + auto map_id2 = immer::persist::node_id{}; + std::tie(ar, map_id2) = immer::persist::champ::add_to_pool(map, ar); REQUIRE(map_id != map_id2); } @@ -282,18 +282,18 @@ void test_table_types(Verify&& verify) const auto t1 = gen_table(T1{}, 0, 100); const auto t2 = gen_table(t1, 200, 210); - auto [ar, t1_id] = immer::archive::champ::save_to_archive(t1, {}); + auto [ar, t1_id] = immer::persist::champ::add_to_pool(t1, {}); - auto t2_id = immer::archive::node_id{}; - std::tie(ar, t2_id) = immer::archive::champ::save_to_archive(t2, ar); + auto t2_id = immer::persist::node_id{}; + std::tie(ar, t2_id) = immer::persist::champ::add_to_pool(t2, ar); const auto ar_str = to_json(ar); // REQUIRE(ar_str == ""); const auto loaded_archive = - from_json>(ar_str); + from_json>(ar_str); - auto loader = immer::archive::champ::container_loader{loaded_archive}; + auto loader = immer::persist::champ::container_loader{loaded_archive}; const auto check = [&loader, &verify](auto id, const auto& expected) { const auto loaded = loader.load(id); @@ -334,9 +334,9 @@ TEST_CASE("Test saving a table") }; REQUIRE_THROWS_AS(test1(), - immer::archive::champ::hash_validation_failed_exception); + immer::persist::champ::hash_validation_failed_exception); REQUIRE_THROWS_AS(test2(), - immer::archive::champ::hash_validation_failed_exception); + immer::persist::champ::hash_validation_failed_exception); } TEST_CASE("Test saving a table, no json") @@ -345,15 +345,15 @@ TEST_CASE("Test saving a table, no json") const auto t1 = gen_table(table_t{}, 0, 100); const auto t2 = gen_table(t1, 200, 210); - auto [ar, t1_id] = immer::archive::champ::save_to_archive(t1, {}); + auto [ar, t1_id] = immer::persist::champ::add_to_pool(t1, {}); - auto t2_id = immer::archive::node_id{}; - std::tie(ar, t2_id) = immer::archive::champ::save_to_archive(t2, ar); + auto t2_id = immer::persist::node_id{}; + std::tie(ar, t2_id) = immer::persist::champ::add_to_pool(t2, ar); const auto ar_str = to_json(ar); // REQUIRE(ar_str == ""); - auto loader = immer::archive::champ::container_loader{to_load_archive(ar)}; + auto loader = immer::persist::champ::container_loader{to_output_pool(ar)}; const auto check = [&loader](auto id, const auto& expected) { const auto loaded = loader.load(id); @@ -373,16 +373,15 @@ TEST_CASE("Test saving a table, no json") TEST_CASE("Test modifying set nodes") { using Container = - immer::set>; + immer::set>; const auto expected_set = gen_set(Container{}, 30); const auto expected_set2 = expected_set.insert("thirty"); - auto [ar, set_id] = - immer::archive::champ::save_to_archive(expected_set, {}); - auto set2_id = immer::archive::node_id{}; + auto [ar, set_id] = immer::persist::champ::add_to_pool(expected_set, {}); + auto set2_id = immer::persist::node_id{}; std::tie(ar, set2_id) = - immer::archive::champ::save_to_archive(expected_set2, std::move(ar)); + immer::persist::champ::add_to_pool(expected_set2, std::move(ar)); const auto ar_str = to_json(ar); const auto expected_data = json_t::parse(ar_str); // REQUIRE(ar_str == ""); @@ -486,9 +485,9 @@ TEST_CASE("Test modifying set nodes") const auto load_set = [&data](auto id) { const auto loaded_archive = - from_json>( + from_json>( data.dump()); - auto loader = immer::archive::champ::container_loader{loaded_archive}; + auto loader = immer::persist::champ::container_loader{loaded_archive}; return loader.load(id); }; @@ -504,7 +503,7 @@ TEST_CASE("Test modifying set nodes") nodemap = 1343560971; REQUIRE_THROWS_AS( load_set(set_id), - immer::archive::champ::children_count_corrupted_exception); + immer::persist::champ::children_count_corrupted_exception); // Node 0 doesn't affect the second set REQUIRE(load_set(set2_id) == expected_set2); } @@ -515,7 +514,7 @@ TEST_CASE("Test modifying set nodes") datamap = 19407008; REQUIRE_THROWS_AS( load_set(set_id), - immer::archive::champ::data_count_corrupted_exception); + immer::persist::champ::data_count_corrupted_exception); // Node 0 doesn't affect the second set REQUIRE(load_set(set2_id) == expected_set2); } @@ -526,10 +525,10 @@ TEST_CASE("Test modifying set nodes") nodemap = 1; REQUIRE_THROWS_AS( load_set(set_id), - immer::archive::champ::children_count_corrupted_exception); + immer::persist::champ::children_count_corrupted_exception); REQUIRE_THROWS_AS( load_set(set2_id), - immer::archive::champ::children_count_corrupted_exception); + immer::persist::champ::children_count_corrupted_exception); } SECTION("Modify datamap of node 1") { @@ -538,10 +537,10 @@ TEST_CASE("Test modifying set nodes") datamap = 536875007; REQUIRE_THROWS_AS( load_set(set_id), - immer::archive::champ::data_count_corrupted_exception); + immer::persist::champ::data_count_corrupted_exception); REQUIRE_THROWS_AS( load_set(set2_id), - immer::archive::champ::data_count_corrupted_exception); + immer::persist::champ::data_count_corrupted_exception); } SECTION("Corrupt datamap but keep the same popcount") { @@ -550,10 +549,10 @@ TEST_CASE("Test modifying set nodes") datamap = 536875008; // This number also has 2 bits set REQUIRE_THROWS_AS( load_set(set_id), - immer::archive::champ::hash_validation_failed_exception); + immer::persist::champ::hash_validation_failed_exception); REQUIRE_THROWS_AS( load_set(set2_id), - immer::archive::champ::hash_validation_failed_exception); + immer::persist::champ::hash_validation_failed_exception); } SECTION("Corrupt nodemap but keep the same popcount") { @@ -562,7 +561,7 @@ TEST_CASE("Test modifying set nodes") nodemap = 1343560460; // This number has the same number of bits set REQUIRE_THROWS_AS( load_set(set_id), - immer::archive::champ::hash_validation_failed_exception); + immer::persist::champ::hash_validation_failed_exception); // Node 0 doesn't affect the second set REQUIRE(load_set(set2_id) == expected_set2); } @@ -570,7 +569,7 @@ TEST_CASE("Test modifying set nodes") { auto& children = data["value0"][0]["children"]; children = {1, 2, 99, 4, 5, 6, 7, 8, 9, 10, 11}; - REQUIRE_THROWS_AS(load_set(set_id), immer::archive::invalid_node_id); + REQUIRE_THROWS_AS(load_set(set_id), immer::persist::invalid_node_id); REQUIRE(load_set(set2_id) == expected_set2); } SECTION("Same identity") @@ -578,9 +577,9 @@ TEST_CASE("Test modifying set nodes") // Have to keep the loader alive between loads, otherwise there's no way // to share the nodes. const auto loaded_archive = - from_json>( + from_json>( data.dump()); - auto loader = immer::archive::champ::container_loader{loaded_archive}; + auto loader = immer::persist::champ::container_loader{loaded_archive}; REQUIRE(loader.load(node_id{0}).identity() == loader.load(node_id{0}).identity()); } @@ -593,11 +592,10 @@ TEST_CASE("Test modifying nodes with collisions") const auto expected_set = gen_set(Container{}, 30); const auto expected_set2 = expected_set.insert("thirty"); - auto [ar, set_id] = - immer::archive::champ::save_to_archive(expected_set, {}); - auto set2_id = immer::archive::node_id{}; + auto [ar, set_id] = immer::persist::champ::add_to_pool(expected_set, {}); + auto set2_id = immer::persist::node_id{}; std::tie(ar, set2_id) = - immer::archive::champ::save_to_archive(expected_set2, std::move(ar)); + immer::persist::champ::add_to_pool(expected_set2, std::move(ar)); const auto ar_str = to_json(ar); const auto expected_data = json_t::parse(ar_str); @@ -750,9 +748,9 @@ TEST_CASE("Test modifying nodes with collisions") const auto load_set = [&data](auto id) { const auto loaded_archive = - from_json>( + from_json>( data.dump()); - auto loader = immer::archive::champ::container_loader{loaded_archive}; + auto loader = immer::persist::champ::container_loader{loaded_archive}; return loader.load(id); }; @@ -783,9 +781,9 @@ TEST_CASE("Test champ archive conversion, map") using test::old_type; using old_map_t = - immer::map>; + immer::map>; using new_map_t = - immer::map>; + immer::map>; const auto map1 = [] { auto map = old_map_t{}; @@ -797,9 +795,9 @@ TEST_CASE("Test champ archive conversion, map") }(); const auto map2 = map1.set("345", old_type{.data = 345}); - auto [ar, map1_id] = immer::archive::champ::save_to_archive(map1, {}); - auto map2_id = immer::archive::node_id{}; - std::tie(ar, map2_id) = save_to_archive(map2, ar); + auto [ar, map1_id] = immer::persist::champ::add_to_pool(map1, {}); + auto map2_id = immer::persist::node_id{}; + std::tie(ar, map2_id) = add_to_pool(map2, ar); // Confirm that map1 and map2 have structural sharing in the beginning. // For example, "x21x" is stored only once, it's shared. @@ -1222,11 +1220,11 @@ TEST_CASE("Test champ archive conversion, map") return result; }; - const auto load_archive = to_load_archive(ar); + const auto load_archive = to_output_pool(ar); const auto load_archive_new_type = - transform_archive(load_archive, convert_old_type_map); + transform_pool(load_archive, convert_old_type_map); auto loader = - immer::archive::champ::container_loader{load_archive_new_type}; + immer::persist::champ::container_loader{load_archive_new_type}; const auto loaded_1 = loader.load(map1_id); const auto loaded_2 = loader.load(map2_id); @@ -1235,9 +1233,9 @@ TEST_CASE("Test champ archive conversion, map") SECTION("Loaded maps still share the structure") { - auto [ar, id] = immer::archive::champ::save_to_archive(loaded_1, {}); - std::tie(ar, id) = save_to_archive(loaded_1, ar); - std::tie(ar, id) = save_to_archive(loaded_2, ar); + auto [ar, id] = immer::persist::champ::add_to_pool(loaded_1, {}); + std::tie(ar, id) = add_to_pool(loaded_1, ar); + std::tie(ar, id) = add_to_pool(loaded_2, ar); // "_21_" is stored only once const auto expected_ar = json_t::parse(R"( @@ -1701,10 +1699,10 @@ TEST_CASE("Test champ archive conversion, table") using old_table_t = immer::table>; + immer::persist::xx_hash>; using new_table_t = immer::table>; + immer::persist::xx_hash>; const auto table1 = [] { auto table = old_table_t{}; @@ -1721,9 +1719,9 @@ TEST_CASE("Test champ archive conversion, table") .data = 345, }); - auto [ar, table1_id] = immer::archive::champ::save_to_archive(table1, {}); - auto table2_id = immer::archive::node_id{}; - std::tie(ar, table2_id) = save_to_archive(table2, ar); + auto [ar, table1_id] = immer::persist::champ::add_to_pool(table1, {}); + auto table2_id = immer::persist::node_id{}; + std::tie(ar, table2_id) = add_to_pool(table2, ar); // Confirm that table1 and table2 have structural sharing in the beginning. // "q2q" is stored only once. @@ -2038,7 +2036,7 @@ TEST_CASE("Test champ archive conversion, table") return result; }; - const auto load_archive = to_load_archive(ar); + const auto load_archive = to_output_pool(ar); SECTION("Invalid conversion, ID is corrupted") { @@ -2050,27 +2048,27 @@ TEST_CASE("Test champ archive conversion, table") .data2 = fmt::format("_{}_", val.data), }; }, - [](immer::archive::target_container_type_request) { + [](immer::persist::target_container_type_request) { return immer::table{}; }); const auto load_archive_new_type = - transform_archive(load_archive, badly_convert_old_type); + transform_pool(load_archive, badly_convert_old_type); auto loader = - immer::archive::champ::container_loader{load_archive_new_type}; + immer::persist::champ::container_loader{load_archive_new_type}; REQUIRE_THROWS_AS( loader.load(table1_id), - immer::archive::champ::hash_validation_failed_exception); + immer::persist::champ::hash_validation_failed_exception); REQUIRE_THROWS_AS( loader.load(table2_id), - immer::archive::champ::hash_validation_failed_exception); + immer::persist::champ::hash_validation_failed_exception); } SECTION("Valid conversion, ID is not changed") { const auto load_archive_new_type = - transform_archive(load_archive, convert_old_type_table); + transform_pool(load_archive, convert_old_type_table); auto loader = - immer::archive::champ::container_loader{load_archive_new_type}; + immer::persist::champ::container_loader{load_archive_new_type}; const auto loaded_1 = loader.load(table1_id); const auto loaded_2 = loader.load(table2_id); @@ -2079,10 +2077,9 @@ TEST_CASE("Test champ archive conversion, table") SECTION("Loaded tables still share the structure") { - auto [ar, id] = - immer::archive::champ::save_to_archive(loaded_1, {}); - std::tie(ar, id) = save_to_archive(loaded_1, ar); - std::tie(ar, id) = save_to_archive(loaded_2, ar); + auto [ar, id] = immer::persist::champ::add_to_pool(loaded_1, {}); + std::tie(ar, id) = add_to_pool(loaded_1, ar); + std::tie(ar, id) = add_to_pool(loaded_2, ar); // For example, "q17q" is stored only once const auto expected_ar = json_t::parse(R"( @@ -2457,8 +2454,8 @@ TEST_CASE("Test set conversion breaks counts") old_type{.id = "3", .data = 93}}; REQUIRE(old_set.size() == 3); const auto [old_save_archive, set_id] = - immer::archive::champ::save_to_archive(old_set, {}); - const auto old_load_archive = to_load_archive(old_save_archive); + immer::persist::champ::add_to_pool(old_set, {}); + const auto old_load_archive = to_output_pool(old_save_archive); const auto transform = [](const old_type& val) { // The id is messed up which would lead to the new set @@ -2473,12 +2470,12 @@ TEST_CASE("Test set conversion breaks counts") using new_set_t = immer::set; using transform_t = std::decay_t; - auto loader = immer::archive::champ:: + auto loader = immer::persist::champ:: container_loader{ old_load_archive, transform}; REQUIRE_THROWS_AS(loader.load(set_id), - immer::archive::champ::hash_validation_failed_exception); + immer::persist::champ::hash_validation_failed_exception); } namespace { @@ -2541,9 +2538,8 @@ TEST_CASE("Champ: converting loader can handle exceptions") } return result; }(); - const auto [ar_save, set_id] = - immer::archive::champ::save_to_archive(set, {}); - const auto ar_load = to_load_archive(ar_save); + const auto [ar_save, set_id] = immer::persist::champ::add_to_pool(set, {}); + const auto ar_load = to_output_pool(ar_save); using Archive = std::decay_t; @@ -2561,7 +2557,7 @@ TEST_CASE("Champ: converting loader can handle exceptions") }; using TransformF = std::decay_t; - using Loader = immer::archive::champ:: + using Loader = immer::persist::champ:: container_loader, Archive, TransformF>; auto loader = Loader{ar_load, transform}; const auto loaded = loader.load(set_id); @@ -2579,7 +2575,7 @@ TEST_CASE("Champ: converting loader can handle exceptions") }; using TransformF = std::decay_t; - using Loader = immer::archive::champ:: + using Loader = immer::persist::champ:: container_loader, Archive, TransformF>; auto loader = Loader{ar_load, transform}; REQUIRE_THROWS_WITH(loader.load(set_id), "it's 111"); @@ -2596,7 +2592,7 @@ TEST_CASE("Champ: converting loader can handle exceptions") }; using TransformF = std::decay_t; - using Loader = immer::archive::champ:: + using Loader = immer::persist::champ:: container_loader, Archive, TransformF>; auto loader = Loader{ar_load, transform}; REQUIRE_THROWS_WITH(loader.load(set_id), "it's 3"); diff --git a/test/extra/archive/test_circular_dependency_conversion.cpp b/test/extra/persist/test_circular_dependency_conversion.cpp similarity index 77% rename from test/extra/archive/test_circular_dependency_conversion.cpp rename to test/extra/persist/test_circular_dependency_conversion.cpp index 4b98cf46..be953262 100644 --- a/test/extra/archive/test_circular_dependency_conversion.cpp +++ b/test/extra/persist/test_circular_dependency_conversion.cpp @@ -1,12 +1,12 @@ #include -#include +#include #include "utils.hpp" -#include -#include -#include +#include +#include +#include #define DEFINE_OPERATIONS(name) \ bool operator==(const name& left, const name& right) \ @@ -50,7 +50,7 @@ struct key friend std::size_t xx_hash_value(const key& value) { - return immer::archive::xx_hash_value_string(value.str); + return immer::persist::xx_hash_value_string(value.str); } }; @@ -65,14 +65,14 @@ struct value_one (flex_vector_one, twos_flex), (immer::table>, + immer::persist::xx_hash>, twos_table), (immer::table>, + immer::persist::xx_hash>, twos_table_2), - (immer::map>, twos_map), - (immer::set>, twos_set) + (immer::map>, twos_map), + (immer::set>, twos_set) ); }; @@ -142,7 +142,7 @@ struct key friend std::size_t xx_hash_value(const key& value) { - return immer::archive::xx_hash_value_string(value.str); + return immer::persist::xx_hash_value_string(value.str); } }; @@ -157,14 +157,14 @@ struct value_one (flex_vector_one, twos_flex), (immer::table>, + immer::persist::xx_hash>, twos_table), (immer::table>, + immer::persist::xx_hash>, twos_table_2), - (immer::map>, twos_map), - (immer::set>, twos_set) + (immer::map>, twos_map), + (immer::set>, twos_set) ); }; @@ -222,7 +222,7 @@ TEST_CASE("Test exception while circular converting") const auto value = [&] { const auto t1 = immer::table>{two1}; + immer::persist::xx_hash>{two1}; const auto t2 = t1.insert(two2); return model::value_one{ .twos = {two1, two2}, @@ -234,18 +234,18 @@ TEST_CASE("Test exception while circular converting") }; }(); - const auto names = immer::archive::get_archives_for_types( + const auto names = immer::persist::get_pools_for_types( hana::tuple_t, hana::make_map()); const auto [json_str, model_archives] = - immer::archive::to_json_with_auto_archive(value, names); + immer::persist::to_json_with_auto_pool(value, names); // REQUIRE(json_str == ""); SECTION("Try to load") { const auto loaded = - immer::archive::from_json_with_auto_archive( - json_str, names); + immer::persist::from_json_with_auto_pool(json_str, + names); REQUIRE(loaded == value); } @@ -267,28 +267,28 @@ TEST_CASE("Test exception while circular converting") hana::make_pair( hana::type_c>>, + immer::persist::xx_hash>>, hana::overload( - [](immer::archive::target_container_type_request) { + [](immer::persist::target_container_type_request) { return immer::table>{}; + immer::persist::xx_hash>{}; }, convert_two_boxed)), hana::make_pair( hana::type_c>>, + immer::persist::xx_hash>>, hana::overload( - [](immer::archive::target_container_type_request) { + [](immer::persist::target_container_type_request) { return immer::set< format::two_boxed, - immer::archive::xx_hash>{}; + immer::persist::xx_hash>{}; }, convert_two_boxed)), hana::make_pair( hana::type_c>>, + immer::persist::xx_hash>>, hana::overload( [convert_two_boxed](std::pair p, const auto& convert_container) { @@ -296,10 +296,10 @@ TEST_CASE("Test exception while circular converting") format::key{p.first.str}, convert_two_boxed(p.second, convert_container)); }, - [](immer::archive::target_container_type_request) { + [](immer::persist::target_container_type_request) { return immer::map>{}; + immer::persist::xx_hash>{}; })), hana::make_pair( hana::type_c>, @@ -332,35 +332,35 @@ TEST_CASE("Test exception while circular converting") hana::type_c< immer::table>>, + immer::persist::xx_hash>>, old.twos_table), .twos_table_2 = convert_container( hana::type_c< immer::table>>, + immer::persist::xx_hash>>, old.twos_table_2), .twos_map = convert_container( hana::type_c< immer::map>>, + immer::persist::xx_hash>>, old.twos_map), .twos_set = convert_container( hana::type_c>>, + immer::persist::xx_hash>>, old.twos_set), }; }) ); - auto format_load_archives = - immer::archive::transform_save_archive(model_archives, map); + auto format_load_pools = + immer::persist::transform_input_pool(model_archives, map); - REQUIRE_THROWS_AS(immer::archive::convert_container( - model_archives, format_load_archives, value.twos), - immer::archive::champ::hash_validation_failed_exception); + REQUIRE_THROWS_AS(immer::persist::convert_container( + model_archives, format_load_pools, value.twos), + immer::persist::champ::hash_validation_failed_exception); } TEST_CASE("Test circular dependency archives", "[conversion]") @@ -386,7 +386,7 @@ TEST_CASE("Test circular dependency archives", "[conversion]") const auto value = [&] { const auto t1 = immer::table>{two1}; + immer::persist::xx_hash>{two1}; const auto t2 = t1.insert(two2); return model::value_one{ .twos = {two1, two2}, @@ -398,10 +398,10 @@ TEST_CASE("Test circular dependency archives", "[conversion]") }; }(); - const auto names = immer::archive::get_archives_for_types( + const auto names = immer::persist::get_pools_for_types( hana::tuple_t, hana::make_map()); - const auto model_archives = immer::archive::get_auto_archive(value, names); + const auto model_archives = immer::persist::get_auto_pool(value, names); /** * NOTE: There is a circular dependency between archives: to convert @@ -421,28 +421,28 @@ TEST_CASE("Test circular dependency archives", "[conversion]") hana::make_pair( hana::type_c>>, + immer::persist::xx_hash>>, hana::overload( - [](immer::archive::target_container_type_request) { + [](immer::persist::target_container_type_request) { return immer::table>{}; + immer::persist::xx_hash>{}; }, convert_two_boxed)), hana::make_pair( hana::type_c>>, + immer::persist::xx_hash>>, hana::overload( - [](immer::archive::target_container_type_request) { + [](immer::persist::target_container_type_request) { return immer::set< format::two_boxed, - immer::archive::xx_hash>{}; + immer::persist::xx_hash>{}; }, convert_two_boxed)), hana::make_pair( hana::type_c>>, + immer::persist::xx_hash>>, hana::overload( [convert_two_boxed](std::pair p, const auto& convert_container) { @@ -450,10 +450,10 @@ TEST_CASE("Test circular dependency archives", "[conversion]") format::key{p.first.str}, convert_two_boxed(p.second, convert_container)); }, - [](immer::archive::target_container_type_request) { + [](immer::persist::target_container_type_request) { return immer::map>{}; + immer::persist::xx_hash>{}; })), hana::make_pair( hana::type_c>, @@ -480,47 +480,47 @@ TEST_CASE("Test circular dependency archives", "[conversion]") hana::type_c< immer::table>>, + immer::persist::xx_hash>>, old.twos_table), .twos_table_2 = convert_container( hana::type_c< immer::table>>, + immer::persist::xx_hash>>, old.twos_table_2), .twos_map = convert_container( hana::type_c< immer::map>>, + immer::persist::xx_hash>>, old.twos_map), .twos_set = convert_container( hana::type_c>>, + immer::persist::xx_hash>>, old.twos_set), }; }) ); - auto format_load_archives = - immer::archive::transform_save_archive(model_archives, map); - (void) format_load_archives; - // show_type qwe; + auto format_load_pools = + immer::persist::transform_input_pool(model_archives, map); + (void) format_load_pools; + // show_type qwe; - const auto format_names = immer::archive::get_archives_for_types( + const auto format_names = immer::persist::get_pools_for_types( hana::tuple_t, hana::make_map()); SECTION("vector") { - const auto format_twos = immer::archive::convert_container( - model_archives, format_load_archives, value.twos); + const auto format_twos = immer::persist::convert_container( + model_archives, format_load_pools, value.twos); SECTION("Same thing twice, same result") { - const auto format_twos_2 = immer::archive::convert_container( - model_archives, format_load_archives, value.twos); + const auto format_twos_2 = immer::persist::convert_container( + model_archives, format_load_pools, value.twos); REQUIRE(format_twos.identity() == format_twos_2.identity()); } @@ -543,23 +543,23 @@ TEST_CASE("Test circular dependency archives", "[conversion]") SECTION("Compare structure") { const auto [format_twos_json, ar] = - immer::archive::to_json_with_auto_archive(format_twos, - format_names); + immer::persist::to_json_with_auto_pool(format_twos, + format_names); const auto [model_twos_json, ar2] = - immer::archive::to_json_with_auto_archive(value.twos, names); + immer::persist::to_json_with_auto_pool(value.twos, names); REQUIRE(model_twos_json == format_twos_json); } } SECTION("flex_vector") { - const auto format_twos = immer::archive::convert_container( - model_archives, format_load_archives, value.twos_flex); + const auto format_twos = immer::persist::convert_container( + model_archives, format_load_pools, value.twos_flex); SECTION("Same thing twice, same result") { - const auto format_twos_2 = immer::archive::convert_container( - model_archives, format_load_archives, value.twos_flex); + const auto format_twos_2 = immer::persist::convert_container( + model_archives, format_load_pools, value.twos_flex); REQUIRE(format_twos.identity() == format_twos_2.identity()); } REQUIRE(test::to_json(value.twos_flex) == test::to_json(format_twos)); @@ -567,13 +567,13 @@ TEST_CASE("Test circular dependency archives", "[conversion]") SECTION("table") { - const auto format_twos = immer::archive::convert_container( - model_archives, format_load_archives, value.twos_table); + const auto format_twos = immer::persist::convert_container( + model_archives, format_load_pools, value.twos_table); SECTION("Same thing twice, same result") { - const auto format_twos_2 = immer::archive::convert_container( - model_archives, format_load_archives, value.twos_table); + const auto format_twos_2 = immer::persist::convert_container( + model_archives, format_load_pools, value.twos_table); REQUIRE(format_twos.impl().root == format_twos_2.impl().root); } REQUIRE(test::to_json(value.twos_table) == test::to_json(format_twos)); @@ -581,13 +581,13 @@ TEST_CASE("Test circular dependency archives", "[conversion]") SECTION("map") { - const auto format_twos = immer::archive::convert_container( - model_archives, format_load_archives, value.twos_map); + const auto format_twos = immer::persist::convert_container( + model_archives, format_load_pools, value.twos_map); SECTION("Same thing twice, same result") { - const auto format_twos_2 = immer::archive::convert_container( - model_archives, format_load_archives, value.twos_map); + const auto format_twos_2 = immer::persist::convert_container( + model_archives, format_load_pools, value.twos_map); REQUIRE(format_twos.impl().root == format_twos_2.impl().root); } @@ -616,35 +616,33 @@ TEST_CASE("Test circular dependency archives", "[conversion]") SECTION("Compare structure") { const auto [format_twos_json, ar] = - immer::archive::to_json_with_auto_archive(format_twos, - format_names); + immer::persist::to_json_with_auto_pool(format_twos, + format_names); const auto [model_twos_json, ar2] = - immer::archive::to_json_with_auto_archive(value.twos_map, - names); + immer::persist::to_json_with_auto_pool(value.twos_map, names); REQUIRE(model_twos_json == format_twos_json); } } SECTION("set") { - const auto format_twos = immer::archive::convert_container( - model_archives, format_load_archives, value.twos_set); + const auto format_twos = immer::persist::convert_container( + model_archives, format_load_pools, value.twos_set); SECTION("Same thing twice, same result") { - const auto format_twos_2 = immer::archive::convert_container( - model_archives, format_load_archives, value.twos_set); + const auto format_twos_2 = immer::persist::convert_container( + model_archives, format_load_pools, value.twos_set); REQUIRE(format_twos.impl().root == format_twos_2.impl().root); } SECTION("Compare structure") { const auto [format_twos_json, ar] = - immer::archive::to_json_with_auto_archive(format_twos, - format_names); + immer::persist::to_json_with_auto_pool(format_twos, + format_names); const auto [model_twos_json, ar2] = - immer::archive::to_json_with_auto_archive(value.twos_set, - names); + immer::persist::to_json_with_auto_pool(value.twos_set, names); REQUIRE(model_twos_json == format_twos_json); } } @@ -652,8 +650,8 @@ TEST_CASE("Test circular dependency archives", "[conversion]") SECTION("everything") { const auto convert = [&](const auto& value) { - return immer::archive::convert_container( - model_archives, format_load_archives, value); + return immer::persist::convert_container( + model_archives, format_load_pools, value); }; const auto format_value = [&] { auto result = format::value_one{}; @@ -663,18 +661,17 @@ TEST_CASE("Test circular dependency archives", "[conversion]") return result; }(); const auto [format_json_str, model_archives] = - immer::archive::to_json_with_auto_archive(format_value, - format_names); + immer::persist::to_json_with_auto_pool(format_value, format_names); const auto [json_str, model_archives_] = - immer::archive::to_json_with_auto_archive(value, names); + immer::persist::to_json_with_auto_pool(value, names); REQUIRE(format_json_str == json_str); } SECTION("Test converting inside the archive vs outside") { const auto convert = [&](const auto& value) { - return immer::archive::convert_container( - model_archives, format_load_archives, value); + return immer::persist::convert_container( + model_archives, format_load_pools, value); }; // Here we convert a box directly, aka "outside" the archive diff --git a/test/extra/archive/test_conversion.cpp b/test/extra/persist/test_conversion.cpp similarity index 84% rename from test/extra/archive/test_conversion.cpp rename to test/extra/persist/test_conversion.cpp index cecd5931..089da0a3 100644 --- a/test/extra/archive/test_conversion.cpp +++ b/test/extra/persist/test_conversion.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include "utils.hpp" @@ -141,16 +141,16 @@ class Z; TEST_CASE("Convert between two hierarchies via JSON compatibility", "[conversion]") { - const auto model_names = immer::archive::get_archives_for_types( + const auto model_names = immer::persist::get_pools_for_types( hana::tuple_t, hana::make_map()); - const auto format_names = immer::archive::get_archives_for_types( + const auto format_names = immer::persist::get_pools_for_types( hana::tuple_t, hana::make_map()); (void) format_names; const auto value = model::make_example_history(); const auto [json_str, model_archives] = - immer::archive::to_json_with_auto_archive(value, model_names); + immer::persist::to_json_with_auto_pool(value, model_names); const auto map = hana::make_map( hana::make_pair(hana::type_c>, @@ -168,23 +168,23 @@ TEST_CASE("Convert between two hierarchies via JSON compatibility", }) ); - auto format_load_archives = - immer::archive::transform_save_archive(model_archives, map); - (void) format_load_archives; + auto format_load_pools = + immer::persist::transform_input_pool(model_archives, map); + (void) format_load_pools; - const auto format_snapshots = immer::archive::convert_container( - model_archives, format_load_archives, value.snapshots); + const auto format_snapshots = immer::persist::convert_container( + model_archives, format_load_pools, value.snapshots); { const auto [json_str2, archives] = - immer::archive::to_json_with_auto_archive(format_snapshots, - format_names); + immer::persist::to_json_with_auto_pool(format_snapshots, + format_names); (void) json_str2; REQUIRE(test::to_json(format_snapshots) == test::to_json(value.snapshots)); } { - const auto [json, ar] = immer::archive::to_json_with_auto_archive( + const auto [json, ar] = immer::persist::to_json_with_auto_pool( format::history{.snapshots = format_snapshots}, format_names); REQUIRE(json == json_str); } @@ -203,10 +203,10 @@ struct two_vectors TEST_CASE("Not every type is converted", "[conversion]") { - const auto names = immer::archive::get_archives_for_types( + const auto names = immer::persist::get_pools_for_types( hana::tuple_t, hana::make_map()); const auto [json_str, archives] = - immer::archive::to_json_with_auto_archive(two_vectors{}, names); + immer::persist::to_json_with_auto_pool(two_vectors{}, names); const auto map = hana::make_map(hana::make_pair(hana::type_c>, @@ -215,7 +215,7 @@ TEST_CASE("Not every type is converted", "[conversion]") }) ); - const auto format_load_archives = - immer::archive::transform_save_archive(archives, map); - (void) format_load_archives; + const auto format_load_pools = + immer::persist::transform_input_pool(archives, map); + (void) format_load_pools; } diff --git a/test/extra/archive/test_special_archive.cpp b/test/extra/persist/test_special_archive.cpp similarity index 89% rename from test/extra/archive/test_special_archive.cpp rename to test/extra/persist/test_special_archive.cpp index 94773e6c..09b5ea0d 100644 --- a/test/extra/archive/test_special_archive.cpp +++ b/test/extra/persist/test_special_archive.cpp @@ -5,12 +5,12 @@ #include "utils.hpp" #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include // to save std::pair #include @@ -24,8 +24,8 @@ namespace { namespace hana = boost::hana; /** - * Some user data type that contains some vector_one_archivable, which should be - * serialized in a special way. + * Some user data type that contains some vector_one_persistable, which should + * be serialized in a special way. */ using test::flex_vector_one; @@ -34,7 +34,7 @@ using test::vector_one; using json_t = nlohmann::json; template -using arch = immer::archive::archivable; +using arch = immer::persist::persistable; template std::string string_via_tie(const T& value) @@ -106,13 +106,13 @@ struct test_data arch> metas; - // Map value is indirectly archivable + // Map value is indirectly persistable arch> metas_map; - // Map value is directly archivable + // Map value is directly persistable arch>>> vectors_map; - // Also test having meta directly, not inside an archivable type + // Also test having meta directly, not inside an persistable type meta single_meta; arch> box; @@ -157,7 +157,7 @@ struct test_data * A special function that enumerates which types of archives are * required. Explicitly name each type, for simplicity. */ -inline auto get_archives_types(const test_data&) +inline auto get_pools_types(const test_data&) { auto names = hana::make_map( hana::make_pair(hana::type_c>, @@ -185,9 +185,9 @@ inline auto get_archives_types(const test_data&) return names; } -inline auto get_archives_types(const std::pair&) +inline auto get_pools_types(const std::pair&) { - return get_archives_types(test_data{}); + return get_pools_types(test_data{}); } } // namespace @@ -264,16 +264,15 @@ TEST_CASE("Special archive minimal test") }, }; - const auto [json_str, archives] = - immer::archive::to_json_with_archive(test1); + const auto [json_str, archives] = immer::persist::to_json_with_pool(test1); // REQUIRE(json_str == ""); { auto full_load = - immer::archive::from_json_with_archive(json_str); + immer::persist::from_json_with_pool(json_str); REQUIRE(full_load == test1); - // REQUIRE(immer::archive::to_json_with_archive(full_load).first == ""); + // REQUIRE(immer::persist::to_json_with_pool(full_load).first == ""); } } @@ -312,14 +311,13 @@ TEST_CASE("Save with a special archive") }, }; - const auto [json_str, archives] = - immer::archive::to_json_with_archive(test1); + const auto [json_str, archives] = immer::persist::to_json_with_pool(test1); SECTION("Try to save and load the archive") { const auto archives_json = [&archives = archives] { auto os = std::ostringstream{}; { - auto ar = immer::archive::json_immer_output_archive< + auto ar = immer::persist::json_immer_output_archive< cereal::JSONOutputArchive, std::decay_t>{os}; ar(123); @@ -328,10 +326,10 @@ TEST_CASE("Save with a special archive") return os.str(); }(); // REQUIRE(archives_json == ""); - const auto archives_loaded = [&archives_json] { + const auto loaded_pools = [&archives_json] { using Archives = - decltype(immer::archive::detail::generate_archives_load( - get_archives_types(test_data{}))); + decltype(immer::persist::detail::generate_output_pools( + get_pools_types(test_data{}))); auto archives = Archives{}; { @@ -342,7 +340,7 @@ TEST_CASE("Save with a special archive") { auto is = std::istringstream{archives_json}; - auto ar = immer::archive::json_immer_input_archive< + auto ar = immer::persist::json_immer_input_archive< cereal::JSONInputArchive, Archives>{archives, is}; ar(CEREAL_NVP(archives)); @@ -350,17 +348,17 @@ TEST_CASE("Save with a special archive") return archives; }(); - REQUIRE(archives_loaded.storage()[hana::type_c>] - .archive.leaves.size() == 7); + REQUIRE(loaded_pools.storage()[hana::type_c>] + .pool.leaves.size() == 7); } // REQUIRE(json_str == ""); { auto full_load = - immer::archive::from_json_with_archive(json_str); + immer::persist::from_json_with_pool(json_str); REQUIRE(full_load == test1); - // REQUIRE(immer::archive::to_json_with_archive(full_load).first == ""); + // REQUIRE(immer::persist::to_json_with_pool(full_load).first == ""); } } @@ -412,12 +410,12 @@ TEST_CASE("Save with a special archive, special type is enclosed") test2.flex_ints.container.identity()); const auto [json_str, archives] = - immer::archive::to_json_with_archive(std::make_pair(test1, test2)); + immer::persist::to_json_with_pool(std::make_pair(test1, test2)); // REQUIRE(json_str == ""); { - auto [loaded1, loaded2] = immer::archive::from_json_with_archive< + auto [loaded1, loaded2] = immer::persist::from_json_with_pool< std::pair>(json_str); REQUIRE(loaded1 == test1); REQUIRE(loaded2 == test2); @@ -444,12 +442,13 @@ TEST_CASE("Special archive must load and save types that have no archive") const auto value = std::make_pair(val1, val2); const auto json_archive_str = - immer::archive::to_json_with_archive(value).first; + immer::persist::to_json_with_pool(value).first; REQUIRE(json_archive_str == test::to_json(value)); { - auto loaded = immer::archive::from_json_with_archive< - std::decay_t>(json_archive_str); + auto loaded = + immer::persist::from_json_with_pool>( + json_archive_str); REQUIRE(loaded == value); } } @@ -459,7 +458,7 @@ TEST_CASE("Special archive loads empty test_data") const auto value = test_data{}; // const auto json_archive_str = - // immer::archive::to_json_with_archive(value).first; + // immer::persist::to_json_with_pool(value).first; // REQUIRE(json_archive_str == ""); const auto json_archive_str = R"({ @@ -474,7 +473,7 @@ TEST_CASE("Special archive loads empty test_data") "single_meta": {"ints": 0, "metas": 0}, "box": 0 }, - "archives": { + "pools": { "ints": { "leaves": [{"key": 1, "value": []}], "inners": [{"key": 0, "value": {"children": [], "relaxed": false}}], @@ -515,8 +514,9 @@ TEST_CASE("Special archive loads empty test_data") })"; { - auto loaded = immer::archive::from_json_with_archive< - std::decay_t>(json_archive_str); + auto loaded = + immer::persist::from_json_with_pool>( + json_archive_str); REQUIRE(loaded == value); } } @@ -526,7 +526,7 @@ TEST_CASE("Special archive throws cereal::Exception") const auto value = test_data{}; // const auto json_archive_str = - // immer::archive::to_json_with_archive(value).first; + // immer::persist::to_json_with_pool(value).first; // REQUIRE(json_archive_str == ""); const auto json_archive_str = R"({ @@ -538,7 +538,7 @@ TEST_CASE("Special archive throws cereal::Exception") "metas": 0, "single_meta": {"ints": 0, "metas": 0} }, - "archives": { + "pools": { "ints": { "leaves": [{"key": 1, "value": []}], "inners": [{"key": 0, "value": {"children": [], "relaxed": false}}], @@ -575,11 +575,11 @@ TEST_CASE("Special archive throws cereal::Exception") })"; REQUIRE_THROWS_MATCHES( - immer::archive::from_json_with_archive(json_archive_str), + immer::persist::from_json_with_pool(json_archive_str), ::cereal::Exception, MessageMatches(Catch::Matchers::ContainsSubstring( "Failed to load a container ID 99 from the " - "archive of immer::vector>, @@ -633,15 +633,14 @@ TEST_CASE("Test recursive type") immer::box{v2}}, }; - const auto [json_str, archives] = immer::archive::to_json_with_archive(v3); + const auto [json_str, archives] = immer::persist::to_json_with_pool(v3); // REQUIRE(json_str == ""); { auto full_load = - immer::archive::from_json_with_archive(json_str); + immer::persist::from_json_with_pool(json_str); REQUIRE(full_load == v3); - REQUIRE(immer::archive::to_json_with_archive(full_load).first == - json_str); + REQUIRE(immer::persist::to_json_with_pool(full_load).first == json_str); } } @@ -673,15 +672,14 @@ TEST_CASE("Test recursive type, saving the box triggers saving the box of the " }, }; - const auto [json_str, archives] = immer::archive::to_json_with_archive(v5); + const auto [json_str, archives] = immer::persist::to_json_with_pool(v5); // REQUIRE(json_str == ""); { const auto full_load = - immer::archive::from_json_with_archive(json_str); + immer::persist::from_json_with_pool(json_str); REQUIRE(full_load == v5); - REQUIRE(immer::archive::to_json_with_archive(full_load).first == - json_str); + REQUIRE(immer::persist::to_json_with_pool(full_load).first == json_str); } } @@ -705,7 +703,7 @@ struct rec_map } }; -auto get_archives_types(const rec_map&) +auto get_pools_types(const rec_map&) { auto names = hana::make_map( hana::make_pair(hana::type_c>, @@ -739,16 +737,14 @@ TEST_CASE("Test saving a map that contains the same map") }, }; - const auto [json_str, archives] = - immer::archive::to_json_with_archive(value); + const auto [json_str, archives] = immer::persist::to_json_with_pool(value); // REQUIRE(json_str == ""); { const auto full_load = - immer::archive::from_json_with_archive(json_str); + immer::persist::from_json_with_pool(json_str); REQUIRE(full_load == value); - REQUIRE(immer::archive::to_json_with_archive(full_load).first == - json_str); + REQUIRE(immer::persist::to_json_with_pool(full_load).first == json_str); } } @@ -764,7 +760,7 @@ TEST_CASE("Test non-unique names in the map") ); using IsUnique = - decltype(immer::archive::detail::are_type_names_unique(names)); + decltype(immer::persist::detail::are_type_names_unique(names)); static_assert(IsUnique::value, "Names are unique"); } } @@ -774,11 +770,11 @@ using test::new_type; using test::old_type; template -using map_t = immer::map>; +using map_t = immer::map>; template using table_t = - immer::table>; + immer::table>; // Some type that an application would serialize. Contains multiple vectors and // maps to demonstrate structural sharing. @@ -801,7 +797,7 @@ struct old_app_type } }; -auto get_archives_types(const old_app_type&) +auto get_pools_types(const old_app_type&) { return hana::make_map( hana::make_pair(hana::type_c>, @@ -826,7 +822,7 @@ auto get_archives_types(const old_app_type&) * used to materialize these new vectors that would preserve SS. * * The new type can't differ much from the old type. The type's JSON layout must - * be the same as the old type. Each archivable member gets serialized into an + * be the same as the old type. Each persistable member gets serialized into an * integer (container ID within the archive), so that works. But we can't add * new members. */ @@ -851,7 +847,7 @@ struct new_app_type } }; -auto get_archives_types(const new_app_type&) +auto get_pools_types(const new_app_type&) { return hana::make_map( hana::make_pair(hana::type_c>, @@ -897,8 +893,7 @@ TEST_CASE("Test conversion with a special archive") old_type{"_53_", 53}, }, }; - const auto [json_str, archives] = - immer::archive::to_json_with_archive(value); + const auto [json_str, archives] = immer::persist::to_json_with_pool(value); // REQUIRE(json_str == ""); // Describe how to go from the old archive to the desired new archive. @@ -916,8 +911,8 @@ TEST_CASE("Test conversion with a special archive") // Having a JSON from serializing old_app_type and a conversion function, // we need to somehow load new_app_type. const new_app_type full_load = - immer::archive::from_json_with_archive_with_conversion( + immer::persist::from_json_with_pool_with_conversion( json_str, archives_conversions); { @@ -934,11 +929,11 @@ TEST_CASE("Test conversion with a special archive") "Demonstrate that the loaded vectors and maps still share structure") { const auto [json_str, archives] = - immer::archive::to_json_with_archive(full_load); + immer::persist::to_json_with_pool(full_load); // For example, "x21x" is stored only once. const auto expected = json_t::parse(R"( { - "archives": { + "pools": { "map": [ { "children": [ diff --git a/test/extra/archive/test_special_archive_auto.cpp b/test/extra/persist/test_special_archive_auto.cpp similarity index 84% rename from test/extra/archive/test_special_archive_auto.cpp rename to test/extra/persist/test_special_archive_auto.cpp index 34ebd8e6..6cc5997d 100644 --- a/test/extra/archive/test_special_archive_auto.cpp +++ b/test/extra/persist/test_special_archive_auto.cpp @@ -4,7 +4,7 @@ #include "utils.hpp" -#include +#include #include #define DEFINE_OPERATIONS(name) \ @@ -28,7 +28,7 @@ using test::test_value; using test::vector_one; /** - * A data type with immer members, note the absence of `archivable`. + * A data type with immer members, note the absence of `persistable`. */ struct meta_meta { @@ -77,11 +77,11 @@ struct test_data_with_immer (vector_one, strings), (immer::map, map), (vector_one, metas), - // Map value is indirectly archivable + // Map value is indirectly persistable (immer::map, metas_map), - // Map value is directly archivable + // Map value is directly persistable (immer::map>, vectors_map), - // Also test having meta directly, not inside an archivable type + // Also test having meta directly, not inside an persistable type (meta, single_meta), (immer::box, box), @@ -111,7 +111,7 @@ struct test_data_with_immer TEST_CASE("Auto-archiving") { constexpr auto names = [] { - return immer::archive::get_archives_for_types( + return immer::persist::get_pools_for_types( hana::tuple_t, hana::make_map(hana::make_pair(hana::type_c>, BOOST_HANA_STRING("meta_meta")))); @@ -172,12 +172,12 @@ TEST_CASE("Auto-archiving") }; const auto [json_str, archives] = - immer::archive::to_json_with_auto_archive(value, archive_types); + immer::persist::to_json_with_auto_pool(value, archive_types); // REQUIRE(json_str == ""); { const auto loaded = - immer::archive::from_json_with_auto_archive( + immer::persist::from_json_with_auto_pool( json_str, archive_types); REQUIRE(loaded == value); } @@ -190,12 +190,11 @@ TEST_CASE("Auto-archive must load and save types that have no archive") const auto value = std::make_pair(val1, val2); const auto json_archive_str = - immer::archive::to_json_with_auto_archive(value, hana::make_map()) - .first; + immer::persist::to_json_with_auto_pool(value, hana::make_map()).first; REQUIRE(json_archive_str == test::to_json(value)); { - auto loaded = immer::archive::from_json_with_auto_archive< + auto loaded = immer::persist::from_json_with_auto_pool< std::decay_t>(json_archive_str, hana::make_map()); INFO(loaded.first); INFO(loaded.second); @@ -237,13 +236,13 @@ TEST_CASE("Test save and load small type") const auto value = test_data_with_one_immer_member{ .ints = ints1, }; - const auto archive_types = immer::archive::get_auto_archives_types(value); + const auto archive_types = immer::persist::get_auto_pools_types(value); const auto [json_str, archives] = - immer::archive::to_json_with_auto_archive(value, archive_types); + immer::persist::to_json_with_auto_pool(value, archive_types); // REQUIRE(json_str == ""); { - const auto loaded = immer::archive::from_json_with_auto_archive< + const auto loaded = immer::persist::from_json_with_auto_pool< test_data_with_one_immer_member>(json_str, archive_types); INFO(test::to_json(loaded)); INFO(test::to_json(value)); @@ -257,11 +256,11 @@ using test::new_type; using test::old_type; template -using map_t = immer::map>; +using map_t = immer::map>; template using table_t = - immer::table>; + immer::table>; // Some type that an application would serialize. Contains multiple vectors and // maps to demonstrate structural sharing. @@ -337,14 +336,14 @@ TEST_CASE("Test conversion with auto-archive") }; constexpr auto old_names = [] { - return immer::archive::get_archives_for_types( - hana::tuple_t, hana::make_map()); + return immer::persist::get_pools_for_types(hana::tuple_t, + hana::make_map()); }; using OldArchiveTypes = decltype(old_names()); constexpr auto old_archive_types = OldArchiveTypes{}; const auto [json_str, archives] = - immer::archive::to_json_with_auto_archive(value, old_archive_types); + immer::persist::to_json_with_auto_pool(value, old_archive_types); // REQUIRE(json_str == ""); // Describe how to go from the old archive to the desired new archive. @@ -359,8 +358,9 @@ TEST_CASE("Test conversion with auto-archive") // Having a JSON from serializing old_app_type and a conversion function, // we need to somehow load new_app_type. - const new_app_type full_load = immer::archive:: - from_json_with_auto_archive_with_conversion( + const new_app_type full_load = + immer::persist::from_json_with_auto_pool_with_conversion( json_str, archives_conversions, old_archive_types); { @@ -390,7 +390,7 @@ struct key friend std::size_t xx_hash_value(const key& value) { - return immer::archive::xx_hash_value_string(value.str); + return immer::persist::xx_hash_value_string(value.str); } }; @@ -412,7 +412,7 @@ struct value_one BOOST_HANA_DEFINE_STRUCT( value_one, // (vector_one, twos), - (immer::table>, + (immer::table>, twos_table)); }; @@ -492,7 +492,7 @@ TEST_CASE("Test table with a funny value") const auto t1 = immer::table>{two1}; + immer::persist::xx_hash>{two1}; const auto two2 = champ_test::two_boxed{champ_test::value_two{ .ones = { @@ -507,18 +507,18 @@ TEST_CASE("Test table with a funny value") .twos_table = t1.insert(two2), }; - const auto names = immer::archive::get_archives_for_types( + const auto names = immer::persist::get_pools_for_types( hana::tuple_t, hana::make_map()); const auto [json_str, ar] = - immer::archive::to_json_with_auto_archive(value, names); + immer::persist::to_json_with_auto_pool(value, names); // REQUIRE(json_str == ""); const auto loaded = - immer::archive::from_json_with_auto_archive( + immer::persist::from_json_with_auto_pool( json_str, names); REQUIRE(loaded == value); } @@ -531,7 +531,7 @@ TEST_CASE("Test loading broken table") const auto t1 = immer::table>{two1}; + immer::persist::xx_hash>{two1}; const auto two2 = champ_test::two_boxed{champ_test::value_two{ .ones = { @@ -552,20 +552,20 @@ TEST_CASE("Test loading broken table") .twos_table = t1.insert(two2), }; - const auto names = immer::archive::get_archives_for_types( + const auto names = immer::persist::get_pools_for_types( hana::tuple_t, hana::make_map()); const auto [json_str, ar] = - immer::archive::to_json_with_auto_archive(value, names); + immer::persist::to_json_with_auto_pool(value, names); // REQUIRE(json_str == ""); constexpr auto expected_json_str = R"( { "value0": {"twos": 0, "twos_table": 0}, - "archives": { + "pools": { "two": [ {"ones": 0, "key": {"str": "90"}}, {"ones": 0, "key": {"str": "91"}}, @@ -616,7 +616,7 @@ TEST_CASE("Test loading broken table") { INFO(json_str); const auto loaded = - immer::archive::from_json_with_auto_archive( + immer::persist::from_json_with_auto_pool( json_str, names); REQUIRE(loaded == value); } @@ -625,7 +625,7 @@ TEST_CASE("Test loading broken table") { INFO(json.dump()); const auto loaded = - immer::archive::from_json_with_auto_archive( + immer::persist::from_json_with_auto_pool( json.dump(), names); REQUIRE(loaded == value); } @@ -635,20 +635,20 @@ TEST_CASE("Test loading broken table") { SECTION("box exists") { - json["archives"]["twos_table"][1]["values"][0]["two"] = 0; + json["pools"]["twos_table"][1]["values"][0]["two"] = 0; REQUIRE_THROWS_MATCHES( - immer::archive::from_json_with_auto_archive< - champ_test::value_one>(json.dump(), names), + immer::persist::from_json_with_auto_pool( + json.dump(), names), ::cereal::Exception, MessageMatches(Catch::Matchers::ContainsSubstring( "Couldn't find an element"))); } SECTION("box doesn't exist") { - json["archives"]["twos_table"][1]["values"][0]["two"] = 99; + json["pools"]["twos_table"][1]["values"][0]["two"] = 99; REQUIRE_THROWS_MATCHES( - immer::archive::from_json_with_auto_archive< - champ_test::value_one>(json.dump(), names), + immer::persist::from_json_with_auto_pool( + json.dump(), names), ::cereal::Exception, MessageMatches(Catch::Matchers::ContainsSubstring( "Couldn't find an element"))); @@ -657,9 +657,9 @@ TEST_CASE("Test loading broken table") SECTION("Box that doesn't exist is referenced in the table for the value") { - json["archives"]["twos_table"][0]["values"][0]["two"] = 99; + json["pools"]["twos_table"][0]["values"][0]["two"] = 99; REQUIRE_THROWS_MATCHES( - immer::archive::from_json_with_auto_archive( + immer::persist::from_json_with_auto_pool( json.dump(), names), ::cereal::Exception, MessageMatches(Catch::Matchers::ContainsSubstring( @@ -669,14 +669,14 @@ TEST_CASE("Test loading broken table") namespace test_no_auto { -using immer::archive::archivable; +using immer::persist::persistable; struct value_two; struct two_boxed { BOOST_HANA_DEFINE_STRUCT(two_boxed, - (archivable>, two)); + (persistable>, two)); two_boxed() = default; explicit two_boxed(value_two val); @@ -688,7 +688,7 @@ struct key friend std::size_t xx_hash_value(const key& value) { - return immer::archive::xx_hash_value_string(value.str); + return immer::persist::xx_hash_value_string(value.str); } }; @@ -710,9 +710,9 @@ struct value_one BOOST_HANA_DEFINE_STRUCT( value_one, // (vector_one, twos), - (archivable>>, + (persistable>>, twos_table)); }; @@ -775,7 +775,7 @@ DEFINE_OPERATIONS(key); DEFINE_OPERATIONS(value_one); DEFINE_OPERATIONS(value_two); -auto get_archives_types(const value_one&) +auto get_pools_types(const value_one&) { return hana::make_map( hana::make_pair(hana::type_c>, @@ -783,7 +783,7 @@ auto get_archives_types(const value_one&) hana::make_pair( hana::type_c>>, + immer::persist::xx_hash>>, BOOST_HANA_STRING("table"))); } } // namespace test_no_auto @@ -796,7 +796,7 @@ TEST_CASE("Test table with a funny value no auto") const auto t1 = immer::table>{two1}; + immer::persist::xx_hash>{two1}; const auto two2 = test_no_auto::two_boxed{test_no_auto::value_two{ .ones = { @@ -811,12 +811,11 @@ TEST_CASE("Test table with a funny value no auto") .twos_table = t1.insert(two2), }; - const auto [json_str, ar] = immer::archive::to_json_with_archive(value); + const auto [json_str, ar] = immer::persist::to_json_with_pool(value); // REQUIRE(json_str == ""); const auto loaded = - immer::archive::from_json_with_archive( - json_str); + immer::persist::from_json_with_pool(json_str); REQUIRE(loaded == value); } @@ -853,11 +852,11 @@ TEST_CASE("Structure breaks when hash is changed") .map = {{123, "123"}, {456, "456"}}, }; - const auto names = immer::archive::get_archives_for_types( + const auto names = immer::persist::get_pools_for_types( hana::tuple_t, hana::make_map()); const auto [json_str, ar] = - immer::archive::to_json_with_auto_archive(value, names); + immer::persist::to_json_with_auto_pool(value, names); // REQUIRE(json_str == ""); constexpr auto convert_pair = [](const std::pair& old) { @@ -867,7 +866,7 @@ TEST_CASE("Structure breaks when hash is changed") const auto map = hana::make_map(hana::make_pair( hana::type_c>, hana::overload(convert_pair, - [](immer::archive::target_container_type_request) { + [](immer::persist::target_container_type_request) { // We just return the desired new type, but the hash // of int is not compatible with the hash of string. return immer::map{}; @@ -875,10 +874,10 @@ TEST_CASE("Structure breaks when hash is changed") ); - auto load_ar = immer::archive::transform_save_archive(ar, map); + auto load_ar = immer::persist::transform_input_pool(ar, map); - REQUIRE_THROWS_AS(immer::archive::convert_container(ar, load_ar, value.map), - immer::archive::champ::hash_validation_failed_exception); + REQUIRE_THROWS_AS(immer::persist::convert_container(ar, load_ar, value.map), + immer::persist::champ::hash_validation_failed_exception); } TEST_CASE("Converting between incompatible keys") @@ -888,10 +887,10 @@ TEST_CASE("Converting between incompatible keys") .table = {{901}, {902}}, }; - const auto names = immer::archive::get_archives_for_types( + const auto names = immer::persist::get_pools_for_types( hana::tuple_t, hana::make_map()); - const auto ar = immer::archive::get_auto_archive(value, names); + const auto ar = immer::persist::get_auto_pool(value, names); constexpr auto convert_pair = [](const std::pair& old) { return std::make_pair(fmt::format("_{}_", old.first), old.second); @@ -913,16 +912,16 @@ TEST_CASE("Converting between incompatible keys") hana::type_c>, hana::overload( convert_pair, - [](immer::archive::target_container_type_request) { - return immer::archive::champ::incompatible_hash_wrapper< + [](immer::persist::target_container_type_request) { + return immer::persist::champ::incompatible_hash_wrapper< immer::map>{}; })), hana::make_pair( hana::type_c>, hana::overload( convert_int_key, - [](immer::archive::target_container_type_request) { - return immer::archive::champ::incompatible_hash_wrapper< + [](immer::persist::target_container_type_request) { + return immer::persist::champ::incompatible_hash_wrapper< immer::table>{}; })), hana::make_pair( @@ -931,14 +930,14 @@ TEST_CASE("Converting between incompatible keys") [convert_int_key](int old) { return convert_int_key(int_key{old}).id; }, - [](immer::archive::target_container_type_request) { - return immer::archive::champ::incompatible_hash_wrapper< + [](immer::persist::target_container_type_request) { + return immer::persist::champ::incompatible_hash_wrapper< immer::set>{}; })) ); - auto load_ar = immer::archive::transform_save_archive(ar, map); + auto load_ar = immer::persist::transform_input_pool(ar, map); SECTION("maps") { constexpr auto convert_map = [convert_pair](const auto& map) { @@ -950,12 +949,12 @@ TEST_CASE("Converting between incompatible keys") }; const auto converted = - immer::archive::convert_container(ar, load_ar, value.map); + immer::persist::convert_container(ar, load_ar, value.map); REQUIRE(converted == convert_map(value.map)); // Converting the same thing should return the same data const auto converted_2 = - immer::archive::convert_container(ar, load_ar, value.map); + immer::persist::convert_container(ar, load_ar, value.map); REQUIRE(converted.identity() == converted_2.identity()); } SECTION("tables") @@ -969,12 +968,12 @@ TEST_CASE("Converting between incompatible keys") }; const auto converted = - immer::archive::convert_container(ar, load_ar, value.table); + immer::persist::convert_container(ar, load_ar, value.table); REQUIRE(converted == convert_table(value.table)); // Converting the same thing should return the same data const auto converted_2 = - immer::archive::convert_container(ar, load_ar, value.table); + immer::persist::convert_container(ar, load_ar, value.table); REQUIRE(converted.impl().root == converted_2.impl().root); } SECTION("sets") @@ -989,12 +988,12 @@ TEST_CASE("Converting between incompatible keys") }; const auto converted = - immer::archive::convert_container(ar, load_ar, value.set); + immer::persist::convert_container(ar, load_ar, value.set); REQUIRE(converted == convert_set(value.set)); // Converting the same thing should return the same data const auto converted_2 = - immer::archive::convert_container(ar, load_ar, value.set); + immer::persist::convert_container(ar, load_ar, value.set); REQUIRE(converted.impl().root == converted_2.impl().root); } } diff --git a/test/extra/archive/test_vectors.cpp b/test/extra/persist/test_vectors.cpp similarity index 84% rename from test/extra/archive/test_vectors.cpp rename to test/extra/persist/test_vectors.cpp index 0f911421..d3592140 100644 --- a/test/extra/archive/test_vectors.cpp +++ b/test/extra/persist/test_vectors.cpp @@ -10,8 +10,8 @@ #include #include -#include -#include +#include +#include #include "utils.hpp" @@ -24,32 +24,32 @@ namespace { using namespace test; -using immer::archive::container_id; -using immer::archive::rbts::save_to_archive; +using immer::persist::container_id; +using immer::persist::rbts::add_to_pool; using json_t = nlohmann::json; namespace hana = boost::hana; auto load_vec(const auto& json, std::size_t vec_id) { - const auto archive = - test::from_json>(json); + const auto pool = + test::from_json>(json); auto loader = - immer::archive::rbts::make_loader_for(test::example_vector{}, archive); + immer::persist::rbts::make_loader_for(test::example_vector{}, pool); return loader.load(container_id{vec_id}); } auto load_flex_vec(const auto& json, std::size_t vec_id) { - const auto archive = - test::from_json>(json); - auto loader = immer::archive::rbts::make_loader_for( - test::example_flex_vector{}, archive); + const auto pool = + test::from_json>(json); + auto loader = immer::persist::rbts::make_loader_for( + test::example_flex_vector{}, pool); return loader.load(container_id{vec_id}); } } // namespace -TEST_CASE("Save and load multiple times into the same archive") +TEST_CASE("Save and load multiple times into the same pool") { // spdlog::set_level(spdlog::level::trace); @@ -58,19 +58,18 @@ TEST_CASE("Save and load multiple times into the same archive") example_vector{}, }; auto counter = std::size_t{}; - auto ar = immer::archive::rbts::make_save_archive_for(example_vector{}); + auto ar = immer::persist::rbts::make_input_pool_for(example_vector{}); const auto save_and_load = [&]() { const auto vec = test_vectors.back().push_back(++counter); test_vectors.push_back(vec); - auto vector_id = immer::archive::container_id{}; - std::tie(ar, vector_id) = - immer::archive::rbts::save_to_archive(vec, ar); + auto vector_id = immer::persist::container_id{}; + std::tie(ar, vector_id) = immer::persist::rbts::add_to_pool(vec, ar); SPDLOG_DEBUG("start test size {}", vec.size()); { auto loader = - std::make_optional(example_loader{to_load_archive(ar)}); + std::make_optional(example_loader{to_output_pool(ar)}); auto loaded_vec = loader->load_vector(vector_id); REQUIRE(loaded_vec == vec); } @@ -98,12 +97,12 @@ TEST_CASE("Save and load vectors with shared nodes") // Save them const auto save_vectors = [](const auto& vectors) - -> std::pair> { - auto ar = example_archive_save{}; - auto ids = std::vector{}; + -> std::pair> { + auto ar = example_input_pool{}; + auto ids = std::vector{}; for (const auto& v : vectors) { - auto [ar2, id] = save_to_archive(v, ar); + auto [ar2, id] = add_to_pool(v, ar); ar = ar2; ids.push_back(id); } @@ -122,7 +121,7 @@ TEST_CASE("Save and load vectors with shared nodes") } // Load them and verify they're equal to the original vectors - auto loader = std::make_optional(example_loader{to_load_archive(ar)}); + auto loader = std::make_optional(example_loader{to_output_pool(ar)}); std::vector loaded; auto index = std::size_t{}; for (const auto& id : ids) { @@ -175,12 +174,12 @@ TEST_CASE("Save and load vectors and flex vectors with shared nodes") }; // Save them - const auto save_vectors = [](example_archive_save ar, const auto& vectors) - -> std::pair> { - auto ids = std::vector{}; + const auto save_vectors = [](example_input_pool ar, const auto& vectors) + -> std::pair> { + auto ids = std::vector{}; for (const auto& v : vectors) { - auto [ar2, id] = save_to_archive(v, ar); + auto [ar2, id] = add_to_pool(v, ar); ar = ar2; ids.push_back(id); } @@ -188,11 +187,11 @@ TEST_CASE("Save and load vectors and flex vectors with shared nodes") return {std::move(ar), std::move(ids)}; }; - auto ar = example_archive_save{}; + auto ar = example_input_pool{}; const auto vectors = generate_vectors(); const auto flex_vectors = generate_flex_vectors(); - auto vector_ids = std::vector{}; - auto flex_vectors_ids = std::vector{}; + auto vector_ids = std::vector{}; + auto flex_vectors_ids = std::vector{}; std::tie(ar, vector_ids) = save_vectors(ar, vectors); std::tie(ar, flex_vectors_ids) = save_vectors(ar, flex_vectors); REQUIRE(!vector_ids.empty()); @@ -209,7 +208,7 @@ TEST_CASE("Save and load vectors and flex vectors with shared nodes") } // Load them and verify they're equal to the original vectors - auto loader = example_loader{to_load_archive(ar)}; + auto loader = example_loader{to_output_pool(ar)}; auto loaded = [&] { auto result = std::vector{}; auto index = std::size_t{}; @@ -243,17 +242,17 @@ TEST_CASE("Save and load vectors and flex vectors with shared nodes") TEST_CASE("Archive in-place mutated vector") { auto vec = example_vector{1, 2, 3}; - auto ar = example_archive_save{}; - auto id1 = immer::archive::container_id{}; - std::tie(ar, id1) = save_to_archive(vec, ar); + auto ar = example_input_pool{}; + auto id1 = immer::persist::container_id{}; + std::tie(ar, id1) = add_to_pool(vec, ar); vec = std::move(vec).push_back(90); - auto id2 = immer::archive::container_id{}; - std::tie(ar, id2) = save_to_archive(vec, ar); + auto id2 = immer::persist::container_id{}; + std::tie(ar, id2) = add_to_pool(vec, ar); REQUIRE(id1 != id2); - auto loader = example_loader{to_load_archive(ar)}; + auto loader = example_loader{to_output_pool(ar)}; const auto loaded1 = loader.load_vector(id1); const auto loaded2 = loader.load_vector(id2); REQUIRE(loaded2 == loaded1.push_back(90)); @@ -262,17 +261,17 @@ TEST_CASE("Archive in-place mutated vector") TEST_CASE("Archive in-place mutated flex_vector") { auto vec = example_flex_vector{1, 2, 3}; - auto ar = example_archive_save{}; - auto id1 = immer::archive::container_id{}; - std::tie(ar, id1) = save_to_archive(vec, ar); + auto ar = example_input_pool{}; + auto id1 = immer::persist::container_id{}; + std::tie(ar, id1) = add_to_pool(vec, ar); vec = std::move(vec).push_back(90); - auto id2 = immer::archive::container_id{}; - std::tie(ar, id2) = save_to_archive(vec, ar); + auto id2 = immer::persist::container_id{}; + std::tie(ar, id2) = add_to_pool(vec, ar); REQUIRE(id1 != id2); - auto loader = example_loader{to_load_archive(ar)}; + auto loader = example_loader{to_output_pool(ar)}; const auto loaded1 = loader.load_flex_vector(id1); const auto loaded2 = loader.load_flex_vector(id2); REQUIRE(loaded2 == loaded1.push_back(90)); @@ -283,13 +282,13 @@ TEST_CASE("Test nodes reuse") const auto small_vec = gen(test::flex_vector_one{}, 67); const auto big_vec = small_vec + small_vec; - auto ar = example_archive_save{}; - auto id1 = immer::archive::container_id{}; - std::tie(ar, id1) = save_to_archive(big_vec, ar); + auto ar = example_input_pool{}; + auto id1 = immer::persist::container_id{}; + std::tie(ar, id1) = add_to_pool(big_vec, ar); { // Loads correctly - auto loader = example_loader{to_load_archive(ar)}; + auto loader = example_loader{to_output_pool(ar)}; const auto loaded1 = loader.load_flex_vector(id1); REQUIRE(loaded1 == big_vec); } @@ -312,30 +311,30 @@ TEST_CASE("Test saving and loading vectors of different lengths", "[slow]") { for_each_generated_length( test::vector_one{}, 350, [&](const auto& vec) { - auto ar = example_archive_save{}; - auto id1 = immer::archive::container_id{}; - std::tie(ar, id1) = save_to_archive(vec, ar); + auto ar = example_input_pool{}; + auto id1 = immer::persist::container_id{}; + std::tie(ar, id1) = add_to_pool(vec, ar); { // Loads correctly - auto loader = example_loader{to_load_archive(ar)}; + auto loader = example_loader{to_output_pool(ar)}; const auto loaded1 = loader.load_vector(id1); REQUIRE(loaded1 == vec); } }); } - SECTION("keep archiving into the same archive") + SECTION("keep archiving into the same pool") { - auto ar = example_archive_save{}; + auto ar = example_input_pool{}; for_each_generated_length( test::vector_one{}, 350, [&](const auto& vec) { - auto id1 = immer::archive::container_id{}; - std::tie(ar, id1) = save_to_archive(vec, ar); + auto id1 = immer::persist::container_id{}; + std::tie(ar, id1) = add_to_pool(vec, ar); { // Loads correctly - auto loader = example_loader{to_load_archive(ar)}; + auto loader = example_loader{to_output_pool(ar)}; const auto loaded1 = loader.load_vector(id1); REQUIRE(loaded1 == vec); } @@ -361,13 +360,13 @@ TEST_CASE("Test flex vectors memory leak") for_each_generated_length_flex( test::flex_vector_one{}, max_length, [&](const auto& vec) { - auto ar = example_archive_save{}; - auto id1 = immer::archive::container_id{}; - std::tie(ar, id1) = save_to_archive(vec, ar); + auto ar = example_input_pool{}; + auto id1 = immer::persist::container_id{}; + std::tie(ar, id1) = add_to_pool(vec, ar); { // Loads correctly - loaders.emplace_back(to_load_archive(ar)); + loaders.emplace_back(to_output_pool(ar)); auto& loader = loaders.back(); const auto loaded1 = loader.load_flex_vector(id1); REQUIRE(loaded1 == vec); @@ -387,21 +386,21 @@ TEST_CASE("Test flex vectors memory leak") * So it must be an inner node that has the last pointer to another * inner node. */ - auto ar = example_archive_save{}; - auto ids = std::vector{}; + auto ar = example_input_pool{}; + auto ids = std::vector{}; auto vecs = std::vector>{}; for_each_generated_length_flex( test::flex_vector_one{}, max_length, [&](const auto& vec) { - auto id1 = immer::archive::container_id{}; - std::tie(ar, id1) = save_to_archive(vec, ar); + auto id1 = immer::persist::container_id{}; + std::tie(ar, id1) = add_to_pool(vec, ar); ids.push_back(id1); vecs.push_back(vec); }); auto index = std::size_t{}; for (const auto& id : ids) { - auto loader = example_loader{to_load_archive(ar)}; + auto loader = example_loader{to_output_pool(ar)}; const auto loaded1 = loader.load_flex_vector(id); REQUIRE(loaded1 == vecs[index]); ++index; @@ -411,14 +410,14 @@ TEST_CASE("Test flex vectors memory leak") { for_each_generated_length_flex( test::flex_vector_one{}, max_length, [&](const auto& vec) { - auto ar = example_archive_save{}; - auto id1 = immer::archive::container_id{}; - std::tie(ar, id1) = save_to_archive(vec, ar); + auto ar = example_input_pool{}; + auto id1 = immer::persist::container_id{}; + std::tie(ar, id1) = add_to_pool(vec, ar); { // Loads correctly const auto loaded1 = - example_loader{to_load_archive(ar)}.load_flex_vector( + example_loader{to_output_pool(ar)}.load_flex_vector( id1); REQUIRE(loaded1 == vec); } @@ -445,17 +444,17 @@ TEST_CASE("Test saving and loading flex vectors of different lengths", "[slow]") } }; - SECTION("one vector per archive") + SECTION("one vector per pool") { for_each_generated_length_flex( test::flex_vector_one{}, 350, [&](const auto& vec) { - auto ar = example_archive_save{}; - auto id1 = immer::archive::container_id{}; - std::tie(ar, id1) = save_to_archive(vec, ar); + auto ar = example_input_pool{}; + auto id1 = immer::persist::container_id{}; + std::tie(ar, id1) = add_to_pool(vec, ar); { // Loads correctly - auto loader = example_loader{to_load_archive(ar)}; + auto loader = example_loader{to_output_pool(ar)}; const auto loaded1 = loader.load_flex_vector(id1); REQUIRE(loaded1 == vec); } @@ -464,14 +463,14 @@ TEST_CASE("Test saving and loading flex vectors of different lengths", "[slow]") SECTION("one archive for all") { - auto ar = example_archive_save{}; + auto ar = example_input_pool{}; for_each_generated_length_flex( test::vector_one{}, 350, [&](const auto& vec) { - auto id1 = immer::archive::container_id{}; - std::tie(ar, id1) = save_to_archive(vec, ar); + auto id1 = immer::persist::container_id{}; + std::tie(ar, id1) = add_to_pool(vec, ar); // Loads correctly - auto loader = make_loader_for(vec, to_load_archive(ar)); + auto loader = make_loader_for(vec, to_output_pool(ar)); const auto loaded1 = loader.load(id1); REQUIRE(loaded1 == vec); }); @@ -758,8 +757,7 @@ TEST_CASE("A loop with 2 nodes") } } )"}; - REQUIRE_THROWS_AS(load_flex_vec(json, 0), - immer::archive::archive_has_cycles); + REQUIRE_THROWS_AS(load_flex_vec(json, 0), immer::persist::pool_has_cycles); } namespace { @@ -840,15 +838,15 @@ TEST_CASE("Test vector with very big objects") const auto small_vec = gen(test::vector_one{}, 67); - auto ar = immer::archive::rbts::make_save_archive_for( + auto ar = immer::persist::rbts::make_input_pool_for( test::vector_one{}); - auto id1 = immer::archive::container_id{}; - std::tie(ar, id1) = save_to_archive(small_vec, ar); + auto id1 = immer::persist::container_id{}; + std::tie(ar, id1) = add_to_pool(small_vec, ar); { // Loads correctly - auto loader = immer::archive::rbts::make_loader_for( - test::vector_one{}, to_load_archive(ar)); + auto loader = immer::persist::rbts::make_loader_for( + test::vector_one{}, to_output_pool(ar)); const auto loaded1 = loader.load(id1); REQUIRE(loaded1 == small_vec); } @@ -906,21 +904,21 @@ TEST_CASE("Test modifying vector nodes") SECTION("Load non-existing vector") { REQUIRE_THROWS_AS(load_vec(data.dump(), 99), - immer::archive::archive_exception); + immer::persist::pool_exception); } SECTION("Invalid root id") { data["value0"]["vectors"][0]["root"] = 1; REQUIRE_THROWS_AS(load_vec(data.dump(), 0), - immer::archive::invalid_node_id); + immer::persist::invalid_node_id); } SECTION("Invalid tail id") { data["value0"]["vectors"][0]["tail"] = 999; REQUIRE_THROWS_AS(load_vec(data.dump(), 0), - immer::archive::invalid_node_id); + immer::persist::invalid_node_id); } SECTION("A leaf with too few elements") @@ -930,7 +928,7 @@ TEST_CASE("Test modifying vector nodes") // Leaf #3 should have two elements, but it has only one. item["value"] = {2}; REQUIRE_THROWS_AS(load_vec(data.dump(), 0), - immer::archive::rbts::vector_corrupted_exception); + immer::persist::rbts::vector_corrupted_exception); } SECTION("Mess with the tail") @@ -947,14 +945,14 @@ TEST_CASE("Test modifying vector nodes") { item["value"] = json_t::array(); REQUIRE_THROWS_AS(load_vec(data.dump(), 0), - immer::archive::rbts::vector_corrupted_exception); + immer::persist::rbts::vector_corrupted_exception); } SECTION("Add too many elements") { // Three elements can't be in a leaf item["value"] = {6, 7, 8}; REQUIRE_THROWS_AS(load_vec(data.dump(), 0), - immer::archive::invalid_children_count); + immer::persist::invalid_children_count); } } @@ -966,7 +964,7 @@ TEST_CASE("Test modifying vector nodes") { item["value"]["children"] = std::vector(33, 2); REQUIRE_THROWS_AS(load_vec(data.dump(), 0), - immer::archive::invalid_children_count); + immer::persist::invalid_children_count); } SECTION("Remove one") { @@ -978,20 +976,20 @@ TEST_CASE("Test modifying vector nodes") { item["value"]["children"] = {2, 4, 9}; REQUIRE_THROWS_AS(load_vec(data.dump(), 0), - immer::archive::invalid_node_id); + immer::persist::invalid_node_id); } SECTION("Node has itself as a child") { item["value"]["children"] = {2, 0, 4}; REQUIRE_THROWS_AS(load_vec(data.dump(), 0), - immer::archive::archive_has_cycles); + immer::persist::pool_has_cycles); } SECTION("Strict vector can not have relaxed nodes") { item["value"]["relaxed"] = true; REQUIRE_THROWS_AS( load_vec(data.dump(), 0), - immer::archive::rbts::relaxed_node_not_allowed_exception); + immer::persist::rbts::relaxed_node_not_allowed_exception); } } } @@ -1059,13 +1057,13 @@ TEST_CASE("Test modifying flex vector nodes") SECTION("Load non-existing vector") { REQUIRE_THROWS_AS(load_flex_vec(data.dump(), 99), - immer::archive::archive_exception); + immer::persist::pool_exception); } SECTION("Non-relaxed vector can not have relaxed nodes") { REQUIRE_THROWS_AS( load_vec(data.dump(), 0), - immer::archive::rbts::relaxed_node_not_allowed_exception); + immer::persist::rbts::relaxed_node_not_allowed_exception); } SECTION("Modify starting leaf") { @@ -1126,7 +1124,7 @@ TEST_CASE("Test modifying flex vector nodes") children = {2, 3, 4, 902, 4}; REQUIRE_THROWS_AS( load_flex_vec(data.dump(), 0), - immer::archive::rbts::same_depth_children_exception); + immer::persist::rbts::same_depth_children_exception); } SECTION("No children") { @@ -1144,7 +1142,7 @@ TEST_CASE("Test modifying flex vector nodes") const auto is_relaxed = GENERATE(false, true); item["value"]["relaxed"] = is_relaxed; REQUIRE_THROWS_AS(load_flex_vec(data.dump(), 0), - immer::archive::invalid_children_count); + immer::persist::invalid_children_count); } SECTION("Remove a child") { @@ -1167,7 +1165,7 @@ TEST_CASE("Test modifying flex vector nodes") item["value"]["relaxed"] = false; REQUIRE_THROWS_AS( load_flex_vec(data.dump(), 0), - immer::archive::rbts::vector_corrupted_exception); + immer::persist::rbts::vector_corrupted_exception); } SECTION("Relaxed works") { @@ -1292,7 +1290,7 @@ TEST_CASE("Test more inner nodes") REQUIRE(children == json_t::array({2, 35})); children = {2, 28}; REQUIRE_THROWS_AS(load_vec(data.dump(), 0), - immer::archive::rbts::same_depth_children_exception); + immer::persist::rbts::same_depth_children_exception); } SECTION("Strict vector can't contain relaxed nodes at all") { @@ -1304,7 +1302,7 @@ TEST_CASE("Test more inner nodes") item["relaxed"] = true; REQUIRE_THROWS_AS( load_vec(data.dump(), 0), - immer::archive::rbts::relaxed_node_not_allowed_exception); + immer::persist::rbts::relaxed_node_not_allowed_exception); } SECTION("Relaxed non-root") { @@ -1314,7 +1312,7 @@ TEST_CASE("Test more inner nodes") item["relaxed"] = true; REQUIRE_THROWS_AS( load_vec(data.dump(), 0), - immer::archive::rbts::relaxed_node_not_allowed_exception); + immer::persist::rbts::relaxed_node_not_allowed_exception); } } SECTION("Flex vector loads as well") @@ -1342,7 +1340,7 @@ TEST_CASE("Test more inner nodes") inners[1]["value"]["children"] = {3, 4, 5}; REQUIRE_THROWS_AS( load_flex_vec(data.dump(), 0), - immer::archive::rbts::relaxed_node_not_allowed_exception); + immer::persist::rbts::relaxed_node_not_allowed_exception); } } } @@ -1406,7 +1404,7 @@ TEST_CASE("Exception while loading 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), - immer::archive::rbts::same_depth_children_exception); + immer::persist::rbts::same_depth_children_exception); } TEST_CASE("Test flex vector with a weird shape relaxed") @@ -1429,10 +1427,10 @@ TEST_CASE("Test flex vector with a weird shape relaxed") const auto loaded = load_flex_vec(data.dump(), 0); // { - // auto ar = immer::archive::rbts::make_save_archive_for(loaded); - // auto vector_id = immer::archive::node_id{}; + // auto ar = immer::persist::rbts::make_input_pool_for(loaded); + // auto vector_id = immer::persist::node_id{}; // std::tie(ar, vector_id) = - // immer::archive::rbts::save_to_archive(loaded, ar); + // immer::persist::rbts::add_to_pool(loaded, ar); // SPDLOG_INFO("{}", test::to_json(ar)); // } @@ -1464,10 +1462,10 @@ TEST_CASE("Test flex vector with a weird shape strict", "[.broken]") const auto loaded = load_flex_vec(data.dump(), 0); // { - // auto ar = immer::archive::rbts::make_save_archive_for(loaded); - // auto vector_id = immer::archive::node_id{}; + // auto ar = immer::persist::rbts::make_input_pool_for(loaded); + // auto vector_id = immer::persist::node_id{}; // std::tie(ar, vector_id) = - // immer::archive::rbts::save_to_archive(loaded, ar); + // immer::persist::rbts::add_to_pool(loaded, ar); // SPDLOG_INFO("{}", test::to_json(ar)); // } @@ -1493,19 +1491,19 @@ TEST_CASE("Flex vector converted from strict") const auto small_vec = gen(test::vector_one{}, 67); const auto small_flex_vec = test::flex_vector_one{small_vec}; - auto ar = immer::archive::rbts::make_save_archive_for(small_vec); - auto small_vec_id = immer::archive::container_id{}; - auto small_flex_vec_id = immer::archive::container_id{}; + auto ar = immer::persist::rbts::make_input_pool_for(small_vec); + auto small_vec_id = immer::persist::container_id{}; + auto small_flex_vec_id = immer::persist::container_id{}; SECTION("First save strict") { - std::tie(ar, small_vec_id) = save_to_archive(small_vec, ar); - std::tie(ar, small_flex_vec_id) = save_to_archive(small_flex_vec, ar); + std::tie(ar, small_vec_id) = add_to_pool(small_vec, ar); + std::tie(ar, small_flex_vec_id) = add_to_pool(small_flex_vec, ar); } SECTION("First save flex") { - std::tie(ar, small_flex_vec_id) = save_to_archive(small_flex_vec, ar); - std::tie(ar, small_vec_id) = save_to_archive(small_vec, ar); + std::tie(ar, small_flex_vec_id) = add_to_pool(small_flex_vec, ar); + std::tie(ar, small_vec_id) = add_to_pool(small_vec, ar); } // The id is the same @@ -1513,11 +1511,11 @@ TEST_CASE("Flex vector converted from strict") // Can be loaded either way, as flex or normal { - auto loader_flex = make_loader_for(small_flex_vec, to_load_archive(ar)); + auto loader_flex = make_loader_for(small_flex_vec, to_output_pool(ar)); REQUIRE(small_flex_vec == loader_flex.load(small_flex_vec_id)); } { - auto loader = make_loader_for(small_vec, to_load_archive(ar)); + auto loader = make_loader_for(small_vec, to_output_pool(ar)); REQUIRE(small_vec == loader.load(small_vec_id)); } } @@ -1526,23 +1524,23 @@ TEST_CASE("Can't load saved flex vector with relaxed nodes as strict") { const auto small_vec = gen(test::flex_vector_one{}, 67); const auto vec = small_vec + small_vec; - auto ar = immer::archive::rbts::make_save_archive_for(vec); - auto vec_id = immer::archive::container_id{}; + auto ar = immer::persist::rbts::make_input_pool_for(vec); + auto vec_id = immer::persist::container_id{}; - std::tie(ar, vec_id) = save_to_archive(vec, ar); + std::tie(ar, vec_id) = add_to_pool(vec, ar); SECTION("Flex loads well") { auto loader_flex = - make_loader_for(test::flex_vector_one{}, to_load_archive(ar)); + make_loader_for(test::flex_vector_one{}, to_output_pool(ar)); REQUIRE(vec == loader_flex.load(vec_id)); } SECTION("Strict can't load") { auto loader = - make_loader_for(test::vector_one{}, to_load_archive(ar)); + make_loader_for(test::vector_one{}, to_output_pool(ar)); REQUIRE_THROWS_AS( loader.load(vec_id), - immer::archive::rbts::relaxed_node_not_allowed_exception); + immer::persist::rbts::relaxed_node_not_allowed_exception); } } @@ -1557,11 +1555,11 @@ TEST_CASE("Test vector archive conversion") }; const auto vec2 = vec1.push_back(old_type{.data = 345}); - auto ar = immer::archive::rbts::make_save_archive_for(vec1); - auto vec1_id = immer::archive::container_id{}; - std::tie(ar, vec1_id) = save_to_archive(vec1, ar); - auto vec2_id = immer::archive::container_id{}; - std::tie(ar, vec2_id) = save_to_archive(vec2, ar); + auto ar = immer::persist::rbts::make_input_pool_for(vec1); + auto vec1_id = immer::persist::container_id{}; + std::tie(ar, vec1_id) = add_to_pool(vec1, ar); + auto vec2_id = immer::persist::container_id{}; + std::tie(ar, vec2_id) = add_to_pool(vec2, ar); // Confirm that vec1 and vec2 have structural sharing in the beginning. const auto expected_ar = json_t::parse(R"( @@ -1625,9 +1623,9 @@ TEST_CASE("Test vector archive conversion") REQUIRE(json_t::parse(to_json(ar)) == expected_ar); - const auto load_archive = to_load_archive(ar); + const auto load_archive = to_output_pool(ar); const auto load_archive_new_type = - transform_archive(load_archive, convert_old_type); + transform_pool(load_archive, convert_old_type); auto loader = make_loader_for(test::vector_one{}, load_archive_new_type); @@ -1638,10 +1636,10 @@ TEST_CASE("Test vector archive conversion") SECTION("Loaded vectors still share the structure") { - auto ar = immer::archive::rbts::make_save_archive_for(loaded_1); - auto id = immer::archive::container_id{}; - std::tie(ar, id) = save_to_archive(loaded_1, ar); - std::tie(ar, id) = save_to_archive(loaded_2, ar); + auto ar = immer::persist::rbts::make_input_pool_for(loaded_1); + auto id = immer::persist::container_id{}; + std::tie(ar, id) = add_to_pool(loaded_1, ar); + std::tie(ar, id) = add_to_pool(loaded_2, ar); const auto expected_ar = json_t::parse(R"( { @@ -1711,8 +1709,8 @@ TEST_CASE("Test vector archive conversion") TEST_CASE("Vector: converting loader can handle exceptions") { const auto vec = example_vector{1, 2, 3}; - const auto [ar_save, vec_id] = save_to_archive(vec, {}); - const auto ar_load = to_load_archive(ar_save); + const auto [ar_save, vec_id] = add_to_pool(vec, {}); + const auto ar_load = to_output_pool(ar_save); using Archive = std::decay_t; @@ -1731,7 +1729,7 @@ TEST_CASE("Vector: converting loader can handle exceptions") using TransformF = std::decay_t; using Loader = - immer::archive::rbts::loader; using Loader = - immer::archive::rbts::loader -#include +#include #include -#include +#include #include #include "utils.hpp" @@ -22,11 +22,11 @@ const auto gen_map = [](auto map, int count) { TEST_CASE("Test hash strings") { auto str = std::string{}; - REQUIRE(immer::archive::xx_hash{}(str) == 3244421341483603138); + REQUIRE(immer::persist::xx_hash{}(str) == 3244421341483603138); REQUIRE(XXH3_64bits(str.c_str(), str.size()) == 3244421341483603138); str = "hello"; - REQUIRE(immer::archive::xx_hash{}(str) == + REQUIRE(immer::persist::xx_hash{}(str) == 10760762337991515389UL); REQUIRE(XXH3_64bits(str.c_str(), str.size()) == 10760762337991515389UL); } @@ -36,7 +36,7 @@ TEST_CASE("Test loading a big map saved on macOS with std::hash", "[.macos]") using Container = immer::map; const auto set = gen_map(Container{}, 200); - const auto [ar, set_id] = immer::archive::champ::save_to_archive(set, {}); + const auto [ar, set_id] = immer::persist::champ::add_to_pool(set, {}); const auto ar_str = test::to_json(ar); // REQUIRE(ar_str == ""); const auto expected_json = R"({ @@ -655,9 +655,9 @@ TEST_CASE("Test loading a big map saved on macOS with std::hash", "[.macos]") REQUIRE(expected == actual); const auto loaded_archive = test::from_json< - immer::archive::champ::container_archive_load>(ar_str); + immer::persist::champ::container_output_pool>(ar_str); - auto loader = immer::archive::champ::container_loader{loaded_archive}; + auto loader = immer::persist::champ::container_loader{loaded_archive}; const auto loaded = loader.load(set_id); REQUIRE(loaded == set); } @@ -665,10 +665,10 @@ TEST_CASE("Test loading a big map saved on macOS with std::hash", "[.macos]") TEST_CASE("Test loading a big map with xxHash") { using Container = immer:: - map>; + map>; const auto set = gen_map(Container{}, 200); - const auto [ar, set_id] = immer::archive::champ::save_to_archive(set, {}); + const auto [ar, set_id] = immer::persist::champ::add_to_pool(set, {}); const auto ar_str = test::to_json(ar); const auto expected_json = R"({ "value0": [ @@ -1323,9 +1323,9 @@ TEST_CASE("Test loading a big map with xxHash") REQUIRE(expected == actual); const auto loaded_archive = test::from_json< - immer::archive::champ::container_archive_load>(ar_str); + immer::persist::champ::container_output_pool>(ar_str); - auto loader = immer::archive::champ::container_loader{loaded_archive}; + auto loader = immer::persist::champ::container_loader{loaded_archive}; const auto loaded = loader.load(set_id); REQUIRE(loaded == set); } diff --git a/test/extra/archive/utils.hpp b/test/extra/persist/utils.hpp similarity index 86% rename from test/extra/archive/utils.hpp rename to test/extra/persist/utils.hpp index 863d68cb..fafc0d84 100644 --- a/test/extra/archive/utils.hpp +++ b/test/extra/persist/utils.hpp @@ -1,10 +1,9 @@ #pragma once -#include -#include -#include +#include +#include -#include +#include #include @@ -30,9 +29,9 @@ using flex_vector_one = using example_vector = vector_one; using example_flex_vector = flex_vector_one; -using example_archive_save = - decltype(immer::archive::rbts::make_save_archive_for(example_vector{})); -using example_loader = immer::archive::rbts:: +using example_input_pool = + decltype(immer::persist::rbts::make_input_pool_for(example_vector{})); +using example_loader = immer::persist::rbts:: loader; inline auto gen(auto init, int count) @@ -146,17 +145,17 @@ constexpr auto convert_old_type = [](auto&& arg) { }; constexpr auto convert_old_type_map = boost::hana::overload( - [](immer::archive::target_container_type_request) { + [](immer::persist::target_container_type_request) { return immer:: - map>{}; + map>{}; }, convert_old_type); constexpr auto convert_old_type_table = boost::hana::overload( - [](immer::archive::target_container_type_request) { + [](immer::persist::target_container_type_request) { return immer::table>{}; + immer::persist::xx_hash>{}; }, convert_old_type); @@ -172,7 +171,7 @@ inline auto transform_vec(const auto& vec) inline auto transform_map(const auto& map) { auto result = immer:: - map>{}; + map>{}; for (const auto& [key, value] : map) { result = std::move(result).set(key, convert_old_type(value)); } @@ -183,7 +182,7 @@ inline auto transform_table(const auto& table) { auto result = immer::table>{}; + immer::persist::xx_hash>{}; for (const auto& item : table) { result = std::move(result).insert(convert_old_type(item)); } diff --git a/test/extra/archive/valgrind.supp b/test/extra/persist/valgrind.supp similarity index 100% rename from test/extra/archive/valgrind.supp rename to test/extra/persist/valgrind.supp