Skip to content

Commit

Permalink
Separate details from public API
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-sparus committed Aug 8, 2024
1 parent 685a914 commit a3a5c72
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 133 deletions.
58 changes: 58 additions & 0 deletions immer/extra/persist/detail/json/input_archive_util.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#pragma once

#include <immer/extra/io.hpp>
#include <immer/extra/persist/json/json_immer.hpp>

namespace immer::persist::detail {

template <class Pools, class Archive, class PoolNameFn>
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<Archive,
Pools,
decltype(wrap),
PoolNameFn>{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<Pools>()) {
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
21 changes: 21 additions & 0 deletions immer/extra/persist/detail/transform.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include <immer/extra/persist/detail/json/pools.hpp>

namespace immer::persist::detail {

template <class Storage, class Container>
auto get_container_id(const output_pools<Storage>& pools,
const Container& container)
{
const auto& old_pool =
pools.template get_output_pool<std::decay_t<Container>>();
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
116 changes: 17 additions & 99 deletions immer/extra/persist/json/json_with_pool.hpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
#pragma once

#include <immer/extra/persist/detail/json/input_archive_util.hpp>
#include <immer/extra/persist/detail/json/pools.hpp>
#include <immer/extra/persist/detail/json/wrap.hpp>
#include <immer/extra/persist/json/policy.hpp>

/**
* to_json_with_pool
*/

namespace immer::persist {

/**
Expand Down Expand Up @@ -63,56 +60,6 @@ std::string to_json_with_pool(const T& value0, const Policy& policy = Policy{})
return os.str();
}

template <class Pools, class Archive, class PoolNameFn>
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<Archive,
Pools,
decltype(wrap),
PoolNameFn>{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<Pools>()) {
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 <class T,
class Archive = cereal::JSONInputArchive,
Policy<T> Policy = default_policy>
Expand Down Expand Up @@ -147,53 +94,24 @@ T from_json_with_pool(const std::string& input, const Policy& policy = Policy{})
return from_json_with_pool<T, Archive>(is, policy);
}

template <class Storage, class Container>
auto get_container_id(const detail::output_pools<Storage>& pools,
const Container& container)
{
const auto& old_pool =
pools.template get_output_pool<std::decay_t<Container>>();
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 <class Storage, class ConversionMap>
inline auto
transform_output_pool(const detail::output_pools<Storage>& old_pools,
const ConversionMap& conversion_map)
template <typename T, Policy<T> 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<decltype(pools)>;

/**
* Given an old save pools and a new (transformed) load pools, effectively
* convert the given container.
*/
template <class SaveStorage, class LoadStorage, class Container>
auto convert_container(const detail::output_pools<SaveStorage>& old_save_pools,
detail::input_pools<LoadStorage>& 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<std::decay_t<Container>>();
auto result = loader.load(container_id);
return result;
{
auto ar = json_immer_output_archive<detail::blackhole_output_archive,
Pools,
decltype(wrap),
detail::empty_name_fn>{pools, wrap};
ar(CEREAL_NVP(value0));
ar.finalize();
pools = std::move(ar).get_output_pools();
}
return pools;
}

} // namespace immer::persist
27 changes: 0 additions & 27 deletions immer/extra/persist/json/json_with_pool_auto.hpp

This file was deleted.

43 changes: 43 additions & 0 deletions immer/extra/persist/transform.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#pragma once

#include <immer/extra/persist/detail/transform.hpp>

namespace immer::persist {

/**
* Given an output_pools and a map of transformations, produce a new type of
* load pool with those transformations applied
*/
template <class Storage, class ConversionMap>
inline auto
transform_output_pool(const detail::output_pools<Storage>& 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 <class SaveStorage, class LoadStorage, class Container>
auto convert_container(const detail::output_pools<SaveStorage>& old_save_pools,
detail::input_pools<LoadStorage>& 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<std::decay_t<Container>>();
auto result = loader.load(container_id);
return result;
}

} // namespace immer::persist
2 changes: 1 addition & 1 deletion test/extra/persist/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
<immer/extra/persist/json/json_with_pool_auto.hpp>)
<immer/extra/persist/json/json_with_pool.hpp>)
add_dependencies(tests persist-tests)
add_test("test/persist-tests" persist-tests)
target_include_directories(persist-tests PRIVATE ${CMAKE_SOURCE_DIR})
Expand Down
3 changes: 2 additions & 1 deletion test/extra/persist/test_circular_dependency_conversion.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <catch2/catch_test_macros.hpp>

#include <immer/extra/persist/json/json_with_pool_auto.hpp>
#include <immer/extra/persist/json/json_with_pool.hpp>
#include <immer/extra/persist/transform.hpp>

#include "utils.hpp"

Expand Down
4 changes: 2 additions & 2 deletions test/extra/persist/test_conversion.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#include <catch2/catch_test_macros.hpp>

#include <immer/extra/persist/json/json_with_pool_auto.hpp>

#include <immer/extra/persist/detail/type_traverse.hpp>
#include <immer/extra/persist/json/json_with_pool.hpp>
#include <immer/extra/persist/transform.hpp>

#include "utils.hpp"

Expand Down
2 changes: 1 addition & 1 deletion test/extra/persist/test_for_docs.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include <catch2/catch_test_macros.hpp>

#include <immer/extra/persist/json/json_with_pool_auto.hpp>
#include <immer/extra/persist/json/json_with_pool.hpp>

#include "utils.hpp"
#include <nlohmann/json.hpp>
Expand Down
3 changes: 2 additions & 1 deletion test/extra/persist/test_special_pool_auto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

#include "utils.hpp"

#include <immer/extra/persist/json/json_with_pool_auto.hpp>
#include <immer/extra/persist/json/json_with_pool.hpp>
#include <immer/extra/persist/transform.hpp>
#include <nlohmann/json.hpp>

#define DEFINE_OPERATIONS(name) \
Expand Down
2 changes: 1 addition & 1 deletion test/extra/persist/test_table_box_recursive.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include <catch2/catch_test_macros.hpp>

#include <immer/extra/persist/json/json_with_pool_auto.hpp>
#include <immer/extra/persist/json/json_with_pool.hpp>

#include <test/extra/persist/utils.hpp>

Expand Down

0 comments on commit a3a5c72

Please sign in to comment.