Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make persist compatible with C++17 #289

Merged
merged 2 commits into from
Sep 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/persist-introduction.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Dependencies
------------

In addition to the `dependencies <introduction.html#dependencies>`_ of
``immer``, this library makes use of **C++20**, `Boost.Hana
``immer``, this library makes use of **C++17**, `Boost.Hana
<https://boostorg.github.io/hana/>`_, `fmt <https://fmt.dev/>`_ and
`cereal <https://uscilab.github.io/cereal/>`_.

Expand Down
2 changes: 2 additions & 0 deletions extra/fuzzer/persist/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ foreach(_file IN LISTS immer_fuzzers)
add_executable(${_target} EXCLUDE_FROM_ALL "${_file}")
set_target_properties(${_target} PROPERTIES OUTPUT_NAME ${_output})
target_compile_options(${_target} PUBLIC ${immer_fuzzing_engine})
target_compile_options(${_target} PRIVATE ${immer_fuzzing_engine}
-Wno-c++20-designator)
target_include_directories(${_target} PRIVATE ../..)
target_link_libraries(${_target} PUBLIC ${immer_fuzzing_engine} immer-dev)
add_dependencies(fuzzers ${_target})
Expand Down
3 changes: 2 additions & 1 deletion extra/fuzzer/persist/flex-vector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
#include <array>

