nfx-serialization 0.3.0
Cross-platform C++ JSON serialization library with extensible trait capabilities
Loading...
Searching...
No Matches
ContainersTraits.h
Go to the documentation of this file.
1/*
2 * MIT License
3 *
4 * Copyright (c) 2025 nfx
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
39
40#pragma once
41
45
46//=====================================================================
47// PerfectHashMap support - enabled only if header is available
48//=====================================================================
49
50#if __has_include( <nfx/containers/PerfectHashMap.h>)
51
52# include <nfx/containers/PerfectHashMap.h>
53
54namespace nfx::serialization::json
55{
59 template <typename TKey, typename TValue, typename HashType, HashType Seed, typename Hasher, typename KeyEqual>
60 struct SerializationTraits<nfx::containers::PerfectHashMap<TKey, TValue, HashType, Seed, Hasher, KeyEqual>>
61 {
68 static void serialize( const nfx::containers::PerfectHashMap<TKey, TValue, HashType, Seed, Hasher, KeyEqual>& obj, Document& doc )
69 {
70 // Create array to hold key-value pairs
71 doc.set<Document::Array>( "" );
72 auto arrayRef = doc.get<Document::Array>( "" );
73
74 if ( !arrayRef.has_value() )
75 {
76 return;
77 }
78
79 // Use PerfectHashMap's iterator to traverse all key-value pairs
80 for ( auto it = obj.begin(); it != obj.end(); ++it )
81 {
82 const auto& pair = *it;
83 const TKey& key = pair.first;
84 const TValue& value = pair.second;
85
86 // Create object for this key-value pair
87 Document pairDoc;
88 pairDoc.set<Document::Object>( "" );
89
90 // Serialize the key
91 Document keyDoc;
92 Serializer<TKey> keySerializer;
93 keyDoc = keySerializer.serialize( key );
94
95 // Serialize the value
96 Document valueDoc;
97 Serializer<TValue> valueSerializer;
98 valueDoc = valueSerializer.serialize( value );
99
100 // Add key and value to pair object
101 if ( keyDoc.is<std::string>( "" ) )
102 {
103 auto str = keyDoc.get<std::string>( "" );
104 pairDoc.set<std::string>( "/key", str.value() );
105 }
106 else if ( keyDoc.is<int>( "" ) )
107 {
108 auto val = keyDoc.get<int64_t>( "" );
109 pairDoc.set<int64_t>( "/key", val.value() );
110 }
111 else if ( keyDoc.is<double>( "" ) )
112 {
113 auto val = keyDoc.get<double>( "" );
114 pairDoc.set<double>( "/key", val.value() );
115 }
116 else if ( keyDoc.is<bool>( "" ) )
117 {
118 auto val = keyDoc.get<bool>( "" );
119 pairDoc.set<bool>( "/key", val.value() );
120 }
121 else if ( keyDoc.is<Document::Array>( "" ) || keyDoc.is<Document::Object>( "" ) )
122 {
123 pairDoc.set<Document>( "/key", keyDoc );
124 }
125
126 if ( valueDoc.is<std::string>( "" ) )
127 {
128 auto str = valueDoc.get<std::string>( "" );
129 pairDoc.set<std::string>( "/value", str.value() );
130 }
131 else if ( valueDoc.is<int>( "" ) )
132 {
133 auto val = valueDoc.get<int64_t>( "" );
134 pairDoc.set<int64_t>( "/value", val.value() );
135 }
136 else if ( valueDoc.is<double>( "" ) )
137 {
138 auto val = valueDoc.get<double>( "" );
139 pairDoc.set<double>( "/value", val.value() );
140 }
141 else if ( valueDoc.is<bool>( "" ) )
142 {
143 auto val = valueDoc.get<bool>( "" );
144 pairDoc.set<bool>( "/value", val.value() );
145 }
146 else if ( valueDoc.isNull( "" ) )
147 {
148 pairDoc.setNull( "/value" );
149 }
150 else if ( valueDoc.is<Document::Array>( "" ) || valueDoc.is<Document::Object>( "" ) )
151 {
152 pairDoc.set<Document>( "/value", valueDoc );
153 }
154
155 // Add pair to array
156 arrayRef->append<Document>( pairDoc );
157 }
158 }
159
166 static void deserialize( nfx::containers::PerfectHashMap<TKey, TValue, HashType, Seed, Hasher, KeyEqual>& obj, const Document& doc )
167 {
168 if ( !doc.is<Document::Array>( "" ) )
169 {
170 throw std::runtime_error( "Cannot deserialize non-array JSON value into PerfectHashMap" );
171 }
172
173 // Collect key-value pairs for PerfectHashMap construction
174 std::vector<std::pair<TKey, TValue>> items;
175
176 // Get array and iterate using STL iterator
177 auto arrayOpt = doc.get<Document::Array>( "" );
178 if ( arrayOpt.has_value() )
179 {
180 for ( const auto& pairDoc : arrayOpt.value() )
181 {
182 // Extract key
183 TKey key{};
184 if ( pairDoc.contains( "/key" ) )
185 {
186 Document keyDoc = pairDoc.get<Document>( "/key" ).value_or( Document{} );
187 Serializer<TKey> keySerializer;
188 key = keySerializer.deserialize( keyDoc );
189 }
190
191 // Extract value
192 TValue value{};
193 if ( pairDoc.contains( "/value" ) )
194 {
195 Document valueDoc = pairDoc.get<Document>( "/value" ).value_or( Document{} );
196 Serializer<TValue> valueSerializer;
197 value = valueSerializer.deserialize( valueDoc );
198 }
199
200 items.emplace_back( std::move( key ), std::move( value ) );
201 }
202 }
203
204 obj = nfx::containers::PerfectHashMap<TKey, TValue, HashType, Seed, Hasher, KeyEqual>( std::move( items ) );
205 }
206 };
207} // namespace nfx::serialization::json
208
209#endif // __has_include(<nfx/containers/PerfectHashMap.h>)
210
211//=====================================================================
212// FastHashMap support - enabled only if header is available
213//=====================================================================
214
215#if __has_include( <nfx/containers/FastHashMap.h>)
216
217# include <nfx/containers/FastHashMap.h>
218
219namespace nfx::serialization::json
220{
224 template <typename TKey, typename TValue, typename HashType, HashType Seed, typename Hasher, typename KeyEqual>
225 struct SerializationTraits<nfx::containers::FastHashMap<TKey, TValue, HashType, Seed, Hasher, KeyEqual>>
226 {
233 static void serialize( const nfx::containers::FastHashMap<TKey, TValue, HashType, Seed, Hasher, KeyEqual>& obj, Document& doc )
234 {
235 // Create array to hold key-value pairs
236 doc.set<Document::Array>( "" );
237 auto arrayRef = doc.get<Document::Array>( "" );
238
239 if ( !arrayRef.has_value() )
240 {
241 return;
242 }
243
244 // Use FastHashMap's iterator to traverse all key-value pairs
245 for ( auto it = obj.begin(); it != obj.end(); ++it )
246 {
247 const auto& pair = *it;
248 const TKey& key = pair.first;
249 const TValue& value = pair.second;
250
251 // Create object for this key-value pair
252 Document pairDoc;
253 pairDoc.set<Document::Object>( "" );
254
255 // Serialize the key
256 Document keyDoc;
257 Serializer<TKey> keySerializer;
258 keyDoc = keySerializer.serialize( key );
259
260 // Serialize the value
261 Document valueDoc;
262 Serializer<TValue> valueSerializer;
263 valueDoc = valueSerializer.serialize( value );
264
265 // Add key to pair object
266 if ( keyDoc.is<std::string>( "" ) )
267 {
268 auto str = keyDoc.get<std::string>( "" );
269 pairDoc.set<std::string>( "/key", str.value() );
270 }
271 else if ( keyDoc.is<int>( "" ) )
272 {
273 auto val = keyDoc.get<int64_t>( "" );
274 pairDoc.set<int64_t>( "/key", val.value() );
275 }
276 else if ( keyDoc.is<double>( "" ) )
277 {
278 auto val = keyDoc.get<double>( "" );
279 pairDoc.set<double>( "/key", val.value() );
280 }
281 else if ( keyDoc.is<bool>( "" ) )
282 {
283 auto val = keyDoc.get<bool>( "" );
284 pairDoc.set<bool>( "/key", val.value() );
285 }
286 else if ( keyDoc.is<Document::Array>( "" ) || keyDoc.is<Document::Object>( "" ) )
287 {
288 pairDoc.set<Document>( "/key", keyDoc );
289 }
290
291 // Add value to pair object
292 if ( valueDoc.is<std::string>( "" ) )
293 {
294 auto str = valueDoc.get<std::string>( "" );
295 pairDoc.set<std::string>( "/value", str.value() );
296 }
297 else if ( valueDoc.is<int>( "" ) )
298 {
299 auto val = valueDoc.get<int64_t>( "" );
300 pairDoc.set<int64_t>( "/value", val.value() );
301 }
302 else if ( valueDoc.is<double>( "" ) )
303 {
304 auto val = valueDoc.get<double>( "" );
305 pairDoc.set<double>( "/value", val.value() );
306 }
307 else if ( valueDoc.is<bool>( "" ) )
308 {
309 auto val = valueDoc.get<bool>( "" );
310 pairDoc.set<bool>( "/value", val.value() );
311 }
312 else if ( valueDoc.isNull( "" ) )
313 {
314 pairDoc.setNull( "/value" );
315 }
316 else if ( valueDoc.is<Document::Array>( "" ) || valueDoc.is<Document::Object>( "" ) )
317 {
318 pairDoc.set<Document>( "/value", valueDoc );
319 }
320
321 // Add pair to array
322 arrayRef->append<Document>( pairDoc );
323 }
324 }
325
332 static void deserialize( nfx::containers::FastHashMap<TKey, TValue, HashType, Seed, Hasher, KeyEqual>& obj, const Document& doc )
333 {
334 // Clear existing content
335 obj.clear();
336
337 // Check if it's an object format (standard JSON map representation)
338 if ( doc.is<Document::Object>( "" ) )
339 {
340 // Use Object iterator for object format
341 auto objectOpt = doc.get<Document::Object>( "" );
342 if ( objectOpt.has_value() )
343 {
344 for ( const auto& [keyStr, valueDoc] : objectOpt.value() )
345 {
346 // Deserialize key (typically string, but support other types)
347 TKey key{};
348 if constexpr ( std::is_same_v<TKey, std::string> )
349 {
350 key = keyStr;
351 }
352 else
353 {
354 Document keyDoc;
355 keyDoc.set( "", keyStr );
356 Serializer<TKey> keySerializer;
357 key = keySerializer.deserialize( keyDoc );
358 }
359
360 // Extract value
361 TValue value{};
362 Serializer<TValue> valueSerializer;
363 value = valueSerializer.deserialize( valueDoc );
364 obj.insertOrAssign( std::move( key ), std::move( value ) );
365 }
366 }
367 }
368 // Check if it's an array format (for backward compatibility)
369 else if ( doc.is<Document::Array>( "" ) )
370 {
371 // Get array and iterate using STL iterator
372 auto arrayOpt = doc.get<Document::Array>( "" );
373 if ( arrayOpt.has_value() )
374 {
375 for ( const auto& pairDoc : arrayOpt.value() )
376 {
377 // Extract key
378 TKey key{};
379 if ( pairDoc.contains( "/key" ) )
380 {
381 Document keyDoc = pairDoc.get<Document>( "/key" ).value_or( Document{} );
382 Serializer<TKey> keySerializer;
383 key = keySerializer.deserialize( keyDoc );
384 }
385
386 // Extract value
387 TValue value{};
388 if ( pairDoc.contains( "/value" ) )
389 {
390 Document valueDoc = pairDoc.get<Document>( "/value" ).value_or( Document{} );
391 Serializer<TValue> valueSerializer;
392 value = valueSerializer.deserialize( valueDoc );
393 }
394
395 obj.insertOrAssign( std::move( key ), std::move( value ) );
396 }
397 }
398 }
399 else
400 {
401 throw std::runtime_error( "Cannot deserialize JSON value into FastHashMap: must be object or array" );
402 }
403 }
404 };
405} // namespace nfx::serialization::json
406
407#endif // __has_include(<nfx/containers/FastHashMap.h>)
408
409//=====================================================================
410// FastHashSet support - enabled only if header is available
411//=====================================================================
412
413#if __has_include( <nfx/containers/FastHashSet.h>)
414
415# include <nfx/containers/FastHashSet.h>
416
417namespace nfx::serialization::json
418{
422 template <typename TKey, typename HashType, HashType Seed, typename Hasher, typename KeyEqual>
423 struct SerializationTraits<nfx::containers::FastHashSet<TKey, HashType, Seed, Hasher, KeyEqual>>
424 {
430 static void serialize( const nfx::containers::FastHashSet<TKey, HashType, Seed, Hasher, KeyEqual>& obj, Document& doc )
431 {
432 // Create array document
433 doc.set<Document::Array>( "" );
434 auto arrayRef = doc.get<Document::Array>( "" );
435
436 if ( arrayRef.has_value() )
437 {
438 // Use FastHashSet's iterator to traverse all elements
439 for ( auto it = obj.begin(); it != obj.end(); ++it )
440 {
441 const TKey& key = *it;
442
443 // Serialize the key using a temporary serializer
444 Document keyDoc;
445 Serializer<TKey> keySerializer;
446 keyDoc = keySerializer.serialize( key );
447
448 // Add to array based on type
449 if ( keyDoc.is<std::string>( "" ) )
450 {
451 auto str = keyDoc.get<std::string>( "" );
452 arrayRef->append<std::string>( str.value() );
453 }
454 else if ( keyDoc.is<int>( "" ) )
455 {
456 auto val = keyDoc.get<int64_t>( "" );
457 arrayRef->append<int64_t>( val.value() );
458 }
459 else if ( keyDoc.is<double>( "" ) )
460 {
461 auto val = keyDoc.get<double>( "" );
462 arrayRef->append<double>( val.value() );
463 }
464 else if ( keyDoc.is<bool>( "" ) )
465 {
466 auto val = keyDoc.get<bool>( "" );
467 arrayRef->append<bool>( val.value() );
468 }
469 else if ( keyDoc.is<Document::Object>( "" ) || keyDoc.is<Document::Array>( "" ) )
470 {
471 // Handle nested objects and arrays
472 arrayRef->append<Document>( keyDoc );
473 }
474 }
475 }
476 }
477
483 static void deserialize( nfx::containers::FastHashSet<TKey, HashType, Seed, Hasher, KeyEqual>& obj, const Document& doc )
484 {
485 if ( !doc.is<Document::Array>( "" ) )
486 {
487 throw std::runtime_error( "Cannot deserialize non-array JSON value into FastHashSet" );
488 }
489
490 // Clear existing content
491 obj.clear();
492
493 // Get array and iterate using STL iterator
494 auto arrayOpt = doc.get<Document::Array>( "" );
495 if ( arrayOpt.has_value() )
496 {
497 for ( const auto& elementDoc : arrayOpt.value() )
498 {
499 // Deserialize the key using a temporary serializer
500 TKey key{};
501 Serializer<TKey> keySerializer;
502 key = keySerializer.deserialize( elementDoc );
503
504 obj.insert( std::move( key ) );
505 }
506 }
507 }
508 };
509} // namespace nfx::serialization::json
510
511#endif // __has_include(<nfx/containers/FastHashSet.h>)
Generic document abstraction for JSON serialization.
Serialization traits and type specializations for JSON serialization.
Templated JSON serializer with compile-time type mapping.
Default serialization traits - users can specialize this.
static void serialize(const T &obj, Document &doc)
Default serialize implementation - delegates to member method.
static void deserialize(T &obj, const Document &doc)
Default deserialize implementation - delegates to member method.