added serialization support (pending docs and testing)

This commit is contained in:
joaquintides
2023-08-04 17:18:04 +02:00
parent bcd8969b9a
commit 5239b101e2
19 changed files with 975 additions and 10 deletions

View File

@ -19,6 +19,7 @@
#include <boost/container_hash/hash.hpp>
#include <boost/core/allocator_access.hpp>
#include <boost/core/serialization.hpp>
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/list.hpp>
#include <boost/type_traits/type_identity.hpp>
@ -101,6 +102,11 @@ namespace boost {
friend typename concurrent_flat_map<K, V, H, KE, A>::size_type erase_if(
concurrent_flat_map<K, V, H, KE, A>& set, Predicate pred);
template<class Archive, class K, class V, class H, class KE, class A>
friend void serialize(
Archive& ar, concurrent_flat_map<K, V, H, KE, A>& c,
unsigned int version);
public:
using key_type = Key;
using mapped_type = T;
@ -772,6 +778,14 @@ namespace boost {
return c.table_.erase_if(pred);
}
template<class Archive, class K, class V, class H, class KE, class A>
void serialize(
Archive& ar, concurrent_flat_map<K, V, H, KE, A>& c,
unsigned int version)
{
ar & core::make_nvp("table",c.table_);
}
#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
template <class InputIterator,

View File

@ -0,0 +1,71 @@
/* 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_ARCHIVE_CONSTRUCTED_HPP
#define BOOST_UNORDERED_DETAIL_ARCHIVE_CONSTRUCTED_HPP
#include <boost/config.hpp>
#include <boost/core/no_exceptions_support.hpp>
#include <boost/core/noncopyable.hpp>
#include <boost/core/serialization.hpp>
#include <boost/type_traits/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp>
namespace boost{
namespace unordered{
namespace detail{
/* constructs a stack-based object from a serialization archive */
template<typename T>
struct archive_constructed:private noncopyable
{
template<class Archive>
archive_constructed(const char* name,Archive& ar,unsigned int version)
{
core::load_construct_data_adl(ar,&get(),version);
BOOST_TRY{
ar>>core::make_nvp(name,get());
}
BOOST_CATCH(...){
(&get())->~T();
BOOST_RETHROW;
}
BOOST_CATCH_END
}
~archive_constructed()
{
(&get())->~T();
}
#if defined(BOOST_GCC)&&(BOOST_GCC>=4*10000+6*100)
#define BOOST_UNORDERED_IGNORE_WSTRICT_ALIASING
#endif
#if defined(BOOST_UNORDERED_IGNORE_WSTRICT_ALIASING)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
T& get(){return *reinterpret_cast<T*>(&space);}
#if defined(BOOST_UNORDERED_IGNORE_WSTRICT_ALIASING)
#pragma GCC diagnostic pop
#undef BOOST_UNORDERED_IGNORE_WSTRICT_ALIASING
#endif
private:
typename aligned_storage<sizeof(T),alignment_of<T>::value>::type space;
};
} /* namespace detail */
} /* namespace unordered */
} /* namespace boost */
#endif

View File

@ -0,0 +1,27 @@
/* 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_BAD_ARCHIVE_EXCEPTION_HPP
#define BOOST_UNORDERED_DETAIL_BAD_ARCHIVE_EXCEPTION_HPP
#include <stdexcept>
namespace boost{
namespace unordered{
namespace detail{
struct bad_archive_exception:std::runtime_error
{
bad_archive_exception():std::runtime_error("Invalid or corrupted archive"){}
};
} /* namespace detail */
} /* namespace unordered */
} /* namespace boost */
#endif

View File

