Line data Source code
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 912 : value_ref(
211 : T const& t) noexcept
212 912 : : arg_(string_view(t))
213 912 : , what_(what::str)
214 : {
215 912 : }
216 : #endif
217 :
218 : /// Overload
219 : template<class T>
220 22 : 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 22 : : cf_{&from_const<T>, &t}
231 22 : , what_(what::cfunc)
232 : {
233 22 : }
234 :
235 : /// Overload
236 : template<class T>
237 76 : 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 76 : : f_{&from_rvalue<
251 : detail::remove_cvref<T>>, &t}
252 76 : , what_(std::is_same<string, T>::value ?
253 76 : what::strfunc : what::func)
254 : {
255 76 : }
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
|