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