2020#include " sst/core/serialization/impl/serialize_utility.h"
2121#include " sst/core/serialization/serializer.h"
2222
23+ #include < cstddef>
24+ #include < deque>
2325#include < forward_list>
26+ #include < list>
2427#include < map>
2528#include < set>
29+ #include < type_traits>
2630#include < unordered_map>
2731#include < unordered_set>
32+ #include < utility>
2833#include < vector>
2934
3035namespace SST ::Core::Serialization {
3136
32- // A type with begin(), end() methods with value_type elements which can call insert_element()
33- // to insert them in begin() to end() order
34- //
37+ // If the type is a pair with a const first, map it to pair with non-const first
38+ template <typename T>
39+ struct remove_const_key
40+ {
41+ using type = T;
42+ };
43+
44+ template <typename KEY, typename VALUE>
45+ struct remove_const_key <std::pair<const KEY, VALUE>>
46+ {
47+ using type = std::pair<KEY, VALUE>;
48+ };
49+
50+ // Whether a size() method exists for a type
51+ template <typename , typename = void >
52+ constexpr bool has_size_v = false ;
53+
54+ template <typename T>
55+ constexpr bool has_size_v<T, std::void_t <decltype (std::declval<T>().size())>> = true ;
56+
57+ // Whether std::distance(begin(), end()) exists for a type
58+ template <typename , typename = void >
59+ constexpr bool has_distance_v = false ;
60+
61+ template <typename T>
62+ constexpr bool
63+ has_distance_v<T, std::void_t <decltype (std::distance(std::declval<T>().begin(), std::declval<T>().end()))>> = true ;
64+
65+ // Get the size of a container, using a size() method if it exists, otherwise distance(begin, end)
66+ template <typename T>
67+ std::enable_if_t <has_size_v<T> || has_distance_v<T>, size_t >
68+ get_size (const T& t)
69+ {
70+ if constexpr ( has_size_v<T> )
71+ return t.size ();
72+ else
73+ return std::distance (t.begin (), t.end ());
74+ }
75+
76+ // Whether it is a std::vector<bool>
77+ template <typename >
78+ constexpr bool is_vector_bool_v = false ;
79+
80+ template <typename ... Ts>
81+ constexpr bool is_vector_bool_v<std::vector<bool , Ts...>> = true ;
82+
83+ // Whether it is a simple map (not a multimap and has integral, floating-point, enum, or convertible to string keys)
84+ template <typename , typename = void >
85+ constexpr bool is_simple_map_v = false ;
86+
87+ template <template <typename ...> class MAP , typename KEY, typename ... REST>
88+ constexpr bool is_simple_map_v<
89+ MAP<KEY, REST...>,
90+ std::enable_if_t <
91+ (is_same_template_v<MAP, std::map> || is_same_template_v<MAP, std::unordered_map>) &&
92+ (std::is_arithmetic_v<KEY> || std::is_enum_v<KEY> || std::is_convertible_v<KEY, std::string>)>> = true ;
93+
94+ // Whether it is a simple set (not a multiset and has integral, floating-point, enum, or convertible to string keys)
95+ template <typename , typename = void >
96+ constexpr bool is_simple_set_v = false ;
97+
98+ template <template <typename ...> class SET , typename KEY, typename ... REST>
99+ constexpr bool is_simple_set_v<
100+ SET<KEY, REST...>,
101+ std::enable_if_t <
102+ (is_same_template_v<SET, std::set> || is_same_template_v<SET, std::unordered_set>) &&
103+ (std::is_arithmetic_v<KEY> || std::is_enum_v<KEY> || std::is_convertible_v<KEY, std::string>)>> = true ;
104+
35105// std::deque
36106// std::forward_list
37107// std::list
@@ -45,171 +115,129 @@ namespace SST::Core::Serialization {
45115// std::unordered_set
46116// std::vector, including std::vector<bool>
47117//
48- // and any user-defined or future STL classes which have begin() and end() methods, a
49- // value_type element type, and an insert_element() overload which can append value_type
50-
51- template <class T >
118+ // clang-format off
119+ template <template <typename ...> class T , typename ... Ts>
52120class serialize_impl <
53- T, std::void_t <
54- // exclude std::string and std::string* to prevent specialization ambiguity
55- std::enable_if_t <!std::is_same_v<std::remove_pointer_t <T>, std::string>>,
56-
57- // whether begin() method exists
58- decltype (std::declval<T>().begin()),
59-
60- // whether end() method exists
61- decltype(std::declval<T>().end()),
62-
63- // whether a clear() method exists
64- decltype(std::declval<T>().clear()),
65-
66- // whether get_size() can determine size because it has a matching overload
67- decltype(get_size(std::declval<T>())),
68-
69- // whether insert_element() can insert value_type elements
70- decltype(insert_element(std::declval<T>(), std::declval<typename T::value_type>()))>>
121+ T<Ts...>, std::enable_if_t <
122+ is_same_template_v< T, std::deque > ||
123+ is_same_template_v< T, std::forward_list > ||
124+ is_same_template_v< T, std::list > ||
125+ is_same_template_v< T, std::map > ||
126+ is_same_template_v< T, std::multimap > ||
127+ is_same_template_v< T, std::multiset > ||
128+ is_same_template_v< T, std::set > ||
129+ is_same_template_v< T, std::unordered_map > ||
130+ is_same_template_v< T, std::unordered_multimap > ||
131+ is_same_template_v< T, std::unordered_multiset > ||
132+ is_same_template_v< T, std::unordered_set > ||
133+ is_same_template_v< T, std::vector >
134+ > >
135+ // clang-format on
71136{
72- // If the type is a pair with a const first, map it to pair with non-const first
73- template <typename U>
74- struct remove_const_key
75- {
76- using type = U;
77- };
137+ // Object type = container template with template arguments
138+ using OBJ = T<Ts...>;
78139
79- template <typename KEY, typename VALUE>
80- struct remove_const_key <std::pair<const KEY, VALUE>>
81- {
82- using type = std::pair<KEY, VALUE>;
83- };
84-
85- // Value type of element, with const removed from first of pair if it exists
86- using value_type = typename remove_const_key<typename T::value_type>::type;
87-
88- // Note: the following use struct templates because of a GCC bug which does
89- // not allow static constexpr variable templates defined inside of a class.
90-
91- // Whether it is a std::vector
92- template <typename >
93- struct is_vector : std::false_type
94- {};
95-
96- template <typename ... Ts>
97- struct is_vector <std::vector<Ts...>> : std::true_type
98- {};
99-
100- // Whether it is a std::vector<bool>
101- template <typename >
102- struct is_vector_bool : std::false_type
103- {};
104-
105- template <typename ... Ts>
106- struct is_vector_bool <std::vector<bool , Ts...>> : std::true_type
107- {};
108-
109- // Whether it is a std::forward_list
110- template <typename >
111- struct is_forward_list : std::false_type
112- {};
113-
114- template <typename ... Ts>
115- struct is_forward_list <std::forward_list<Ts...>> : std::true_type
116- {};
117-
118- // Whether it is a simple map (not a multimap and has integral, floating-point, enum, or convertible to string keys)
119- template <typename , typename = void >
120- struct is_simple_map : std::false_type
121- {};
122-
123- template <template <typename ...> class MAP , typename KEY, typename ... REST>
124- struct is_simple_map <
125- MAP<KEY, REST...>,
126- std::enable_if_t <(is_same_template_v<MAP, std::map> || is_same_template_v<MAP, std::unordered_map>)&&(
127- std::is_arithmetic_v<KEY> || std::is_enum_v<KEY> || std::is_convertible_v<KEY, std::string>)>> :
128- std::true_type
129- {};
130-
131- // Whether it is a simple set (not a multiset and has integral, floating-point, enum, or convertible to string keys)
132- template <typename , typename = void >
133- struct is_simple_set : std::false_type
134- {};
135-
136- template <template <typename ...> class SET , typename KEY, typename ... REST>
137- struct is_simple_set <
138- SET<KEY, REST...>,
139- std::enable_if_t <(is_same_template_v<SET, std::set> || is_same_template_v<SET, std::unordered_set>)&&(
140- std::is_arithmetic_v<KEY> || std::is_enum_v<KEY> || std::is_convertible_v<KEY, std::string>)>> :
141- std::true_type
142- {};
140+ // Value type of element with const removed from first of pair if it exists
141+ using value_type = typename remove_const_key<typename OBJ::value_type>::type;
143142
144143public:
145- void operator ()(T& t , serializer& ser)
144+ void operator ()(OBJ& obj , serializer& ser)
146145 {
147146 switch ( const auto mode = ser.mode () ) {
148147 case serializer::SIZER:
149148 case serializer::PACK:
150149 {
151- size_t size = get_size (t );
150+ size_t size = get_size (obj );
152151
153152 if ( mode == serializer::PACK )
154153 ser.pack (size);
155154 else
156155 ser.size (size);
157156
158- if constexpr ( is_vector_bool<T>::value ) {
157+ if constexpr ( is_vector_bool_v<OBJ> ) {
159158 // For std::vector<bool>, iterate over bool values instead of references to elements
160- for ( bool e : t )
161- ser& e ;
159+ for ( bool e : obj )
160+ SST_SER (e) ;
162161 }
163162 else {
164163 // Iterate over references to elements, casting away any const in keys
165- for ( auto & e : t )
166- ser&( value_type&)e ;
164+ for ( auto & e : obj )
165+ SST_SER (( value_type&) e) ;
167166 }
168167 break ;
169168 }
170169
171170 case serializer::UNPACK:
172171 {
172+ // Get the total size of the container
173173 size_t size;
174174 ser.unpack (size);
175175
176- t.clear (); // Clear the container
177- if constexpr ( is_vector<T>::value ) t.reserve (size); // Reserve size of vector
178-
179- // For std::forward_list, last is iterator of last element inserted
180- decltype (t.begin ()) last [[maybe_unused]];
181- if constexpr ( is_forward_list<T>::value ) last = t.before_begin ();
182-
183- for ( size_t i = 0 ; i < size; ++i ) {
184- value_type e {}; // For now, elements have to be default-initializable
185- ser& e; // Unpack the element
186-
187- // Insert the element, moving it for efficiency
188- if constexpr ( is_forward_list<T>::value )
189- last = insert_element (t, std::move (e), last);
190- else
191- insert_element (t, std::move (e));
176+ // Erase the container
177+ obj.clear ();
178+ if constexpr ( is_same_template_v<T, std::vector> ) obj.reserve (size); // Reserve size of vector
179+
180+ if constexpr ( is_same_template_v<T, std::forward_list> ) {
181+ auto last = obj.before_begin (); // iterator of last element inserted
182+ for ( size_t i = 0 ; i < size; ++i ) {
183+ last = obj.emplace_after (last);
184+ auto & value = *last;
185+ SST_SER (value);
186+ }
187+ }
188+ else {
189+ for ( size_t i = 0 ; i < size; ++i ) {
190+ if constexpr ( is_same_template_v<T, std::map> || is_same_template_v<T, std::unordered_map> ) {
191+ typename OBJ::key_type key {};
192+ SST_SER (key);
193+ auto & value = obj[std::move (key)];
194+ SST_SER (value);
195+ }
196+ else if constexpr (
197+ is_same_template_v<T, std::multimap> || is_same_template_v<T, std::unordered_multimap> ) {
198+ typename OBJ::key_type key {};
199+ SST_SER (key);
200+ auto & value = obj.emplace (std::move (key), typename OBJ::mapped_type {})->second ;
201+ SST_SER (value);
202+ }
203+ else if constexpr (
204+ is_same_template_v<T, std::set> || is_same_template_v<T, std::unordered_set> ||
205+ is_same_template_v<T, std::multiset> || is_same_template_v<T, std::unordered_multiset> ) {
206+ typename OBJ::key_type key {};
207+ SST_SER (key);
208+ obj.emplace (std::move (key));
209+ }
210+ else if constexpr ( is_vector_bool_v<OBJ> ) {
211+ bool value {};
212+ SST_SER (value);
213+ obj.push_back (value);
214+ }
215+ else { // std::vector, std::deque, std::list
216+ auto & value = obj.emplace_back ();
217+ SST_SER (value);
218+ }
219+ }
192220 }
193- // assert(size == get_size(t ));
221+ // assert(size == get_size(obj ));
194222 break ;
195223 }
196224
197225 case serializer::MAP:
198226 {
199227 using SST::Core::to_string;
200228 const std::string& name = ser.getMapName ();
201- auto * obj_map = new ObjectMapContainer<T >(&t );
229+ auto * obj_map = new ObjectMapContainer<OBJ >(&obj );
202230 ser.mapper ().map_hierarchy_start (name, obj_map);
203231
204- if constexpr ( is_vector_bool<T>::value ) {
232+ if constexpr ( is_vector_bool_v<OBJ> ) {
205233 // std::vector<bool>
206234 size_t i = 0 ;
207- for ( bool e : t )
235+ for ( bool e : obj )
208236 sst_map_object (ser, e, to_string (i++));
209237 }
210- else if constexpr ( is_simple_map<T>::value ) {
238+ else if constexpr ( is_simple_map_v<OBJ> ) {
211239 // non-multi maps with a simple key
212- for ( auto & [key, value] : t )
240+ for ( auto & [key, value] : obj )
213241 sst_map_object (ser, value, to_string (key));
214242 }
215243 // TODO: handle is_simple_set
@@ -218,7 +246,7 @@ class serialize_impl<
218246 // std::unordered_multimap, std::multiset, std::unordered_multiset, and
219247 // std::map, std::set, std::unordered_map std::unordered_set with non-simple keys
220248 size_t i = 0 ;
221- for ( auto & e : t )
249+ for ( auto & e : obj )
222250 sst_map_object (ser, (value_type&)e, to_string (i++));
223251 }
224252 ser.mapper ().map_hierarchy_end ();
0 commit comments