diff --git a/include/boost/unordered/concurrent_flat_map.hpp b/include/boost/unordered/concurrent_flat_map.hpp index 6e2eef98..f4b2be88 100644 --- a/include/boost/unordered/concurrent_flat_map.hpp +++ b/include/boost/unordered/concurrent_flat_map.hpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -101,6 +102,11 @@ namespace boost { friend typename concurrent_flat_map::size_type erase_if( concurrent_flat_map& set, Predicate pred); + template + friend void serialize( + Archive& ar, concurrent_flat_map& 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 + void serialize( + Archive& ar, concurrent_flat_map& c, + unsigned int version) + { + ar & core::make_nvp("table",c.table_); + } + #if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES template +#include +#include +#include +#include +#include + +namespace boost{ +namespace unordered{ +namespace detail{ + +/* constructs a stack-based object from a serialization archive */ + +template +struct archive_constructed:private noncopyable +{ + template + 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(&space);} + +#if defined(BOOST_UNORDERED_IGNORE_WSTRICT_ALIASING) +#pragma GCC diagnostic pop +#undef BOOST_UNORDERED_IGNORE_WSTRICT_ALIASING +#endif + +private: + typename aligned_storage::value>::type space; +}; + +} /* namespace detail */ +} /* namespace unordered */ +} /* namespace boost */ + +#endif diff --git a/include/boost/unordered/detail/bad_archive_exception.hpp b/include/boost/unordered/detail/bad_archive_exception.hpp new file mode 100644 index 00000000..5c7f4462 --- /dev/null +++ b/include/boost/unordered/detail/bad_archive_exception.hpp @@ -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 + +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 diff --git a/include/boost/unordered/detail/fca.hpp b/include/boost/unordered/detail/fca.hpp index e88faab1..4a0cada1 100644 --- a/include/boost/unordered/detail/fca.hpp +++ b/include/boost/unordered/detail/fca.hpp @@ -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 +#include #include #include #include #include #include +#include #include #include #include @@ -287,6 +289,25 @@ namespace boost { p = pbg->buckets + x; } } + + template + 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 + void serialize(Archive& ar,unsigned int) + { + // requires: not at end() position + serialize_node_pointer(ar, p); + serialize_node_pointer(ar, pbg); + } }; template struct const_grouped_local_bucket_iterator; diff --git a/include/boost/unordered/detail/foa/concurrent_table.hpp b/include/boost/unordered/detail/foa/concurrent_table.hpp index a3c35628..c6bbb91b 100644 --- a/include/boost/unordered/detail/foa/concurrent_table.hpp +++ b/include/boost/unordered/detail/foa/concurrent_table.hpp @@ -16,13 +16,18 @@ #include #include #include +#include #include #include #include +#include +#include +#include #include #include #include #include +#include #include #include #include @@ -1442,6 +1447,139 @@ private: } #endif + friend class boost::serialization::access; + + template + void serialize(Archive& ar,unsigned int version) + { + core::split_member(ar,*this,version); + } + + template + void save(Archive& ar,unsigned int version)const + { + save( + ar,version, + std::integral_constant::value>{}); + } + + template + 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_version; + + ar< + void save(Archive& ar,unsigned int version,std::false_type /* map */)const + { + using key_type=typename std::remove_const::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_version; + const serialization_version mapped_version; + + ar< + void load(Archive& ar,unsigned int version) + { + load( + ar,version, + std::integral_constant::value>{}); + } + + template + void load(Archive& ar,unsigned int version,std::true_type /* set */) + { + auto lck=exclusive_access(); + std::size_t s; + serialization_version 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 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 + void load(Archive& ar,unsigned int version,std::false_type /* map */) + { + using key_type=typename std::remove_const::type; + using mapped_type=typename std::remove_const< + typename TypePolicy::mapped_type>::type; + + auto lck=exclusive_access(); + std::size_t s; + serialization_version key_version; + serialization_version 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 key("key",ar,key_version); + archive_constructed 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 thread_counter; mutable multimutex_type mutexes; }; diff --git a/include/boost/unordered/detail/foa/core.hpp b/include/boost/unordered/detail/foa/core.hpp index f0a2ef5c..db0fd933 100644 --- a/include/boost/unordered/detail/foa/core.hpp +++ b/include/boost/unordered/detail/foa/core.hpp @@ -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 rather diff --git a/include/boost/unordered/detail/foa/flat_map_types.hpp b/include/boost/unordered/detail/foa/flat_map_types.hpp index 8a4d25f2..712df5fb 100644 --- a/include/boost/unordered/detail/foa/flat_map_types.hpp +++ b/include/boost/unordered/detail/foa/flat_map_types.hpp @@ -14,6 +14,7 @@ namespace boost { template struct flat_map_types { using key_type = Key; + using mapped_type = T; using raw_key_type = typename std::remove_const::type; using raw_mapped_type = typename std::remove_const::type; diff --git a/include/boost/unordered/detail/foa/table.hpp b/include/boost/unordered/detail/foa/table.hpp index 6cc11ed8..8764b47b 100644 --- a/include/boost/unordered/detail/foa/table.hpp +++ b/include/boost/unordered/detail/foa/table.hpp @@ -15,7 +15,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -195,6 +197,25 @@ private: } } + template + 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 + 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; }; diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 1fffdc4a..a26fc1f3 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -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 #include #include +#include #include #include #include @@ -47,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -1703,6 +1705,25 @@ namespace boost { p = (++itb)->next; } } + + template + 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 + 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 c_iterator @@ -1793,6 +1814,25 @@ namespace boost { p = (++itb)->next; } } + + template + 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 + 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 diff --git a/include/boost/unordered/detail/serialization_version.hpp b/include/boost/unordered/detail/serialization_version.hpp new file mode 100644 index 00000000..c63eb034 --- /dev/null +++ b/include/boost/unordered/detail/serialization_version.hpp @@ -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 +#include + +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 circumvents this design + * error by acting as a regular serializable type with the same serialization + * version as T; loading/saving serialization_version does nothing with + * the archive data itself but captures the stored serialization version + * at load() time. + */ + +template +struct serialization_version +{ + serialization_version(): + value(boost::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 + void serialize(Archive& ar,unsigned int version) + { + core::split_member(ar,*this,version); + } + + template + void save(Archive&,unsigned int)const{} + + template + void load(Archive&,unsigned int version) + { + this->value=version; + } + + unsigned int value; +}; + +} /* namespace detail */ +} /* namespace unordered */ + +namespace serialization{ + +template +struct version > +{ + BOOST_STATIC_CONSTANT(int,value=version::value); +}; + +} /* namespace serialization */ + +} /* namespace boost */ + +#endif diff --git a/include/boost/unordered/detail/serialize_container.hpp b/include/boost/unordered/detail/serialize_container.hpp new file mode 100644 index 00000000..ca257a5c --- /dev/null +++ b/include/boost/unordered/detail/serialize_container.hpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 +std::pair adapt_insert_return_type(Iterator it) +{ + return std::pair(it,true); +} + +template +std::pair adapt_insert_return_type(std::pair p) +{ + return p; +} + +template struct load_or_save_unordered_set; + +template struct load_or_save_unordered_set /* save */ +{ + template + 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_version; + + ar< struct load_or_save_unordered_set /* load */ +{ + template + 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_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 value("item",ar,value_version); + + std::pair 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 struct load_or_save_unordered_map; + +template struct load_or_save_unordered_map /* save */ +{ + template + 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_version; + const serialization_version mapped_version; + + ar<first),key_version); + ar<first); + core::save_construct_data_adl( + ar,boost::addressof(first->second),mapped_version); + ar<second); + serialization_track(ar,first); + } + } +}; + +template struct load_or_save_unordered_map /* load */ +{ + template + 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_version; + serialization_version 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 key("key",ar,key_version); + archive_constructed mapped("mapped",ar,mapped_version); + + std::pair 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 +struct load_or_save_container; + +template +struct load_or_save_container: + load_or_save_unordered_set{}; + +template +struct load_or_save_container: + load_or_save_unordered_map{}; + +template +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 diff --git a/include/boost/unordered/detail/serialize_fca_container.hpp b/include/boost/unordered/detail/serialize_fca_container.hpp new file mode 100644 index 00000000..7555a82e --- /dev/null +++ b/include/boost/unordered/detail/serialize_fca_container.hpp @@ -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 + +#if defined(BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0) + +#define BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER \ + +#include BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER +#undef BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER +#define BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER \ + +#include BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER +#undef BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER +#define BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER \ + +#include BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER +#undef BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER +#define BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER \ + +#include BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER +#undef BOOST_UNORDERED_BLOCK_BOOSTDEP_HEADER + +#include +#include + +#else + +#include +#include + +#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 +struct archive_input; + +template< + typename Archive,typename K,typename T,typename H,typename P,typename A +> +struct archive_input >: + boost::serialization::stl::archive_input_unordered_map< + Archive, + boost::unordered_map + > +{}; + +template< + typename Archive,typename K,typename T,typename H,typename P,typename A +> +struct archive_input >: + boost::serialization::stl::archive_input_unordered_multimap< + Archive, + boost::unordered_multimap + > +{}; + +template< + typename Archive,typename K,typename H,typename P,typename A +> +struct archive_input >: + boost::serialization::stl::archive_input_unordered_set< + Archive, + boost::unordered_set + > +{}; + +template< + typename Archive,typename K,typename H,typename P,typename A +> +struct archive_input >: + boost::serialization::stl::archive_input_unordered_multiset< + Archive, + boost::unordered_multiset + > +{}; + +#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 +struct load_or_save_fca_container; + +template +struct load_or_save_fca_container /* save */ +{ + template + void operator()(Archive& ar,Container& x,unsigned int version)const + { + serialize_container(ar,x,version); + } +}; + +template +struct load_or_save_fca_container /* load */ +{ + template + 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 + >(ar,x); +#else + throw_exception(legacy_archive_exception()); +#endif + } + else{ + serialize_container(ar,x,version); + } + } +}; + +template +void serialize_fca_container(Archive& ar,Container& x,unsigned int version) +{ + load_or_save_fca_container()( + ar,x,version); +} + +} /* namespace detail */ +} /* namespace unordered */ +} /* namespace boost */ + +#endif diff --git a/include/boost/unordered/detail/serialize_node_pointer.hpp b/include/boost/unordered/detail/serialize_node_pointer.hpp new file mode 100644 index 00000000..ea4a4da2 --- /dev/null +++ b/include/boost/unordered/detail/serialize_node_pointer.hpp @@ -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 +#include +#include +#include +#include + +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 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 +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 + void serialize(Archive&,unsigned int){} /* no data emitted */ +}; + +template +void track_node_pointer(Archive& ar,const Node* p) +{ + if(p){ + ar&core::make_nvp( + "node", + *reinterpret_cast*>(const_cast(p))); + } +} + +template +void serialize_node_pointer(Archive& ar,Node*& p,boost::true_type /* save */) +{ + typedef typename boost::remove_const::type node_type; + typedef serialization_tracker tracker; + + tracker* pn= + const_cast( + reinterpret_cast( + const_cast(p))); + ar< +void serialize_node_pointer(Archive& ar,Node*& p,boost::false_type /* load */) +{ + typedef typename boost::remove_const::type node_type; + typedef serialization_tracker tracker; + + tracker* pn; + ar>>core::make_nvp("pointer",pn); + p=const_cast( + reinterpret_cast( + const_cast(pn))); +} + +template +void serialize_node_pointer(Archive& ar,Node*& p) +{ + serialize_node_pointer( + ar,p, + boost::integral_constant()); +} + +} /* namespace detail */ +} /* namespace unordered */ +} /* namespace boost */ + +#endif diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 1f7984ec..1e829c1d 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -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 #include #include +#include #include #include @@ -696,6 +697,16 @@ namespace boost { return erase_if(map.table_, pred); } + template + void serialize( + Archive & ar, + unordered_flat_map& map, + unsigned int version) + { + detail::serialize_container(ar, map, version); + } + #if defined(BOOST_MSVC) #pragma warning(pop) /* C4714 */ #endif diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index a3c7748e..01cadf21 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -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 #include +#include #include #include @@ -505,6 +506,16 @@ namespace boost { return erase_if(set.table_, pred); } + template + void serialize( + Archive & ar, + unordered_flat_set& set, + unsigned int version) + { + detail::serialize_container(ar, set, version); + } + #if defined(BOOST_MSVC) #pragma warning(pop) /* C4714 */ #endif diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 35eb2f2e..b60acb75 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -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 +#include #include #include #include #include #include +#include #include #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -1059,6 +1060,13 @@ namespace boost { #endif }; // class template unordered_map + template + void serialize( + Archive & ar,unordered_map& m,unsigned int version) + { + detail::serialize_fca_container(ar, m, version); + } + #if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES template + void serialize( + Archive & ar,unordered_multimap& m,unsigned int version) + { + detail::serialize_fca_container(ar, m, version); + } + #if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES template + struct version > + { + BOOST_STATIC_CONSTANT(int, value = 1); + }; + + template + struct version > + { + BOOST_STATIC_CONSTANT(int, value = 1); + }; + } // namespace serialization + } // namespace boost #if defined(BOOST_MSVC) diff --git a/include/boost/unordered/unordered_node_map.hpp b/include/boost/unordered/unordered_node_map.hpp index 32bd5989..3329b1b6 100644 --- a/include/boost/unordered/unordered_node_map.hpp +++ b/include/boost/unordered/unordered_node_map.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -788,6 +789,16 @@ namespace boost { return erase_if(map.table_, pred); } + template + void serialize( + Archive & ar, + unordered_node_map& map, + unsigned int version) + { + detail::serialize_container(ar, map, version); + } + #if defined(BOOST_MSVC) #pragma warning(pop) /* C4714 */ #endif diff --git a/include/boost/unordered/unordered_node_set.hpp b/include/boost/unordered/unordered_node_set.hpp index 06833a8b..21d3d28f 100644 --- a/include/boost/unordered/unordered_node_set.hpp +++ b/include/boost/unordered/unordered_node_set.hpp @@ -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 #include #include +#include #include #include @@ -601,6 +602,16 @@ namespace boost { return erase_if(set.table_, pred); } + template + void serialize( + Archive & ar, + unordered_node_set& set, + unsigned int version) + { + detail::serialize_container(ar, set, version); + } + #if defined(BOOST_MSVC) #pragma warning(pop) /* C4714 */ #endif diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 23837b2d..7ebba5a9 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -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 #include #include +#include #include #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -641,6 +641,13 @@ namespace boost { #endif }; // class template unordered_set + template + void serialize( + Archive & ar,unordered_set& c,unsigned int version) + { + detail::serialize_fca_container(ar, c, version); + } + #if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES template + void serialize( + Archive & ar,unordered_multiset& c,unsigned int version) + { + detail::serialize_fca_container(ar, c, version); + } + #if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES template + struct version > + { + BOOST_STATIC_CONSTANT(int, value = 1); + }; + + template + struct version > + { + BOOST_STATIC_CONSTANT(int, value = 1); + }; + } // namespace serialization + } // namespace boost #if defined(BOOST_MSVC)