diff --git a/immer/extra/persist/alias.hpp b/immer/extra/persist/alias.hpp index 68a18e76..165ab638 100644 --- a/immer/extra/persist/alias.hpp +++ b/immer/extra/persist/alias.hpp @@ -18,10 +18,8 @@ struct type_alias { } - friend bool operator==(const type_alias& left, const type_alias& right) - { - return left.value == right.value; - } + friend bool operator==(const type_alias& left, + const type_alias& right) = default; /** * This works only starting with fmt v10. diff --git a/immer/extra/persist/box/pool.hpp b/immer/extra/persist/box/pool.hpp index a974903d..736fa33a 100644 --- a/immer/extra/persist/box/pool.hpp +++ b/immer/extra/persist/box/pool.hpp @@ -64,10 +64,8 @@ struct input_pool { immer::vector> boxes; - friend bool operator==(const input_pool& left, const input_pool& right) - { - return left.boxes == right.boxes; - } + friend bool operator==(const input_pool& left, + const input_pool& right) = default; template void load(Archive& ar) diff --git a/immer/extra/persist/champ/pool.hpp b/immer/extra/persist/champ/pool.hpp index 6f881000..4105fd7e 100644 --- a/immer/extra/persist/champ/pool.hpp +++ b/immer/extra/persist/champ/pool.hpp @@ -165,10 +165,7 @@ struct container_input_pool nodes_load nodes; friend bool operator==(const container_input_pool& left, - const container_input_pool& right) - { - return left.nodes == right.nodes; - } + const container_input_pool& right) = default; template void load(Archive& ar) diff --git a/immer/extra/persist/common/pool.hpp b/immer/extra/persist/common/pool.hpp index 4355995a..d05c4554 100644 --- a/immer/extra/persist/common/pool.hpp +++ b/immer/extra/persist/common/pool.hpp @@ -42,10 +42,8 @@ struct values_load { } - friend bool operator==(const values_load& left, const values_load& right) - { - return left.data == right.data; - } + friend bool operator==(const values_load& left, + const values_load& right) = default; }; template diff --git a/immer/extra/persist/json/json_immer.hpp b/immer/extra/persist/json/json_immer.hpp index 5e010919..e535a600 100644 --- a/immer/extra/persist/json/json_immer.hpp +++ b/immer/extra/persist/json/json_immer.hpp @@ -263,8 +263,16 @@ class json_immer_input_archive { } - Pools& get_input_pools() { return pools; } - const Pools& get_input_pools() const { return pools; } + template + auto& get_loader() + { + auto& loader = loaders[boost::hana::type_c]; + if (!loader) { + const auto& type_pool = pools.template get_pool(); + loader.emplace(type_pool.pool, type_pool.transform); + } + return *loader; + } template friend void prologue(json_immer_input_archive& ar, T&& v) @@ -322,10 +330,15 @@ class json_immer_input_archive CEREAL_LOAD_FUNCTION_NAME(ar.previous, st); } + bool ignore_pool_exceptions = false; + private: WrapF wrap; Previous previous; Pools pools; + + using Loaders = decltype(Pools::generate_loaders()); + Loaders loaders; }; } // namespace immer::persist diff --git a/immer/extra/persist/json/json_with_pool.hpp b/immer/extra/persist/json/json_with_pool.hpp index ea9fb401..2ac72029 100644 --- a/immer/extra/persist/json/json_with_pool.hpp +++ b/immer/extra/persist/json/json_with_pool.hpp @@ -113,20 +113,53 @@ struct output_pools } }; +template +struct no_loader +{}; + +template +struct with_loader +{ + std::optional loader; + + auto& get_loader_from_per_type_pool() + { + if (!loader) { + auto& self = static_cast(*this); + loader.emplace(self.pool, self.transform); + } + return *loader; + } +}; + +/** + * A pool for one container type. + * Normally, the pool does not contain a loader, which is located inside the + * json_immer_input_archive. + * + * But in case of transformations, there is no json_immer_input_archive involved + * and it becomes convenient to have the corresponding loader stored here, too, + * via with_loader. + */ template ::input_pool_t, class TransformF = boost::hana::id_t, - class OldContainerType = boost::hana::id_t> + class OldContainerType = boost::hana::id_t, + template class LoaderMixin = no_loader> struct input_pool + : LoaderMixin, + typename container_traits< + Container>::template loader_t> { using container_t = Container; using old_container_t = OldContainerType; Pool pool = {}; TransformF transform; - std::optional::template loader_t> - loader; input_pool() = default; @@ -142,27 +175,6 @@ struct input_pool { } - input_pool(const input_pool& other) - : pool{other.pool} - , transform{other.transform} - { - } - - input_pool& operator=(const input_pool& other) - { - pool = other.pool; - transform = other.transform; - return *this; - } - - auto& get_loader() - { - if (!loader) { - loader.emplace(pool, transform); - } - return *loader; - } - template auto with_transform(Func&& func) const { @@ -174,8 +186,8 @@ struct input_pool func))>; using TransF = std::function; // the transform function must be filled in later - return input_pool{pool, - TransF{}}; + return input_pool{ + pool, TransF{}}; } friend bool operator==(const input_pool& left, const input_pool& right) @@ -187,6 +199,12 @@ struct input_pool { pool.merge_previous(original.pool); } + + static auto generate_loader() + { + return std::optional::template loader_t>{}; + } }; /** @@ -230,20 +248,18 @@ class input_pools { } - bool ignore_pool_exceptions = false; - auto& storage() { return storage_(); } const auto& storage() const { return storage_(); } template - auto& get_loader() + const auto& get_pool() { using Contains = decltype(hana::contains(storage(), hana::type_c)); if constexpr (!Contains::value) { auto err = error_missing_pool_for_type{}; } - return storage()[hana::type_c].get_loader(); + return storage()[hana::type_c]; } template @@ -261,7 +277,7 @@ class input_pools if constexpr (!IsJust::value) { auto err = error_missing_pool_for_type{}; } - return storage()[Key{}.value()].get_loader(); + return storage()[Key{}.value()].get_loader_from_per_type_pool(); } template @@ -353,7 +369,8 @@ class input_pools auto err = error_missing_pool_for_type< typename decltype(new_type)::type>{}; } - auto& loader = get_data()[new_type].get_loader(); + auto& loader = + get_data()[new_type].get_loader_from_per_type_pool(); return loader.load(id); }; }; @@ -395,6 +412,20 @@ class input_pools s[key].merge_previous(original_s[key]); }); } + + static auto generate_loaders() + { + using Storage = std::decay_t()())>; + using Types = decltype(hana::keys(std::declval())); + auto storage = + hana::fold_left(Types{}, hana::make_map(), [](auto map, auto type) { + using TypePool = + std::decay_t()[type])>; + return hana::insert( + map, hana::make_pair(type, TypePool::generate_loader())); + }); + return storage; + } }; inline auto generate_output_pools(auto type_names) @@ -468,11 +499,11 @@ 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; - pools.ignore_pool_exceptions = 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 diff --git a/immer/extra/persist/json/persistable.hpp b/immer/extra/persist/json/persistable.hpp index 8c296106..4089365b 100644 --- a/immer/extra/persist/json/persistable.hpp +++ b/immer/extra/persist/json/persistable.hpp @@ -50,24 +50,8 @@ struct persistable { } - persistable(const persistable& other) - : container{other.container} - { - } - - persistable& operator=(const persistable&) = default; - - persistable(persistable&& other) - : container{std::move(other.container)} - { - } - - persistable& operator=(persistable&&) = default; - - friend bool operator==(const persistable& left, const persistable& right) - { - return left.container == right.container; - } + friend bool operator==(const persistable& left, + const persistable& right) = default; // template , bool> = true> // friend auto begin(const persistable& value) @@ -131,7 +115,6 @@ void load_minimal( { auto& loader = const_cast&>(ar) - .get_input_pools() .template get_loader(); // Have to be specific because for vectors container_id is different from @@ -142,7 +125,7 @@ void load_minimal( try { value.container = loader.load(container_id_{id}); } catch (const pool_exception& ex) { - if (!ar.get_input_pools().ignore_pool_exceptions) { + if (!ar.ignore_pool_exceptions) { throw ::cereal::Exception{fmt::format( "Failed to load a container ID {} from the pool of {}: {}", id,