@ -1,4 +1,4 @@
// Copyright (C) 2022 Joaquin M Lopez Munoz.
// Copyright (C) 2022-2023 Joaquin M Lopez Munoz.
// Copyright (C) 2022 Christian Mazakas
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@ -114,12 +114,14 @@ to normal separate chaining implementations.
*/
#include <boost/unordered/detail/prime_fmod.hpp>
#include <boost/unordered/detail/serialize_node_pointer.hpp>
#include <boost/core/addressof.hpp>
#include <boost/core/allocator_access.hpp>
#include <boost/core/bit.hpp>
#include <boost/core/empty_value.hpp>
#include <boost/core/no_exceptions_support.hpp>
#include <boost/core/serialization.hpp>
#include <boost/cstdint.hpp>
#include <boost/move/core.hpp>
#include <boost/move/utility_core.hpp>
@ -287,6 +289,25 @@ namespace boost {
p = pbg->buckets + x;
}
}
template<typename Archive>
friend void serialization_track(
Archive& ar, grouped_bucket_iterator const& x)
{
// requires: not at end() position
track_node_pointer(ar, x.p);
track_node_pointer(ar, x.pbg);
}
friend class boost::serialization::access;
template<typename Archive>
void serialize(Archive& ar,unsigned int)
{
// requires: not at end() position
serialize_node_pointer(ar, p);
serialize_node_pointer(ar, pbg);
}
};
template <class Node> struct const_grouped_local_bucket_iterator;

View File

@ -16,13 +16,18 @@
#include <boost/config.hpp>
#include <boost/core/ignore_unused.hpp>
#include <boost/core/no_exceptions_support.hpp>
#include <boost/core/serialization.hpp>
#include <boost/cstdint.hpp>
#include <boost/mp11/tuple.hpp>
#include <boost/static_assert.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/foa/core.hpp>
#include <boost/unordered/detail/foa/reentrancy_check.hpp>
#include <boost/unordered/detail/foa/rw_spinlock.hpp>
#include <boost/unordered/detail/foa/tuple_rotate_right.hpp>
#include <boost/unordered/detail/serialization_version.hpp>
#include <cstddef>
#include <functional>
#include <initializer_list>
@ -1442,6 +1447,139 @@ private:
}
#endif
friend class boost::serialization::access;
template<typename Archive>
void serialize(Archive& ar,unsigned int version)
{
core::split_member(ar,*this,version);
}
template<typename Archive>
void save(Archive& ar,unsigned int version)const
{
save(
ar,version,
std::integral_constant<bool,std::is_same<key_type,value_type>::value>{});
}
template<typename Archive>
void save(Archive& ar,unsigned int version,std::true_type /* set */)const
{
auto lck=exclusive_access();
const std::size_t s=super::size();
const serialization_version<value_type> value_version;
ar<<core::make_nvp("count",s);
ar<<core::make_nvp("value_version",value_version);
super::for_all_elements([&,this](element_type* p){
auto& x=type_policy::value_from(*p);
core::save_construct_data_adl(ar,std::addressof(x),value_version);
ar<<serialization::make_nvp("item",x);
});
}
template<typename Archive>
void save(Archive& ar,unsigned int version,std::false_type /* map */)const
{
using key_type=typename std::remove_const<key_type>::type;
using mapped_type=typename std::remove_const<
typename TypePolicy::mapped_type>::type;
auto lck=exclusive_access();
const std::size_t s=super::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);
super::for_all_elements([&,this](element_type* p){
/* 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.
*/
auto& x=type_policy::value_from(*p);
core::save_construct_data_adl(
ar,std::addressof(x.first),key_version);
ar<<serialization::make_nvp("key",x.first);
core::save_construct_data_adl(
ar,std::addressof(x.second),mapped_version);
ar<<serialization::make_nvp("mapped",x.second);
});
}
template<typename Archive>
void load(Archive& ar,unsigned int version)
{
load(
ar,version,
std::integral_constant<bool,std::is_same<key_type,value_type>::value>{});
}
template<typename Archive>
void load(Archive& ar,unsigned int version,std::true_type /* set */)
{
auto lck=exclusive_access();
std::size_t s;
serialization_version<value_type> value_version;
ar>>core::make_nvp("count",s);
ar>>core::make_nvp("value_version",value_version);
super::clear();
super::reserve(s);
for(std::size_t n=0;n<s;++n){
archive_constructed<value_type> value("item",ar,value_version);
auto& x=value.get();
auto hash=this->hash_for(x);
auto pos0=this->position_for(hash);
if(this->find(x,pos0,hash))throw_exception(bad_archive_exception());
auto loc=this->unchecked_emplace_at(pos0,hash,std::move(x));
ar.reset_object_address(std::addressof(*loc.p),std::addressof(x));
}
}
template<typename Archive>
void load(Archive& ar,unsigned int version,std::false_type /* map */)
{
using key_type=typename std::remove_const<key_type>::type;
using mapped_type=typename std::remove_const<
typename TypePolicy::mapped_type>::type;
auto lck=exclusive_access();
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);
super::clear();
super::reserve(s);
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);
auto& k=key.get();
auto& m=mapped.get();
auto hash=this->hash_for(k);
auto pos0=this->position_for(hash);
if(this->find(k,pos0,hash))throw_exception(bad_archive_exception());
auto loc=this->unchecked_emplace_at(pos0,hash,std::move(k),std::move(m));
ar.reset_object_address(std::addressof(loc.p->first),std::addressof(k));
ar.reset_object_address(std::addressof(loc.p->second),std::addressof(m));
}
}
static std::atomic<std::size_t> thread_counter;
mutable multimutex_type mutexes;
};

