to_json.hpp 17 KB

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