]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/json/test/snippets.cpp
c6e0305320544ae7e50c6b79ed1027696ee2faaa
[ceph.git] / ceph / src / boost / libs / json / test / snippets.cpp
1 //
2 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/boostorg/json
8 //
9
10 #include <boost/json.hpp>
11
12 #ifndef BOOST_JSON_STANDALONE
13
14 #include <algorithm>
15 #include <cmath>
16 #include <complex>
17 #include <iostream>
18 #include <map>
19 #include <numeric>
20 #include <string>
21 #include <unordered_map>
22 #include <vector>
23
24 #include "test_suite.hpp"
25
26 #ifdef _MSC_VER
27 # pragma warning(push)
28 # pragma warning(disable: 4101)
29 #elif defined(__clang__)
30 # pragma clang diagnostic push
31 # pragma clang diagnostic ignored "-Wunused"
32 # pragma clang diagnostic ignored "-Wmismatched-tags"
33 #elif defined(__GNUC__)
34 # pragma GCC diagnostic push
35 # pragma GCC diagnostic ignored "-Wunused"
36 #endif
37
38 //[snippet_conv_3
39
40 template< std::size_t N >
41 struct static_string { };
42
43 namespace std
44 {
45
46 template< std::size_t N >
47 class hash< static_string< N > >
48 {
49 public:
50 std::size_t
51 operator()(const static_string< N >& str ) const noexcept
52 {
53 return std::hash< std::string >()( str );
54 }
55 };
56
57 } // std
58
59 //]
60
61 BOOST_JSON_NS_BEGIN
62
63 //[snippet_conv_4
64
65 template< class T >
66 void
67 tag_invoke( const value_from_tag&, value& jv, std::complex< T > const& t)
68 {
69 // Store a complex number as a 2-element array
70 // with the real part followed by the imaginary part
71 jv = { t.real(), t.imag() };
72 }
73
74 template< class T >
75 std::complex< T >
76 tag_invoke( const value_to_tag< std::complex< T > >&, value const& jv )
77 {
78 return std::complex< T >(
79 jv.as_array().at(0).to_number< T >(),
80 jv.as_array().at(1).to_number< T >());
81 }
82
83 //]
84
85 namespace {
86
87 void
88 usingStrings()
89 {
90 {
91 //[snippet_strings_1
92
93 string str1; // empty string, uses the default memory resource
94
95 string str2( make_shared_resource<monotonic_resource>() ); // empty string, uses a counted monotonic resource
96
97 //]
98 }
99 {
100 //[snippet_strings_2
101
102 std::string sstr1 = "helloworld";
103 std::string sstr2 = "world";
104
105 json::string jstr1 = "helloworld";
106 json::string jstr2 = "world";
107
108 assert( jstr2.insert(0, jstr1.subview(0, 5)) == "helloworld" );
109
110 // this is equivalent to
111 assert( sstr2.insert(0, sstr1, 0, 5) == "helloworld" );
112
113 //]
114 }
115 {
116 //[snippet_strings_3
117
118 std::string sstr = "hello";
119
120 json::string jstr = "hello";
121
122 assert(sstr.append({'w', 'o', 'r', 'l', 'd'}) == "helloworld");
123
124 // such syntax is inefficient, and the same can
125 // be achieved with a character array.
126
127 assert(jstr.append("world") == "helloworld");
128
129 //]
130 }
131
132 {
133 //[snippet_strings_4
134
135 json::string str = "Boost.JSON";
136 json::string_view sv = str;
137
138 // all of these call compare(string_view)
139 str.compare(sv);
140
141 str.compare(sv.substr(0, 5));
142
143 str.compare(str);
144
145 str.compare("Boost");
146
147 //]
148 }
149 }
150
151 //----------------------------------------------------------
152
153 void
154 usingValues()
155 {
156 {
157 //[snippet_value_1
158
159 value jv1;
160 value jv2( nullptr );
161
162 assert( jv1.is_null() );
163 assert( jv2.is_null() );
164
165 //]
166 }
167 {
168 //[snippet_value_2
169
170 value jv( object_kind );
171
172 assert( jv.kind() == kind::object );
173 assert( jv.is_object() );
174 assert( ! jv.is_number() );
175
176 //]
177 }
178 {
179 auto f = []{
180 //[snippet_value_3
181
182 value jv( object_kind );
183
184 if( auto p = jv.if_object() )
185 return p->size();
186
187 //]
188 return std::size_t(0);
189 };
190 (void)f;
191 }
192 {
193 //[snippet_value_4
194
195 value jv;
196 jv = value( array_kind );
197
198 assert( jv.is_array() );
199
200 jv.emplace_string();
201
202 assert( jv.is_string() );
203
204 //]
205 }
206 {
207 //[snippet_value_5
208
209 value jv;
210 jv.emplace_string() = "Hello, world!";
211
212 int64_t& num = jv.emplace_int64();
213 num = 1;
214
215 assert( jv.is_int64() );
216
217 //]
218 }
219 {
220 try
221 {
222 //[snippet_value_6
223
224 value jv( true );
225 jv.as_bool() = true;
226
227 jv.as_string() = "Hello, world!"; // throws an exception
228
229 //]
230 }
231 catch(...)
232 {
233 }
234 }
235 {
236 //[snippet_value_7
237
238 value jv( string_kind );
239 if( string* str = jv.if_string() )
240 *str = "Hello, world!";
241
242 //]
243 }
244 {
245 //[snippet_value_8
246
247 value jv( string_kind );
248
249 // The compiler's static analysis can see that
250 // a null pointer is never dereferenced.
251 *jv.if_string() = "Hello, world!";
252
253 //]
254 }
255 }
256
257 //----------------------------------------------------------
258
259 void
260 usingInitLists()
261 {
262 {
263 //[snippet_init_list_1
264
265 value jv = {
266 { "name", "John Doe" },
267 { "active", true },
268 { "associated-accounts", nullptr },
269 { "total-balance", 330.00 },
270 { "account-balances", { 84, 120, 126 } } };
271
272 //]
273 }
274
275 {
276 //[snippet_init_list_2
277
278 value jv = { true, 2, "hello", nullptr };
279
280 assert( jv.is_array() );
281
282 assert( jv.as_array().size() == 4 );
283
284 assert( serialize(jv) == "[true,2,\"hello\",null]" );
285
286 //]
287 }
288
289 {
290 //[snippet_init_list_3
291
292 value jv = { true, 2, "hello", { "bye", nullptr, false } };
293
294 assert( jv.is_array() );
295
296 assert( jv.as_array().back().is_array() );
297
298 assert( serialize(jv) == "[true,2,\"hello\",[\"bye\",null,false]]" );
299
300 //]
301 }
302
303 {
304 //[snippet_init_list_4
305
306 // Should this be an array or an object?
307 value jv = { { "hello", 42 }, { "world", 43 } };
308
309 //]
310 }
311
312 {
313 //[snippet_init_list_5
314
315 value jv1 = { { "hello", 42 }, { "world", 43 } };
316
317 assert( jv1.is_object() );
318
319 assert( jv1.as_object().size() == 2 );
320
321 assert( serialize(jv1) == R"({"hello":42,"world":43})" );
322
323 // All of the following are arrays
324
325 value jv2 = { { "make", "Tesla" }, { "model", 3 }, "black" };
326
327 value jv3 = { { "library", "JSON" }, { "Boost", "C++", "Fast", "JSON" } };
328
329 value jv4 = { { "color", "blue" }, { 1, "red" } };
330
331 assert( jv2.is_array() && jv3.is_array() && jv4.is_array() );
332
333 //]
334 }
335
336 {
337 //[snippet_init_list_6
338
339 value jv = { { "hello", 42 }, array{ "world", 43 } };
340
341 assert( jv.is_array() );
342
343 array& ja = jv.as_array();
344
345 assert( ja[0].is_array() && ja[1].is_array());
346
347 assert ( serialize(jv) == R"([["hello",42],["world",43]])" );
348
349 //]
350
351 (void)ja;
352 }
353
354 {
355 //[snippet_init_list_7
356
357 value jv = { { "mercury", 36 }, { "venus", 67 }, { "earth", 93 } };
358
359 assert( jv.is_object() );
360
361 assert( serialize(jv) == "{\"mercury\":36,\"venus\":67,\"earth\":93}" );
362
363 array ja = { { "mercury", 36 }, { "venus", 67 }, { "earth", 93 } };
364
365 assert( serialize(ja) == "[[\"mercury\",36],[\"venus\",67],[\"earth\",93]]" );
366
367 //]
368
369 (void)ja;
370 }
371
372 {
373 //[snippet_init_list_8
374
375 object jo = { { "mercury", { { "distance", 36 } } }, { "venus", { 67, "million miles" } }, { "earth", 93 } };
376
377 assert( jo["mercury"].is_object() );
378
379 assert( jo["venus"].is_array() );
380
381 //]
382 }
383
384 {
385 //[snippet_init_list_9
386
387 object jo1 = { { "john", 100 }, { "dave", 500 }, { "joe", 300 } };
388
389 value jv = { { "clients", std::move(jo1) } };
390
391 object& jo2 = jv.as_object()["clients"].as_object();
392
393 assert( ! jo2.empty() && jo1.empty() );
394
395 assert( serialize(jv) == R"({"clients":{"john":100,"dave":500,"joe":300}})" );
396
397 //]
398
399 (void)jo2;
400 }
401 }
402
403 //----------------------------------------------------------
404
405 void
406 usingArrays()
407 {
408 {
409 //[snippet_arrays_1
410
411 array arr1; // empty array, uses the default memory resource
412
413 array arr2( make_shared_resource<monotonic_resource>() ); // empty array, uses a counted monotonic resource
414
415 //]
416 }
417 {
418 //[snippet_arrays_2
419
420 array arr( { "Hello", 42, true } );
421
422 //]
423 }
424 try
425 {
426 //[snippet_arrays_3
427
428 array arr;
429
430 arr.emplace_back( "Hello" );
431 arr.emplace_back( 42 );
432 arr.emplace_back( true );
433
434 //]
435
436 //[snippet_arrays_4
437
438 assert( arr[0].as_string() == "Hello" );
439
440 // The following line throws std::out_of_range, since the index is out of range
441 arr.at( 3 ) = nullptr;
442
443 //]
444 }
445 catch (...)
446 {
447 }
448 }
449
450 //----------------------------------------------------------
451
452 void
453 usingObjects()
454 {
455 {
456 //[snippet_objects_1
457
458 object obj1; // empty object, uses the default memory resource
459
460 object obj2( make_shared_resource<monotonic_resource>() ); // empty object, uses a counted monotonic resource
461
462 //]
463 }
464 {
465 //[snippet_objects_2
466
467 object obj( {{"key1", "value1" }, { "key2", 42 }, { "key3", false }} );
468
469 //]
470 }
471 {
472 //[snippet_objects_3
473
474 object obj;
475
476 obj.emplace( "key1", "value1" );
477 obj.emplace( "key2", 42 );
478 obj.emplace( "key3", false );
479
480 //]
481 }
482 try
483 {
484 //[snippet_objects_4
485
486 object obj;
487
488 obj["key1"] = "value1";
489 obj["key2"] = 42;
490 obj["key3"] = false;
491
492 // The following line throws std::out_of_range, since the key does not exist
493 obj.at( "key4" );
494
495 //]
496 }
497 catch (...)
498 {
499 }
500 }
501
502 //----------------------------------------------------------
503
504 //[snippet_conv_2
505
506 template< class T >
507 void identity_swap( T& a, T& b )
508 {
509 // introduces the declaration of
510 // std::swap into this scope
511 using std::swap;
512 if( &a == &b )
513 return;
514 // the overload set will contain std::swap,
515 // any declarations of swap within the enclosing
516 // namespace, and any declarations of swap within
517 // the namespaces associated with T
518 swap( a, b );
519 }
520
521 //]
522
523 //[snippet_conv_5
524
525 template< class T >
526 struct vec3
527 {
528 T x, y, z;
529 };
530
531 template< class T >
532 void tag_invoke( const value_from_tag&, value& jv, const vec3<T>& vec )
533 {
534 jv = {
535 { "x", vec.x },
536 { "y", vec.y },
537 { "z", vec.z }
538 };
539 }
540
541 //]
542
543 #ifdef BOOST_JSON_DOCS
544 //[snippet_conv_7
545
546 template< class T, typename std::enable_if<
547 std::is_floating_point< T >::value>::type* = nullptr >
548 void tag_invoke( const value_from_tag&, value& jv, T t )
549 {
550 jv = std::llround( t );
551 }
552
553 //]
554 #endif
555
556 //[snippet_conv_10
557
558 struct customer
559 {
560 std::uint64_t id;
561 std::string name;
562 bool late;
563
564 customer() = default;
565
566 customer( std::uint64_t i, const std::string& n, bool l )
567 : id( i ), name( n ), late( l ) { }
568
569 explicit customer( value const& );
570 };
571
572 void tag_invoke( const value_from_tag&, value& jv, customer const& c )
573 {
574 // Assign a JSON value
575 jv = {
576 { "id", c.id },
577 { "name", c.name },
578 { "late", c.late }
579 };
580 }
581
582 //]
583
584 //[snippet_conv_14
585
586 customer tag_invoke( const value_to_tag<customer>&, const value& jv )
587 {
588 // at() throws if `jv` is not an object, or if the key is not found.
589 // as_uint64() will throw if the value is not an unsigned 64-bit integer.
590 std::uint64_t id = jv.at( "id" ).as_uint64();
591
592 // We already know that jv is an object from
593 // the previous call to jv.as_object() succeeding,
594 // now we use jv.get_object() which skips the
595 // check. value_to will throw if jv.kind() != kind::string
596 std::string name = value_to< std::string >( jv.get_object().at( "name" ) );
597
598 // id and name are constructed from JSON in the member
599 // initializer list above, but we can also use regular
600 // assignments in the body of the function as shown below.
601 // as_bool() will throw if kv.kind() != kind::bool
602 bool late = jv.get_object().at( "late" ).as_bool();
603
604 return customer(id, name, late);
605 }
606
607 //]
608
609 void
610 usingExchange()
611 {
612 {
613 //[snippet_conv_1
614
615 std::vector< int > v1{ 1, 2, 3, 4 };
616
617 // Convert the vector to a JSON array
618 value jv = value_from( v1 );
619
620 assert( jv.is_array() );
621
622 array& ja = jv.as_array();
623
624 assert( ja.size() == 4 );
625
626 for ( std::size_t i = 0; i < v1.size(); ++i )
627 assert( v1[i] == ja[i].as_int64() );
628
629 // Convert back to vector< int >
630 std::vector< int > v2 = value_to< std::vector< int > >( jv );
631
632 assert( v1 == v2 );
633
634 //]
635
636 (void)ja;
637 }
638 {
639 //[snippet_conv_6
640
641 vec3< int > pos = { 4, 1, 4 };
642
643 value jv = value_from( pos );
644
645 assert( serialize( jv ) == "{\"x\":4,\"y\":1,\"z\":4}" );
646
647 //]
648 }
649 {
650 //[snippet_conv_8
651
652 value jv = value_from( 1.5 ); // error
653
654 //]
655 }
656 {
657 //[snippet_conv_9
658
659 std::map< std::string, vec3< int > > positions = {
660 { "Alex", { 42, -60, 18 } },
661 { "Blake", { 300, -60, -240} },
662 { "Carol", { -60, 30, 30 } }
663 };
664
665 // conversions are applied recursively;
666 // the key type and value type will be converted
667 // using value_from as well
668 value jv = value_from( positions );
669
670 assert( jv.is_object() );
671
672 object& jo = jv.as_object();
673
674 assert( jo.size() == 3 );
675
676 // The sum of the coordinates is 0
677 assert( std::accumulate( jo.begin(), jo.end(), std::int64_t(0),
678 []( std::int64_t total, const key_value_pair& jp )
679 {
680 assert ( jp.value().is_object() );
681
682 const object& pos = jp.value().as_object();
683
684 return total + pos.at( "x" ).as_int64() +
685 pos.at( "y" ).as_int64() +
686 pos.at( "z" ).as_int64();
687
688 } ) == 0 );
689
690 //]
691
692 (void)jo;
693 }
694 {
695 //[snippet_conv_11
696
697 std::vector< customer > customers = {
698 customer( 0, "Alison", false ),
699 customer( 1, "Bill", false ),
700 customer( 3, "Catherine", true ),
701 customer( 4, "Doug", false )
702 };
703
704 storage_ptr sp = make_shared_resource< monotonic_resource >();
705
706 value jv = value_from( customers, sp );
707
708 assert( jv.storage() == sp );
709
710 assert( jv.is_array() );
711
712 //]
713 }
714
715 {
716 //[snippet_conv_12
717
718 // Satisfies both FromMapLike and FromContainerLike
719 std::unordered_map< std::string, bool > available_tools = {
720 { "Crowbar", true },
721 { "Hammer", true },
722 { "Drill", true },
723 { "Saw", false },
724 };
725
726 value jv = value_from( available_tools );
727
728 assert( jv.is_object() );
729
730 //]
731 }
732 {
733 //[snippet_conv_13
734
735 std::complex< double > c1 = { 3.14159, 2.71828 };
736
737 // Convert a complex number to JSON
738 value jv = value_from( c1 );
739
740 assert ( jv.is_array() );
741
742 // Convert back to a complex number
743
744 std::complex< double > c2 = value_to< std::complex< double > >( jv );
745
746 //]
747
748 (void)c2;
749 }
750 {
751 //[snippet_conv_15
752
753 customer c1( 5, "Ed", false );
754
755 // Convert customer to value
756 value jv = value_from( c1 );
757
758 // Convert the result back to customer
759 customer c2 = value_to< customer >( jv );
760
761 // The resulting customer is unchanged
762 assert( c1.name == c2.name );
763
764 //]
765 }
766 {
767 //[snippet_conv_16
768
769 value available_tools = {
770 { "Crowbar", true },
771 { "Hammer", true },
772 { "Drill", true },
773 { "Saw", false }
774 };
775
776 assert( available_tools.is_object() );
777
778 auto as_map = value_to< std::map< std::string, bool > >( available_tools );
779
780 assert( available_tools.as_object().size() == as_map.size() );
781
782 //]
783 }
784 }
785
786 BOOST_STATIC_ASSERT(
787 has_value_from<customer>::value);
788
789 BOOST_STATIC_ASSERT(
790 has_value_from<std::complex<float>>::value);
791 BOOST_STATIC_ASSERT(
792 has_value_from<std::complex<double>>::value);
793
794 BOOST_STATIC_ASSERT(
795 has_value_to<std::complex<float>>::value);
796 BOOST_STATIC_ASSERT(
797 has_value_to<std::complex<double>>::value);
798
799 } // (anon)
800
801 } // json
802 } // boost
803
804 //----------------------------------------------------------
805
806
807 namespace {
808
809 class my_non_deallocating_resource { };
810
811 } // (anon)
812
813 //[snippet_allocators_14
814 namespace boost {
815 namespace json {
816
817 template<>
818 struct is_deallocate_trivial< my_non_deallocating_resource >
819 {
820 static constexpr bool value = true;
821 };
822
823 } // json
824 } // boost
825
826 //]
827
828 namespace boost {
829 namespace json {
830
831 class snippets_test
832 {
833 public:
834 void
835 run()
836 {
837 usingValues();
838 usingInitLists();
839 usingExchange();
840 usingArrays();
841 usingObjects();
842 usingStrings();
843
844 BOOST_TEST_PASS();
845 }
846 };
847
848 TEST_SUITE(snippets_test, "boost.json.snippets");
849
850 BOOST_JSON_NS_END
851
852 #endif