Skip to content

Commit

Permalink
Policy controls how the final value is saved into the archive
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-sparus committed Jun 6, 2024
1 parent 44ffba1 commit 36d9aaf
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 74 deletions.
21 changes: 0 additions & 21 deletions immer/extra/persist/json/json_immer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,27 +56,6 @@ struct empty_name_fn
auto operator()(const auto& container) const { return ""; }
};

template <class T>
class error_duplicate_pool_name_found;

inline auto are_type_names_unique(auto type_names)
{
namespace hana = boost::hana;
auto names_set =
hana::fold_left(type_names, hana::make_set(), [](auto set, auto pair) {
return hana::if_(
hana::contains(set, hana::second(pair)),
[](auto pair) {
return error_duplicate_pool_name_found<
decltype(hana::second(pair))>{};
},
[&set](auto pair) {
return hana::insert(set, hana::second(pair));
})(pair);
});
return hana::length(type_names) == hana::length(names_set);
}

template <class Pools>
constexpr bool is_pool_empty()
{
Expand Down
5 changes: 2 additions & 3 deletions immer/extra/persist/json/json_with_pool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ auto to_json_with_pool(const T& value0, const Policy& policy = Policy{})
decltype(policy.get_output_wrap_fn()),
decltype(policy.get_pool_name_fn(value0))>{
pools, policy.get_output_wrap_fn(), os};
ar(CEREAL_NVP(value0));
policy.save(ar, value0);
}
return os.str();
}
Expand Down Expand Up @@ -100,7 +100,7 @@ T from_json_with_pool(std::istream& is, const Policy& policy = Policy{})
json_immer_input_archive<Archive, Pools, decltype(wrap), PoolNameFn>{
std::move(pools), wrap, is};
auto value0 = T{};
ar(CEREAL_NVP(value0));
policy.load(ar, value0);
return value0;
}

Expand Down Expand Up @@ -159,7 +159,6 @@ auto convert_container(const detail::output_pools<SaveStorage>& old_save_pools,
new_load_pools
.template get_loader_by_old_container<std::decay_t<Container>>();
auto result = loader.load(container_id);
// return std::make_pair(std::move(result), std::move(new_load_pools));
return result;
}

Expand Down
2 changes: 0 additions & 2 deletions immer/extra/persist/json/json_with_pool_auto.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ auto get_auto_pool(const T& value0, const Policy& policy = Policy{})
Pools,
decltype(wrap),
detail::empty_name_fn>{pools, wrap};
// value0 because that's now cereal saves the unnamed object by default,
// maybe change later.
ar(CEREAL_NVP(value0));
ar.finalize();
pools = std::move(ar).get_output_pools();
Expand Down
24 changes: 24 additions & 0 deletions immer/extra/persist/json/names.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,33 @@ struct get_demangled_name_fn
}
};

template <class T>
class error_duplicate_pool_name_found;

inline auto are_type_names_unique(auto type_names)
{
namespace hana = boost::hana;
auto names_set =
hana::fold_left(type_names, hana::make_set(), [](auto set, auto pair) {
return hana::if_(
hana::contains(set, hana::second(pair)),
[](auto pair) {
return error_duplicate_pool_name_found<
decltype(hana::second(pair))>{};
},
[&set](auto pair) {
return hana::insert(set, hana::second(pair));
})(pair);
});
return hana::length(type_names) == hana::length(names_set);
}

