205 lines
6.9 KiB
C++
205 lines
6.9 KiB
C++
|
/* Copyright 2023 Joaquin M Lopez Munoz.
|
||
|
* Distributed under the Boost Software License, Version 1.0.
|
||
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||
|
*
|
||
|
* See https://www.boost.org/libs/unordered for library home page.
|
||
|
*/
|
||
|
|
||
|
#ifndef BOOST_UNORDERED_DETAIL_SERIALIZE_CONTAINER_HPP
|
||
|
#define BOOST_UNORDERED_DETAIL_SERIALIZE_CONTAINER_HPP
|
||
|
|
||
|
#include <boost/core/serialization.hpp>
|
||
|
#include <boost/throw_exception.hpp>
|
||
|
#include <boost/unordered/detail/archive_constructed.hpp>
|
||
|
#include <boost/unordered/detail/bad_archive_exception.hpp>
|
||
|
#include <boost/unordered/detail/serialization_version.hpp>
|
||
|
#include <cstddef>
|
||
|
|
||
|
namespace boost{
|
||
|
namespace unordered{
|
||
|
namespace detail{
|
||
|
|
||
|
/* serialize_container(ar,x,v) serializes any of the unordered associative
|
||
|
* containers in Boost.Unordered. Iterator serialization is also supported
|
||
|
* through the following protocol:
|
||
|
* - At saving time, for each iterator it in [x.begin(),x.end()),
|
||
|
* serialization_track(ar,it) is ADL-called to instruct the archive to
|
||
|
* track the positions internally pointed to by the iterator via
|
||
|
* track_address().
|
||
|
* - At loading time, these addresses are mapped to those of the equivalent
|
||
|
* reconstructed positions using again serialization_track(ar,it).
|
||
|
* - Serializing an iterator reduces to serializing pointers to previously
|
||
|
* tracked addresses via serialize_address().
|
||
|
*/
|
||
|
|
||
|
template<typename Iterator>
|
||
|
std::pair<Iterator,bool> adapt_insert_return_type(Iterator it)
|
||
|
{
|
||
|
return std::pair<Iterator,bool>(it,true);
|
||
|
}
|
||
|
|
||
|
template<typename Iterator>
|
||
|
std::pair<Iterator,bool> adapt_insert_return_type(std::pair<Iterator,bool> p)
|
||
|
{
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
template<typename Set,bool IsSaving> struct load_or_save_unordered_set;
|
||
|
|
||
|
template<typename Set> struct load_or_save_unordered_set<Set,true> /* save */
|
||
|
{
|
||
|
template<typename Archive>
|
||
|
void operator()(Archive& ar,const Set& x,unsigned int)const
|
||
|
{
|
||
|
typedef typename Set::value_type value_type;
|
||
|
typedef typename Set::const_iterator const_iterator;
|
||
|
|
||
|
const std::size_t s=x.size();
|
||
|
const serialization_version<value_type> value_version;
|
||
|
|
||
|
ar<<core::make_nvp("count",s);
|
||
|
ar<<core::make_nvp("value_version",value_version);
|
||
|
|
||
|
for(const_iterator first=x.begin(),last=x.end();first!=last;++first){
|
||
|
core::save_construct_data_adl(ar,std::addressof(*first),value_version);
|
||
|
ar<<core::make_nvp("item",*first);
|
||
|
serialization_track(ar,first);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<typename Set> struct load_or_save_unordered_set<Set,false> /* load */
|
||
|
{
|
||
|
template<typename Archive>
|
||
|
void operator()(Archive& ar,Set& x,unsigned int)const
|
||
|
{
|
||
|
typedef typename Set::value_type value_type;
|
||
|
typedef typename Set::iterator iterator;
|
||
|
|
||
|
std::size_t s;
|
||
|
serialization_version<value_type> value_version;
|
||
|
|
||
|
ar>>core::make_nvp("count",s);
|
||
|
ar>>core::make_nvp("value_version",value_version);
|
||
|
|
||
|
x.clear();
|
||
|
x.reserve(s); /* critical so that iterator tracking is stable */
|
||
|
|
||
|
for(std::size_t n=0;n<s;++n){
|
||
|
archive_constructed<value_type> value("item",ar,value_version);
|
||
|
|
||
|
std::pair<iterator,bool> p=adapt_insert_return_type(
|
||
|
x.insert(std::move(value.get())));
|
||
|
if(!p.second)throw_exception(bad_archive_exception());
|
||
|
ar.reset_object_address(
|
||
|
std::addressof(*p.first),std::addressof(value.get()));
|
||
|
serialization_track(ar,p.first);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<typename Map,bool IsSaving> struct load_or_save_unordered_map;
|
||
|
|
||
|
template<typename Map> struct load_or_save_unordered_map<Map,true> /* save */
|
||
|
{
|
||
|
template<typename Archive>
|
||
|
void operator()(Archive& ar,const Map& x,unsigned int)const
|
||
|
{
|
||
|
typedef typename std::remove_const<
|
||
|
typename Map::key_type>::type key_type;
|
||
|
typedef typename std::remove_const<
|
||
|
typename Map::mapped_type>::type mapped_type;
|
||
|
typedef typename Map::const_iterator const_iterator;
|
||
|
|
||
|
const std::size_t s=x.size();
|
||
|
const serialization_version<key_type> key_version;
|
||
|
const serialization_version<mapped_type> mapped_version;
|
||
|
|
||
|
ar<<core::make_nvp("count",s);
|
||
|
ar<<core::make_nvp("key_version",key_version);
|
||
|
ar<<core::make_nvp("mapped_version",mapped_version);
|
||
|
|
||
|
for(const_iterator first=x.begin(),last=x.end();first!=last;++first){
|
||
|
/* To remain lib-independent from Boost.Serialization and not rely on
|
||
|
* the user having included the serialization code for std::pair
|
||
|
* (boost/serialization/utility.hpp), we serialize the key and the
|
||
|
* mapped value separately.
|
||
|
*/
|
||
|
|
||
|
core::save_construct_data_adl(
|
||
|
ar,std::addressof(first->first),key_version);
|
||
|
ar<<core::make_nvp("key",first->first);
|
||
|
core::save_construct_data_adl(
|
||
|
ar,std::addressof(first->second),mapped_version);
|
||
|
ar<<core::make_nvp("mapped",first->second);
|
||
|
serialization_track(ar,first);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<typename Map> struct load_or_save_unordered_map<Map,false> /* load */
|
||
|
{
|
||
|
template<typename Archive>
|
||
|
void operator()(Archive& ar,Map& x,unsigned int)const
|
||
|
{
|
||
|
typedef typename std::remove_const<
|
||
|
typename Map::key_type>::type key_type;
|
||
|
typedef typename std::remove_const<
|
||
|
typename Map::mapped_type>::type mapped_type;
|
||
|
typedef typename Map::iterator iterator;
|
||
|
|
||
|
std::size_t s;
|
||
|
serialization_version<key_type> key_version;
|
||
|
serialization_version<mapped_type> mapped_version;
|
||
|
|
||
|
ar>>core::make_nvp("count",s);
|
||
|
ar>>core::make_nvp("key_version",key_version);
|
||
|
ar>>core::make_nvp("mapped_version",mapped_version);
|
||
|
|
||
|
x.clear();
|
||
|
x.reserve(s); /* critical so that iterator tracking is stable */
|
||
|
|
||
|
for(std::size_t n=0;n<s;++n){
|
||
|
archive_constructed<key_type> key("key",ar,key_version);
|
||
|
archive_constructed<mapped_type> mapped("mapped",ar,mapped_version);
|
||
|
|
||
|
std::pair<iterator,bool> p=adapt_insert_return_type(
|
||
|
x.emplace(std::move(key.get()),std::move(mapped.get())));
|
||
|
if(!p.second)throw_exception(bad_archive_exception());
|
||
|
ar.reset_object_address(
|
||
|
std::addressof(p.first->first),std::addressof(key.get()));
|
||
|
ar.reset_object_address(
|
||
|
std::addressof(p.first->second),std::addressof(mapped.get()));
|
||
|
serialization_track(ar,p.first);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<typename Container,bool IsSet,bool IsSaving>
|
||
|
struct load_or_save_container;
|
||
|
|
||
|
template<typename Set,bool IsSaving>
|
||
|
struct load_or_save_container<Set,true,IsSaving>:
|
||
|
load_or_save_unordered_set<Set,IsSaving>{};
|
||
|
|
||
|
template<typename Map,bool IsSaving>
|
||
|
struct load_or_save_container<Map,false,IsSaving>:
|
||
|
load_or_save_unordered_map<Map,IsSaving>{};
|
||
|
|
||
|
template<typename Archive,typename Container>
|
||
|
void serialize_container(Archive& ar,Container& x,unsigned int version)
|
||
|
{
|
||
|
load_or_save_container<
|
||
|
Container,
|
||
|
std::is_same<
|
||
|
typename Container::key_type,typename Container::value_type>::value,
|
||
|
Archive::is_saving::value>()(ar,x,version);
|
||
|
}
|
||
|
|
||
|
} /* namespace detail */
|
||
|
} /* namespace unordered */
|
||
|
} /* namespace boost */
|
||
|
|
||
|
#endif
|