Skip to content

Commit

Permalink
Test vectors archive conversion
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-sparus committed Feb 20, 2024
1 parent 4cbd826 commit 7908190
Show file tree
Hide file tree
Showing 3 changed files with 235 additions and 0 deletions.
22 changes: 22 additions & 0 deletions immer/experimental/immer-archive/common/archive.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <immer/experimental/immer-archive/alias.hpp>

#include <immer/array.hpp>
#include <immer/map.hpp>

#include <cereal/types/utility.hpp>

Expand Down Expand Up @@ -74,4 +75,25 @@ void load(Archive& ar, values_load<T>& m)
}
}

template <class U, class T, class F>
values_load<U> transform(const values_load<T>& values, F&& func)
{
auto data = std::vector<U>{};
for (const auto& item : values.data) {
data.push_back(func(item));
}
return values_load<U>{immer::array<U>{data.begin(), data.end()}};
}

template <class U, class T, class F>
immer::map<node_id, values_load<U>>
transform(const immer::map<node_id, values_load<T>>& map, F&& func)
{
auto result = immer::map<node_id, values_load<U>>{};
for (const auto& [key, value] : map) {
result = std::move(result).set(key, transform<U>(value, func));
}
return result;
}

} // namespace immer_archive
14 changes: 14 additions & 0 deletions immer/experimental/immer-archive/rbts/archive.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,20 @@ archive_load<T> fix_leaf_nodes(archive_save<T, MemoryPolicy, B, BL> ar)
};
}

/**
* Given a transformation function from T to U, transform an archive<T> into
* archive<U>. This allows to preserve structural sharing while loading.
*/
template <class U, class T, class F>
archive_load<U> transform_archive(const archive_load<T>& ar, F&& func)
{
return archive_load<U>{
.leaves = transform<U>(ar.leaves, func),
.inners = ar.inners,
.vectors = ar.vectors,
};
}

} // namespace immer_archive::rbts

namespace std {
Expand Down
199 changes: 199 additions & 0 deletions test/experimental/immer-archive/test_vectors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1543,3 +1543,202 @@ TEST_CASE("Can't load saved flex vector with relaxed nodes as strict")
immer_archive::rbts::relaxed_node_not_allowed_exception);
}
}

namespace {
struct old_type
{
int data;

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

struct new_type
{
int data;
std::string data2;

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

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

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

TEST_CASE("Test archive conversion")
{
const auto vec1 = test::vector_one<old_type>{
old_type{123},
old_type{234},
};
const auto vec2 = vec1.push_back(old_type{345});

auto ar = immer_archive::rbts::make_save_archive_for(vec1);
auto vec1_id = immer_archive::container_id{};
std::tie(ar, vec1_id) = save_to_archive(vec1, ar);
auto vec2_id = immer_archive::container_id{};
std::tie(ar, vec2_id) = save_to_archive(vec2, ar);

// Confirm that vec1 and vec2 have structural sharing in the beginning.
const auto expected_ar = json_t::parse(R"(
{
"value0": {
"leaves": [
{
"key": 1,
"value": [
{
"data": 123
},
{
"data": 234
}
]
},
{
"key": 3,
"value": [
{
"data": 345
}
]
}
],
"inners": [
{
"key": 0,
"value": {
"children": [],
"relaxed": false
}
},
{
"key": 2,
"value": {
"children": [
1
],
"relaxed": false
}
}
],
"vectors": [
{
"root": 0,
"tail": 1
},
{
"root": 2,
"tail": 3
}
]
}
}
)");

REQUIRE(json_t::parse(to_json(ar)) == expected_ar);

const auto f = [](const old_type& val) {
return new_type{
.data = val.data,
.data2 = fmt::format("_{}_", val.data),
};
};
const auto transform_vec = [&](const auto& vec) {
auto result = test::vector_one<new_type>{};
for (const auto& item : vec) {
result = std::move(result).push_back(f(item));
}
return result;
};

const auto load_archive = fix_leaf_nodes(ar);
const auto load_archive_new_type =
transform_archive<new_type>(load_archive, f);
auto loader =
make_loader_for(test::vector_one<new_type>{}, load_archive_new_type);

const auto loaded_1 = loader.load(vec1_id);
const auto loaded_2 = loader.load(vec2_id);
REQUIRE(loaded_1 == transform_vec(vec1));
REQUIRE(loaded_2 == transform_vec(vec2));

SECTION("Loaded vectors still share the structure")
{
auto ar = immer_archive::rbts::make_save_archive_for(loaded_1);
auto id = immer_archive::container_id{};
std::tie(ar, id) = save_to_archive(loaded_1, ar);
std::tie(ar, id) = save_to_archive(loaded_2, ar);

const auto expected_ar = json_t::parse(R"(
{
"value0": {
"inners": [
{
"key": 0,
"value": {
"children": [],
"relaxed": false
}
},
{
"key": 2,
"value": {
"children": [
1
],
"relaxed": false
}
}
],
"leaves": [
{
"key": 1,
"value": [
{
"data": 123,
"data2": "_123_"
},
{
"data": 234,
"data2": "_234_"
}
]
},
{
"key": 3,
"value": [
{
"data": 345,
"data2": "_345_"
}
]
}
],
"vectors": [
{
"root": 0,
"tail": 1
},
{
"root": 2,
"tail": 3
}
]
}
}
)");
REQUIRE(json_t::parse(to_json(ar)) == expected_ar);
}
}

0 comments on commit 7908190

Please sign in to comment.