namespace {
void require_eq(const auto& a, const auto& b)
template <class T>
void require_eq(const T& a, const T& b)
{
if (a != b) {
throw std::runtime_error{
Expand Down
2 changes: 1 addition & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@
"-Dimmer_BUILD_TESTS=ON"
"-Dimmer_BUILD_PERSIST_TESTS=ON"
"-Dimmer_BUILD_EXAMPLES=OFF"
"-DCXX_STANDARD=20"
"-DCXX_STANDARD=17"
];
});
};
Expand Down
1 change: 1 addition & 0 deletions immer/extra/cereal/immer_array.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ void CEREAL_LOAD_FUNCTION_NAME(Archive& ar, immer::array<T, MemoryPolicy>& m)
{
size_type size;
ar(make_size_tag(size));
m = {};

for (auto i = size_type{}; i < size; ++i) {
T x;
Expand Down
2 changes: 2 additions & 0 deletions immer/extra/cereal/immer_map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ CEREAL_LOAD_FUNCTION_NAME(Archive& ar, immer::map<K, T, H, E, MP, B>& m)
{
size_type size;
ar(make_size_tag(size));
m = {};

for (auto i = size_type{}; i < size; ++i) {
T x;
Expand Down Expand Up @@ -71,6 +72,7 @@ CEREAL_LOAD_FUNCTION_NAME(Archive& ar, immer::map<K, T, H, E, MP, B>& m)
{
size_type size;
ar(make_size_tag(size));
m = {};

for (auto i = size_type{}; i < size; ++i) {
K k;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ void CEREAL_LOAD_FUNCTION_NAME(Archive& ar, immer::set<T, H, E, MP, B>& m)
{
size_type size;
ar(make_size_tag(size));
m = {};

for (auto i = size_type{}; i < size; ++i) {
T x;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ void CEREAL_LOAD_FUNCTION_NAME(Archive& ar, immer::table<T, KF, H, E, MP, B>& m)
{
size_type size;
ar(make_size_tag(size));
m = {};

for (auto i = size_type{}; i < size; ++i) {
T x;
Expand Down
2 changes: 2 additions & 0 deletions immer/extra/cereal/immer_vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ void CEREAL_LOAD_FUNCTION_NAME(Archive& ar,
{
size_type size;
ar(make_size_tag(size));
m = {};

for (auto i = size_type{}; i < size; ++i) {
T x;
Expand Down Expand Up @@ -46,6 +47,7 @@ void CEREAL_LOAD_FUNCTION_NAME(Archive& ar,
{
size_type size;
ar(make_size_tag(size));
m = {};

for (auto i = size_type{}; i < size; ++i) {
T x;
Expand Down
8 changes: 4 additions & 4 deletions immer/extra/persist/cereal/archives.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ struct blackhole_output_archive
// blackhole_output_archive doesn't care about names
struct empty_name_fn
{
void operator()(const auto& container) const {}
template <class T>
void operator()(const T& container) const
{
}
};

template <class Pools>
Expand Down Expand Up @@ -99,15 +102,13 @@ class output_pools_cereal_archive_wrapper

template <class... Args>
explicit output_pools_cereal_archive_wrapper(Args&&... args)
requires std::is_same_v<WrapFn, boost::hana::id_t>
: cereal::OutputArchive<output_pools_cereal_archive_wrapper>{this}
, previous{std::forward<Args>(args)...}
{
}

template <class... Args>
output_pools_cereal_archive_wrapper(Pools pools_, Args&&... args)
requires std::is_same_v<WrapFn, boost::hana::id_t>
: cereal::OutputArchive<output_pools_cereal_archive_wrapper>{this}
, previous{std::forward<Args>(args)...}
, pools{std::move(pools_)}
Expand Down Expand Up @@ -279,7 +280,6 @@ class input_pools_cereal_archive_wrapper

template <class... Args>
input_pools_cereal_archive_wrapper(Pools pools_, Args&&... args)
requires std::is_same_v<WrapFn, boost::hana::id_t>
: cereal::InputArchive<input_pools_cereal_archive_wrapper>{this}
, previous{std::forward<Args>(args)...}
, pools{std::move(pools_)}
Expand Down
13 changes: 5 additions & 8 deletions immer/extra/persist/cereal/load.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ namespace immer::persist {
* @ingroup persist-api
*/
template <class T,
class Archive = cereal::JSONInputArchive,
Policy<T> Policy = default_policy,
class Archive = cereal::JSONInputArchive,
class Policy = default_policy,
class... Args>
T cereal_load_with_pools(std::istream& is,
const Policy& policy = Policy{},
Expand All @@ -26,10 +26,7 @@ T cereal_load_with_pools(std::istream& is,
decltype(boost::hana::to_set(policy.get_pool_types(std::declval<T>())));
using Pools = decltype(detail::generate_input_pools(TypesSet{}));

auto get_pool_name_fn = [](const auto& value) {
return Policy{}.get_pool_name(value);
};
using PoolNameFn = decltype(get_pool_name_fn);
using PoolNameFn = get_pool_name_fn_t<Policy>;

const auto wrap =
detail::wrap_known_types(TypesSet{}, detail::wrap_for_loading);
Expand All @@ -53,8 +50,8 @@ T cereal_load_with_pools(std::istream& is,
* @ingroup persist-api
*/
template <class T,
class Archive = cereal::JSONInputArchive,
Policy<T> Policy = default_policy>
class Archive = cereal::JSONInputArchive,
class Policy = default_policy>
T cereal_load_with_pools(const std::string& input,
const Policy& policy = Policy{})
{
Expand Down
53 changes: 30 additions & 23 deletions immer/extra/persist/cereal/policy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,6 @@ namespace immer::persist {
* @defgroup persist-policy
*/

/**
* @brief Policy is a type that describes certain aspects of serialization for
* `immer::persist`.
* - How to call into the `cereal` archive to save and load the
* user-provided value. Can be used to serealize the value inline (without the
* `value0` node) by taking a dependency on <a
* href="https://github.com/LowCostCustoms/cereal-inline">cereal-inline</a>, for
* example.
* - Types of `immer` containers that will be serialized using pools. One
* pool contains nodes of only one `immer` container type.
* - Names for each per-type pool.
*
* @ingroup persist-policy
*/
template <class T, class Value>
concept Policy =
requires(Value value, T policy) { policy.get_pool_types(value); };

template <class T>
auto get_pools_names(const T&)
{
Expand Down Expand Up @@ -67,6 +49,20 @@ struct value0_serialize_t
}
};

/**
* @brief Policy is a type that describes certain aspects of serialization for
* `immer::persist`.
* - How to call into the `cereal` archive to save and load the
* user-provided value. Can be used to serealize the value inline (without the
* `value0` node) by taking a dependency on <a
* href="https://github.com/LowCostCustoms/cereal-inline">cereal-inline</a>, for
* example.
* - Types of `immer` containers that will be serialized using pools. One
* pool contains nodes of only one `immer` container type.
* - Names for each per-type pool.
*
* @ingroup persist-policy
*/
template <class T>
struct via_get_pools_names_policy_t : value0_serialize_t
{
Expand Down Expand Up @@ -100,9 +96,10 @@ struct via_get_pools_names_policy_t : value0_serialize_t
*
* @ingroup persist-policy
*/
auto via_get_pools_names_policy(const auto& value)
template <class T>
auto via_get_pools_names_policy(const T& value)
{
return via_get_pools_names_policy_t<std::decay_t<decltype(value)>>{};
return via_get_pools_names_policy_t<std::decay_t<T>>{};
}

/**
Expand Down Expand Up @@ -187,12 +184,22 @@ struct hana_struct_auto_member_name_policy_t : value0_serialize_t
*
* @ingroup persist-policy
*/
auto hana_struct_auto_member_name_policy(const auto& value)
template <class T>
auto hana_struct_auto_member_name_policy(const T& value)
{
return hana_struct_auto_member_name_policy_t<
std::decay_t<decltype(value)>>{};
return hana_struct_auto_member_name_policy_t<std::decay_t<T>>{};
}

using default_policy = via_get_pools_types_policy;

template <class Policy>
struct get_pool_name_fn_t
{
template <class T>
auto operator()(const T& value) const
{
return Policy{}.get_pool_name(value);
}
};

} // namespace immer::persist
21 changes: 10 additions & 11 deletions immer/extra/persist/cereal/save.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace immer::persist {
*/
template <class Archive = cereal::JSONOutputArchive,
class T,
Policy<T> Policy = default_policy,
class Policy = default_policy,
class... Args>
void cereal_save_with_pools(std::ostream& os,
const T& value0,
Expand All @@ -31,14 +31,11 @@ void cereal_save_with_pools(std::ostream& os,
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)>;
auto get_pool_name_fn = [](const auto& value) {
return Policy{}.get_pool_name(value);
};
auto ar = immer::persist::output_pools_cereal_archive_wrapper<
auto ar = immer::persist::output_pools_cereal_archive_wrapper<
Archive,
Pools,
decltype(wrap),
decltype(get_pool_name_fn)>{
get_pool_name_fn_t<Policy>>{
pools, wrap, os, std::forward<Args>(args)...};
policy.save(ar, value0);
// Calling finalize explicitly, as it might throw on saving the pools,
Expand All @@ -54,16 +51,18 @@ void cereal_save_with_pools(std::ostream& os,
* @return std::string The resulting JSON.
* @ingroup persist-api
*/
template <class Archive = cereal::JSONOutputArchive,
class T,
Policy<T> Policy = default_policy,
class... Args>
template <
class Archive = cereal::JSONOutputArchive,
class T,
class Policy = default_policy,
class = decltype(std::declval<Policy>().get_pool_types(std::declval<T>())),
class... Args>
std::string cereal_save_with_pools(const T& value0,
const Policy& policy = Policy{},
Args&&... args)
{
auto os = std::ostringstream{};
cereal_save_with_pools<Archive>(
cereal_save_with_pools<Archive, T, Policy>(
os, value0, policy, std::forward<Args>(args)...);
return os.str();
}
Expand Down
11 changes: 9 additions & 2 deletions immer/extra/persist/detail/alias.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,15 @@ struct type_alias
{
}

friend bool operator==(const type_alias& left,
const type_alias& right) = default;
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)
{
return left.value != right.value;
}

/**
* This works only starting with fmt v10.
Expand Down
12 changes: 9 additions & 3 deletions immer/extra/persist/detail/array/pool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ struct output_pool
return left.arrays == right.arrays;
}

friend bool operator!=(const output_pool& left, const output_pool& right)
{
return left.arrays != right.arrays;
}

template <class Archive>
void save(Archive& ar) const
{
Expand Down Expand Up @@ -78,8 +83,10 @@ struct input_pool
{
immer::vector<immer::array<T, MemoryPolicy>> arrays;

friend bool operator==(const input_pool& left,
const input_pool& right) = default;
friend bool operator==(const input_pool& left, const input_pool& right)
{
return left.arrays == right.arrays;
}

template <class Archive>
void load(Archive& ar)
Expand Down Expand Up @@ -125,7 +132,6 @@ class loader
{
public:
explicit loader(Pool pool)
requires std::is_same_v<TransformF, boost::hana::id_t>
: pool_{std::move(pool)}
{
}
Expand Down
12 changes: 9 additions & 3 deletions immer/extra/persist/detail/box/pool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ struct output_pool
return left.boxes == right.boxes;
}

friend bool operator!=(const output_pool& left, const output_pool& right)
{
return left.boxes != right.boxes;
}

template <class Archive>
void save(Archive& ar) const
{
Expand Down Expand Up @@ -64,8 +69,10 @@ struct input_pool
{
immer::vector<immer::box<T, MemoryPolicy>> boxes;

friend bool operator==(const input_pool& left,
const input_pool& right) = default;
friend bool operator==(const input_pool& left, const input_pool& right)
{
return left.boxes == right.boxes;
}

template <class Archive>
void load(Archive& ar)
Expand Down Expand Up @@ -141,7 +148,6 @@ class loader
{
public:
explicit loader(Pool pool)
requires std::is_same_v<TransformF, boost::hana::id_t>
: pool_{std::move(pool)}
{
}
Expand Down
1 change: 1 addition & 0 deletions immer/extra/persist/detail/cereal/compact_map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ void CEREAL_LOAD_FUNCTION_NAME(Archive& ar,
{
size_type size;
ar(make_size_tag(size));
m.map = {};

for (auto i = size_type{}; i < size; ++i) {
auto pair = immer::persist::detail::compact_pair<K, T>{};
Expand Down
Loading
Loading