diff --git a/CMakeLists.txt b/CMakeLists.txt index 796fa433eb..6f4c0ec722 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -150,6 +150,7 @@ use_boost( filesystem program_options regex + serialization system thread) diff --git a/SConstruct b/SConstruct index 0a84276365..4dfabdd3c1 100644 --- a/SConstruct +++ b/SConstruct @@ -613,7 +613,8 @@ def config_env(toolchain, variant, env): 'boost_program_options', 'boost_regex', 'boost_system', - 'boost_thread' + 'boost_thread', + 'boost_serialization' ] env.Append(LIBS=['dl']) diff --git a/src/ripple/basics/RangeSet.h b/src/ripple/basics/RangeSet.h index 16b29bd182..71bb879952 100644 --- a/src/ripple/basics/RangeSet.h +++ b/src/ripple/basics/RangeSet.h @@ -24,6 +24,7 @@ #include #include #include +#include namespace ripple { @@ -128,5 +129,72 @@ prevMissing(RangeSet const & rs, T t, T minVal = 0) return boost::none; return boost::icl::last(tgt); } - } // namespace ripple +} // namespace ripple + + +// The boost serialization documents recommended putting free-function helpers +// in the boost serialization namespace + +namespace boost { +namespace serialization { +template +void +save(Archive& ar, + ripple::ClosedInterval const& ci, + const unsigned int version) +{ + ar << ci.lower() << ci.upper(); +} + +template +void +load(Archive& ar, ripple::ClosedInterval& ci, const unsigned int version) +{ + T low, up; + ar >> low >> up; + ci = ripple::ClosedInterval{low, up}; +} + +template +void +serialize(Archive& ar, + ripple::ClosedInterval& ci, + const unsigned int version) +{ + split_free(ar, ci, version); +} + +template +void +save(Archive& ar, ripple::RangeSet const& rs, const unsigned int version) +{ + ar << rs.iterative_size(); + for (auto const& r : rs) + ar << r; +} + +template +void +load(Archive& ar, ripple::RangeSet& rs, const unsigned int version) +{ + rs.clear(); + std::size_t intervals; + ar >> intervals; + for (std::size_t i = 0; i < intervals; ++i) + { + ripple::ClosedInterval ci; + ar >> ci; + rs.insert(ci); + } +} + +template +void +serialize(Archive& ar, ripple::RangeSet& rs, const unsigned int version) +{ + split_free(ar, rs, version); +} + +} // serialization +} // boost #endif diff --git a/src/test/basics/RangeSet_test.cpp b/src/test/basics/RangeSet_test.cpp index ce12c4a240..d1d3862760 100644 --- a/src/test/basics/RangeSet_test.cpp +++ b/src/test/basics/RangeSet_test.cpp @@ -20,6 +20,8 @@ #include #include #include +#include +#include namespace ripple { @@ -75,11 +77,41 @@ public: set.erase(range(4u, 5u)); BEAST_EXPECT(to_string(set) == "1-2,6"); } + + void + testSerialization() + { + + auto works = [](RangeSet const & orig) + { + std::stringstream ss; + boost::archive::binary_oarchive oa(ss); + oa << orig; + + boost::archive::binary_iarchive ia(ss); + RangeSet deser; + ia >> deser; + + return orig == deser; + }; + + RangeSet rs; + + BEAST_EXPECT(works(rs)); + + rs.insert(3); + BEAST_EXPECT(works(rs)); + + rs.insert(range(7u, 10u)); + BEAST_EXPECT(works(rs)); + + } void run() { testPrevMissing(); testToString(); + testSerialization(); } };