template <class Map>
struct name_from_map_fn
{
static_assert(decltype(are_type_names_unique(Map{}))::value,
"Pool names in the map must be unique");

auto operator()(const auto& container) const
{
return Map{}[boost::hana::typeid_(container)].c_str();
Expand Down
96 changes: 58 additions & 38 deletions immer/extra/persist/json/policy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,72 +30,106 @@ auto get_pools_types(const T&)
return boost::hana::make_set();
}

struct via_get_pools_names_policy
struct value0_serialize_t
{
template <class T>
auto get_pool_types(const T& value) const
template <class Archive, class T>
void save(Archive& ar, const T& value0) const
{
return boost::hana::keys(get_pools_names(value));
ar(CEREAL_NVP(value0));
}

template <class Archive, class T>
void load(Archive& ar, T& value0) const
{
ar(CEREAL_NVP(value0));
}
};

struct no_wrap_t
{
auto get_output_wrap_fn() const { return boost::hana::id; }
auto get_input_wrap_fn() const { return boost::hana::id; }
};

template <class T>
auto get_pool_name_fn(const T& value) const
struct default_wrap_t
{
auto get_output_wrap_fn() const
{
using Map = decltype(get_pools_names(value));
return name_from_map_fn<Map>{};
static_assert(
std::is_same_v<decltype(wrap_for_saving(
std::declval<const std::string&>())),
const std::string&>,
"wrap must return a reference when it's not wrapping the type");
static_assert(
std::is_same_v<decltype(wrap_for_saving(immer::vector<int>{})),
persistable<immer::vector<int>>>,
"and a value when it's wrapping");

return wrap_for_saving;
}
auto get_input_wrap_fn() const { return wrap_for_loading; }
};

struct via_get_pools_types_policy
struct via_get_pools_names_policy
: value0_serialize_t
, no_wrap_t
{
template <class T>
auto get_pool_types(const T& value) const
{
return get_pools_types(value);
return boost::hana::keys(get_pools_names(value));
}

auto get_output_wrap_fn() const { return boost::hana::id; }
auto get_input_wrap_fn() const { return boost::hana::id; }
template <class T>
auto get_pool_name_fn(const T& value) const
{
using Map = decltype(get_pools_names(value));
return name_from_map_fn<Map>{};
}
};

struct demangled_names_t
{
template <class T>
auto get_pool_name_fn(const T& value) const
{
return get_demangled_name_fn{};
}
};

struct hana_struct_auto_policy
struct via_get_pools_types_policy
: demangled_names_t
, value0_serialize_t
, no_wrap_t
{
template <class T>
auto get_pool_types(const T& value) const
{
return get_pools_for_type(boost::hana::typeid_(value));
return get_pools_types(value);
}
};

auto get_output_wrap_fn() const { return wrap_for_saving; }
auto get_input_wrap_fn() const { return wrap_for_loading; }

struct hana_struct_auto_policy
: demangled_names_t
, default_wrap_t
{
template <class T>
auto get_pool_name_fn(const T&) const
auto get_pool_types(const T& value) const
{
return get_demangled_name_fn{};
return get_pools_for_type(boost::hana::typeid_(value));
}
};

struct hana_struct_auto_member_name_policy
: value0_serialize_t
, default_wrap_t
{
template <class T>
auto get_pool_types(const T& value) const
{
return get_pools_for_type(boost::hana::typeid_(value));
}

auto get_output_wrap_fn() const { return wrap_for_saving; }
auto get_input_wrap_fn() const { return wrap_for_loading; }

template <class T>
auto get_pool_name_fn(const T& value) const
{
Expand All @@ -107,6 +141,8 @@ struct hana_struct_auto_member_name_policy

template <class Map>
struct via_map_policy
: value0_serialize_t
, default_wrap_t
{
static_assert(boost::hana::is_a<boost::hana::map_tag, Map>,
"via_map_policy accepts a map of types to pool names");
Expand All @@ -117,22 +153,6 @@ struct via_map_policy
return boost::hana::keys(Map{});
}

auto get_output_wrap_fn() const
{
static_assert(
std::is_same_v<decltype(wrap_for_saving(
std::declval<const std::string&>())),
const std::string&>,
"wrap must return a reference when it's not wrapping the type");
static_assert(
std::is_same_v<decltype(wrap_for_saving(immer::vector<int>{})),
persistable<immer::vector<int>>>,
"and a value when it's wrapping");

return wrap_for_saving;
}
auto get_input_wrap_fn() const { return wrap_for_loading; }

template <class T>
auto get_pool_name_fn(const T&) const
{
Expand Down
17 changes: 7 additions & 10 deletions test/extra/persist/test_special_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -714,19 +714,16 @@ TEST_CASE("Test saving a map that contains the same map")

TEST_CASE("Test non-unique names in the map")
{
{
const auto names = hana::make_map(
hana::make_pair(hana::type_c<immer::box<int>>,
BOOST_HANA_STRING("box_1")),
hana::make_pair(hana::type_c<immer::box<std::string>>,
BOOST_HANA_STRING("box_2"))
const auto names =
hana::make_map(hana::make_pair(hana::type_c<immer::box<int>>,
BOOST_HANA_STRING("box_1")),
hana::make_pair(hana::type_c<immer::box<std::string>>,
BOOST_HANA_STRING("box_2"))

);

using IsUnique =
decltype(immer::persist::detail::are_type_names_unique(names));
static_assert(IsUnique::value, "Names are unique");
}
using IsUnique = decltype(immer::persist::are_type_names_unique(names));
static_assert(IsUnique::value, "Names are unique");
}

namespace {
Expand Down

0 comments on commit 36d9aaf

Please sign in to comment.