-
-
Notifications
You must be signed in to change notification settings - Fork 186
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Start the docs for persist, document the policy concept
- Loading branch information
1 parent
9c36ad5
commit dfca577
Showing
6 changed files
with
226 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
#include <catch2/catch_test_macros.hpp> | ||
|
||
#include <immer/extra/persist/json/json_with_pool_auto.hpp> | ||
|
||
#include "utils.hpp" | ||
#include <nlohmann/json.hpp> | ||
|
||
namespace { | ||
|
||
// include:intro/start-types | ||
// Set the BL constant to 1, so that only 2 elements are stored in leaves. | ||
// This allows to demonstrate structural sharing even in vectors with just a few | ||
// elements. | ||
using vector_one = | ||
immer::vector<int, immer::default_memory_policy, immer::default_bits, 1>; | ||
|
||
struct document | ||
{ | ||
// Make it a boost::hana Struct. | ||
// This allows the persist library to determine what pool types are needed | ||
// and also to name the pools. | ||
BOOST_HANA_DEFINE_STRUCT(document, | ||
(vector_one, ints), | ||
(vector_one, ints2) // | ||
); | ||
|
||
friend bool operator==(const document&, const document&) = default; | ||
|
||
// Make the struct serializable with cereal as usual, nothing special | ||
// related to immer-persist. | ||
template <class Archive> | ||
void serialize(Archive& ar) | ||
{ | ||
ar(CEREAL_NVP(ints), CEREAL_NVP(ints2)); | ||
} | ||
}; | ||
|
||
using json_t = nlohmann::json; | ||
// include:intro/end-types | ||
|
||
} // namespace | ||
|
||
TEST_CASE("Docs save with immer-persist", "[docs]") | ||
{ | ||
// include:intro/start-no-persist | ||
const auto v1 = vector_one{1, 2, 3}; | ||
const auto v2 = v1.push_back(4).push_back(5).push_back(6); | ||
// Vector v2 uses structural sharing to reuse the nodes that store the | ||
// values of v1. | ||
const auto value = document{v1, v2}; | ||
|
||
SECTION("Without immer-persist") | ||
{ | ||
// Vectors are serialized directly as lists. Notably, as independent | ||
// lists. | ||
const auto expected_json = json_t::parse(R"( | ||
{"value0": {"ints": [1, 2, 3], "ints2": [1, 2, 3, 4, 5, 6]}} | ||
)"); | ||
const auto str = [&] { | ||
auto os = std::ostringstream{}; | ||
{ | ||
auto ar = cereal::JSONOutputArchive{os}; | ||
ar(value); | ||
} | ||
return os.str(); | ||
}(); | ||
REQUIRE(json_t::parse(str) == expected_json); | ||
|
||
const auto loaded_value = [&] { | ||
auto is = std::istringstream{str}; | ||
auto ar = cereal::JSONInputArchive{is}; | ||
auto r = document{}; | ||
ar(r); | ||
return r; | ||
}(); | ||
|
||
REQUIRE(value == loaded_value); | ||
} | ||
// include:intro/end-no-persist | ||
|
||
SECTION("With immer-persist") | ||
{ | ||
// include:intro/start-with-persist | ||
// Immer-persist uses policies to control certain aspects of | ||
// serialization: | ||
// - types of pools that should be used | ||
// - names of those pools | ||
const auto policy = | ||
immer::persist::hana_struct_auto_member_name_policy(document{}); | ||
const auto str = immer::persist::to_json_with_pool(value, policy); | ||
|
||
// The resulting JSON looks much more complicated for this little | ||
// example but the more structural sharing is used inside the serialized | ||
// value, the bigger the benefit from using immer-persist. | ||
// | ||
// Notable points for the structure of this JSON: | ||
// - vectors "ints" and "ints2" are serialized as integers, referring to | ||
// the vectors inside the pools | ||
// - there is a "pools" object serialized next to the value itself | ||
// - the "pools" object contains pools per type of the container, in | ||
// this example only one, for `immer::vector<int>` | ||
// | ||
// The vector pool contains: | ||
// - B and BL constants for the corresponding `immer::vector` type | ||
// - "inners" and "leaves" maps that store the actual nodes of the | ||
// vector | ||
// - "vectors" list that allows to store the root and tail of the vector | ||
// structure and to refer to the vector with just one integer: | ||
// `{"ints": 0, "ints2": 1}`: 0 and 1 refer to the indices of this | ||
// array. | ||
const auto expected_json = json_t::parse(R"( | ||
{ | ||
"value0": {"ints": 0, "ints2": 1}, | ||
"pools": { | ||
"ints": { | ||
"B": 5, | ||
"BL": 1, | ||
"inners": [ | ||
{"key": 0, "value": {"children": [2], "relaxed": false}}, | ||
{"key": 3, "value": {"children": [2, 5], "relaxed": false}} | ||
], | ||
"leaves": [ | ||
{"key": 1, "value": [3]}, | ||
{"key": 2, "value": [1, 2]}, | ||
{"key": 4, "value": [5, 6]}, | ||
{"key": 5, "value": [3, 4]} | ||
], | ||
"vectors": [{"root": 0, "tail": 1}, {"root": 3, "tail": 4}] | ||
} | ||
} | ||
} | ||
)"); | ||
REQUIRE(json_t::parse(str) == expected_json); | ||
|
||
const auto loaded_value = | ||
immer::persist::from_json_with_pool<document>(str, policy); | ||
REQUIRE(value == loaded_value); | ||
// include:intro/end-with-persist | ||
} | ||
} |