Skip to content

Commit

Permalink
cereal loading into containers must not append
Browse files Browse the repository at this point in the history
Fix and test the loading and saving behavior for all immer containers
  • Loading branch information
alex-sparus committed Sep 13, 2024
1 parent 3aa1ed3 commit 43f26a0
Show file tree
Hide file tree
Showing 10 changed files with 229 additions and 3 deletions.
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
File renamed without changes.
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
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
1 change: 1 addition & 0 deletions test/extra/persist/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ add_executable(
test_circular_dependency_conversion.cpp
test_table_box_recursive.cpp
test_for_docs.cpp
test_containers_cereal.cpp
${PROJECT_SOURCE_DIR}/immer/extra/persist/xxhash/xxhash_64.cpp)
target_precompile_headers(
persist-tests PRIVATE <immer/extra/persist/cereal/save.hpp>
Expand Down
6 changes: 3 additions & 3 deletions test/extra/persist/test_circular_dependency_conversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

#include "utils.hpp"

#include <test/extra/persist/cereal/immer_box.hpp>
#include <test/extra/persist/cereal/immer_set.hpp>
#include <test/extra/persist/cereal/immer_table.hpp>
#include <immer/extra/cereal/immer_box.hpp>
#include <immer/extra/cereal/immer_set.hpp>
#include <immer/extra/cereal/immer_table.hpp>

#include <cereal/archives/xml.hpp>
#include <nlohmann/json.hpp>
Expand Down
217 changes: 217 additions & 0 deletions test/extra/persist/test_containers_cereal.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
#include <catch2/catch_test_macros.hpp>

#include <immer/extra/cereal/immer_array.hpp>
#include <immer/extra/cereal/immer_box.hpp>
#include <immer/extra/cereal/immer_map.hpp>
#include <immer/extra/cereal/immer_set.hpp>
#include <immer/extra/cereal/immer_table.hpp>
#include <immer/extra/cereal/immer_vector.hpp>
#include <immer/extra/persist/detail/cereal/compact_map.hpp>

#include <cereal/archives/json.hpp>

#include <nlohmann/json.hpp>

namespace {

using json_t = nlohmann::json;

struct with_id
{
int id = 99;
std::string data = "_data_";

auto tie() const { return std::tie(id, data); }

template <class Archive>
void serialize(Archive& ar)
{
ar(CEREAL_NVP(id), CEREAL_NVP(data));
}

friend bool operator==(const with_id& left, const with_id& right)
{
return left.tie() == right.tie();
}

friend std::ostream& operator<<(std::ostream& s, const with_id& value)
{
auto ar = cereal::JSONOutputArchive{s};
ar(value);
return s;
}
};

// A struct with non-empty default constructed containers
struct non_empty_default
{
immer::vector<int> vec = {1, 2, 3};
immer::flex_vector<int> flex_vec = {4, 5, 6};
immer::array<int> arr = {7, 8, 9};
immer::map<int, std::string> map = {
{1, "one"},
{2, "two"},
};
immer::map<int, with_id> with_auto_id = {
{1,
with_id{
.id = 1,
.data = "oner",
}},
{2,
with_id{
.id = 2,
.data = "twoer",
}},
{3,
with_id{
.id = 3,
.data = "threer",
}},
};
immer::map<std::string, int> compact_map = {
{"one", 1},
{"two", 2},
};
immer::box<std::string> box{"default!"};
immer::set<int> set = {6, 7, 8, 9};
immer::table<with_id> table = {
with_id{
.id = 1,
.data = "oner",
},
with_id{
.id = 2,
.data = "twoer",
},
with_id{
.id = 3,
.data = "threer",
},
};

auto tie() const
{
return std::tie(vec,
flex_vec,
arr,
map,
with_auto_id,
compact_map,
box,
set,
table);
}

template <class Archive>
void serialize(Archive& ar)
{
ar(CEREAL_NVP(vec),
CEREAL_NVP(flex_vec),
CEREAL_NVP(arr),
CEREAL_NVP(map),
CEREAL_NVP(with_auto_id),
cereal::make_nvp(
"compact_map",
immer::persist::detail::make_compact_map(compact_map)),
CEREAL_NVP(box),
CEREAL_NVP(set),
CEREAL_NVP(table));
}

friend bool operator==(const non_empty_default& left,
const non_empty_default& right)
{
return left.tie() == right.tie();
}

friend std::ostream& operator<<(std::ostream& s,
const non_empty_default& value)
{
auto ar = cereal::JSONOutputArchive{s};
ar(value);
return s;
}
};

} // namespace

TEST_CASE("Test loading struct with non-empty containers")
{
// Create some non-default data
const auto value = non_empty_default{
.vec = {4, 5},
.flex_vec = {6, 7},
.arr = {1, 2},
.map =
{
{3, "three"},
{4, "four"},
},
.with_auto_id =
{
{5,
with_id{
.id = 5,
.data = "fiver",
}},
{6,
with_id{
.id = 6,
.data = "sixer",
}},
},
.compact_map =
{
{"three", 3},
{"four", 4},
},
.box = "non-default-box",
.set = {1, 3, 5},
.table =
{
with_id{
.id = 5,
.data = "fiver",
},
with_id{
.id = 6,
.data = "sixer",
},
},
};
const auto str = [&] {
auto os = std::ostringstream{};
{
auto ar = cereal::JSONOutputArchive{os};
ar(value);
}
return os.str();
}();

const auto expected_json = json_t::parse(R"(
{
"value0": {
"arr": [1, 2],
"box": {"value0": "non-default-box"},
"compact_map": [["three", 3], ["four", 4]],
"flex_vec": [6, 7],
"map": [{"key": 3, "value": "three"}, {"key": 4, "value": "four"}],
"set": [1, 3, 5],
"table": [{"data": "fiver", "id": 5}, {"data": "sixer", "id": 6}],
"vec": [4, 5],
"with_auto_id": [{"data": "fiver", "id": 5}, {"data": "sixer", "id": 6}]
}
}
)");
REQUIRE(json_t::parse(str) == expected_json);

const auto loaded_value = [&] {
auto is = std::istringstream{str};
auto ar = cereal::JSONInputArchive{is};
auto r = non_empty_default{};
ar(r);
return r;
}();
REQUIRE(value == loaded_value);
}

0 comments on commit 43f26a0

Please sign in to comment.