GCC Code Coverage Report


Directory: libs/json/include/boost/json/
File: value_ref.hpp
Date: 2025-12-23 17:38:58
Exec Total Coverage
Lines: 114 114 100.0%
Functions: 54 56 96.4%
Branches: 0 0 -%

Line Branch Exec Source
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 #ifndef BOOST_JSON_VALUE_REF_HPP
11 #define BOOST_JSON_VALUE_REF_HPP
12
13 #include <boost/json/detail/config.hpp>
14 #include <boost/json/storage_ptr.hpp>
15 #include <boost/json/string.hpp>
16 #include <initializer_list>
17 #include <type_traits>
18 #include <utility>
19
20 namespace boost {
21 namespace json {
22
23 #ifndef BOOST_JSON_DOCS
24 class value;
25 class object;
26 class array;
27 class string;
28 #endif
29
30 //----------------------------------------------------------
31
32 /** The type used in initializer lists.
33
34 This type is used in initializer lists for lazy construction of and
35 assignment to the container types @ref value, @ref array, and @ref object.
36 The two types of initializer lists used are:
37
38 @li `std::initializer_list< value_ref >` for constructing or assigning
39 a @ref value or @ref array, and
40 @li `std::initializer_list< std::pair< string_view, value_ref > >` for
41 constructing or assigning an @ref object.
42
43 A `value_ref` uses reference semantics. Creation of the actual container
44 from the initializer list is lazily deferred until the list is used. This
45 means that the @ref boost::container::pmr::memory_resource used to
46 construct a container can be specified after the point where the
47 initializer list is specified. Also, the usage of this type allows to avoid
48 constructing a @ref value until it's necessary.
49
50 @par Example
51 This example demonstrates how a user-defined type containing a JSON value
52 can be constructed from an initializer list:
53
54 @code
55 class my_type
56 {
57 value jv_;
58
59 public:
60 my_type( std::initializer_list<value_ref> init )
61 : jv_(init)
62 {
63 }
64 };
65 @endcode
66
67 @warning `value_ref` does not take ownership of the objects it was
68 constructed with. If those objects' lifetimes end before the `value_ref`
69 object is used, you will get undefined behavior. Because of this it is
70 advised against declaring a variable of type
71 `std::initializer_list<value_ref>` except in function parameter lists.
72
73 @see @ref value, @ref array, @ref object, @ref value::set_at_pointer.
74 */
75 class value_ref
76 {
77 friend class value;
78 friend class object;
79 friend class array;
80
81 friend class value_ref_test;
82
83 enum class what
84 {
85 str,
86 ini,
87 func,
88 cfunc,
89 strfunc,
90 };
91
92 using init_list =
93 std::initializer_list<value_ref>;
94
95 struct func_type
96 {
97 value(*f)(void*, storage_ptr);
98 void* p;
99 };
100
101 struct cfunc_type
102 {
103 value(*f)(void const*, storage_ptr);
104 void const* p;
105 };
106
107 union arg_type
108 {
109 string_view str_;
110 init_list init_list_;
111
112 signed char schar_;
113 short short_;
114 int int_;
115 long long_;
116 long long long_long_;
117 unsigned char uchar_;
118 unsigned short ushort_;
119 unsigned int uint_;
120 unsigned long ulong_;
121 unsigned long long ulong_long_;
122 float float_;
123 double double_;
124 bool bool_;
125 std::nullptr_t nullptr_;
126
127 98 arg_type() {}
128 912 explicit arg_type(string_view t) noexcept : str_(t) {}
129 656 explicit arg_type(init_list t) noexcept : init_list_(t) {}
130 1 explicit arg_type(signed char t) noexcept : schar_(t) {}
131 3 explicit arg_type(short t) noexcept : short_(t) {}
132 2692 explicit arg_type(int t) noexcept : int_(t) {}
133 3 explicit arg_type(long t) noexcept : long_(t) {}
134 3 explicit arg_type(long long t) noexcept : long_long_(t) {}
135 21 explicit arg_type(unsigned char t) noexcept : uchar_(t) {}
136 3 explicit arg_type(unsigned short t) noexcept : ushort_(t) {}
137 45 explicit arg_type(unsigned int t) noexcept : uint_(t) {}
138 3 explicit arg_type(unsigned long t) noexcept : ulong_(t) {}
139 3 explicit arg_type(unsigned long long t) noexcept : ulong_long_(t) {}
140 18 explicit arg_type(float t) noexcept : float_(t) {}
141 34 explicit arg_type(double t) noexcept : double_(t) {}
142 287 explicit arg_type(bool t) noexcept : bool_(t) {}
143 88 explicit arg_type(std::nullptr_t) noexcept : nullptr_() {}
144 };
145
146 arg_type arg_;
147 #ifndef BOOST_JSON_DOCS
148 // VFALCO doc toolchain erroneously
149 // displays private, anonymous unions as public
150 union
151 {
152 func_type f_;
153 cfunc_type cf_;
154 };
155 #endif
156 what what_;
157
158 public:
159 /** Constructors.
160
161 @li **(1)** copy constructor.
162 @li **(2)** move constructor.
163 @li **(3)** the constructed value stores a reference to `t`'s character
164 array.
165 @li **(4)** the constructed value stores a `const` reference to `t`.
166 @li **(5)** the constructed value stores an rvalue reference to `t`.
167 @li **(6)** the constructed value stores a copy of `b`.
168 @li **(7)**--**(18)** the constructed value stores a copy of `t`.
169 @li **(19)** the constrcuted value stores `nullptr`.
170 @li **(20)** the constrcuted value stores a copy of `init`.
171
172 In addition the constructed object stores a pointer to a function that
173 captures the type information necessary to construct a @ref value from
174 the stored data.
175
176 @warning The overloads that accept references do not take ownership of
177 referenced objects. The caller is responsible for making sure those
178 objects do not go out of scope before the `value_ref` object is used.
179 It is advised you only use `value_ref` (or any type that contains a
180 `value_ref` subobject) as function parameters or take special care to
181 not invoke undefeined behavior.
182
183 @par Complexity
184 @li **(1)**--**(19)** constant.
185 @li **(20)** linear in `init.size()`.
186
187 @par Exception Safety
188 No-throw guarantee.
189
190 @{
191 */
192 value_ref(
193 value_ref const&) = default;
194
195 /// Overload
196 value_ref(
197 value_ref&&) = default;
198
199 /// Overload
200 #ifdef BOOST_JSON_DOCS
201 value_ref(string_view s) noexcept;
202 #else
203 template<
204 class T
205 ,class = typename
206 std::enable_if<
207 std::is_constructible<
208 string_view, T>::value>::type
209 >
210 1821 value_ref(
211 T const& t) noexcept
212 1821 : arg_(string_view(t))
213 1821 , what_(what::str)
214 {
215 1821 }
216 #endif
217
218 /// Overload
219 template<class T>
220 42 value_ref(
221 T const& t
222 #ifndef BOOST_JSON_DOCS
223 ,typename std::enable_if<
224 ! std::is_constructible<
225 string_view, T>::value &&
226 ! std::is_same<bool, T>::value
227 >::type* = 0
228 #endif
229 ) noexcept
230 42 : cf_{&from_const<T>, &t}
231 42 , what_(what::cfunc)
232 {
233 42 }
234
235 /// Overload
236 template<class T>
237 129 value_ref(
238 T&& t
239 #ifndef BOOST_JSON_DOCS
240 ,typename std::enable_if<
241 (! std::is_constructible<
242 string_view, T>::value ||
243 std::is_same<string, T>::value) &&
244 ! std::is_same<bool,
245 detail::remove_cvref<T>>::value &&
246 std::is_same<T, detail::remove_cvref<T>>
247 ::value>::type* = 0
248 #endif
249 ) noexcept
250 129 : f_{&from_rvalue<
251 detail::remove_cvref<T>>, &t}
252 129 , what_(std::is_same<string, T>::value ?
253 129 what::strfunc : what::func)
254 {
255 129 }
256
257 /// Overload
258 #ifdef BOOST_JSON_DOCS
259 value_ref(bool b) noexcept;
260 #else
261 template<
262 class T
263 ,class = typename std::enable_if<
264 std::is_same<T, bool>::value>::type
265 >
266 287 value_ref(
267 T b) noexcept
268 287 : arg_(b)
269 287 , cf_{&from_builtin<bool>, &arg_.bool_}
270 287 , what_(what::cfunc)
271 {
272 287 }
273 #endif
274
275 /// Overload
276 1 value_ref(signed char t) noexcept
277 1 : arg_(t)
278 1 , cf_{&from_builtin<signed char>, &arg_.schar_}
279 1 , what_(what::cfunc)
280 {
281 1 }
282
283 /// Overload
284 3 value_ref(short t) noexcept
285 3 : arg_(t)
286 3 , cf_{&from_builtin<short>, &arg_.short_}
287 3 , what_(what::cfunc)
288 {
289 3 }
290
291 /// Overload
292 2692 value_ref(int t) noexcept
293 2692 : arg_(t)
294 2692 , cf_{&from_builtin<int>, &arg_.int_}
295 2692 , what_(what::cfunc)
296 {
297 2692 }
298
299 /// Overload
300 3 value_ref(long t) noexcept
301 3 : arg_(t)
302 3 , cf_{&from_builtin<
303 3 long>, &arg_.long_}
304 3 , what_(what::cfunc)
305 {
306 3 }
307
308 /// Overload
309 3 value_ref(long long t) noexcept
310 3 : arg_(t)
311 3 , cf_{&from_builtin<
312 3 long long>, &arg_.long_long_}
313 3 , what_(what::cfunc)
314 {
315 3 }
316
317 /// Overload
318 21 value_ref(unsigned char t) noexcept
319 21 : arg_(t)
320 21 , cf_{&from_builtin<
321 21 unsigned char>, &arg_.uchar_}
322 21 , what_(what::cfunc)
323 {
324 21 }
325
326 /// Overload
327 3 value_ref(unsigned short t) noexcept
328 3 : arg_(t)
329 3 , cf_{&from_builtin<
330 3 unsigned short>, &arg_.ushort_}
331 3 , what_(what::cfunc)
332 {
333 3 }
334
335 /// Overload
336 45 value_ref(unsigned int t) noexcept
337 45 : arg_(t)
338 45 , cf_{&from_builtin<
339 45 unsigned int>, &arg_.uint_}
340 45 , what_(what::cfunc)
341 {
342 45 }
343
344 /// Overload
345 3 value_ref(unsigned long t) noexcept
346 3 : arg_(t)
347 3 , cf_{&from_builtin<
348 3 unsigned long>, &arg_.ulong_}
349 3 , what_(what::cfunc)
350 {
351 3 }
352
353 /// Overload
354 3 value_ref(unsigned long long t) noexcept
355 3 : arg_(t)
356 3 , cf_{&from_builtin<
357 3 unsigned long long>, &arg_.ulong_long_}
358 3 , what_(what::cfunc)
359 {
360 3 }
361
362 /// Overload
363 18 value_ref(float t) noexcept
364 18 : arg_(t)
365 18 , cf_{&from_builtin<
366 18 float>, &arg_.float_}
367 18 , what_(what::cfunc)
368 {
369 18 }
370
371 /// Overload
372 34 value_ref(double t) noexcept
373 34 : arg_(t)
374 34 , cf_{&from_builtin<
375 34 double>, &arg_.double_}
376 34 , what_(what::cfunc)
377 {
378 34 }
379
380 /// Overload
381 88 value_ref(std::nullptr_t) noexcept
382 88 : arg_(nullptr)
383 88 , cf_{&from_builtin<
384 88 std::nullptr_t>, &arg_.nullptr_}
385 88 , what_(what::cfunc)
386 {
387 88 }
388
389 /// Overload
390 656 value_ref(
391 std::initializer_list<value_ref> init) noexcept
392 656 : arg_(init)
393 656 , what_(what::ini)
394 {
395 656 }
396
397 /// @}
398
399 #ifndef BOOST_JSON_DOCS
400 // Not public
401 //private:
402 // VFALCO Why is this needed?
403 /** Operator conversion to @ref value
404
405 This allows creation of a @ref value from
406 an initializer list element.
407 */
408 BOOST_JSON_DECL
409 operator value() const;
410 #endif
411
412 private:
413 template<class T>
414 static
415 value
416 from_builtin(
417 void const* p,
418 storage_ptr sp) noexcept;
419
420 template<class T>
421 static
422 value
423 from_const(
424 void const* p,
425 storage_ptr sp);
426
427 template<class T>
428 static
429 value
430 from_rvalue(
431 void* p,
432 storage_ptr sp);
433
434 static
435 BOOST_JSON_DECL
436 value
437 from_init_list(
438 void const* p,
439 storage_ptr sp);
440
441 inline
442 bool
443 is_key_value_pair() const noexcept;
444
445 static
446 inline
447 bool
448 maybe_object(
449 std::initializer_list<
450 value_ref> init) noexcept;
451
452 inline
453 string_view
454 get_string() const noexcept;
455
456 BOOST_JSON_DECL
457 value
458 make_value(
459 storage_ptr sp) const;
460
461 BOOST_JSON_DECL
462 static
463 value
464 make_value(
465 std::initializer_list<
466 value_ref> init,
467 storage_ptr sp);
468
469 BOOST_JSON_DECL
470 static
471 object
472 make_object(
473 std::initializer_list<value_ref> init,
474 storage_ptr sp);
475
476 BOOST_JSON_DECL
477 static
478 array
479 make_array(
480 std::initializer_list<
481 value_ref> init,
482 storage_ptr sp);
483
484 BOOST_JSON_DECL
485 static
486 void
487 write_array(
488 value* dest,
489 std::initializer_list<
490 value_ref> init,
491 storage_ptr const& sp);
492 };
493
494 } // namespace json
495 } // namespace boost
496
497 // Must be included here for this file to stand alone
498 #include <boost/json/value.hpp>
499
500 // includes are at the bottom of <boost/json/value.hpp>
501 //#include <boost/json/impl/value.hpp>
502 //#include <boost/json/impl/value.ipp>
503
504 #endif
505