View File

@ -1180,7 +1180,8 @@ alloc_make_insert_type(const Allocator& al,Args&&... args)
* init_type and element_type:
*
* - TypePolicy::key_type and TypePolicy::value_type have the obvious
* meaning.
* meaning. TypePolicy::mapped_type is expected to be provided as well
* when key_type and value_type are not the same.
*
* - TypePolicy::init_type is the type implicitly converted to when
* writing x.insert({...}). For maps, this is std::pair<Key,T> rather

View File

@ -14,6 +14,7 @@ namespace boost {
template <class Key, class T> struct flat_map_types
{
using key_type = Key;
using mapped_type = T;
using raw_key_type = typename std::remove_const<Key>::type;
using raw_mapped_type = typename std::remove_const<T>::type;

View File

@ -15,7 +15,9 @@
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#include <boost/core/serialization.hpp>
#include <boost/unordered/detail/foa/core.hpp>
#include <boost/unordered/detail/serialize_node_pointer.hpp>
#include <cstddef>
#include <iterator>
#include <memory>
@ -195,6 +197,25 @@ private:
}
}
template<typename Archive>
friend void serialization_track(Archive& ar,const table_iterator& x)
{
if(x.p){
track_node_pointer(ar,x.pc);
track_node_pointer(ar,x.p);
}
}
friend class boost::serialization::access;
template<typename Archive>
void serialize(Archive& ar,unsigned int)
{
if(!p)pc=nullptr;
serialize_node_pointer(ar,pc);
serialize_node_pointer(ar,p);
}
unsigned char *pc=nullptr;
table_element_type *p=nullptr;
};

View File

@ -1,6 +1,6 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2016 Daniel James
// Copyright (C) 2022 Joaquin M Lopez Munoz.
// Copyright (C) 2022-2023 Joaquin M Lopez Munoz.
// Copyright (C) 2022 Christian Mazakas
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@ -19,6 +19,7 @@
#include <boost/core/bit.hpp>
#include <boost/core/no_exceptions_support.hpp>
#include <boost/core/pointer_traits.hpp>
#include <boost/core/serialization.hpp>
#include <boost/limits.hpp>
#include <boost/move/move.hpp>
#include <boost/preprocessor/arithmetic/inc.hpp>
@ -47,6 +48,7 @@
#include <boost/type_traits/make_void.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/unordered/detail/fca.hpp>
#include <boost/unordered/detail/serialize_node_pointer.hpp>
#include <boost/unordered/detail/type_traits.hpp>
#include <boost/unordered/detail/fwd.hpp>
#include <boost/utility/addressof.hpp>
@ -1703,6 +1705,25 @@ namespace boost {
p = (++itb)->next;
}
}
template<typename Archive>
friend void serialization_track(Archive& ar, const iterator& x)
{
if(x.p){
track_node_pointer(ar, x.p);
serialization_track(ar, x.itb);
}
}
friend class boost::serialization::access;
template<typename Archive>
void serialize(Archive& ar,unsigned int)
{
if(!p) itb = bucket_iterator();
serialize_node_pointer(ar, p);
ar & core::make_nvp("bucket_iterator", itb);
}
};
template <class Node, class Bucket> class c_iterator
@ -1793,6 +1814,25 @@ namespace boost {
p = (++itb)->next;
}
}
template<typename Archive>
friend void serialization_track(Archive& ar, const c_iterator& x)
{
if(x.p){
track_node_pointer(ar, x.p);
serialization_track(ar, x.itb);
}
}
friend class boost::serialization::access;
template<typename Archive>
void serialize(Archive& ar,unsigned int)
{
if(!p) itb = bucket_iterator();
serialize_node_pointer(ar, p);
ar & core::make_nvp("bucket_iterator", itb);
}
};
} // namespace iterator_detail

