How to implement boost::serialize for tbb::concurrent_vector

99 Views Asked by At

I am using tbb::concurrent_vector in place of std::vector in some places but am also using boost serialization in order to serialise the containers, and concurrent_vector does not come with one provided (obviously).

Any idea how to implement this easily and correctly?

Many thanks

1

There are 1 best solutions below

1
On

You can use non-intrusive serialization. The simplest I can think of:

template <typename Ar, typename... Ts>
void serialize(Ar& ar, tbb::concurrent_vector<Ts...>& v, unsigned) {
    size_t n = v.size();

    ar & n;
    if constexpr (Ar::is_loading::value)
        v.resize(n);
    ar & make_array(&v.front(), n);
}

However this would be very wrong, as concurrent_vector is apparently not a vector at all:

[because] elements in a concurrent_vector might not be at consecutive addresses

Fix

We can take a hint from e.g. boost/serialization/list.hpp and reuse their collection loading/saving primitives. This has the benefit of also adding correct item versioning and NVP wrapping (e.g. needed for XML archives)

Demo Time

Live On Coliru

#include <boost/serialization/collections_load_imp.hpp>
#include <boost/serialization/collections_save_imp.hpp>
#include <boost/serialization/library_version_type.hpp>
#include <tbb/concurrent_vector.h>

namespace boost::serialization {
    template <typename Ar, typename... Ts>
    inline void save(Ar& ar, tbb::concurrent_vector<Ts...> const& t, unsigned) {
        boost::serialization::stl::save_collection<Ar, tbb::concurrent_vector<Ts...>>(ar, t);
    }

    template <typename Ar, typename... Ts>
    inline void load(Ar& ar, tbb::concurrent_vector<Ts...>& t, unsigned) {
        item_version_type    item_version(0);
        collection_size_type count;
        ar >> BOOST_SERIALIZATION_NVP(count);
        if (library_version_type{3} < ar.get_library_version())
            ar >> BOOST_SERIALIZATION_NVP(item_version);
        stl::collection_load_impl(ar, t, count, item_version);
    }

    template <typename Ar, typename... Ts>
    inline void serialize(Ar& ar, tbb::concurrent_vector<Ts...>& t, unsigned version) {
        boost::serialization::split_free(ar, t, version);
    }

} // namespace boost::serialization

#include <boost/serialization/collection_traits.hpp>

BOOST_SERIALIZATION_COLLECTION_TRAITS(tbb::concurrent_vector)

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <fmt/ranges.h>
int main() {
    std::stringstream ss;

    boost::archive::text_oarchive(ss) << tbb::concurrent_vector<int>{1, 2, 3};

    tbb::concurrent_vector<int> roundtrip;
    fmt::print("Archive: {}\n", ss.str());

    boost::archive::text_iarchive(ss) >> roundtrip;
    fmt::print("Deserialized: {}\n", roundtrip);
}

Printing

Archive: 22 serialization::archive 19 3 0 1 2 3

Deserialized: [1, 2, 3]