/src/valijson/include/valijson/internal/basic_adapter.hpp
Line | Count | Source (jump to first uncovered line) |
1 | | #pragma once |
2 | | |
3 | | #include <cstdint> |
4 | | #include <sstream> |
5 | | |
6 | | #include <valijson/internal/adapter.hpp> |
7 | | #include <valijson/internal/optional.hpp> |
8 | | #include <valijson/exceptions.hpp> |
9 | | |
10 | | namespace valijson { |
11 | | namespace adapters { |
12 | | |
13 | | /** |
14 | | * @brief A helper for the array and object member iterators. |
15 | | * |
16 | | * See http://www.stlsoft.org/doc-1.9/group__group____pattern____dereference__proxy.html |
17 | | * for motivation |
18 | | * |
19 | | * @tparam Value Name of the value type |
20 | | */ |
21 | | template<class Value> |
22 | | struct DerefProxy |
23 | | { |
24 | | explicit DerefProxy(const Value& x) |
25 | 0 | : m_ref(x) { } |
26 | | |
27 | | Value* operator->() |
28 | 0 | { |
29 | 0 | return std::addressof(m_ref); |
30 | 0 | } |
31 | | |
32 | | explicit operator Value*() |
33 | | { |
34 | | return std::addressof(m_ref); |
35 | | } |
36 | | |
37 | | private: |
38 | | Value m_ref; |
39 | | }; |
40 | | |
41 | | /** |
42 | | * @brief Template class that implements the expected semantics of an Adapter. |
43 | | * |
44 | | * Implementing all of the type-casting functionality for each Adapter is error |
45 | | * prone and tedious, so this template class aims to minimise the duplication |
46 | | * of code between various Adapter implementations. This template doesn't quite |
47 | | * succeed in removing all duplication, but it has greatly simplified the |
48 | | * implementation of a new Adapter by encapsulating the type-casting semantics |
49 | | * and a lot of the trivial functionality associated with the Adapter interface. |
50 | | * |
51 | | * By inheriting from this template class, Adapter implementations will inherit |
52 | | * the exception throwing behaviour that is expected by other parts of the |
53 | | * Valijson library. |
54 | | * |
55 | | * @tparam AdapterType Self-referential name of the Adapter being |
56 | | * specialised. |
57 | | * @tparam ArrayType Name of the type that will be returned by the |
58 | | * getArray() function. Instances of this type should |
59 | | * provide begin(), end() and size() functions so |
60 | | * that it is possible to iterate over the values in |
61 | | * the array. |
62 | | * @tparam ObjectMemberType Name of the type exposed when iterating over the |
63 | | * contents of an object returned by getObject(). |
64 | | * @tparam ObjectType Name of the type that will be returned by the |
65 | | * getObject() function. Instances of this type |
66 | | * should provide begin(), end(), find() and size() |
67 | | * functions so that it is possible to iterate over |
68 | | * the members of the object. |
69 | | * @tparam ValueType Name of the type that provides a consistent |
70 | | * interface to a JSON value for a parser. For |
71 | | * example, this type should provide the getDouble() |
72 | | * and isDouble() functions. But it does not need to |
73 | | * know how to cast values from one type to another - |
74 | | * that functionality is provided by this template |
75 | | * class. |
76 | | */ |
77 | | template< |
78 | | typename AdapterType, |
79 | | typename ArrayType, |
80 | | typename ObjectMemberType, |
81 | | typename ObjectType, |
82 | | typename ValueType> |
83 | | class BasicAdapter: public Adapter |
84 | | { |
85 | | protected: |
86 | | |
87 | | /** |
88 | | * @brief Functor for comparing two arrays. |
89 | | * |
90 | | * This functor is used to compare the elements in an array of the type |
91 | | * ArrayType with individual values provided as generic Adapter objects. |
92 | | * Comparison is performed by the () operator. |
93 | | * |
94 | | * The functor works by maintaining an iterator for the current position |
95 | | * in an array. Each time the () operator is called, the value at this |
96 | | * position is compared with the value passed as an argument to (). |
97 | | * Immediately after the comparison, the iterator will be incremented. |
98 | | * |
99 | | * This functor is designed to be passed to the applyToArray() function |
100 | | * of an Adapter object. |
101 | | */ |
102 | | class ArrayComparisonFunctor |
103 | | { |
104 | | public: |
105 | | |
106 | | /** |
107 | | * @brief Construct an ArrayComparisonFunctor for an array. |
108 | | * |
109 | | * @param array Array to compare values against |
110 | | * @param strict Flag to use strict type comparison |
111 | | */ |
112 | | ArrayComparisonFunctor(const ArrayType &array, bool strict) |
113 | | : m_itr(array.begin()), |
114 | | m_end(array.end()), |
115 | 0 | m_strict(strict) { } |
116 | | |
117 | | /** |
118 | | * @brief Compare a value against the current element in the array. |
119 | | * |
120 | | * @param adapter Value to be compared with current element |
121 | | * |
122 | | * @returns true if values are equal, false otherwise. |
123 | | */ |
124 | | bool operator()(const Adapter &adapter) |
125 | 0 | { |
126 | 0 | if (m_itr == m_end) { |
127 | 0 | return false; |
128 | 0 | } |
129 | | |
130 | 0 | return AdapterType(*m_itr++).equalTo(adapter, m_strict); |
131 | 0 | } |
132 | | |
133 | | private: |
134 | | |
135 | | /// Iterator for current element in the array |
136 | | typename ArrayType::const_iterator m_itr; |
137 | | |
138 | | /// Iterator for one-past the last element of the array |
139 | | typename ArrayType::const_iterator m_end; |
140 | | |
141 | | /// Flag to use strict type comparison |
142 | | const bool m_strict; |
143 | | }; |
144 | | |
145 | | /** |
146 | | * @brief Functor for comparing two objects |
147 | | * |
148 | | * This functor is used to compare the members of an object of the type |
149 | | * ObjectType with key-value pairs belonging to another object. |
150 | | * |
151 | | * The functor works by maintaining a reference to an object provided via |
152 | | * the constructor. When time the () operator is called with a key-value |
153 | | * pair as arguments, the function will attempt to find the key in the |
154 | | * base object. If found, the associated value will be compared with the |
155 | | * value provided to the () operator. |
156 | | * |
157 | | * This functor is designed to be passed to the applyToObject() function |
158 | | * of an Adapter object. |
159 | | */ |
160 | | class ObjectComparisonFunctor |
161 | | { |
162 | | public: |
163 | | |
164 | | /** |
165 | | * @brief Construct a new ObjectComparisonFunctor for an object. |
166 | | * |
167 | | * @param object object to use as comparison baseline |
168 | | * @param strict flag to use strict type-checking |
169 | | */ |
170 | | ObjectComparisonFunctor(const ObjectType &object, bool strict) |
171 | | : m_object(object), |
172 | 0 | m_strict(strict) { } |
173 | | |
174 | | /** |
175 | | * @brief Find a key in the object and compare its value. |
176 | | * |
177 | | * @param key Key to find |
178 | | * @param value Value to be compared against |
179 | | * |
180 | | * @returns true if key is found and values are equal, false otherwise. |
181 | | */ |
182 | | bool operator()(const std::string &key, const Adapter &value) |
183 | 0 | { |
184 | 0 | const typename ObjectType::const_iterator itr = m_object.find(key); |
185 | 0 | if (itr == m_object.end()) { |
186 | 0 | return false; |
187 | 0 | } |
188 | | |
189 | 0 | return (*itr).second.equalTo(value, m_strict); |
190 | 0 | } |
191 | | |
192 | | private: |
193 | | |
194 | | /// Object to be used as a comparison baseline |
195 | | const ObjectType &m_object; |
196 | | |
197 | | /// Flag to use strict type-checking |
198 | | bool m_strict; |
199 | | }; |
200 | | |
201 | | |
202 | | public: |
203 | | |
204 | | /// Alias for ArrayType template parameter |
205 | | typedef ArrayType Array; |
206 | | |
207 | | /// Alias for ObjectMemberType template parameter |
208 | | typedef ObjectMemberType ObjectMember; |
209 | | |
210 | | /// Alias for ObjectType template parameter |
211 | | typedef ObjectType Object; |
212 | | |
213 | | /** |
214 | | * @brief Construct an Adapter using the default value. |
215 | | * |
216 | | * This constructor relies on the default constructor of the ValueType |
217 | | * class provided as a template argument. |
218 | | */ |
219 | | BasicAdapter() = default; |
220 | | |
221 | | /** |
222 | | * @brief Construct an Adapter using a specified ValueType object. |
223 | | * |
224 | | * This constructor relies on the copy constructor of the ValueType |
225 | | * class provided as template argument. |
226 | | */ |
227 | | explicit BasicAdapter(const ValueType &value) |
228 | 103 | : m_value(value) { } |
229 | | |
230 | | bool applyToArray(ArrayValueCallback fn) const override |
231 | 0 | { |
232 | 0 | if (!maybeArray()) { |
233 | 0 | return false; |
234 | 0 | } |
235 | | |
236 | | // Due to the fact that the only way a value can be 'maybe an array' is |
237 | | // if it is an empty string or empty object, we only need to go to |
238 | | // effort of constructing an ArrayType instance if the value is |
239 | | // definitely an array. |
240 | 0 | if (m_value.isArray()) { |
241 | 0 | const opt::optional<Array> array = m_value.getArrayOptional(); |
242 | 0 | for (const AdapterType element : *array) { |
243 | 0 | if (!fn(element)) { |
244 | 0 | return false; |
245 | 0 | } |
246 | 0 | } |
247 | 0 | } |
248 | | |
249 | 0 | return true; |
250 | 0 | } |
251 | | |
252 | | bool applyToObject(ObjectMemberCallback fn) const override |
253 | 0 | { |
254 | 0 | if (!maybeObject()) { |
255 | 0 | return false; |
256 | 0 | } |
257 | | |
258 | 0 | if (m_value.isObject()) { |
259 | 0 | const opt::optional<Object> object = m_value.getObjectOptional(); |
260 | 0 | for (const ObjectMemberType member : *object) { |
261 | 0 | if (!fn(member.first, AdapterType(member.second))) { |
262 | 0 | return false; |
263 | 0 | } |
264 | 0 | } |
265 | 0 | } |
266 | | |
267 | 0 | return true; |
268 | 0 | } |
269 | | |
270 | | /** |
271 | | * @brief Return an ArrayType instance containing an array representation |
272 | | * of the value held by this Adapter. |
273 | | * |
274 | | * This is a convenience function that is not actually declared in the |
275 | | * Adapter interface, but allows for useful techniques such as procedural |
276 | | * iteration over the elements in an array. The ArrayType instance that is |
277 | | * returned by this function is compatible with the BOOST_FOREACH macro. |
278 | | * |
279 | | * If the contained value is either an empty object, or an empty string, |
280 | | * then this function will cast the value to an empty array. |
281 | | * |
282 | | * @returns ArrayType instance containing an array representation of the |
283 | | * value held by this Adapter. |
284 | | */ |
285 | | ArrayType asArray() const |
286 | 0 | { |
287 | 0 | if (m_value.isArray()) { |
288 | 0 | return *m_value.getArrayOptional(); |
289 | 0 | } else if (m_value.isObject()) { |
290 | 0 | size_t objectSize; |
291 | 0 | if (m_value.getObjectSize(objectSize) && objectSize == 0) { |
292 | 0 | return ArrayType(); |
293 | 0 | } |
294 | 0 | } else if (m_value.isString()) { |
295 | 0 | std::string stringValue; |
296 | 0 | if (m_value.getString(stringValue) && stringValue.empty()) { |
297 | 0 | return ArrayType(); |
298 | 0 | } |
299 | 0 | } |
300 | | |
301 | 0 | throwRuntimeError("JSON value cannot be cast to an array."); |
302 | 0 | } |
303 | | |
304 | | bool asBool() const override |
305 | 0 | { |
306 | 0 | bool result; |
307 | 0 | if (asBool(result)) { |
308 | 0 | return result; |
309 | 0 | } |
310 | | |
311 | 0 | throwRuntimeError("JSON value cannot be cast to a boolean."); |
312 | 0 | } |
313 | | |
314 | | bool asBool(bool &result) const override |
315 | 0 | { |
316 | 0 | if (m_value.isBool()) { |
317 | 0 | return m_value.getBool(result); |
318 | 0 | } else if (m_value.isString()) { |
319 | 0 | std::string s; |
320 | 0 | if (m_value.getString(s)) { |
321 | 0 | if (s == "true") { |
322 | 0 | result = true; |
323 | 0 | return true; |
324 | 0 | } else if (s == "false") { |
325 | 0 | result = false; |
326 | 0 | return true; |
327 | 0 | } |
328 | 0 | } |
329 | 0 | } |
330 | | |
331 | 0 | return false; |
332 | 0 | } |
333 | | |
334 | | double asDouble() const override |
335 | 0 | { |
336 | 0 | double result; |
337 | 0 | if (asDouble(result)) { |
338 | 0 | return result; |
339 | 0 | } |
340 | | |
341 | 0 | throwRuntimeError("JSON value cannot be cast to a double."); |
342 | 0 | } |
343 | | |
344 | | bool asDouble(double &result) const override |
345 | 0 | { |
346 | 0 | if (m_value.isDouble()) { |
347 | 0 | return m_value.getDouble(result); |
348 | 0 | } else if (m_value.isInteger()) { |
349 | 0 | int64_t i; |
350 | 0 | if (m_value.getInteger(i)) { |
351 | 0 | result = double(i); |
352 | 0 | return true; |
353 | 0 | } |
354 | 0 | } else if (m_value.isString()) { |
355 | 0 | std::string s; |
356 | 0 | if (m_value.getString(s)) { |
357 | 0 | const char *b = s.c_str(); |
358 | 0 | char *e = nullptr; |
359 | 0 | double x = strtod(b, &e); |
360 | 0 | if (e == b || e != b + s.length()) { |
361 | 0 | return false; |
362 | 0 | } |
363 | 0 | result = x; |
364 | 0 | return true; |
365 | 0 | } |
366 | 0 | } |
367 | | |
368 | 0 | return false; |
369 | 0 | } |
370 | | |
371 | | int64_t asInteger() const override |
372 | 0 | { |
373 | 0 | int64_t result; |
374 | 0 | if (asInteger(result)) { |
375 | 0 | return result; |
376 | 0 | } |
377 | | |
378 | 0 | throwRuntimeError("JSON value cannot be cast as an integer."); |
379 | 0 | } |
380 | | |
381 | | bool asInteger(int64_t &result) const override |
382 | 0 | { |
383 | 0 | if (m_value.isInteger()) { |
384 | 0 | return m_value.getInteger(result); |
385 | 0 | } else if (m_value.isString()) { |
386 | 0 | std::string s; |
387 | 0 | if (m_value.getString(s)) { |
388 | 0 | std::istringstream i(s); |
389 | 0 | int64_t x; |
390 | 0 | char c; |
391 | 0 | if (!(!(i >> x) || i.get(c))) { |
392 | 0 | result = x; |
393 | 0 | return true; |
394 | 0 | } |
395 | 0 | } |
396 | 0 | } |
397 | | |
398 | 0 | return false; |
399 | 0 | } |
400 | | |
401 | | /** |
402 | | * @brief Return an ObjectType instance containing an array representation |
403 | | * of the value held by this Adapter. |
404 | | * |
405 | | * This is a convenience function that is not actually declared in the |
406 | | * Adapter interface, but allows for useful techniques such as procedural |
407 | | * iteration over the members of the object. The ObjectType instance that is |
408 | | * returned by this function is compatible with the BOOST_FOREACH macro. |
409 | | * |
410 | | * @returns ObjectType instance containing an object representation of the |
411 | | * value held by this Adapter. |
412 | | */ |
413 | | ObjectType asObject() const |
414 | 0 | { |
415 | 0 | if (m_value.isObject()) { |
416 | 0 | return *m_value.getObjectOptional(); |
417 | 0 | } else if (m_value.isArray()) { |
418 | 0 | size_t arraySize; |
419 | 0 | if (m_value.getArraySize(arraySize) && arraySize == 0) { |
420 | 0 | return ObjectType(); |
421 | 0 | } |
422 | 0 | } else if (m_value.isString()) { |
423 | 0 | std::string stringValue; |
424 | 0 | if (m_value.getString(stringValue) && stringValue.empty()) { |
425 | 0 | return ObjectType(); |
426 | 0 | } |
427 | 0 | } |
428 | | |
429 | 0 | throwRuntimeError("JSON value cannot be cast to an object."); |
430 | 0 | } |
431 | | |
432 | | std::string asString() const override |
433 | 0 | { |
434 | 0 | std::string result; |
435 | 0 | if (asString(result)) { |
436 | 0 | return result; |
437 | 0 | } |
438 | | |
439 | 0 | throwRuntimeError("JSON value cannot be cast to a string."); |
440 | 0 | } |
441 | | |
442 | | bool asString(std::string &result) const override |
443 | 0 | { |
444 | 0 | if (m_value.isString()) { |
445 | 0 | return m_value.getString(result); |
446 | 0 | } else if (m_value.isNull()) { |
447 | 0 | result.clear(); |
448 | 0 | return true; |
449 | 0 | } else if (m_value.isArray()) { |
450 | 0 | size_t arraySize; |
451 | 0 | if (m_value.getArraySize(arraySize) && arraySize == 0) { |
452 | 0 | result.clear(); |
453 | 0 | return true; |
454 | 0 | } |
455 | 0 | } else if (m_value.isObject()) { |
456 | 0 | size_t objectSize; |
457 | 0 | if (m_value.getObjectSize(objectSize) && objectSize == 0) { |
458 | 0 | result.clear(); |
459 | 0 | return true; |
460 | 0 | } |
461 | 0 | } else if (m_value.isBool()) { |
462 | 0 | bool boolValue; |
463 | 0 | if (m_value.getBool(boolValue)) { |
464 | 0 | result = boolValue ? "true" : "false"; |
465 | 0 | return true; |
466 | 0 | } |
467 | 0 | } else if (m_value.isInteger()) { |
468 | 0 | int64_t integerValue; |
469 | 0 | if (m_value.getInteger(integerValue)) { |
470 | 0 | result = std::to_string(integerValue); |
471 | 0 | return true; |
472 | 0 | } |
473 | 0 | } else if (m_value.isDouble()) { |
474 | 0 | double doubleValue; |
475 | 0 | if (m_value.getDouble(doubleValue)) { |
476 | 0 | result = std::to_string(doubleValue); |
477 | 0 | return true; |
478 | 0 | } |
479 | 0 | } |
480 | | |
481 | 0 | return false; |
482 | 0 | } |
483 | | |
484 | | bool equalTo(const Adapter &other, bool strict) const override |
485 | 0 | { |
486 | 0 | if (isNull() || (!strict && maybeNull())) { |
487 | 0 | return other.isNull() || (!strict && other.maybeNull()); |
488 | 0 | } else if (isBool() || (!strict && maybeBool())) { |
489 | 0 | return (other.isBool() || (!strict && other.maybeBool())) && other.asBool() == asBool(); |
490 | 0 | } else if (isNumber() && strict) { |
491 | 0 | return other.isNumber() && other.getNumber() == getNumber(); |
492 | 0 | } else if (!strict && maybeDouble()) { |
493 | 0 | return (other.maybeDouble() && other.asDouble() == asDouble()); |
494 | 0 | } else if (!strict && maybeInteger()) { |
495 | 0 | return (other.maybeInteger() && other.asInteger() == asInteger()); |
496 | 0 | } else if (isString() || (!strict && maybeString())) { |
497 | 0 | return (other.isString() || (!strict && other.maybeString())) && |
498 | 0 | other.asString() == asString(); |
499 | 0 | } else if (isArray()) { |
500 | 0 | if (other.isArray() && getArraySize() == other.getArraySize()) { |
501 | 0 | const opt::optional<ArrayType> array = m_value.getArrayOptional(); |
502 | 0 | if (array) { |
503 | 0 | ArrayComparisonFunctor fn(*array, strict); |
504 | 0 | return other.applyToArray(fn); |
505 | 0 | } |
506 | 0 | } else if (!strict && other.maybeArray() && getArraySize() == 0) { |
507 | 0 | return true; |
508 | 0 | } |
509 | 0 | } else if (isObject()) { |
510 | 0 | if (other.isObject() && other.getObjectSize() == getObjectSize()) { |
511 | 0 | const opt::optional<ObjectType> object = m_value.getObjectOptional(); |
512 | 0 | if (object) { |
513 | 0 | ObjectComparisonFunctor fn(*object, strict); |
514 | 0 | return other.applyToObject(fn); |
515 | 0 | } |
516 | 0 | } else if (!strict && other.maybeObject() && getObjectSize() == 0) { |
517 | 0 | return true; |
518 | 0 | } |
519 | 0 | } |
520 | | |
521 | 0 | return false; |
522 | 0 | } |
523 | | |
524 | | /** |
525 | | * @brief Return an ArrayType instance representing the array contained |
526 | | * by this Adapter instance. |
527 | | * |
528 | | * This is a convenience function that is not actually declared in the |
529 | | * Adapter interface, but allows for useful techniques such as procedural |
530 | | * iteration over the elements in an array. The ArrayType instance that is |
531 | | * returned by this function is compatible with the BOOST_FOREACH macro. |
532 | | * |
533 | | * If the contained is not an array, this function will throw an exception. |
534 | | * |
535 | | * @returns ArrayType instance containing an array representation of the |
536 | | * value held by this Adapter. |
537 | | */ |
538 | | ArrayType getArray() const |
539 | 0 | { |
540 | 0 | opt::optional<ArrayType> arrayValue = m_value.getArrayOptional(); |
541 | 0 | if (arrayValue) { |
542 | 0 | return *arrayValue; |
543 | 0 | } |
544 | | |
545 | 0 | throwRuntimeError("JSON value is not an array."); |
546 | 0 | } |
547 | | |
548 | | size_t getArraySize() const override |
549 | 0 | { |
550 | 0 | size_t result; |
551 | 0 | if (m_value.getArraySize(result)) { |
552 | 0 | return result; |
553 | 0 | } |
554 | | |
555 | 0 | throwRuntimeError("JSON value is not an array."); |
556 | 0 | } |
557 | | |
558 | | bool getArraySize(size_t &result) const override |
559 | 0 | { |
560 | 0 | return m_value.getArraySize(result); |
561 | 0 | } |
562 | | |
563 | | bool getBool() const override |
564 | 0 | { |
565 | 0 | bool result; |
566 | 0 | if (getBool(result)) { |
567 | 0 | return result; |
568 | 0 | } |
569 | | |
570 | 0 | throwRuntimeError("JSON value is not a boolean."); |
571 | 0 | } |
572 | | |
573 | | bool getBool(bool &result) const override |
574 | 0 | { |
575 | 0 | return m_value.getBool(result); |
576 | 0 | } |
577 | | |
578 | | double getDouble() const override |
579 | 0 | { |
580 | 0 | double result; |
581 | 0 | if (getDouble(result)) { |
582 | 0 | return result; |
583 | 0 | } |
584 | | |
585 | 0 | throwRuntimeError("JSON value is not a double."); |
586 | 0 | } |
587 | | |
588 | | bool getDouble(double &result) const override |
589 | 0 | { |
590 | 0 | return m_value.getDouble(result); |
591 | 0 | } |
592 | | |
593 | | int64_t getInteger() const override |
594 | 0 | { |
595 | 0 | int64_t result; |
596 | 0 | if (getInteger(result)) { |
597 | 0 | return result; |
598 | 0 | } |
599 | | |
600 | 0 | throwRuntimeError("JSON value is not an integer."); |
601 | 0 | } |
602 | | |
603 | | bool getInteger(int64_t &result) const override |
604 | 0 | { |
605 | 0 | return m_value.getInteger(result); |
606 | 0 | } |
607 | | |
608 | | double getNumber() const override |
609 | 0 | { |
610 | 0 | double result; |
611 | 0 | if (getNumber(result)) { |
612 | 0 | return result; |
613 | 0 | } |
614 | | |
615 | 0 | throwRuntimeError("JSON value is not a number."); |
616 | 0 | } |
617 | | |
618 | | bool getNumber(double &result) const override |
619 | 0 | { |
620 | 0 | if (isDouble()) { |
621 | 0 | return getDouble(result); |
622 | 0 | } else if (isInteger()) { |
623 | 0 | int64_t integerResult; |
624 | 0 | if (getInteger(integerResult)) { |
625 | 0 | result = static_cast<double>(integerResult); |
626 | 0 | return true; |
627 | 0 | } |
628 | 0 | } |
629 | | |
630 | 0 | return false; |
631 | 0 | } |
632 | | |
633 | | /** |
634 | | * @brief Return an ObjectType instance representing the object contained |
635 | | * by this Adapter instance. |
636 | | * |
637 | | * This is a convenience function that is not actually declared in the |
638 | | * Adapter interface, but allows for useful techniques such as procedural |
639 | | * iteration over the members of an object. The ObjectType instance that is |
640 | | * returned by this function is compatible with the BOOST_FOREACH macro. |
641 | | * |
642 | | * If the contained is not an object, this function will throw an exception. |
643 | | * |
644 | | * @returns ObjectType instance containing an array representation of the |
645 | | * value held by this Adapter. |
646 | | */ |
647 | | ObjectType getObject() const |
648 | 0 | { |
649 | 0 | opt::optional<ObjectType> objectValue = m_value.getObjectOptional(); |
650 | 0 | if (objectValue) { |
651 | 0 | return *objectValue; |
652 | 0 | } |
653 | | |
654 | 0 | throwRuntimeError("JSON value is not an object."); |
655 | 0 | } |
656 | | |
657 | | size_t getObjectSize() const override |
658 | 0 | { |
659 | 0 | size_t result; |
660 | 0 | if (getObjectSize(result)) { |
661 | 0 | return result; |
662 | 0 | } |
663 | | |
664 | 0 | throwRuntimeError("JSON value is not an object."); |
665 | 0 | } |
666 | | |
667 | | bool getObjectSize(size_t &result) const override |
668 | 0 | { |
669 | 0 | return m_value.getObjectSize(result); |
670 | 0 | } |
671 | | |
672 | | std::string getString() const override |
673 | 0 | { |
674 | 0 | std::string result; |
675 | 0 | if (getString(result)) { |
676 | 0 | return result; |
677 | 0 | } |
678 | | |
679 | 0 | throwRuntimeError("JSON value is not a string."); |
680 | 0 | } |
681 | | |
682 | | bool getString(std::string &result) const override |
683 | 0 | { |
684 | 0 | return m_value.getString(result); |
685 | 0 | } |
686 | | |
687 | | FrozenValue * freeze() const override |
688 | 0 | { |
689 | 0 | return m_value.freeze(); |
690 | 0 | } |
691 | | |
692 | | bool hasStrictTypes() const override |
693 | 0 | { |
694 | 0 | return ValueType::hasStrictTypes(); |
695 | 0 | } |
696 | | |
697 | | bool isArray() const override |
698 | 103 | { |
699 | 103 | return m_value.isArray(); |
700 | 103 | } |
701 | | |
702 | | bool isBool() const override |
703 | 0 | { |
704 | 0 | return m_value.isBool(); |
705 | 0 | } |
706 | | |
707 | | bool isDouble() const override |
708 | 0 | { |
709 | 0 | return m_value.isDouble(); |
710 | 0 | } |
711 | | |
712 | | bool isInteger() const override |
713 | 0 | { |
714 | 0 | return m_value.isInteger(); |
715 | 0 | } |
716 | | |
717 | | bool isNull() const override |
718 | 103 | { |
719 | 103 | return m_value.isNull(); |
720 | 103 | } |
721 | | |
722 | | bool isNumber() const override |
723 | 0 | { |
724 | 0 | return m_value.isInteger() || m_value.isDouble(); |
725 | 0 | } |
726 | | |
727 | | bool isObject() const override |
728 | 309 | { |
729 | 309 | return m_value.isObject(); |
730 | 309 | } |
731 | | |
732 | | bool isString() const override |
733 | 103 | { |
734 | 103 | return m_value.isString(); |
735 | 103 | } |
736 | | |
737 | | bool maybeArray() const override |
738 | 0 | { |
739 | 0 | if (m_value.isArray()) { |
740 | 0 | return true; |
741 | 0 | } else if (m_value.isObject()) { |
742 | 0 | size_t objectSize; |
743 | 0 | if (m_value.getObjectSize(objectSize) && objectSize == 0) { |
744 | 0 | return true; |
745 | 0 | } |
746 | 0 | } |
747 | | |
748 | 0 | return false; |
749 | 0 | } |
750 | | |
751 | | bool maybeBool() const override |
752 | 103 | { |
753 | 103 | if (m_value.isBool()) { |
754 | 0 | return true; |
755 | 103 | } else if (maybeString()) { |
756 | 0 | std::string stringValue; |
757 | 0 | if (m_value.getString(stringValue)) { |
758 | 0 | if (stringValue == "true" || stringValue == "false") { |
759 | 0 | return true; |
760 | 0 | } |
761 | 0 | } |
762 | 0 | } |
763 | | |
764 | 103 | return false; |
765 | 103 | } |
766 | | |
767 | | bool maybeDouble() const override |
768 | 0 | { |
769 | 0 | if (m_value.isNumber()) { |
770 | 0 | return true; |
771 | 0 | } else if (maybeString()) { |
772 | 0 | std::string s; |
773 | 0 | if (m_value.getString(s)) { |
774 | 0 | const char *b = s.c_str(); |
775 | 0 | char *e = nullptr; |
776 | 0 | strtod(b, &e); |
777 | 0 | return e != b && e == b + s.length(); |
778 | 0 | } |
779 | 0 | } |
780 | | |
781 | 0 | return false; |
782 | 0 | } |
783 | | |
784 | | bool maybeInteger() const override |
785 | 0 | { |
786 | 0 | if (m_value.isInteger()) { |
787 | 0 | return true; |
788 | 0 | } else if (maybeString()) { |
789 | 0 | std::string s; |
790 | 0 | if (m_value.getString(s)) { |
791 | 0 | std::istringstream i(s); |
792 | 0 | int64_t x; |
793 | 0 | char c; |
794 | 0 | if (!(i >> x) || i.get(c)) { |
795 | 0 | return false; |
796 | 0 | } |
797 | 0 | return true; |
798 | 0 | } |
799 | 0 | } |
800 | | |
801 | 0 | return false; |
802 | 0 | } |
803 | | |
804 | | bool maybeNull() const override |
805 | 0 | { |
806 | 0 | if (m_value.isNull()) { |
807 | 0 | return true; |
808 | 0 | } else if (maybeString()) { |
809 | 0 | std::string stringValue; |
810 | 0 | if (m_value.getString(stringValue)) { |
811 | 0 | if (stringValue.empty()) { |
812 | 0 | return true; |
813 | 0 | } |
814 | 0 | } |
815 | 0 | } |
816 | | |
817 | 0 | return false; |
818 | 0 | } |
819 | | |
820 | | bool maybeObject() const override |
821 | 0 | { |
822 | 0 | if (m_value.isObject()) { |
823 | 0 | return true; |
824 | 0 | } else if (maybeArray()) { |
825 | 0 | size_t arraySize; |
826 | 0 | if (m_value.getArraySize(arraySize) && arraySize == 0) { |
827 | 0 | return true; |
828 | 0 | } |
829 | 0 | } |
830 | | |
831 | 0 | return false; |
832 | 0 | } |
833 | | |
834 | | bool maybeString() const override |
835 | 103 | { |
836 | 103 | if (m_value.isString() || m_value.isBool() || m_value.isInteger() || m_value.isDouble()) { |
837 | 0 | return true; |
838 | 103 | } else if (m_value.isObject()) { |
839 | 0 | size_t objectSize; |
840 | 0 | if (m_value.getObjectSize(objectSize) && objectSize == 0) { |
841 | 0 | return true; |
842 | 0 | } |
843 | 103 | } else if (m_value.isArray()) { |
844 | 0 | size_t arraySize; |
845 | 0 | if (m_value.getArraySize(arraySize) && arraySize == 0) { |
846 | 0 | return true; |
847 | 0 | } |
848 | 0 | } |
849 | | |
850 | 103 | return false; |
851 | 103 | } |
852 | | |
853 | | private: |
854 | | |
855 | | const ValueType m_value; |
856 | | }; |
857 | | |
858 | | } // namespace adapters |
859 | | } // namespace valijson |