View File

@ -0,0 +1,74 @@
/* 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_SERIALIZATION_VERSION_HPP
#define BOOST_UNORDERED_DETAIL_SERIALIZATION_VERSION_HPP
#include <boost/config.hpp>
#include <boost/core/serialization.hpp>
namespace boost{
namespace unordered{
namespace detail{
/* boost::serialization::load_construct_adl(ar,t,version) requires user code
* to pass the serialization version for t, when this information is really
* stored in the archive. serialization_version<T> circumvents this design
* error by acting as a regular serializable type with the same serialization
* version as T; loading/saving serialization_version<T> does nothing with
* the archive data itself but captures the stored serialization version
* at load() time.
*/
template<typename T>
struct serialization_version
{
serialization_version():
value(boost::serialization::version<serialization_version>::value){}
serialization_version& operator=(unsigned int x){value=x;return *this;};
operator unsigned int()const{return value;}
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive& ar,unsigned int version)
{
core::split_member(ar,*this,version);
}
template<class Archive>
void save(Archive&,unsigned int)const{}
template<class Archive>
void load(Archive&,unsigned int version)
{
this->value=version;
}
unsigned int value;
};
} /* namespace detail */
} /* namespace unordered */
namespace serialization{
template<typename T>
struct version<boost::unordered::detail::serialization_version<T> >
{
BOOST_STATIC_CONSTANT(int,value=version<T>::value);
};
} /* namespace serialization */
} /* namespace boost */
#endif

View File

@ -0,0 +1,208 @@
/* 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/addressof.hpp>
#include <boost/core/serialization.hpp>
#include <boost/move/move.hpp>
#include <boost/throw_exception.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/remove_const.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 addresses of the iterator's associated node(s) via
* track_node_pointer().
* - At loading time, these addresses are mapped to those of the equivalent
* reconstructed nodes using again serialization_track(ar,it).
* - Serializing an iterator reduces to serializing pointers to previously
* tracked nodes via serialize_node_pointer().
*/
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 version)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,boost::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 version)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(boost::move(value.get())));
if(!p.second)throw_exception(bad_archive_exception());
ar.reset_object_address(
boost::addressof(*p.first),boost::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 version)const
{
typedef typename boost::remove_const<
typename Map::key_type>::type key_type;
typedef typename boost::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,boost::addressof(first->first),key_version);
ar<<core::make_nvp("key",first->first);
core::save_construct_data_adl(
ar,boost::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 version)const
{
typedef typename boost::remove_const<
typename Map::key_type>::type key_type;
typedef typename boost::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);
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(boost::move(key.get()),boost::move(mapped.get())));
if(!p.second)throw_exception(bad_archive_exception());
ar.reset_object_address(
boost::addressof(p.first->first),boost::addressof(key.get()));
ar.reset_object_address(
boost::addressof(p.first->second),boost::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,
boost::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

View File

@ -0,0 +1,156 @@
/* 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_FCA_CONTAINER_HPP
#define BOOST_UNORDERED_DETAIL_SERIALIZE_FCA_CONTAINER_HPP
#include <boost/unordered/detail/serialize_container.hpp>
#if defined(BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0)
#define BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER \
<boost/serialization/archive_input_unordered_map.hpp>
#include BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER
#undef BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER
#define BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER \
<boost/serialization/archive_input_unordered_set.hpp>
#include BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER
#undef BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER
#define BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER \
<boost/serialization/unordered_collections_load_imp.hpp>
#include BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER
#undef BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER
#define BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER \
<boost/serialization/utility.hpp>
#include BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER
#undef BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER
#include <boost/unordered/unordered_map_fwd.hpp>
#include <boost/unordered/unordered_set_fwd.hpp>
#else
#include <boost/throw_exception.hpp>
#include <stdexcept>
#endif
namespace boost{
namespace unordered{
namespace detail{
/* Support for boost::unordered_[multi](map|set) loading from legacy archives.
* Until Boost 1.84, serialization of these containers was provided from
* Boost.Serialization via boost/serialization/boost_unordered_(map|set).hpp,
* from that release on support is native in Boost.Unordered. To enable legacy
* archive loading, BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0
* must be defined (it implies header dependency from Boost.Serialization).
*/
#if defined(BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0)
template<typename Archive,typename Container>
struct archive_input;
template<
typename Archive,typename K,typename T,typename H,typename P,typename A
>
struct archive_input<Archive,boost::unordered_map<K,T,H,P,A> >:
boost::serialization::stl::archive_input_unordered_map<
Archive,
boost::unordered_map<K,T,H,P,A>
>
{};
template<
typename Archive,typename K,typename T,typename H,typename P,typename A
>
struct archive_input<Archive,boost::unordered_multimap<K,T,H,P,A> >:
boost::serialization::stl::archive_input_unordered_multimap<
Archive,
boost::unordered_multimap<K,T,H,P,A>
>
{};
template<
typename Archive,typename K,typename H,typename P,typename A
>
struct archive_input<Archive,boost::unordered_set<K,H,P,A> >:
boost::serialization::stl::archive_input_unordered_set<
Archive,
boost::unordered_set<K,H,P,A>
>
{};
template<
typename Archive,typename K,typename H,typename P,typename A
>
struct archive_input<Archive,boost::unordered_multiset<K,H,P,A> >:
boost::serialization::stl::archive_input_unordered_multiset<
Archive,
boost::unordered_multiset<K,H,P,A>
>
{};
#else
struct legacy_archive_exception:std::runtime_error
{
legacy_archive_exception():std::runtime_error(
"Legacy archive detected, define "
"BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0 to load"){}
};
#endif
template<typename Container,bool IsSaving>
struct load_or_save_fca_container;
template<typename Container>
struct load_or_save_fca_container<Container,true> /* save */
{
template<typename Archive>
void operator()(Archive& ar,Container& x,unsigned int version)const
{
serialize_container(ar,x,version);
}
};
template<typename Container>
struct load_or_save_fca_container<Container,false> /* load */
{
template<typename Archive>
void operator()(Archive& ar,Container& x,unsigned int version)const
{
if(version==0){
#if defined(BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0)
boost::serialization::stl::load_unordered_collection<
Archive,Container,archive_input<Archive,Container>
>(ar,x);
#else
throw_exception(legacy_archive_exception());
#endif
}
else{
serialize_container(ar,x,version);
}
}
};
template<typename Archive,typename Container>
void serialize_fca_container(Archive& ar,Container& x,unsigned int version)
{
load_or_save_fca_container<Container,Archive::is_saving::value>()(
ar,x,version);
}
} /* namespace detail */
} /* namespace unordered */
} /* namespace boost */
#endif

