1 | #pragma once |
2 | |
3 | #include <algorithm> // copy |
4 | #include <ciso646> // or, and, not |
5 | #include <iterator> // begin, end |
6 | #include <string> // string |
7 | #include <tuple> // tuple, get |
8 | #include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type |
9 | #include <utility> // move, forward, declval, pair |
10 | #include <valarray> // valarray |
11 | #include <vector> // vector |
12 | |
13 | #include <nlohmann/detail/iterators/iteration_proxy.hpp> |
14 | #include <nlohmann/detail/meta/cpp_future.hpp> |
15 | #include <nlohmann/detail/meta/type_traits.hpp> |
16 | #include <nlohmann/detail/value_t.hpp> |
17 | |
18 | namespace nlohmann |
19 | { |
20 | namespace detail |
21 | { |
22 | ////////////////// |
23 | // constructors // |
24 | ////////////////// |
25 | |
26 | template<value_t> struct external_constructor; |
27 | |
28 | template<> |
29 | struct external_constructor<value_t::boolean> |
30 | { |
31 | template<typename BasicJsonType> |
32 | static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept |
33 | { |
34 | j.m_type = value_t::boolean; |
35 | j.m_value = b; |
36 | j.assert_invariant(); |
37 | } |
38 | }; |
39 | |
40 | template<> |
41 | struct external_constructor<value_t::string> |
42 | { |
43 | template<typename BasicJsonType> |
44 | static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) |
45 | { |
46 | j.m_type = value_t::string; |
47 | j.m_value = s; |
48 | j.assert_invariant(); |
49 | } |
50 | |
51 | template<typename BasicJsonType> |
52 | static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) |
53 | { |
54 | j.m_type = value_t::string; |
55 | j.m_value = std::move(s); |
56 | j.assert_invariant(); |
57 | } |
58 | |
59 | template<typename BasicJsonType, typename CompatibleStringType, |
60 | enable_if_t<not std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value, |
61 | int> = 0> |
62 | static void construct(BasicJsonType& j, const CompatibleStringType& str) |
63 | { |
64 | j.m_type = value_t::string; |
65 | j.m_value.string = j.template create<typename BasicJsonType::string_t>(str); |
66 | j.assert_invariant(); |
67 | } |
68 | }; |
69 | |
70 | template<> |
71 | struct external_constructor<value_t::number_float> |
72 | { |
73 | template<typename BasicJsonType> |
74 | static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept |
75 | { |
76 | j.m_type = value_t::number_float; |
77 | j.m_value = val; |
78 | j.assert_invariant(); |
79 | } |
80 | }; |
81 | |
82 | template<> |
83 | struct external_constructor<value_t::number_unsigned> |
84 | { |
85 | template<typename BasicJsonType> |
86 | static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept |
87 | { |
88 | j.m_type = value_t::number_unsigned; |
89 | j.m_value = val; |
90 | j.assert_invariant(); |
91 | } |
92 | }; |
93 | |
94 | template<> |
95 | struct external_constructor<value_t::number_integer> |
96 | { |
97 | template<typename BasicJsonType> |
98 | static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept |
99 | { |
100 | j.m_type = value_t::number_integer; |
101 | j.m_value = val; |
102 | j.assert_invariant(); |
103 | } |
104 | }; |
105 | |
106 | template<> |
107 | struct external_constructor<value_t::array> |
108 | { |
109 | template<typename BasicJsonType> |
110 | static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) |
111 | { |
112 | j.m_type = value_t::array; |
113 | j.m_value = arr; |
114 | j.assert_invariant(); |
115 | } |
116 | |
117 | template<typename BasicJsonType> |
118 | static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) |
119 | { |
120 | j.m_type = value_t::array; |
121 | j.m_value = std::move(arr); |
122 | j.assert_invariant(); |
123 | } |
124 | |
125 | template<typename BasicJsonType, typename CompatibleArrayType, |
126 | enable_if_t<not std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value, |
127 | int> = 0> |
128 | static void construct(BasicJsonType& j, const CompatibleArrayType& arr) |
129 | { |
130 | using std::begin; |
131 | using std::end; |
132 | j.m_type = value_t::array; |
133 | j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr)); |
134 | j.assert_invariant(); |
135 | } |
136 | |
137 | template<typename BasicJsonType> |
138 | static void construct(BasicJsonType& j, const std::vector<bool>& arr) |
139 | { |
140 | j.m_type = value_t::array; |
141 | j.m_value = value_t::array; |
142 | j.m_value.array->reserve(arr.size()); |
143 | for (const bool x : arr) |
144 | { |
145 | j.m_value.array->push_back(x); |
146 | } |
147 | j.assert_invariant(); |
148 | } |
149 | |
150 | template<typename BasicJsonType, typename T, |
151 | enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0> |
152 | static void construct(BasicJsonType& j, const std::valarray<T>& arr) |
153 | { |
154 | j.m_type = value_t::array; |
155 | j.m_value = value_t::array; |
156 | j.m_value.array->resize(arr.size()); |
157 | if (arr.size() > 0) |
158 | { |
159 | std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); |
160 | } |
161 | j.assert_invariant(); |
162 | } |
163 | }; |
164 | |
165 | template<> |
166 | struct external_constructor<value_t::object> |
167 | { |
168 | template<typename BasicJsonType> |
169 | static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) |
170 | { |
171 | j.m_type = value_t::object; |
172 | j.m_value = obj; |
173 | j.assert_invariant(); |
174 | } |
175 | |
176 | template<typename BasicJsonType> |
177 | static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) |
178 | { |
179 | j.m_type = value_t::object; |
180 | j.m_value = std::move(obj); |
181 | j.assert_invariant(); |
182 | } |
183 | |
184 | template<typename BasicJsonType, typename CompatibleObjectType, |
185 | enable_if_t<not std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int> = 0> |
186 | static void construct(BasicJsonType& j, const CompatibleObjectType& obj) |
187 | { |
188 | using std::begin; |
189 | using std::end; |
190 | |
191 | j.m_type = value_t::object; |
192 | j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj)); |
193 | j.assert_invariant(); |
194 | } |
195 | }; |
196 | |
197 | ///////////// |
198 | // to_json // |
199 | ///////////// |
200 | |
201 | template<typename BasicJsonType, typename T, |
202 | enable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0> |
203 | void to_json(BasicJsonType& j, T b) noexcept |
204 | { |
205 | external_constructor<value_t::boolean>::construct(j, b); |
206 | } |
207 | |
208 | template<typename BasicJsonType, typename CompatibleString, |
209 | enable_if_t<std::is_constructible<typename BasicJsonType::string_t, CompatibleString>::value, int> = 0> |
210 | void to_json(BasicJsonType& j, const CompatibleString& s) |
211 | { |
212 | external_constructor<value_t::string>::construct(j, s); |
213 | } |
214 | |
215 | template<typename BasicJsonType> |
216 | void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) |
217 | { |
218 | external_constructor<value_t::string>::construct(j, std::move(s)); |
219 | } |
220 | |
221 | template<typename BasicJsonType, typename FloatType, |
222 | enable_if_t<std::is_floating_point<FloatType>::value, int> = 0> |
223 | void to_json(BasicJsonType& j, FloatType val) noexcept |
224 | { |
225 | external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val)); |
226 | } |
227 | |
228 | template<typename BasicJsonType, typename CompatibleNumberUnsignedType, |
229 | enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, CompatibleNumberUnsignedType>::value, int> = 0> |
230 | void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept |
231 | { |
232 | external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val)); |
233 | } |
234 | |
235 | template<typename BasicJsonType, typename CompatibleNumberIntegerType, |
236 | enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, CompatibleNumberIntegerType>::value, int> = 0> |
237 | void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept |
238 | { |
239 | external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val)); |
240 | } |
241 | |
242 | template<typename BasicJsonType, typename EnumType, |
243 | enable_if_t<std::is_enum<EnumType>::value, int> = 0> |
244 | void to_json(BasicJsonType& j, EnumType e) noexcept |
245 | { |
246 | using underlying_type = typename std::underlying_type<EnumType>::type; |
247 | external_constructor<value_t::number_integer>::construct(j, static_cast<underlying_type>(e)); |
248 | } |
249 | |
250 | template<typename BasicJsonType> |
251 | void to_json(BasicJsonType& j, const std::vector<bool>& e) |
252 | { |
253 | external_constructor<value_t::array>::construct(j, e); |
254 | } |
255 | |
256 | template <typename BasicJsonType, typename CompatibleArrayType, |
257 | enable_if_t<is_compatible_array_type<BasicJsonType, |
258 | CompatibleArrayType>::value and |
259 | not is_compatible_object_type< |
260 | BasicJsonType, CompatibleArrayType>::value and |
261 | not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and |
262 | not is_basic_json<CompatibleArrayType>::value, |
263 | int> = 0> |
264 | void to_json(BasicJsonType& j, const CompatibleArrayType& arr) |
265 | { |
266 | external_constructor<value_t::array>::construct(j, arr); |
267 | } |
268 | |
269 | template<typename BasicJsonType, typename T, |
270 | enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0> |
271 | void to_json(BasicJsonType& j, const std::valarray<T>& arr) |
272 | { |
273 | external_constructor<value_t::array>::construct(j, std::move(arr)); |
274 | } |
275 | |
276 | template<typename BasicJsonType> |
277 | void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) |
278 | { |
279 | external_constructor<value_t::array>::construct(j, std::move(arr)); |
280 | } |
281 | |
282 | template<typename BasicJsonType, typename CompatibleObjectType, |
283 | enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value and not is_basic_json<CompatibleObjectType>::value, int> = 0> |
284 | void to_json(BasicJsonType& j, const CompatibleObjectType& obj) |
285 | { |
286 | external_constructor<value_t::object>::construct(j, obj); |
287 | } |
288 | |
289 | template<typename BasicJsonType> |
290 | void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) |
291 | { |
292 | external_constructor<value_t::object>::construct(j, std::move(obj)); |
293 | } |
294 | |
295 | template < |
296 | typename BasicJsonType, typename T, std::size_t N, |
297 | enable_if_t<not std::is_constructible<typename BasicJsonType::string_t, |
298 | const T(&)[N]>::value, |
299 | int> = 0 > |
300 | void to_json(BasicJsonType& j, const T(&arr)[N]) |
301 | { |
302 | external_constructor<value_t::array>::construct(j, arr); |
303 | } |
304 | |
305 | template<typename BasicJsonType, typename... Args> |
306 | void to_json(BasicJsonType& j, const std::pair<Args...>& p) |
307 | { |
308 | j = { p.first, p.second }; |
309 | } |
310 | |
311 | // for https://github.com/nlohmann/json/pull/1134 |
312 | template < typename BasicJsonType, typename T, |
313 | enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0> |
314 | void to_json(BasicJsonType& j, const T& b) |
315 | { |
316 | j = { {b.key(), b.value()} }; |
317 | } |
318 | |
319 | template<typename BasicJsonType, typename Tuple, std::size_t... Idx> |
320 | void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/) |
321 | { |
322 | j = { std::get<Idx>(t)... }; |
323 | } |
324 | |
325 | template<typename BasicJsonType, typename... Args> |
326 | void to_json(BasicJsonType& j, const std::tuple<Args...>& t) |
327 | { |
328 | to_json_tuple_impl(j, t, index_sequence_for<Args...> {}); |
329 | } |
330 | |
331 | struct to_json_fn |
332 | { |
333 | template<typename BasicJsonType, typename T> |
334 | auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val)))) |
335 | -> decltype(to_json(j, std::forward<T>(val)), void()) |
336 | { |
337 | return to_json(j, std::forward<T>(val)); |
338 | } |
339 | }; |
340 | } // namespace detail |
341 | |
342 | /// namespace to hold default `to_json` function |
343 | namespace |
344 | { |
345 | constexpr const auto& to_json = detail::static_const<detail::to_json_fn>::value; |
346 | } // namespace |
347 | } // namespace nlohmann |
348 | |