diff --git a/immer/extra/persist/detail/json/input_archive_util.hpp b/immer/extra/persist/detail/json/input_archive_util.hpp new file mode 100644 index 00000000..08ad4bf2 --- /dev/null +++ b/immer/extra/persist/detail/json/input_archive_util.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include +#include + +namespace immer::persist::detail { + +template +auto load_pools(std::istream& is, const auto& wrap) +{ + const auto reload_pool = [wrap](std::istream& is, + Pools pools, + bool ignore_pool_exceptions) { + auto restore = immer::util::istream_snapshot{is}; + const auto original_pools = pools; + auto ar = + json_immer_input_archive{std::move(pools), wrap, is}; + ar.ignore_pool_exceptions = ignore_pool_exceptions; + /** + * 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)); + pools.merge_previous(original_pools); + return pools; + }; + + auto pools = Pools{}; + if constexpr (detail::is_pool_empty()) { + return pools; + } + + auto prev = pools; + while (true) { + // Keep reloading until everything is loaded. + // Reloading of the pool might trigger validation of some containers + // (hash-based, for example) because the elements actually come from + // 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. + pools = reload_pool(is, std::move(pools), false); + break; + } + prev = pools; + } + + return pools; +} + +} // namespace immer::persist::detail diff --git a/immer/extra/persist/detail/transform.hpp b/immer/extra/persist/detail/transform.hpp new file mode 100644 index 00000000..d421c8c9 --- /dev/null +++ b/immer/extra/persist/detail/transform.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include + +namespace immer::persist::detail { + +template +auto get_container_id(const output_pools& pools, + const Container& container) +{ + const auto& old_pool = + pools.template get_output_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 persisted"}; + } + return id; +} + +} // namespace immer::persist::detail diff --git a/immer/extra/persist/json/json_with_pool.hpp b/immer/extra/persist/json/json_with_pool.hpp index 68e12960..cf9e968c 100644 --- a/immer/extra/persist/json/json_with_pool.hpp +++ b/immer/extra/persist/json/json_with_pool.hpp @@ -1,13 +1,10 @@ #pragma once +#include #include #include #include -/** - * to_json_with_pool - */ - namespace immer::persist { /** @@ -63,56 +60,6 @@ std::string to_json_with_pool(const T& value0, const Policy& policy = Policy{}) return os.str(); } -template -auto load_pools(std::istream& is, const auto& wrap) -{ - const auto reload_pool = [wrap](std::istream& is, - Pools pools, - bool ignore_pool_exceptions) { - auto restore = immer::util::istream_snapshot{is}; - const auto original_pools = pools; - auto ar = - json_immer_input_archive{std::move(pools), wrap, is}; - ar.ignore_pool_exceptions = ignore_pool_exceptions; - /** - * 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)); - pools.merge_previous(original_pools); - return pools; - }; - - auto pools = Pools{}; - if constexpr (detail::is_pool_empty()) { - return pools; - } - - auto prev = pools; - while (true) { - // Keep reloading until everything is loaded. - // Reloading of the pool might trigger validation of some containers - // (hash-based, for example) because the elements actually come from - // 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. - pools = reload_pool(is, std::move(pools), false); - break; - } - prev = pools; - } - - return pools; -} - template Policy = default_policy> @@ -147,53 +94,24 @@ T from_json_with_pool(const std::string& input, const Policy& policy = Policy{}) return from_json_with_pool(is, policy); } -template -auto get_container_id(const detail::output_pools& pools, - const Container& container) -{ - const auto& old_pool = - pools.template get_output_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 persisted"}; - } - return id; -} - -/** - * Given an output_pools and a map of transformations, produce a new type of - * load pool with those transformations applied - */ -template -inline auto -transform_output_pool(const detail::output_pools& old_pools, - const ConversionMap& conversion_map) +template Policy = hana_struct_auto_policy> +auto get_auto_pool(const T& value0, const Policy& policy = Policy{}) { - const auto old_load_pools = to_input_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_pools](const auto& immer_container) { - return get_container_id(old_pools, immer_container); - }; - return old_load_pools.transform_recursive(conversion_map, get_id); -} + const auto types = policy.get_pool_types(value0); + auto pools = detail::generate_output_pools(types); + const auto wrap = detail::wrap_known_types(types, detail::wrap_for_saving); + using Pools = std::decay_t; -/** - * Given an old save pools and a new (transformed) load pools, effectively - * convert the given container. - */ -template -auto convert_container(const detail::output_pools& old_save_pools, - detail::input_pools& new_load_pools, - const Container& container) -{ - const auto container_id = get_container_id(old_save_pools, container); - auto& loader = - new_load_pools - .template get_loader_by_old_container>(); - auto result = loader.load(container_id); - return result; + { + auto ar = json_immer_output_archive{pools, wrap}; + ar(CEREAL_NVP(value0)); + ar.finalize(); + pools = std::move(ar).get_output_pools(); + } + return pools; } } // 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 deleted file mode 100644 index df3aaf62..00000000 --- a/immer/extra/persist/json/json_with_pool_auto.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include - -namespace immer::persist { - -template Policy = hana_struct_auto_policy> -auto get_auto_pool(const T& value0, const Policy& policy = Policy{}) -{ - const auto types = policy.get_pool_types(value0); - auto pools = detail::generate_output_pools(types); - const auto wrap = detail::wrap_known_types(types, detail::wrap_for_saving); - using Pools = std::decay_t; - - { - auto ar = json_immer_output_archive{pools, wrap}; - ar(CEREAL_NVP(value0)); - ar.finalize(); - pools = std::move(ar).get_output_pools(); - } - return pools; -} - -} // namespace immer::persist diff --git a/immer/extra/persist/transform.hpp b/immer/extra/persist/transform.hpp new file mode 100644 index 00000000..022cf5de --- /dev/null +++ b/immer/extra/persist/transform.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include + +namespace immer::persist { + +/** + * Given an output_pools and a map of transformations, produce a new type of + * load pool with those transformations applied + */ +template +inline auto +transform_output_pool(const detail::output_pools& old_pools, + const ConversionMap& conversion_map) +{ + const auto old_load_pools = to_input_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_pools](const auto& immer_container) { + return detail::get_container_id(old_pools, immer_container); + }; + return old_load_pools.transform_recursive(conversion_map, get_id); +} + +/** + * Given an old save pools and a new (transformed) load pools, effectively + * convert the given container. + */ +template +auto convert_container(const detail::output_pools& old_save_pools, + detail::input_pools& new_load_pools, + const Container& container) +{ + const auto container_id = + detail::get_container_id(old_save_pools, container); + auto& loader = + new_load_pools + .template get_loader_by_old_container>(); + auto result = loader.load(container_id); + return result; +} + +} // namespace immer::persist diff --git a/test/extra/persist/CMakeLists.txt b/test/extra/persist/CMakeLists.txt index d41ee3a6..6bd31a07 100644 --- a/test/extra/persist/CMakeLists.txt +++ b/test/extra/persist/CMakeLists.txt @@ -22,7 +22,7 @@ add_executable( test_for_docs.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}) diff --git a/test/extra/persist/test_circular_dependency_conversion.cpp b/test/extra/persist/test_circular_dependency_conversion.cpp index cee41a8e..95e57f04 100644 --- a/test/extra/persist/test_circular_dependency_conversion.cpp +++ b/test/extra/persist/test_circular_dependency_conversion.cpp @@ -1,6 +1,7 @@ #include -#include +#include +#include #include "utils.hpp" diff --git a/test/extra/persist/test_conversion.cpp b/test/extra/persist/test_conversion.cpp index 8d1f97f8..c3957144 100644 --- a/test/extra/persist/test_conversion.cpp +++ b/test/extra/persist/test_conversion.cpp @@ -1,8 +1,8 @@ #include -#include - #include +#include +#include #include "utils.hpp" diff --git a/test/extra/persist/test_for_docs.cpp b/test/extra/persist/test_for_docs.cpp index 1db39533..ea44ff86 100644 --- a/test/extra/persist/test_for_docs.cpp +++ b/test/extra/persist/test_for_docs.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include "utils.hpp" #include diff --git a/test/extra/persist/test_special_pool_auto.cpp b/test/extra/persist/test_special_pool_auto.cpp index b0d80cfb..4fc8de84 100644 --- a/test/extra/persist/test_special_pool_auto.cpp +++ b/test/extra/persist/test_special_pool_auto.cpp @@ -4,7 +4,8 @@ #include "utils.hpp" -#include +#include +#include #include #define DEFINE_OPERATIONS(name) \ diff --git a/test/extra/persist/test_table_box_recursive.cpp b/test/extra/persist/test_table_box_recursive.cpp index 38ab9325..58291a09 100644 --- a/test/extra/persist/test_table_box_recursive.cpp +++ b/test/extra/persist/test_table_box_recursive.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include