View File

@ -0,0 +1,90 @@
/* 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_NODE_POINTER_HPP
#define BOOST_UNORDERED_DETAIL_SERIALIZE_NODE_POINTER_HPP
#include <boost/core/serialization.hpp>
#include <boost/throw_exception.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/type_traits/integral_constant.hpp>
#include <boost/unordered/detail/bad_archive_exception.hpp>
namespace boost{
namespace unordered{
namespace detail{
/* Node pointer serialization to support iterator serialization as described
* in serialize_container.hpp. The underlying technique is to reinterpret_cast
* Node pointers to serialization_tracker<Node> pointers, which, when
* dereferenced and serialized, do not emit any serialization payload to the
* archive, but activate object tracking on the relevant addresses for later
* use with serialize_node_pointer().
*/
template<typename Node>
struct serialization_tracker
{
/* An attempt to construct a serialization_tracker means a stray address
* in the archive, that is, one without a previously tracked node.
*/
serialization_tracker(){throw_exception(bad_archive_exception());}
template<typename Archive>
void serialize(Archive&,unsigned int){} /* no data emitted */
};
template<typename Archive,typename Node>
void track_node_pointer(Archive& ar,const Node* p)
{
if(p){
ar&core::make_nvp(
"node",
*reinterpret_cast<serialization_tracker<Node>*>(const_cast<Node*>(p)));
}
}
template<typename Archive,typename Node>
void serialize_node_pointer(Archive& ar,Node*& p,boost::true_type /* save */)
{
typedef typename boost::remove_const<Node>::type node_type;
typedef serialization_tracker<node_type> tracker;
tracker* pn=
const_cast<tracker*>(
reinterpret_cast<const tracker*>(
const_cast<const Node*>(p)));
ar<<core::make_nvp("pointer",pn);
}
template<typename Archive,typename Node>
void serialize_node_pointer(Archive& ar,Node*& p,boost::false_type /* load */)
{
typedef typename boost::remove_const<Node>::type node_type;
typedef serialization_tracker<node_type> tracker;
tracker* pn;
ar>>core::make_nvp("pointer",pn);
p=const_cast<Node*>(
reinterpret_cast<const Node*>(
const_cast<const tracker*>(pn)));
}
template<typename Archive,typename Node>
void serialize_node_pointer(Archive& ar,Node*& p)
{
serialize_node_pointer(
ar,p,
boost::integral_constant<bool,Archive::is_saving::value>());
}
} /* namespace detail */
} /* namespace unordered */
} /* namespace boost */
#endif

