• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //     __ _____ _____ _____
2 //  __|  |   __|     |   | |  JSON for Modern C++
3 // |  |  |__   |  |  | | | |  version 3.11.2
4 // |_____|_____|_____|_|___|  https://github.com/nlohmann/json
5 //
6 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
7 // SPDX-License-Identifier: MIT
8 
9 #pragma once
10 
11 #include <algorithm> // copy
12 #include <iterator> // begin, end
13 #include <string> // string
14 #include <tuple> // tuple, get
15 #include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type
16 #include <utility> // move, forward, declval, pair
17 #include <valarray> // valarray
18 #include <vector> // vector
19 
20 #include <nlohmann/detail/iterators/iteration_proxy.hpp>
21 #include <nlohmann/detail/macro_scope.hpp>
22 #include <nlohmann/detail/meta/cpp_future.hpp>
23 #include <nlohmann/detail/meta/std_fs.hpp>
24 #include <nlohmann/detail/meta/type_traits.hpp>
25 #include <nlohmann/detail/value_t.hpp>
26 
27 NLOHMANN_JSON_NAMESPACE_BEGIN
28 namespace detail
29 {
30 
31 //////////////////
32 // constructors //
33 //////////////////
34 
35 /*
36  * Note all external_constructor<>::construct functions need to call
37  * j.m_value.destroy(j.m_type) to avoid a memory leak in case j contains an
38  * allocated value (e.g., a string). See bug issue
39  * https://github.com/nlohmann/json/issues/2865 for more information.
40  */
41 
42 template<value_t> struct external_constructor;
43 
44 template<>
45 struct external_constructor<value_t::boolean>
46 {
47     template<typename BasicJsonType>
constructdetail::external_constructor48     static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept
49     {
50         j.m_value.destroy(j.m_type);
51         j.m_type = value_t::boolean;
52         j.m_value = b;
53         j.assert_invariant();
54     }
55 };
56 
57 template<>
58 struct external_constructor<value_t::string>
59 {
60     template<typename BasicJsonType>
constructdetail::external_constructor61     static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)
62     {
63         j.m_value.destroy(j.m_type);
64         j.m_type = value_t::string;
65         j.m_value = s;
66         j.assert_invariant();
67     }
68 
69     template<typename BasicJsonType>
constructdetail::external_constructor70     static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)
71     {
72         j.m_value.destroy(j.m_type);
73         j.m_type = value_t::string;
74         j.m_value = std::move(s);
75         j.assert_invariant();
76     }
77 
78     template < typename BasicJsonType, typename CompatibleStringType,
79                enable_if_t < !std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,
80                              int > = 0 >
constructdetail::external_constructor81     static void construct(BasicJsonType& j, const CompatibleStringType& str)
82     {
83         j.m_value.destroy(j.m_type);
84         j.m_type = value_t::string;
85         j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
86         j.assert_invariant();
87     }
88 };
89 
90 template<>
91 struct external_constructor<value_t::binary>
92 {
93     template<typename BasicJsonType>
constructdetail::external_constructor94     static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b)
95     {
96         j.m_value.destroy(j.m_type);
97         j.m_type = value_t::binary;
98         j.m_value = typename BasicJsonType::binary_t(b);
99         j.assert_invariant();
100     }
101 
102     template<typename BasicJsonType>
constructdetail::external_constructor103     static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b)
104     {
105         j.m_value.destroy(j.m_type);
106         j.m_type = value_t::binary;
107         j.m_value = typename BasicJsonType::binary_t(std::move(b));
108         j.assert_invariant();
109     }
110 };
111 
112 template<>
113 struct external_constructor<value_t::number_float>
114 {
115     template<typename BasicJsonType>
constructdetail::external_constructor116     static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept
117     {
118         j.m_value.destroy(j.m_type);
119         j.m_type = value_t::number_float;
120         j.m_value = val;
121         j.assert_invariant();
122     }
123 };
124 
125 template<>
126 struct external_constructor<value_t::number_unsigned>
127 {
128     template<typename BasicJsonType>
constructdetail::external_constructor129     static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept
130     {
131         j.m_value.destroy(j.m_type);
132         j.m_type = value_t::number_unsigned;
133         j.m_value = val;
134         j.assert_invariant();
135     }
136 };
137 
138 template<>
139 struct external_constructor<value_t::number_integer>
140 {
141     template<typename BasicJsonType>
constructdetail::external_constructor142     static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept
143     {
144         j.m_value.destroy(j.m_type);
145         j.m_type = value_t::number_integer;
146         j.m_value = val;
147         j.assert_invariant();
148     }
149 };
150 
151 template<>
152 struct external_constructor<value_t::array>
153 {
154     template<typename BasicJsonType>
constructdetail::external_constructor155     static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
156     {
157         j.m_value.destroy(j.m_type);
158         j.m_type = value_t::array;
159         j.m_value = arr;
160         j.set_parents();
161         j.assert_invariant();
162     }
163 
164     template<typename BasicJsonType>
constructdetail::external_constructor165     static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
166     {
167         j.m_value.destroy(j.m_type);
168         j.m_type = value_t::array;
169         j.m_value = std::move(arr);
170         j.set_parents();
171         j.assert_invariant();
172     }
173 
174     template < typename BasicJsonType, typename CompatibleArrayType,
175                enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,
176                              int > = 0 >
constructdetail::external_constructor177     static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
178     {
179         using std::begin;
180         using std::end;
181 
182         j.m_value.destroy(j.m_type);
183         j.m_type = value_t::array;
184         j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
185         j.set_parents();
186         j.assert_invariant();
187     }
188 
189     template<typename BasicJsonType>
constructdetail::external_constructor190     static void construct(BasicJsonType& j, const std::vector<bool>& arr)
191     {
192         j.m_value.destroy(j.m_type);
193         j.m_type = value_t::array;
194         j.m_value = value_t::array;
195         j.m_value.array->reserve(arr.size());
196         for (const bool x : arr)
197         {
198             j.m_value.array->push_back(x);
199             j.set_parent(j.m_value.array->back());
200         }
201         j.assert_invariant();
202     }
203 
204     template<typename BasicJsonType, typename T,
205              enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
constructdetail::external_constructor206     static void construct(BasicJsonType& j, const std::valarray<T>& arr)
207     {
208         j.m_value.destroy(j.m_type);
209         j.m_type = value_t::array;
210         j.m_value = value_t::array;
211         j.m_value.array->resize(arr.size());
212         if (arr.size() > 0)
213         {
214             std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin());
215         }
216         j.set_parents();
217         j.assert_invariant();
218     }
219 };
220 
221 template<>
222 struct external_constructor<value_t::object>
223 {
224     template<typename BasicJsonType>
constructdetail::external_constructor225     static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
226     {
227         j.m_value.destroy(j.m_type);
228         j.m_type = value_t::object;
229         j.m_value = obj;
230         j.set_parents();
231         j.assert_invariant();
232     }
233 
234     template<typename BasicJsonType>
constructdetail::external_constructor235     static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
236     {
237         j.m_value.destroy(j.m_type);
238         j.m_type = value_t::object;
239         j.m_value = std::move(obj);
240         j.set_parents();
241         j.assert_invariant();
242     }
243 
244     template < typename BasicJsonType, typename CompatibleObjectType,
245                enable_if_t < !std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int > = 0 >
constructdetail::external_constructor246     static void construct(BasicJsonType& j, const CompatibleObjectType& obj)
247     {
248         using std::begin;
249         using std::end;
250 
251         j.m_value.destroy(j.m_type);
252         j.m_type = value_t::object;
253         j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
254         j.set_parents();
255         j.assert_invariant();
256     }
257 };
258 
259 /////////////
260 // to_json //
261 /////////////
262 
263 template<typename BasicJsonType, typename T,
264          enable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0>
to_json(BasicJsonType & j,T b)265 inline void to_json(BasicJsonType& j, T b) noexcept
266 {
267     external_constructor<value_t::boolean>::construct(j, b);
268 }
269 
270 template < typename BasicJsonType, typename BoolRef,
271            enable_if_t <
272                ((std::is_same<std::vector<bool>::reference, BoolRef>::value
273                  && !std::is_same <std::vector<bool>::reference, typename BasicJsonType::boolean_t&>::value)
274                 || (std::is_same<std::vector<bool>::const_reference, BoolRef>::value
275                     && !std::is_same <detail::uncvref_t<std::vector<bool>::const_reference>,
276                                       typename BasicJsonType::boolean_t >::value))
277                && std::is_convertible<const BoolRef&, typename BasicJsonType::boolean_t>::value, int > = 0 >
to_json(BasicJsonType & j,const BoolRef & b)278 inline void to_json(BasicJsonType& j, const BoolRef& b) noexcept
279 {
280     external_constructor<value_t::boolean>::construct(j, static_cast<typename BasicJsonType::boolean_t>(b));
281 }
282 
283 template<typename BasicJsonType, typename CompatibleString,
284          enable_if_t<std::is_constructible<typename BasicJsonType::string_t, CompatibleString>::value, int> = 0>
to_json(BasicJsonType & j,const CompatibleString & s)285 inline void to_json(BasicJsonType& j, const CompatibleString& s)
286 {
287     external_constructor<value_t::string>::construct(j, s);
288 }
289 
290 template<typename BasicJsonType>
to_json(BasicJsonType & j,typename BasicJsonType::string_t && s)291 inline void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s)
292 {
293     external_constructor<value_t::string>::construct(j, std::move(s));
294 }
295 
296 template<typename BasicJsonType, typename FloatType,
297          enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>
to_json(BasicJsonType & j,FloatType val)298 inline void to_json(BasicJsonType& j, FloatType val) noexcept
299 {
300     external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val));
301 }
302 
303 template<typename BasicJsonType, typename CompatibleNumberUnsignedType,
304          enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, CompatibleNumberUnsignedType>::value, int> = 0>
to_json(BasicJsonType & j,CompatibleNumberUnsignedType val)305 inline void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept
306 {
307     external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));
308 }
309 
310 template<typename BasicJsonType, typename CompatibleNumberIntegerType,
311          enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, CompatibleNumberIntegerType>::value, int> = 0>
to_json(BasicJsonType & j,CompatibleNumberIntegerType val)312 inline void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept
313 {
314     external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));
315 }
316 
317 #if !JSON_DISABLE_ENUM_SERIALIZATION
318 template<typename BasicJsonType, typename EnumType,
319          enable_if_t<std::is_enum<EnumType>::value, int> = 0>
to_json(BasicJsonType & j,EnumType e)320 inline void to_json(BasicJsonType& j, EnumType e) noexcept
321 {
322     using underlying_type = typename std::underlying_type<EnumType>::type;
323     external_constructor<value_t::number_integer>::construct(j, static_cast<underlying_type>(e));
324 }
325 #endif  // JSON_DISABLE_ENUM_SERIALIZATION
326 
327 template<typename BasicJsonType>
to_json(BasicJsonType & j,const std::vector<bool> & e)328 inline void to_json(BasicJsonType& j, const std::vector<bool>& e)
329 {
330     external_constructor<value_t::array>::construct(j, e);
331 }
332 
333 template < typename BasicJsonType, typename CompatibleArrayType,
334            enable_if_t < is_compatible_array_type<BasicJsonType,
335                          CompatibleArrayType>::value&&
336                          !is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value&&
337                          !is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value&&
338                          !std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&&
339                          !is_basic_json<CompatibleArrayType>::value,
340                          int > = 0 >
to_json(BasicJsonType & j,const CompatibleArrayType & arr)341 inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
342 {
343     external_constructor<value_t::array>::construct(j, arr);
344 }
345 
346 template<typename BasicJsonType>
to_json(BasicJsonType & j,const typename BasicJsonType::binary_t & bin)347 inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin)
348 {
349     external_constructor<value_t::binary>::construct(j, bin);
350 }
351 
352 template<typename BasicJsonType, typename T,
353          enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
to_json(BasicJsonType & j,const std::valarray<T> & arr)354 inline void to_json(BasicJsonType& j, const std::valarray<T>& arr)
355 {
356     external_constructor<value_t::array>::construct(j, std::move(arr));
357 }
358 
359 template<typename BasicJsonType>
to_json(BasicJsonType & j,typename BasicJsonType::array_t && arr)360 inline void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
361 {
362     external_constructor<value_t::array>::construct(j, std::move(arr));
363 }
364 
365 template < typename BasicJsonType, typename CompatibleObjectType,
366            enable_if_t < is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value&& !is_basic_json<CompatibleObjectType>::value, int > = 0 >
to_json(BasicJsonType & j,const CompatibleObjectType & obj)367 inline void to_json(BasicJsonType& j, const CompatibleObjectType& obj)
368 {
369     external_constructor<value_t::object>::construct(j, obj);
370 }
371 
372 template<typename BasicJsonType>
to_json(BasicJsonType & j,typename BasicJsonType::object_t && obj)373 inline void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
374 {
375     external_constructor<value_t::object>::construct(j, std::move(obj));
376 }
377 
378 template <
379     typename BasicJsonType, typename T, std::size_t N,
380     enable_if_t < !std::is_constructible<typename BasicJsonType::string_t,
381                   const T(&)[N]>::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
382                   int > = 0 >
to_json(BasicJsonType & j,const T (& arr)[N])383 inline void to_json(BasicJsonType& j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
384 {
385     external_constructor<value_t::array>::construct(j, arr);
386 }
387 
388 template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible<BasicJsonType, T1>::value&& std::is_constructible<BasicJsonType, T2>::value, int > = 0 >
to_json(BasicJsonType & j,const std::pair<T1,T2> & p)389 inline void to_json(BasicJsonType& j, const std::pair<T1, T2>& p)
390 {
391     j = { p.first, p.second };
392 }
393 
394 // for https://github.com/nlohmann/json/pull/1134
395 template<typename BasicJsonType, typename T,
396          enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0>
to_json(BasicJsonType & j,const T & b)397 inline void to_json(BasicJsonType& j, const T& b)
398 {
399     j = { {b.key(), b.value()} };
400 }
401 
402 template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
to_json_tuple_impl(BasicJsonType & j,const Tuple & t,index_sequence<Idx...>)403 inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/)
404 {
405     j = { std::get<Idx>(t)... };
406 }
407 
408 template<typename BasicJsonType, typename T, enable_if_t<is_constructible_tuple<BasicJsonType, T>::value, int > = 0>
to_json(BasicJsonType & j,const T & t)409 inline void to_json(BasicJsonType& j, const T& t)
410 {
411     to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value> {});
412 }
413 
414 #if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
415 template<typename BasicJsonType>
to_json(BasicJsonType & j,const std_fs::path & p)416 inline void to_json(BasicJsonType& j, const std_fs::path& p)
417 {
418     j = p.string();
419 }
420 #endif
421 
422 struct to_json_fn
423 {
424     template<typename BasicJsonType, typename T>
operator ()detail::to_json_fn425     auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val))))
426     -> decltype(to_json(j, std::forward<T>(val)), void())
427     {
428         return to_json(j, std::forward<T>(val));
429     }
430 };
431 }  // namespace detail
432 
433 #ifndef JSON_HAS_CPP_17
434 /// namespace to hold default `to_json` function
435 /// to see why this is required:
436 /// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
437 namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)
438 {
439 #endif
440 JSON_INLINE_VARIABLE constexpr const auto& to_json = // NOLINT(misc-definitions-in-headers)
441     detail::static_const<detail::to_json_fn>::value;
442 #ifndef JSON_HAS_CPP_17
443 }  // namespace
444 #endif
445 
446 NLOHMANN_JSON_NAMESPACE_END
447