1 #pragma once
2
3 #include <algorithm> // transform
4 #include <array> // array
5 #include <forward_list> // forward_list
6 #include <iterator> // inserter, front_inserter, end
7 #include <map> // map
8 #include <string> // string
9 #include <tuple> // tuple, make_tuple
10 #include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible
11 #include <unordered_map> // unordered_map
12 #include <utility> // pair, declval
13 #include <valarray> // valarray
14
15 #include <nlohmann/detail/exceptions.hpp>
16 #include <nlohmann/detail/macro_scope.hpp>
17 #include <nlohmann/detail/meta/cpp_future.hpp>
18 #include <nlohmann/detail/meta/type_traits.hpp>
19 #include <nlohmann/detail/value_t.hpp>
20
21 namespace nlohmann
22 {
23 namespace detail
24 {
25 template<typename BasicJsonType>
from_json(const BasicJsonType & j,typename std::nullptr_t & n)26 void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
27 {
28 if (JSON_HEDLEY_UNLIKELY(!j.is_null()))
29 {
30 JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name())));
31 }
32 n = nullptr;
33 }
34
35 // overloads for basic_json template parameters
36 template < typename BasicJsonType, typename ArithmeticType,
37 enable_if_t < std::is_arithmetic<ArithmeticType>::value&&
38 !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
39 int > = 0 >
get_arithmetic_value(const BasicJsonType & j,ArithmeticType & val)40 void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
41 {
42 switch (static_cast<value_t>(j))
43 {
44 case value_t::number_unsigned:
45 {
46 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
47 break;
48 }
49 case value_t::number_integer:
50 {
51 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
52 break;
53 }
54 case value_t::number_float:
55 {
56 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
57 break;
58 }
59
60 default:
61 JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name())));
62 }
63 }
64
65 template<typename BasicJsonType>
from_json(const BasicJsonType & j,typename BasicJsonType::boolean_t & b)66 void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
67 {
68 if (JSON_HEDLEY_UNLIKELY(!j.is_boolean()))
69 {
70 JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name())));
71 }
72 b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
73 }
74
75 template<typename BasicJsonType>
from_json(const BasicJsonType & j,typename BasicJsonType::string_t & s)76 void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
77 {
78 if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
79 {
80 JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name())));
81 }
82 s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
83 }
84
85 template <
86 typename BasicJsonType, typename ConstructibleStringType,
87 enable_if_t <
88 is_constructible_string_type<BasicJsonType, ConstructibleStringType>::value&&
89 !std::is_same<typename BasicJsonType::string_t,
90 ConstructibleStringType>::value,
91 int > = 0 >
from_json(const BasicJsonType & j,ConstructibleStringType & s)92 void from_json(const BasicJsonType& j, ConstructibleStringType& s)
93 {
94 if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
95 {
96 JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name())));
97 }
98
99 s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
100 }
101
102 template<typename BasicJsonType>
from_json(const BasicJsonType & j,typename BasicJsonType::number_float_t & val)103 void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)
104 {
105 get_arithmetic_value(j, val);
106 }
107
108 template<typename BasicJsonType>
from_json(const BasicJsonType & j,typename BasicJsonType::number_unsigned_t & val)109 void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val)
110 {
111 get_arithmetic_value(j, val);
112 }
113
114 template<typename BasicJsonType>
from_json(const BasicJsonType & j,typename BasicJsonType::number_integer_t & val)115 void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)
116 {
117 get_arithmetic_value(j, val);
118 }
119
120 template<typename BasicJsonType, typename EnumType,
121 enable_if_t<std::is_enum<EnumType>::value, int> = 0>
from_json(const BasicJsonType & j,EnumType & e)122 void from_json(const BasicJsonType& j, EnumType& e)
123 {
124 typename std::underlying_type<EnumType>::type val;
125 get_arithmetic_value(j, val);
126 e = static_cast<EnumType>(val);
127 }
128
129 // forward_list doesn't have an insert method
130 template<typename BasicJsonType, typename T, typename Allocator,
131 enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
from_json(const BasicJsonType & j,std::forward_list<T,Allocator> & l)132 void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
133 {
134 if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
135 {
136 JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
137 }
138 l.clear();
139 std::transform(j.rbegin(), j.rend(),
140 std::front_inserter(l), [](const BasicJsonType & i)
141 {
142 return i.template get<T>();
143 });
144 }
145
146 // valarray doesn't have an insert method
147 template<typename BasicJsonType, typename T,
148 enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
from_json(const BasicJsonType & j,std::valarray<T> & l)149 void from_json(const BasicJsonType& j, std::valarray<T>& l)
150 {
151 if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
152 {
153 JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
154 }
155 l.resize(j.size());
156 std::transform(j.begin(), j.end(), std::begin(l),
157 [](const BasicJsonType & elem)
158 {
159 return elem.template get<T>();
160 });
161 }
162
163 template<typename BasicJsonType, typename T, std::size_t N>
from_json(const BasicJsonType & j,T (& arr)[N])164 auto from_json(const BasicJsonType& j, T (&arr)[N])
165 -> decltype(j.template get<T>(), void())
166 {
167 for (std::size_t i = 0; i < N; ++i)
168 {
169 arr[i] = j.at(i).template get<T>();
170 }
171 }
172
173 template<typename BasicJsonType>
from_json_array_impl(const BasicJsonType & j,typename BasicJsonType::array_t & arr,priority_tag<3>)174 void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)
175 {
176 arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
177 }
178
179 template<typename BasicJsonType, typename T, std::size_t N>
from_json_array_impl(const BasicJsonType & j,std::array<T,N> & arr,priority_tag<2>)180 auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
181 priority_tag<2> /*unused*/)
182 -> decltype(j.template get<T>(), void())
183 {
184 for (std::size_t i = 0; i < N; ++i)
185 {
186 arr[i] = j.at(i).template get<T>();
187 }
188 }
189
190 template<typename BasicJsonType, typename ConstructibleArrayType>
from_json_array_impl(const BasicJsonType & j,ConstructibleArrayType & arr,priority_tag<1>)191 auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/)
192 -> decltype(
193 arr.reserve(std::declval<typename ConstructibleArrayType::size_type>()),
194 j.template get<typename ConstructibleArrayType::value_type>(),
195 void())
196 {
197 using std::end;
198
199 ConstructibleArrayType ret;
200 ret.reserve(j.size());
201 std::transform(j.begin(), j.end(),
202 std::inserter(ret, end(ret)), [](const BasicJsonType & i)
203 {
204 // get<BasicJsonType>() returns *this, this won't call a from_json
205 // method when value_type is BasicJsonType
206 return i.template get<typename ConstructibleArrayType::value_type>();
207 });
208 arr = std::move(ret);
209 }
210
211 template<typename BasicJsonType, typename ConstructibleArrayType>
from_json_array_impl(const BasicJsonType & j,ConstructibleArrayType & arr,priority_tag<0>)212 void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,
213 priority_tag<0> /*unused*/)
214 {
215 using std::end;
216
217 ConstructibleArrayType ret;
218 std::transform(
219 j.begin(), j.end(), std::inserter(ret, end(ret)),
220 [](const BasicJsonType & i)
221 {
222 // get<BasicJsonType>() returns *this, this won't call a from_json
223 // method when value_type is BasicJsonType
224 return i.template get<typename ConstructibleArrayType::value_type>();
225 });
226 arr = std::move(ret);
227 }
228
229 template < typename BasicJsonType, typename ConstructibleArrayType,
230 enable_if_t <
231 is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&
232 !is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&&
233 !is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
234 !std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&&
235 !is_basic_json<ConstructibleArrayType>::value,
236 int > = 0 >
from_json(const BasicJsonType & j,ConstructibleArrayType & arr)237 auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
238 -> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),
239 j.template get<typename ConstructibleArrayType::value_type>(),
240 void())
241 {
242 if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
243 {
244 JSON_THROW(type_error::create(302, "type must be array, but is " +
245 std::string(j.type_name())));
246 }
247
248 from_json_array_impl(j, arr, priority_tag<3> {});
249 }
250
251 template<typename BasicJsonType>
from_json(const BasicJsonType & j,typename BasicJsonType::binary_t & bin)252 void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin)
253 {
254 if (JSON_HEDLEY_UNLIKELY(!j.is_binary()))
255 {
256 JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(j.type_name())));
257 }
258
259 bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>();
260 }
261
262 template<typename BasicJsonType, typename ConstructibleObjectType,
263 enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
from_json(const BasicJsonType & j,ConstructibleObjectType & obj)264 void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
265 {
266 if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
267 {
268 JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name())));
269 }
270
271 ConstructibleObjectType ret;
272 auto inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
273 using value_type = typename ConstructibleObjectType::value_type;
274 std::transform(
275 inner_object->begin(), inner_object->end(),
276 std::inserter(ret, ret.begin()),
277 [](typename BasicJsonType::object_t::value_type const & p)
278 {
279 return value_type(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>());
280 });
281 obj = std::move(ret);
282 }
283
284 // overload for arithmetic types, not chosen for basic_json template arguments
285 // (BooleanType, etc..); note: Is it really necessary to provide explicit
286 // overloads for boolean_t etc. in case of a custom BooleanType which is not
287 // an arithmetic type?
288 template < typename BasicJsonType, typename ArithmeticType,
289 enable_if_t <
290 std::is_arithmetic<ArithmeticType>::value&&
291 !std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value&&
292 !std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value&&
293 !std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value&&
294 !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
295 int > = 0 >
from_json(const BasicJsonType & j,ArithmeticType & val)296 void from_json(const BasicJsonType& j, ArithmeticType& val)
297 {
298 switch (static_cast<value_t>(j))
299 {
300 case value_t::number_unsigned:
301 {
302 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
303 break;
304 }
305 case value_t::number_integer:
306 {
307 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
308 break;
309 }
310 case value_t::number_float:
311 {
312 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
313 break;
314 }
315 case value_t::boolean:
316 {
317 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());
318 break;
319 }
320
321 default:
322 JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name())));
323 }
324 }
325
326 template<typename BasicJsonType, typename A1, typename A2>
from_json(const BasicJsonType & j,std::pair<A1,A2> & p)327 void from_json(const BasicJsonType& j, std::pair<A1, A2>& p)
328 {
329 p = {j.at(0).template get<A1>(), j.at(1).template get<A2>()};
330 }
331
332 template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
from_json_tuple_impl(const BasicJsonType & j,Tuple & t,index_sequence<Idx...>)333 void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence<Idx...> /*unused*/)
334 {
335 t = std::make_tuple(j.at(Idx).template get<typename std::tuple_element<Idx, Tuple>::type>()...);
336 }
337
338 template<typename BasicJsonType, typename... Args>
from_json(const BasicJsonType & j,std::tuple<Args...> & t)339 void from_json(const BasicJsonType& j, std::tuple<Args...>& t)
340 {
341 from_json_tuple_impl(j, t, index_sequence_for<Args...> {});
342 }
343
344 template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
345 typename = enable_if_t < !std::is_constructible <
346 typename BasicJsonType::string_t, Key >::value >>
from_json(const BasicJsonType & j,std::map<Key,Value,Compare,Allocator> & m)347 void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
348 {
349 if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
350 {
351 JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
352 }
353 m.clear();
354 for (const auto& p : j)
355 {
356 if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
357 {
358 JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name())));
359 }
360 m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
361 }
362 }
363
364 template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
365 typename = enable_if_t < !std::is_constructible <
366 typename BasicJsonType::string_t, Key >::value >>
from_json(const BasicJsonType & j,std::unordered_map<Key,Value,Hash,KeyEqual,Allocator> & m)367 void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
368 {
369 if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
370 {
371 JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
372 }
373 m.clear();
374 for (const auto& p : j)
375 {
376 if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
377 {
378 JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name())));
379 }
380 m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
381 }
382 }
383
384 struct from_json_fn
385 {
386 template<typename BasicJsonType, typename T>
operator ()nlohmann::detail::from_json_fn387 auto operator()(const BasicJsonType& j, T& val) const
388 noexcept(noexcept(from_json(j, val)))
389 -> decltype(from_json(j, val), void())
390 {
391 return from_json(j, val);
392 }
393 };
394 } // namespace detail
395
396 /// namespace to hold default `from_json` function
397 /// to see why this is required:
398 /// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
399 namespace
400 {
401 constexpr const auto& from_json = detail::static_const<detail::from_json_fn>::value;
402 } // namespace
403 } // namespace nlohmann
404