View File

@ -1,4 +1,4 @@
// Copyright (C) 2022 Christian Mazakas
// Copyright (C) 2022-2023 Christian Mazakas
// 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)
@ -13,6 +13,7 @@
#include <boost/unordered/concurrent_flat_map_fwd.hpp>
#include <boost/unordered/detail/foa/flat_map_types.hpp>
#include <boost/unordered/detail/foa/table.hpp>
#include <boost/unordered/detail/serialize_container.hpp>
#include <boost/unordered/detail/type_traits.hpp>
#include <boost/unordered/unordered_flat_map_fwd.hpp>
@ -696,6 +697,16 @@ namespace boost {
return erase_if(map.table_, pred);
}
template <class Archive,
class Key, class T, class Hash, class KeyEqual, class Allocator>
void serialize(
Archive & ar,
unordered_flat_map<Key, T, Hash, KeyEqual, Allocator>& map,
unsigned int version)
{
detail::serialize_container(ar, map, version);
}
#if defined(BOOST_MSVC)
#pragma warning(pop) /* C4714 */
#endif

View File

@ -1,4 +1,4 @@
// Copyright (C) 2022 Christian Mazakas
// Copyright (C) 2022-2023 Christian Mazakas
// 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)
@ -12,6 +12,7 @@
#include <boost/unordered/detail/foa/flat_set_types.hpp>
#include <boost/unordered/detail/foa/table.hpp>
#include <boost/unordered/detail/serialize_container.hpp>
#include <boost/unordered/detail/type_traits.hpp>
#include <boost/unordered/unordered_flat_set_fwd.hpp>
@ -505,6 +506,16 @@ namespace boost {
return erase_if(set.table_, pred);
}
template <class Archive,
class Key, class Hash, class KeyEqual, class Allocator>
void serialize(
Archive & ar,
unordered_flat_set<Key, Hash, KeyEqual, Allocator>& set,
unsigned int version)
{
detail::serialize_container(ar, set, version);
}
#if defined(BOOST_MSVC)
#pragma warning(pop) /* C4714 */
#endif

View File

@ -1,7 +1,6 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2011 Daniel James.
// Copyright (C) 2022 Christian Mazakas
// Copyright (C) 2022-2023 Christian Mazakas
// 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)
@ -16,11 +15,13 @@
#endif
#include <boost/unordered/detail/requires_cxx11.hpp>
#include <boost/config.hpp>
#include <boost/core/explicit_operator_bool.hpp>
#include <boost/functional/hash.hpp>
#include <boost/move/move.hpp>
#include <boost/type_traits/is_constructible.hpp>
#include <boost/unordered/detail/map.hpp>
#include <boost/unordered/detail/serialize_fca_container.hpp>
#include <boost/unordered/detail/type_traits.hpp>
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
@ -1059,6 +1060,13 @@ namespace boost {
#endif
}; // class template unordered_map
template <class Archive, class K, class T, class H, class P, class A>
void serialize(
Archive & ar,unordered_map<K, T, H, P, A>& m,unsigned int version)
{
detail::serialize_fca_container(ar, m, version);
}
#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
template <class InputIterator,
@ -1762,6 +1770,13 @@ namespace boost {
#endif
}; // class template unordered_multimap
template <class Archive, class K, class T, class H, class P, class A>
void serialize(
Archive & ar,unordered_multimap<K, T, H, P, A>& m,unsigned int version)
{
detail::serialize_fca_container(ar, m, version);
}
#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
template <class InputIterator,
@ -3019,6 +3034,21 @@ namespace boost {
boost::swap(x.position, y.position);
}
} // namespace unordered
namespace serialization {
template <class K, class T, class H, class P, class A>
struct version<boost::unordered_map<K, T, H, P, A> >
{
BOOST_STATIC_CONSTANT(int, value = 1);
};
template <class K, class T, class H, class P, class A>
struct version<boost::unordered_multimap<K, T, H, P, A> >
{
BOOST_STATIC_CONSTANT(int, value = 1);
};
} // namespace serialization
} // namespace boost
#if defined(BOOST_MSVC)

