1/* Copyright 2023 Joaquin M Lopez Munoz.
2 * Distributed under the Boost Software License, Version 1.0.
3 * (See accompanying file LICENSE_1_0.txt or copy at
4 * http://www.boost.org/LICENSE_1_0.txt)
5 *
6 * See https://www.boost.org/libs/unordered for library home page.
7 */
8
9#ifndef BOOST_UNORDERED_DETAIL_SERIALIZE_CONTAINER_HPP
10#define BOOST_UNORDERED_DETAIL_SERIALIZE_CONTAINER_HPP
11
12#include <boost/core/serialization.hpp>
13#include <boost/throw_exception.hpp>
14#include <boost/unordered/detail/archive_constructed.hpp>
15#include <boost/unordered/detail/bad_archive_exception.hpp>
16#include <boost/unordered/detail/serialization_version.hpp>
17#include <cstddef>
18
19namespace boost{
20namespace unordered{
21namespace detail{
22
23/* serialize_container(ar,x,v) serializes any of the unordered associative
24 * containers in Boost.Unordered. Iterator serialization is also supported
25 * through the following protocol:
26 * - At saving time, for each iterator it in [x.begin(),x.end()),
27 * serialization_track(ar,it) is ADL-called to instruct the archive to
28 * track the positions internally pointed to by the iterator via
29 * track_address().
30 * - At loading time, these addresses are mapped to those of the equivalent
31 * reconstructed positions using again serialization_track(ar,it).
32 * - Serializing an iterator reduces to serializing pointers to previously
33 * tracked addresses via serialize_address().
34 */
35
36template<typename Iterator>
37std::pair<Iterator,bool> adapt_insert_return_type(Iterator it)
38{
39 return std::pair<Iterator,bool>(it,true);
40}
41
42template<typename Iterator>
43std::pair<Iterator,bool> adapt_insert_return_type(std::pair<Iterator,bool> p)
44{
45 return p;
46}
47
48template<typename Set,bool IsSaving> struct load_or_save_unordered_set;
49
50template<typename Set> struct load_or_save_unordered_set<Set,true> /* save */
51{
52 template<typename Archive>
53 void operator()(Archive& ar,const Set& x,unsigned int)const
54 {
55 typedef typename Set::value_type value_type;
56 typedef typename Set::const_iterator const_iterator;
57
58 const std::size_t s=x.size();
59 const serialization_version<value_type> value_version;
60
61 ar<<core::make_nvp(n: "count",v: s);
62 ar<<core::make_nvp("value_version",value_version);
63
64 for(const_iterator first=x.begin(),last=x.end();first!=last;++first){
65 core::save_construct_data_adl(ar,std::addressof(*first),value_version);
66 ar<<core::make_nvp("item",*first);
67 serialization_track(ar,first);
68 }
69 }
70};
71
72template<typename Set> struct load_or_save_unordered_set<Set,false> /* load */
73{
74 template<typename Archive>
75 void operator()(Archive& ar,Set& x,unsigned int)const
76 {
77 typedef typename Set::value_type value_type;
78 typedef typename Set::iterator iterator;
79
80 std::size_t s;
81 serialization_version<value_type> value_version;
82
83 ar>>core::make_nvp(n: "count",v&: s);
84 ar>>core::make_nvp("value_version",value_version);
85
86 x.clear();
87 x.reserve(s); /* critical so that iterator tracking is stable */
88
89 for(std::size_t n=0;n<s;++n){
90 archive_constructed<value_type> value("item",ar,value_version);
91
92 std::pair<iterator,bool> p=adapt_insert_return_type(
93 x.insert(std::move(value.get())));
94 if(!p.second)throw_exception(e: bad_archive_exception());
95 ar.reset_object_address(
96 std::addressof(*p.first),std::addressof(value.get()));
97 serialization_track(ar,p.first);
98 }
99 }
100};
101
102template<typename Map,bool IsSaving> struct load_or_save_unordered_map;
103
104template<typename Map> struct load_or_save_unordered_map<Map,true> /* save */
105{
106 template<typename Archive>
107 void operator()(Archive& ar,const Map& x,unsigned int)const
108 {
109 typedef typename std::remove_const<
110 typename Map::key_type>::type key_type;
111 typedef typename std::remove_const<
112 typename Map::mapped_type>::type mapped_type;
113 typedef typename Map::const_iterator const_iterator;
114
115 const std::size_t s=x.size();
116 const serialization_version<key_type> key_version;
117 const serialization_version<mapped_type> mapped_version;
118
119 ar<<core::make_nvp(n: "count",v: s);
120 ar<<core::make_nvp("key_version",key_version);
121 ar<<core::make_nvp("mapped_version",mapped_version);
122
123 for(const_iterator first=x.begin(),last=x.end();first!=last;++first){
124 /* To remain lib-independent from Boost.Serialization and not rely on
125 * the user having included the serialization code for std::pair
126 * (boost/serialization/utility.hpp), we serialize the key and the
127 * mapped value separately.
128 */
129
130 core::save_construct_data_adl(
131 ar,std::addressof(first->first),key_version);
132 ar<<core::make_nvp("key",first->first);
133 core::save_construct_data_adl(
134 ar,std::addressof(first->second),mapped_version);
135 ar<<core::make_nvp("mapped",first->second);
136 serialization_track(ar,first);
137 }
138 }
139};
140
141template<typename Map> struct load_or_save_unordered_map<Map,false> /* load */
142{
143 template<typename Archive>
144 void operator()(Archive& ar,Map& x,unsigned int)const
145 {
146 typedef typename std::remove_const<
147 typename Map::key_type>::type key_type;
148 typedef typename std::remove_const<
149 typename Map::mapped_type>::type mapped_type;
150 typedef typename Map::iterator iterator;
151
152 std::size_t s;
153 serialization_version<key_type> key_version;
154 serialization_version<mapped_type> mapped_version;
155
156 ar>>core::make_nvp(n: "count",v&: s);
157 ar>>core::make_nvp("key_version",key_version);
158 ar>>core::make_nvp("mapped_version",mapped_version);
159
160 x.clear();
161 x.reserve(s); /* critical so that iterator tracking is stable */
162
163 for(std::size_t n=0;n<s;++n){
164 archive_constructed<key_type> key("key",ar,key_version);
165 archive_constructed<mapped_type> mapped("mapped",ar,mapped_version);
166
167 std::pair<iterator,bool> p=adapt_insert_return_type(
168 x.emplace(std::move(key.get()),std::move(mapped.get())));
169 if(!p.second)throw_exception(e: bad_archive_exception());
170 ar.reset_object_address(
171 std::addressof(p.first->first),std::addressof(key.get()));
172 ar.reset_object_address(
173 std::addressof(p.first->second),std::addressof(mapped.get()));
174 serialization_track(ar,p.first);
175 }
176 }
177};
178
179template<typename Container,bool IsSet,bool IsSaving>
180struct load_or_save_container;
181
182template<typename Set,bool IsSaving>
183struct load_or_save_container<Set,true,IsSaving>:
184 load_or_save_unordered_set<Set,IsSaving>{};
185
186template<typename Map,bool IsSaving>
187struct load_or_save_container<Map,false,IsSaving>:
188 load_or_save_unordered_map<Map,IsSaving>{};
189
190template<typename Archive,typename Container>
191void serialize_container(Archive& ar,Container& x,unsigned int version)
192{
193 load_or_save_container<
194 Container,
195 std::is_same<
196 typename Container::key_type,typename Container::value_type>::value,
197 Archive::is_saving::value>()(ar,x,version);
198}
199
200} /* namespace detail */
201} /* namespace unordered */
202} /* namespace boost */
203
204#endif
205

source code of boost/libs/unordered/include/boost/unordered/detail/serialize_container.hpp