View File

@ -14,6 +14,7 @@
#include <boost/unordered/detail/foa/node_handle.hpp>
#include <boost/unordered/detail/foa/node_map_types.hpp>
#include <boost/unordered/detail/foa/table.hpp>
#include <boost/unordered/detail/serialize_container.hpp>
#include <boost/unordered/detail/type_traits.hpp>
#include <boost/unordered/unordered_node_map_fwd.hpp>
@ -788,6 +789,16 @@ namespace boost {
return erase_if(map.table_, pred);
}
template <class Archive,
class Key, class T, class Hash, class KeyEqual, class Allocator>
void serialize(
Archive & ar,
unordered_node_map<Key, T, Hash, KeyEqual, Allocator>& map,
unsigned int version)
{
detail::serialize_container(ar, map, version);
}
#if defined(BOOST_MSVC)
#pragma warning(pop) /* C4714 */
#endif

View File

@ -1,4 +1,4 @@
// Copyright (C) 2022 Christian Mazakas
// Copyright (C) 2022-2023 Christian Mazakas
// 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)
@ -14,6 +14,7 @@
#include <boost/unordered/detail/foa/node_handle.hpp>
#include <boost/unordered/detail/foa/node_set_types.hpp>
#include <boost/unordered/detail/foa/table.hpp>
#include <boost/unordered/detail/serialize_container.hpp>
#include <boost/unordered/detail/type_traits.hpp>
#include <boost/unordered/unordered_node_set_fwd.hpp>
@ -601,6 +602,16 @@ namespace boost {
return erase_if(set.table_, pred);
}
template <class Archive,
class Key, class Hash, class KeyEqual, class Allocator>
void serialize(
Archive & ar,
unordered_node_set<Key, Hash, KeyEqual, Allocator>& set,
unsigned int version)
{
detail::serialize_container(ar, set, version);
}
#if defined(BOOST_MSVC)
#pragma warning(pop) /* C4714 */
#endif

View File

@ -1,7 +1,6 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2011 Daniel James.
// Copyright (C) 2022 Christian Mazakas
// Copyright (C) 2022-2023 Christian Mazakas
// 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)
@ -20,6 +19,7 @@
#include <boost/functional/hash.hpp>
#include <boost/move/move.hpp>
#include <boost/unordered/detail/set.hpp>
#include <boost/unordered/detail/serialize_fca_container.hpp>
#include <boost/unordered/detail/type_traits.hpp>
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
@ -641,6 +641,13 @@ namespace boost {
#endif
}; // class template unordered_set
template <class Archive, class K, class H, class P, class A>
void serialize(
Archive & ar,unordered_set<K, H, P, A>& c,unsigned int version)
{
detail::serialize_fca_container(ar, c, version);
}
#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
template <class InputIterator,
@ -1290,6 +1297,13 @@ namespace boost {
#endif
}; // class template unordered_multiset
template <class Archive, class K, class H, class P, class A>
void serialize(
Archive & ar,unordered_multiset<K, H, P, A>& c,unsigned int version)
{
detail::serialize_fca_container(ar, c, version);
}
#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
template <class InputIterator,
@ -2367,6 +2381,21 @@ namespace boost {
boost::swap(x.position, y.position);
}
} // namespace unordered
namespace serialization {
template <class K, class H, class P, class A>
struct version<boost::unordered_set<K, H, P, A> >
{
BOOST_STATIC_CONSTANT(int, value = 1);
};
template <class K, class H, class P, class A>
struct version<boost::unordered_multiset<K, H, P, A> >
{
BOOST_STATIC_CONSTANT(int, value = 1);
};
} // namespace serialization
} // namespace boost
#if defined(BOOST_MSVC)