• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

open-source-parsers / jsoncpp / 25890827385

14 May 2026 11:08PM UTC coverage: 89.987% (-0.2%) from 90.149%
25890827385

Pull #1686

github

baylesj
feat: improve type assertion messages with actual ValueType (#1627)

When indexing into a Json::Value, several assertions check that the value is an object or array. This commit enhances the error messages by reporting the actual type found, making it easier for users to debug type mismatch issues.

Fixes #1627
Pull Request #1686: feat: improve type assertion messages with actual ValueType

2201 of 2614 branches covered (84.2%)

Branch coverage included in aggregate %.

18 of 22 new or added lines in 1 file covered. (81.82%)

36 existing lines in 1 file now uncovered.

2598 of 2719 relevant lines covered (95.55%)

23495.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.48
/src/lib_json/json_value.cpp
1
// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors
2
// Distributed under MIT license, or public domain if desired and
3
// recognized in your jurisdiction.
4
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
5

6
#if !defined(JSON_IS_AMALGAMATION)
7
#include <json/assertions.h>
8
#include <json/value.h>
9
#include <json/writer.h>
10
#endif // if !defined(JSON_IS_AMALGAMATION)
11
#include <algorithm>
12
#include <cassert>
13
#include <cmath>
14
#include <cstddef>
15
#include <cstring>
16
#include <iostream>
17
#include <sstream>
18
#include <utility>
19

20
// Provide implementation equivalent of std::snprintf for older _MSC compilers
21
#if defined(_MSC_VER) && _MSC_VER < 1900
22
#include <stdarg.h>
23
static int msvc_pre1900_c99_vsnprintf(char* outBuf, size_t size,
24
                                      const char* format, va_list ap) {
25
  int count = -1;
26
  if (size != 0)
27
    count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
28
  if (count == -1)
29
    count = _vscprintf(format, ap);
30
  return count;
31
}
32

33
int JSON_API msvc_pre1900_c99_snprintf(char* outBuf, size_t size,
34
                                       const char* format, ...) {
35
  va_list ap;
36
  va_start(ap, format);
37
  const int count = msvc_pre1900_c99_vsnprintf(outBuf, size, format, ap);
38
  va_end(ap);
39
  return count;
40
}
41
#endif
42

43
// Disable warning C4702 : unreachable code
44
#if defined(_MSC_VER)
45
#pragma warning(disable : 4702)
46
#endif
47

48
#define JSON_ASSERT_UNREACHABLE assert(false)
49

50
namespace Json {
51
template <typename T>
52
static std::unique_ptr<T> cloneUnique(const std::unique_ptr<T>& p) {
245,138✔
53
  std::unique_ptr<T> r;
245,138✔
54
  if (p) {
245,138✔
55
    r = std::unique_ptr<T>(new T(*p));
6✔
56
  }
57
  return r;
245,138✔
58
}
59

60
// This is a walkaround to avoid the static initialization of Value::null.
61
// kNull must be word-aligned to avoid crashing on ARM.  We use an alignment of
62
// 8 (instead of 4) as a bit of future-proofing.
63
#if defined(__ARMEL__)
64
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
65
#else
66
#define ALIGNAS(byte_alignment)
67
#endif
68

69
// static
70
Value const& Value::nullSingleton() {
123,416✔
71
  static Value const nullStatic;
123,416!
72
  return nullStatic;
123,416✔
73
}
74

75
#if JSON_USE_NULLREF
76
// for backwards compatibility, we'll leave these global references around, but
77
// DO NOT use them in JSONCPP library code any more!
78
// static
79
Value const& Value::null = Value::nullSingleton();
80

81
// static
82
Value const& Value::nullRef = Value::nullSingleton();
83
#endif
84

85
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
86
template <typename T, typename U>
87
static inline bool InRange(double d, T min, U max) {
88
  // The casts can lose precision, but we are looking only for
89
  // an approximate range. Might fail on edge cases though. ~cdunn
90
  return d >= static_cast<double>(min) && d <= static_cast<double>(max) &&
91
         !(static_cast<U>(d) == min && d != static_cast<double>(min));
92
}
93
#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
94
static inline double integerToDouble(Json::UInt64 value) {
95
  return static_cast<double>(Int64(value / 2)) * 2.0 +
21✔
96
         static_cast<double>(Int64(value & 1));
21✔
97
}
98

99
template <typename T> static inline double integerToDouble(T value) {
100
  return static_cast<double>(value);
101
}
102

103
template <typename T, typename U>
104
static inline bool InRange(double d, T min, U max) {
105
  return d >= integerToDouble(min) && d <= integerToDouble(max) &&
45!
106
         !(static_cast<U>(d) == min && d != integerToDouble(min));
34!
107
}
108
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
109

110
/** Duplicates the specified string value.
111
 * @param value Pointer to the string to duplicate. Must be zero-terminated if
112
 *              length is "unknown".
113
 * @param length Length of the value. if equals to unknown, then it will be
114
 *               computed using strlen(value).
115
 * @return Pointer on the duplicate instance of string.
116
 */
117
static inline char* duplicateStringValue(const char* value, size_t length) {
30,545✔
118
  // Avoid an integer overflow in the call to malloc below by limiting length
119
  // to a sane value.
120
  if (length >= static_cast<size_t>(Value::maxInt))
30,545✔
121
    length = Value::maxInt - 1;
122

123
  auto newString = static_cast<char*>(malloc(length + 1));
30,545✔
124
  if (newString == nullptr) {
30,545!
125
    throwRuntimeError("in Json::Value::duplicateStringValue(): "
×
126
                      "Failed to allocate string value buffer");
127
  }
128
  memcpy(newString, value, length);
129
  newString[length] = 0;
30,545✔
130
  return newString;
30,545✔
131
}
132

133
/* Record the length as a prefix.
134
 */
135
static inline char* duplicateAndPrefixStringValue(const char* value,
2,661✔
136
                                                  unsigned int length) {
137
  // Avoid an integer overflow in the call to malloc below by limiting length
138
  // to a sane value.
139
  JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) -
2,661!
140
                                    sizeof(unsigned) - 1U,
141
                      "in Json::Value::duplicateAndPrefixStringValue(): "
142
                      "length too big for prefixing");
143
  size_t actualLength = sizeof(length) + length + 1;
2,661✔
144
  auto newString = static_cast<char*>(malloc(actualLength));
2,661✔
145
  if (newString == nullptr) {
2,661!
146
    throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): "
×
147
                      "Failed to allocate string value buffer");
148
  }
149
  *reinterpret_cast<unsigned*>(newString) = length;
2,661✔
150
  memcpy(newString + sizeof(unsigned), value, length);
2,661✔
151
  newString[actualLength - 1U] =
2,661✔
152
      0; // to avoid buffer over-run accidents by users later
153
  return newString;
2,661✔
154
}
155
inline static void decodePrefixedString(bool isPrefixed, char const* prefixed,
156
                                        unsigned* length, char const** value) {
157
  if (!isPrefixed) {
4,030!
158
    *length = static_cast<unsigned>(strlen(prefixed));
3✔
159
    *value = prefixed;
×
160
  } else {
161
    *length = *reinterpret_cast<unsigned const*>(prefixed);
4,163✔
162
    *value = prefixed + sizeof(unsigned);
4,027✔
163
  }
164
}
165
/** Free the string duplicated by
166
 * duplicateStringValue()/duplicateAndPrefixStringValue().
167
 */
168
#if JSONCPP_USE_SECURE_MEMORY
169
static inline void releasePrefixedStringValue(char* value) {
170
  unsigned length = 0;
171
  char const* valueDecoded;
172
  decodePrefixedString(true, value, &length, &valueDecoded);
173
  size_t const size = sizeof(unsigned) + length + 1U;
174
  memset(value, 0, size);
175
  free(value);
176
}
177
static inline void releaseStringValue(char* value, unsigned length) {
178
  // length==0 => we allocated the strings memory
179
  size_t size = (length == 0) ? strlen(value) : length;
180
  memset(value, 0, size);
181
  free(value);
182
}
183
#else  // !JSONCPP_USE_SECURE_MEMORY
184
static inline void releasePrefixedStringValue(char* value) { free(value); }
1✔
185
static inline void releaseStringValue(char* value, unsigned) { free(value); }
30,544✔
186
#endif // JSONCPP_USE_SECURE_MEMORY
187

188
} // namespace Json
189

190
// //////////////////////////////////////////////////////////////////
191
// //////////////////////////////////////////////////////////////////
192
// //////////////////////////////////////////////////////////////////
193
// ValueInternals...
194
// //////////////////////////////////////////////////////////////////
195
// //////////////////////////////////////////////////////////////////
196

197
namespace Json {
198

199
static const char* valueTypeToString(ValueType type) {
9✔
200
  switch (type) {
9!
201
  case nullValue: return "nullValue";
202
  case intValue: return "intValue";
3✔
NEW
203
  case uintValue: return "uintValue";
×
NEW
204
  case realValue: return "realValue";
×
205
  case stringValue: return "stringValue";
3✔
NEW
206
  case booleanValue: return "booleanValue";
×
207
  case arrayValue: return "arrayValue";
2✔
208
  case objectValue: return "objectValue";
1✔
209
  }
NEW
210
  return "unknown";
×
211
}
212

213
} // namespace Json
214
// //////////////////////////////////////////////////////////////////
215
#if !defined(JSON_IS_AMALGAMATION)
216

217
#include "json_valueiterator.inl"
218
#endif // if !defined(JSON_IS_AMALGAMATION)
219

220
namespace Json {
221

222
#if JSON_USE_EXCEPTION
223
Exception::Exception(String msg) : msg_(std::move(msg)) {}
49✔
224
Exception::~Exception() noexcept = default;
49✔
225
char const* Exception::what() const noexcept { return msg_.c_str(); }
6✔
226
RuntimeError::RuntimeError(String const& msg) : Exception(msg) {}
18✔
227
LogicError::LogicError(String const& msg) : Exception(msg) {}
80✔
228
JSONCPP_NORETURN void throwRuntimeError(String const& msg) {
9✔
229
  throw RuntimeError(msg);
9✔
230
}
231
JSONCPP_NORETURN void throwLogicError(String const& msg) {
40✔
232
  throw LogicError(msg);
40✔
233
}
234
#else // !JSON_USE_EXCEPTION
235
JSONCPP_NORETURN void throwRuntimeError(String const& msg) {
236
  std::cerr << msg << std::endl;
237
  abort();
238
}
239
JSONCPP_NORETURN void throwLogicError(String const& msg) {
240
  std::cerr << msg << std::endl;
241
  abort();
242
}
243
#endif
244

245
// //////////////////////////////////////////////////////////////////
246
// //////////////////////////////////////////////////////////////////
247
// //////////////////////////////////////////////////////////////////
248
// class Value::CZString
249
// //////////////////////////////////////////////////////////////////
250
// //////////////////////////////////////////////////////////////////
251
// //////////////////////////////////////////////////////////////////
252

253
// Notes: policy_ indicates if the string was allocated when
254
// a string is stored.
255

256
Value::CZString::CZString(ArrayIndex index) : cstr_(nullptr), index_(index) {}
265,335✔
257

258
Value::CZString::CZString(char const* str, unsigned length,
36,653✔
259
                          DuplicationPolicy allocate)
36,653✔
260
    : cstr_(str) {
36,653✔
261
  // allocate != duplicate
262
  storage_.policy_ = allocate & 0x3;
36,653✔
263
  storage_.length_ = length & 0x3FFFFFFF;
36,653✔
264
}
36,653✔
265

266
Value::CZString::CZString(const CZString& other) {
244,837✔
267
  cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr
188,031✔
268
               ? duplicateStringValue(other.cstr_, other.storage_.length_)
432,868✔
269
               : other.cstr_);
270
  if (other.cstr_) {
244,837✔
271
    storage_.policy_ =
30,548✔
272
        static_cast<unsigned>(
273
            other.cstr_
274
                ? (static_cast<DuplicationPolicy>(other.storage_.policy_) ==
30,548✔
275
                           noDuplication
276
                       ? noDuplication
30,548✔
277
                       : duplicate)
278
                : static_cast<DuplicationPolicy>(other.storage_.policy_)) &
30,548✔
279
        3U;
280
    storage_.length_ = other.storage_.length_;
30,548✔
281
  } else {
282
    index_ = other.index_;
214,289✔
283
  }
284
}
244,837✔
285

286
Value::CZString::CZString(CZString&& other) noexcept : cstr_(other.cstr_) {
2✔
287
  if (other.cstr_) {
2✔
288
    storage_.policy_ = other.storage_.policy_;
1✔
289
    storage_.length_ = other.storage_.length_;
1✔
290
  } else {
291
    index_ = other.index_;
1✔
292
  }
293
  other.cstr_ = nullptr;
2✔
294
}
2✔
295

296
Value::CZString::~CZString() {
546,827✔
297
  if (cstr_ && storage_.policy_ == duplicate) {
546,827✔
298
    releaseStringValue(const_cast<char*>(cstr_),
299
                       storage_.length_ + 1U); // +1 for null terminating
300
                                               // character for sake of
301
                                               // completeness but not actually
302
                                               // necessary
303
  }
304
}
546,827✔
305

UNCOV
306
void Value::CZString::swap(CZString& other) {
×
307
  std::swap(cstr_, other.cstr_);
308
  std::swap(index_, other.index_);
UNCOV
309
}
×
310

UNCOV
311
Value::CZString& Value::CZString::operator=(const CZString& other) {
×
UNCOV
312
  cstr_ = other.cstr_;
×
UNCOV
313
  index_ = other.index_;
×
314
  return *this;
×
315
}
316

317
Value::CZString& Value::CZString::operator=(CZString&& other) noexcept {
2✔
318
  if (cstr_ && storage_.policy_ == duplicate) {
2!
319
    releasePrefixedStringValue(const_cast<char*>(cstr_));
320
  }
321
  cstr_ = other.cstr_;
2✔
322
  if (other.cstr_) {
2✔
323
    storage_.policy_ = other.storage_.policy_;
1✔
324
    storage_.length_ = other.storage_.length_;
1✔
325
  } else {
326
    index_ = other.index_;
1✔
327
  }
328
  other.cstr_ = nullptr;
2✔
329
  return *this;
2✔
330
}
331

332
bool Value::CZString::operator<(const CZString& other) const {
3,942,049✔
333
  if (!cstr_)
3,942,049✔
334
    return index_ < other.index_;
3,782,658✔
335
  // return strcmp(cstr_, other.cstr_) < 0;
336
  // Assume both are strings.
337
  unsigned this_len = this->storage_.length_;
159,391✔
338
  unsigned other_len = other.storage_.length_;
159,391✔
339
  unsigned min_len = std::min<unsigned>(this_len, other_len);
159,391✔
340
  JSON_ASSERT(this->cstr_ && other.cstr_);
159,391!
341
  int comp = memcmp(this->cstr_, other.cstr_, min_len);
159,391✔
342
  if (comp < 0)
159,391✔
343
    return true;
344
  if (comp > 0)
81,306✔
345
    return false;
346
  return (this_len < other_len);
40,624✔
347
}
348

349
bool Value::CZString::operator==(const CZString& other) const {
120,415✔
350
  if (!cstr_)
120,415✔
351
    return index_ == other.index_;
104,935✔
352
  // return strcmp(cstr_, other.cstr_) == 0;
353
  // Assume both are strings.
354
  unsigned this_len = this->storage_.length_;
15,480✔
355
  unsigned other_len = other.storage_.length_;
15,480✔
356
  if (this_len != other_len)
15,480✔
357
    return false;
358
  JSON_ASSERT(this->cstr_ && other.cstr_);
5,418!
359
  int comp = memcmp(this->cstr_, other.cstr_, this_len);
5,418✔
360
  return comp == 0;
5,418✔
361
}
362

363
ArrayIndex Value::CZString::index() const { return index_; }
724✔
364

365
// const char* Value::CZString::c_str() const { return cstr_; }
366
const char* Value::CZString::data() const { return cstr_; }
1,736✔
367
unsigned Value::CZString::length() const { return storage_.length_; }
1,717✔
368
bool Value::CZString::isStaticString() const {
3✔
369
  return storage_.policy_ == noDuplication;
3✔
370
}
371

372
// //////////////////////////////////////////////////////////////////
373
// //////////////////////////////////////////////////////////////////
374
// //////////////////////////////////////////////////////////////////
375
// class Value::Value
376
// //////////////////////////////////////////////////////////////////
377
// //////////////////////////////////////////////////////////////////
378
// //////////////////////////////////////////////////////////////////
379

380
/*! \internal Default constructor initialization must be equivalent to:
381
 * memset( this, 0, sizeof(Value) )
382
 * This optimization is used in ValueInternalMap fast allocator.
383
 */
384
Value::Value(ValueType type) {
114,575✔
385
  static char const emptyString[] = "";
386
  initBasic(type);
114,575✔
387
  switch (type) {
114,575!
388
  case nullValue:
389
    break;
390
  case intValue:
2✔
391
  case uintValue:
392
    value_.int_ = 0;
2✔
393
    break;
2✔
394
  case realValue:
1✔
395
    value_.real_ = 0.0;
1✔
396
    break;
1✔
UNCOV
397
  case stringValue:
×
398
    // allocated_ == false, so this is safe.
UNCOV
399
    value_.string_ = const_cast<char*>(static_cast<char const*>(emptyString));
×
UNCOV
400
    break;
×
401
  case arrayValue:
4,940✔
402
  case objectValue:
403
    value_.map_ = new ObjectValues();
4,940✔
404
    break;
4,940✔
405
  case booleanValue:
×
UNCOV
406
    value_.bool_ = false;
×
407
    break;
×
408
  default:
×
UNCOV
409
    JSON_ASSERT_UNREACHABLE;
×
410
  }
411
}
114,575✔
412

413
Value::Value(Int value) {
1,507✔
414
  initBasic(intValue);
1,507✔
415
  value_.int_ = value;
1,507✔
416
}
1,507✔
417

418
Value::Value(UInt value) {
216✔
419
  initBasic(uintValue);
216✔
420
  value_.uint_ = value;
216✔
421
}
216✔
422
#if defined(JSON_HAS_INT64)
423
Value::Value(Int64 value) {
105,106✔
424
  initBasic(intValue);
105,106✔
425
  value_.int_ = value;
105,106✔
426
}
105,106✔
427
Value::Value(UInt64 value) {
126✔
428
  initBasic(uintValue);
126✔
429
  value_.uint_ = value;
126✔
430
}
126✔
431
#endif // defined(JSON_HAS_INT64)
432

433
Value::Value(double value) {
587✔
434
  initBasic(realValue);
587✔
435
  value_.real_ = value;
587✔
436
}
587✔
437

438
Value::Value(const char* value) {
1,261✔
439
  initBasic(stringValue, true);
1,261✔
440
  JSON_ASSERT_MESSAGE(value != nullptr,
1,261!
441
                      "Null Value Passed to Value Constructor");
442
  value_.string_ = duplicateAndPrefixStringValue(
2,522✔
443
      value, static_cast<unsigned>(strlen(value)));
1,261✔
444
}
1,261✔
445

446
Value::Value(const char* begin, const char* end) {
2✔
447
  initBasic(stringValue, true);
2✔
448
  value_.string_ =
2✔
449
      duplicateAndPrefixStringValue(begin, static_cast<unsigned>(end - begin));
2✔
450
}
2✔
451

452
Value::Value(const String& value) {
1,259✔
453
  initBasic(stringValue, true);
1,259✔
454
  value_.string_ = duplicateAndPrefixStringValue(
1,259✔
455
      value.data(), static_cast<unsigned>(value.length()));
456
}
1,259✔
457

458
Value::Value(const StaticString& value) {
2✔
459
  initBasic(stringValue);
2✔
460
  value_.string_ = const_cast<char*>(value.c_str());
2✔
461
}
2✔
462

463
Value::Value(bool value) {
14,711✔
464
  initBasic(booleanValue);
14,711✔
465
  value_.bool_ = value;
14,711✔
466
}
14,711✔
467

468
Value::Value(const Value& other) {
245,130✔
469
  dupPayload(other);
245,130✔
470
  dupMeta(other);
245,130✔
471
}
245,130✔
472

473
Value::Value(Value&& other) noexcept {
55✔
474
  initBasic(nullValue);
55✔
475
  swap(other);
55✔
476
}
55✔
477

478
Value::~Value() {
484,537✔
479
  releasePayload();
484,537✔
480
  value_.uint_ = 0;
484,537✔
481
}
484,537✔
482

483
Value& Value::operator=(const Value& other) {
18✔
484
  Value(other).swap(*this);
18✔
485
  return *this;
18✔
486
}
487

488
Value& Value::operator=(Value&& other) noexcept {
125,140✔
489
  other.swap(*this);
125,140✔
490
  return *this;
125,140✔
491
}
492

493
void Value::swapPayload(Value& other) {
234,786✔
494
  std::swap(bits_, other.bits_);
495
  std::swap(value_, other.value_);
496
}
234,786✔
497

498
void Value::copyPayload(const Value& other) {
8✔
499
  releasePayload();
8✔
500
  dupPayload(other);
8✔
501
}
8✔
502

503
void Value::swap(Value& other) {
125,214✔
504
  swapPayload(other);
125,214✔
505
  std::swap(comments_, other.comments_);
125,214✔
506
  std::swap(start_, other.start_);
507
  std::swap(limit_, other.limit_);
508
}
125,214✔
509

510
void Value::copy(const Value& other) {
8✔
511
  copyPayload(other);
8✔
512
  dupMeta(other);
8✔
513
}
8✔
514

515
ValueType Value::type() const {
2,229,747✔
516
  return static_cast<ValueType>(bits_.value_type_);
2,229,747✔
517
}
518

519
int Value::compare(const Value& other) const {
120✔
520
  if (*this < other)
120✔
521
    return -1;
522
  if (*this > other)
89✔
523
    return 1;
31✔
524
  return 0;
525
}
526

527
bool Value::operator<(const Value& other) const {
1,279✔
528
  int typeDelta = type() - other.type();
1,279✔
529
  if (typeDelta)
1,279✔
530
    return typeDelta < 0;
77✔
531
  switch (type()) {
1,202!
532
  case nullValue:
533
    return false;
534
  case intValue:
564✔
535
    return value_.int_ < other.value_.int_;
564✔
536
  case uintValue:
34✔
537
    return value_.uint_ < other.value_.uint_;
34✔
538
  case realValue:
46✔
539
    return value_.real_ < other.value_.real_;
46✔
540
  case booleanValue:
35✔
541
    return value_.bool_ < other.value_.bool_;
35✔
542
  case stringValue: {
175✔
543
    if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
175!
UNCOV
544
      return other.value_.string_ != nullptr;
×
545
    }
546
    unsigned this_len;
547
    unsigned other_len;
548
    char const* this_str;
549
    char const* other_str;
550
    decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
551
                         &this_str);
552
    decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
553
                         &other_str);
554
    unsigned min_len = std::min<unsigned>(this_len, other_len);
175✔
555
    JSON_ASSERT(this_str && other_str);
556
    int comp = memcmp(this_str, other_str, min_len);
175✔
557
    if (comp < 0)
175✔
558
      return true;
559
    if (comp > 0)
163✔
560
      return false;
561
    return (this_len < other_len);
153✔
562
  }
563
  case arrayValue:
312✔
564
  case objectValue: {
565
    auto thisSize = value_.map_->size();
312✔
566
    auto otherSize = other.value_.map_->size();
312✔
567
    if (thisSize != otherSize)
312✔
568
      return thisSize < otherSize;
66✔
569
    return (*value_.map_) < (*other.value_.map_);
246✔
570
  }
UNCOV
571
  default:
×
UNCOV
572
    JSON_ASSERT_UNREACHABLE;
×
573
  }
574
  return false; // unreachable
575
}
576

577
bool Value::operator<=(const Value& other) const { return !(other < *this); }
120✔
578

579
bool Value::operator>=(const Value& other) const { return !(*this < other); }
120✔
580

581
bool Value::operator>(const Value& other) const { return other < *this; }
209✔
582

583
bool Value::operator==(const Value& other) const {
317✔
584
  if (type() != other.type())
317✔
585
    return false;
586
  switch (type()) {
302!
587
  case nullValue:
588
    return true;
589
  case intValue:
79✔
590
    return value_.int_ == other.value_.int_;
79✔
591
  case uintValue:
10✔
592
    return value_.uint_ == other.value_.uint_;
10✔
593
  case realValue:
14✔
594
    return value_.real_ == other.value_.real_;
14✔
595
  case booleanValue:
15✔
596
    return value_.bool_ == other.value_.bool_;
15✔
597
  case stringValue: {
91✔
598
    if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
91!
UNCOV
599
      return (value_.string_ == other.value_.string_);
×
600
    }
601
    unsigned this_len;
602
    unsigned other_len;
603
    char const* this_str;
604
    char const* other_str;
605
    decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
606
                         &this_str);
607
    decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
608
                         &other_str);
609
    if (this_len != other_len)
91✔
610
      return false;
611
    JSON_ASSERT(this_str && other_str);
612
    int comp = memcmp(this_str, other_str, this_len);
84✔
613
    return comp == 0;
84✔
614
  }
615
  case arrayValue:
60✔
616
  case objectValue:
617
    return value_.map_->size() == other.value_.map_->size() &&
107✔
618
           (*value_.map_) == (*other.value_.map_);
UNCOV
619
  default:
×
UNCOV
620
    JSON_ASSERT_UNREACHABLE;
×
621
  }
622
  return false; // unreachable
623
}
624

625
bool Value::operator!=(const Value& other) const { return !(*this == other); }
135✔
626

627
const char* Value::asCString() const {
4✔
628
  JSON_ASSERT_MESSAGE(type() == stringValue,
6✔
629
                      "in Json::Value::asCString(): requires stringValue");
630
  if (value_.string_ == nullptr)
3!
631
    return nullptr;
632
  unsigned this_len;
633
  char const* this_str;
634
  decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
635
                       &this_str);
636
  return this_str;
637
}
638

639
#if JSONCPP_USE_SECURE_MEMORY
640
unsigned Value::getCStringLength() const {
641
  JSON_ASSERT_MESSAGE(type() == stringValue,
642
                      "in Json::Value::asCString(): requires stringValue");
643
  if (value_.string_ == 0)
644
    return 0;
645
  unsigned this_len;
646
  char const* this_str;
647
  decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
648
                       &this_str);
649
  return this_len;
650
}
651
#endif
652

653
bool Value::getString(char const** begin, char const** end) const {
782✔
654
  if (type() != stringValue)
782!
655
    return false;
656
  if (value_.string_ == nullptr)
782!
657
    return false;
658
  unsigned length;
659
  decodePrefixedString(this->isAllocated(), this->value_.string_, &length,
660
                       begin);
661
  *end = *begin + length;
782✔
662
  return true;
782✔
663
}
664

665
String Value::asString() const {
2,755✔
666
  switch (type()) {
2,755!
667
  case nullValue:
668
    return "";
2✔
669
  case stringValue: {
2,713✔
670
    if (value_.string_ == nullptr)
2,713!
UNCOV
671
      return "";
×
672
    unsigned this_len;
673
    char const* this_str;
674
    decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
675
                         &this_str);
676
    return String(this_str, this_len);
2,713✔
677
  }
678
  case booleanValue:
679
    return value_.bool_ ? "true" : "false";
×
680
  case intValue:
13✔
681
    return valueToString(value_.int_);
13✔
682
  case uintValue:
7✔
683
    return valueToString(value_.uint_);
7✔
684
  case realValue:
18✔
685
    return valueToString(value_.real_);
18✔
686
  default:
2✔
687
    JSON_FAIL_MESSAGE("Type is not convertible to string");
6✔
688
  }
689
}
690

691
Value::Int Value::asInt() const {
30✔
692
  switch (type()) {
30✔
693
  case intValue:
11✔
694
    JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
11!
695
    return Int(value_.int_);
11✔
696
  case uintValue:
8✔
697
    JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
8!
698
    return Int(value_.uint_);
8✔
699
  case realValue:
5✔
700
    JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
5!
701
                        "double out of Int range");
702
    return Int(value_.real_);
703
  case nullValue:
704
    return 0;
705
  case booleanValue:
2✔
706
    return value_.bool_ ? 1 : 0;
2✔
707
  default:
708
    break;
709
  }
710
  JSON_FAIL_MESSAGE("Value is not convertible to Int.");
9✔
711
}
712

713
Value::UInt Value::asUInt() const {
1,582✔
714
  switch (type()) {
1,582✔
715
  case intValue:
1,565✔
716
    JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
1,565!
717
    return UInt(value_.int_);
1,565✔
718
  case uintValue:
6✔
719
    JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
6!
720
    return UInt(value_.uint_);
6✔
721
  case realValue:
5✔
722
    JSON_ASSERT_MESSAGE(InRange(value_.real_, 0u, maxUInt),
5!
723
                        "double out of UInt range");
724
    return UInt(value_.real_);
725
  case nullValue:
726
    return 0;
727
  case booleanValue:
2✔
728
    return value_.bool_ ? 1 : 0;
2✔
729
  default:
730
    break;
731
  }
732
  JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
9✔
733
}
734

735
#if defined(JSON_HAS_INT64)
736

737
Value::Int64 Value::asInt64() const {
157,460✔
738
  switch (type()) {
157,460✔
739
  case intValue:
157,438✔
740
    return Int64(value_.int_);
157,438✔
741
  case uintValue:
6✔
742
    JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
6!
743
    return Int64(value_.uint_);
6✔
744
  case realValue:
10✔
745
    // If the double value is in proximity to minInt64, it will be rounded to
746
    // minInt64. The correct value in this scenario is indeterminable
747
    JSON_ASSERT_MESSAGE(
10!
748
        value_.real_ != minInt64,
749
        "Double value is minInt64, precise value cannot be determined");
UNCOV
750
    JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
×
751
                        "double out of Int64 range");
752
    return Int64(value_.real_);
753
  case nullValue:
754
    return 0;
755
  case booleanValue:
2✔
756
    return value_.bool_ ? 1 : 0;
2✔
757
  default:
758
    break;
759
  }
760
  JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
9✔
761
}
762

763
Value::UInt64 Value::asUInt64() const {
261✔
764
  switch (type()) {
261✔
765
  case intValue:
8✔
766
    JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
8!
767
    return UInt64(value_.int_);
8✔
768
  case uintValue:
237✔
769
    return UInt64(value_.uint_);
237✔
770
  case realValue:
10✔
771
    JSON_ASSERT_MESSAGE(InRange(value_.real_, 0u, maxUInt64),
10!
772
                        "double out of UInt64 range");
773
    return UInt64(value_.real_);
774
  case nullValue:
775
    return 0;
776
  case booleanValue:
2✔
777
    return value_.bool_ ? 1 : 0;
2✔
778
  default:
779
    break;
780
  }
781
  JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
9✔
782
}
783
#endif // if defined(JSON_HAS_INT64)
784

785
LargestInt Value::asLargestInt() const {
157,448✔
786
#if defined(JSON_NO_INT64)
787
  return asInt();
788
#else
789
  return asInt64();
157,448✔
790
#endif
791
}
792

793
LargestUInt Value::asLargestUInt() const {
248✔
794
#if defined(JSON_NO_INT64)
795
  return asUInt();
796
#else
797
  return asUInt64();
248✔
798
#endif
799
}
800

801
double Value::asDouble() const {
528✔
802
  switch (type()) {
528✔
803
  case intValue:
20✔
804
    return static_cast<double>(value_.int_);
20✔
805
  case uintValue:
14✔
806
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
807
    return static_cast<double>(value_.uint_);
808
#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
809
    return integerToDouble(value_.uint_);
14✔
810
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
811
  case realValue:
488✔
812
    return value_.real_;
488✔
813
  case nullValue:
814
    return 0.0;
815
  case booleanValue:
2✔
816
    return value_.bool_ ? 1.0 : 0.0;
2✔
817
  default:
818
    break;
819
  }
820
  JSON_FAIL_MESSAGE("Value is not convertible to double.");
9✔
821
}
822

823
float Value::asFloat() const {
40✔
824
  switch (type()) {
40✔
825
  case intValue:
10✔
826
    return static_cast<float>(value_.int_);
10✔
827
  case uintValue:
7✔
828
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
829
    return static_cast<float>(value_.uint_);
830
#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
831
    // This can fail (silently?) if the value is bigger than MAX_FLOAT.
832
    return static_cast<float>(integerToDouble(value_.uint_));
7✔
833
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
834
  case realValue:
17✔
835
    return static_cast<float>(value_.real_);
17✔
836
  case nullValue:
837
    return 0.0;
838
  case booleanValue:
2✔
839
    return value_.bool_ ? 1.0F : 0.0F;
2✔
840
  default:
841
    break;
842
  }
843
  JSON_FAIL_MESSAGE("Value is not convertible to float.");
9✔
844
}
845

846
bool Value::asBool() const {
12,746✔
847
  switch (type()) {
12,746!
848
  case booleanValue:
12,713✔
849
    return value_.bool_;
12,713✔
850
  case nullValue:
851
    return false;
852
  case intValue:
10✔
853
    return value_.int_ != 0;
10✔
854
  case uintValue:
7✔
855
    return value_.uint_ != 0;
7✔
856
  case realValue: {
13✔
857
    // According to JavaScript language zero or NaN is regarded as false
858
    const auto value_classification = std::fpclassify(value_.real_);
13!
859
    return value_classification != FP_ZERO && value_classification != FP_NAN;
13✔
860
  }
861
  default:
862
    break;
863
  }
864
  JSON_FAIL_MESSAGE("Value is not convertible to bool.");
9✔
865
}
866

867
bool Value::isConvertibleTo(ValueType other) const {
173✔
868
  switch (other) {
173!
869
  case nullValue:
39✔
870
    return (isNumeric() && asDouble() == 0.0) ||
102✔
871
           (type() == booleanValue && !value_.bool_) ||
67✔
872
           (type() == stringValue && asString().empty()) ||
105!
873
           (type() == arrayValue && value_.map_->empty()) ||
63✔
874
           (type() == objectValue && value_.map_->empty()) ||
100✔
875
           type() == nullValue;
29✔
876
  case intValue:
35✔
877
    return isInt() ||
58✔
878
           (type() == realValue && InRange(value_.real_, minInt, maxInt)) ||
54✔
879
           type() == booleanValue || type() == nullValue;
76✔
880
  case uintValue:
35✔
881
    return isUInt() ||
59✔
882
           (type() == realValue && InRange(value_.real_, 0u, maxUInt)) ||
56✔
883
           type() == booleanValue || type() == nullValue;
78✔
884
  case realValue:
13✔
885
    return isNumeric() || type() == booleanValue || type() == nullValue;
13✔
886
  case booleanValue:
12✔
887
    return isNumeric() || type() == booleanValue || type() == nullValue;
12✔
888
  case stringValue:
13✔
889
    return isNumeric() || type() == booleanValue || type() == stringValue ||
16✔
890
           type() == nullValue;
3✔
891
  case arrayValue:
13✔
892
    return type() == arrayValue || type() == nullValue;
13✔
893
  case objectValue:
13✔
894
    return type() == objectValue || type() == nullValue;
13✔
895
  }
UNCOV
896
  JSON_ASSERT_UNREACHABLE;
×
897
  return false;
898
}
899

900
/// Number of values in array or object
901
ArrayIndex Value::size() const {
845✔
902
  switch (type()) {
845!
903
  case nullValue:
904
  case intValue:
905
  case uintValue:
906
  case realValue:
907
  case booleanValue:
908
  case stringValue:
909
    return 0;
910
  case arrayValue: // size of the array is highest index + 1
804✔
911
    if (!value_.map_->empty()) {
804✔
912
      ObjectValues::const_iterator itLast = value_.map_->end();
913
      --itLast;
914
      return (*itLast).first.index() + 1;
717✔
915
    }
916
    return 0;
917
  case objectValue:
28✔
918
    return ArrayIndex(value_.map_->size());
28✔
919
  }
UNCOV
920
  JSON_ASSERT_UNREACHABLE;
×
921
  return 0; // unreachable;
922
}
923

924
bool Value::empty() const {
36✔
925
  if (isNull() || isArray() || isObject())
36!
926
    return size() == 0U;
36✔
927
  return false;
928
}
929

930
Value::operator bool() const { return !isNull(); }
4✔
931

932
void Value::clear() {
3✔
933
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue ||
5!
934
                          type() == objectValue,
935
                      "in Json::Value::clear(): requires complex value");
936
  start_ = 0;
2✔
937
  limit_ = 0;
2✔
938
  switch (type()) {
2!
939
  case arrayValue:
2✔
940
  case objectValue:
941
    value_.map_->clear();
2✔
942
    break;
943
  default:
944
    break;
945
  }
946
}
2✔
947

948
void Value::resize(ArrayIndex newSize) {
7✔
949
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
16✔
950
                      "in Json::Value::resize(): requires arrayValue, but found " << valueTypeToString(type()));
951
  if (type() == nullValue)
4✔
952
    *this = Value(arrayValue);
1✔
953
  ArrayIndex oldSize = size();
4✔
954
  if (newSize == 0)
4✔
955
    clear();
1✔
956
  else if (newSize > oldSize)
3✔
957
    for (ArrayIndex i = oldSize; i < newSize; ++i)
17✔
958
      (*this)[i];
15✔
959
  else {
960
    for (ArrayIndex index = newSize; index < oldSize; ++index) {
11✔
961
      value_.map_->erase(index);
20✔
962
    }
963
    JSON_ASSERT(size() == newSize);
1!
964
  }
965
}
4✔
966

967
Value& Value::operator[](ArrayIndex index) {
212,045✔
968
  JSON_ASSERT_MESSAGE(
212,051✔
969
      type() == nullValue || type() == arrayValue,
970
      "in Json::Value::operator[](ArrayIndex): requires arrayValue");
971
  if (type() == nullValue)
212,042✔
972
    *this = Value(arrayValue);
16✔
973
  CZString key(index);
212,042✔
974
  auto it = value_.map_->lower_bound(key);
212,042✔
975
  if (it != value_.map_->end() && (*it).first == key)
212,042✔
976
    return (*it).second;
104,910✔
977

978
  ObjectValues::value_type defaultValue(key, nullSingleton());
107,132✔
979
  it = value_.map_->insert(it, defaultValue);
107,132✔
980
  return (*it).second;
107,132✔
981
}
212,042✔
982

983
Value& Value::operator[](int index) {
107,037✔
984
  JSON_ASSERT_MESSAGE(
107,037!
985
      index >= 0,
986
      "in Json::Value::operator[](int index): index cannot be negative");
987
  return (*this)[ArrayIndex(index)];
107,037✔
988
}
989

990
const Value& Value::operator[](ArrayIndex index) const {
53,225✔
991
  JSON_ASSERT_MESSAGE(
53,225!
992
      type() == nullValue || type() == arrayValue,
993
      "in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
994
  if (type() == nullValue)
53,225!
UNCOV
995
    return nullSingleton();
×
996
  CZString key(index);
53,225✔
997
  ObjectValues::const_iterator it = value_.map_->find(key);
53,225✔
998
  if (it == value_.map_->end())
53,225✔
999
    return nullSingleton();
1✔
1000
  return (*it).second;
53,224✔
1001
}
53,225✔
1002

1003
const Value& Value::operator[](int index) const {
4✔
1004
  JSON_ASSERT_MESSAGE(
4!
1005
      index >= 0,
1006
      "in Json::Value::operator[](int index) const: index cannot be negative");
1007
  return (*this)[ArrayIndex(index)];
4✔
1008
}
1009

1010
void Value::initBasic(ValueType type, bool allocated) {
239,407✔
1011
  setType(type);
1012
  setIsAllocated(allocated);
1013
  comments_ = Comments{};
239,407✔
1014
  start_ = 0;
239,407✔
1015
  limit_ = 0;
239,407✔
1016
}
239,407✔
1017

1018
void Value::dupPayload(const Value& other) {
245,138✔
1019
  setType(other.type());
245,138✔
1020
  setIsAllocated(false);
1021
  switch (type()) {
245,138!
1022
  case nullValue:
244,944✔
1023
  case intValue:
1024
  case uintValue:
1025
  case realValue:
1026
  case booleanValue:
1027
    value_ = other.value_;
244,944✔
1028
    break;
244,944✔
1029
  case stringValue:
139✔
1030
    if (other.value_.string_ && other.isAllocated()) {
139!
1031
      unsigned len;
1032
      char const* str;
1033
      decodePrefixedString(other.isAllocated(), other.value_.string_, &len,
1034
                           &str);
1035
      value_.string_ = duplicateAndPrefixStringValue(str, len);
139✔
1036
      setIsAllocated(true);
1037
    } else {
UNCOV
1038
      value_.string_ = other.value_.string_;
×
1039
    }
1040
    break;
1041
  case arrayValue:
55✔
1042
  case objectValue:
1043
    value_.map_ = new ObjectValues(*other.value_.map_);
55✔
1044
    break;
55✔
UNCOV
1045
  default:
×
UNCOV
1046
    JSON_ASSERT_UNREACHABLE;
×
1047
  }
1048
}
245,138✔
1049

1050
void Value::releasePayload() {
484,545✔
1051
  switch (type()) {
484,545!
1052
  case nullValue:
1053
  case intValue:
1054
  case uintValue:
1055
  case realValue:
1056
  case booleanValue:
1057
    break;
1058
  case stringValue:
1059
    if (isAllocated())
2,663✔
1060
      releasePrefixedStringValue(value_.string_);
2,661✔
1061
    break;
1062
  case arrayValue:
4,995✔
1063
  case objectValue:
1064
    delete value_.map_;
9,990!
1065
    break;
UNCOV
1066
  default:
×
UNCOV
1067
    JSON_ASSERT_UNREACHABLE;
×
1068
  }
1069
}
484,545✔
1070

1071
void Value::dupMeta(const Value& other) {
245,138✔
1072
  comments_ = other.comments_;
245,138✔
1073
  start_ = other.start_;
245,138✔
1074
  limit_ = other.limit_;
245,138✔
1075
}
245,138✔
1076

1077
// Access an object value by name, create a null member if it does not exist.
1078
// @pre Type of '*this' is object or null.
1079
// @param key is null-terminated.
1080
Value& Value::resolveReference(const char* key) {
1✔
1081
  JSON_ASSERT_MESSAGE(
1!
1082
      type() == nullValue || type() == objectValue,
1083
      "in Json::Value::resolveReference(): requires objectValue, but found " << valueTypeToString(type()));
1084
  if (type() == nullValue)
1!
1085
    *this = Value(objectValue);
1✔
1086
  CZString actualKey(key, static_cast<unsigned>(strlen(key)),
1✔
1087
                     CZString::noDuplication); // NOTE!
1✔
1088
  auto it = value_.map_->lower_bound(actualKey);
1✔
1089
  if (it != value_.map_->end() && (*it).first == actualKey)
1!
UNCOV
1090
    return (*it).second;
×
1091

1092
  ObjectValues::value_type defaultValue(actualKey, nullSingleton());
1✔
1093
  it = value_.map_->insert(it, defaultValue);
1✔
1094
  Value& value = (*it).second;
1✔
1095
  return value;
1096
}
1✔
1097

1098
// @param key is not null-terminated.
1099
Value& Value::resolveReference(char const* key, char const* end) {
19,625✔
1100
  JSON_ASSERT_MESSAGE(
19,634✔
1101
      type() == nullValue || type() == objectValue,
1102
      "in Json::Value::resolveReference(key, end): requires objectValue, but found " << valueTypeToString(type()));
1103
  if (type() == nullValue)
19,622✔
1104
    *this = Value(objectValue);
1,694✔
1105
  CZString actualKey(key, static_cast<unsigned>(end - key),
19,622✔
1106
                     CZString::duplicateOnCopy);
19,622✔
1107
  auto it = value_.map_->lower_bound(actualKey);
19,622✔
1108
  if (it != value_.map_->end() && (*it).first == actualKey)
19,622✔
1109
    return (*it).second;
4,370✔
1110

1111
  ObjectValues::value_type defaultValue(actualKey, nullSingleton());
15,252✔
1112
  it = value_.map_->insert(it, defaultValue);
15,252✔
1113
  Value& value = (*it).second;
15,252✔
1114
  return value;
1115
}
19,622✔
1116

1117
Value Value::get(ArrayIndex index, const Value& defaultValue) const {
6✔
1118
  const Value* value = &((*this)[index]);
6✔
1119
  return value == &nullSingleton() ? defaultValue : *value;
11✔
1120
}
1121

1122
bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
7✔
1123

1124
Value const* Value::find(char const* begin, char const* end) const {
17,018✔
1125
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
17,018!
1126
                      "in Json::Value::find(begin, end): requires "
1127
                      "objectValue or nullValue");
1128
  if (type() == nullValue)
17,018!
1129
    return nullptr;
1130
  CZString actualKey(begin, static_cast<unsigned>(end - begin),
17,018✔
1131
                     CZString::noDuplication);
17,018✔
1132
  ObjectValues::const_iterator it = value_.map_->find(actualKey);
17,018✔
1133
  if (it == value_.map_->end())
17,018✔
1134
    return nullptr;
1135
  return &(*it).second;
17,003✔
1136
}
17,018✔
1137
Value const* Value::find(const String& key) const {
896✔
1138
  return find(key.data(), key.data() + key.length());
896✔
1139
}
1140

1141
Value const* Value::findNull(const String& key) const {
2✔
1142
  return findValue<Value, &Value::isNull>(key);
2✔
1143
}
1144
Value const* Value::findBool(const String& key) const {
2✔
1145
  return findValue<Value, &Value::isBool>(key);
2✔
1146
}
1147
Value const* Value::findInt(const String& key) const {
2✔
1148
  return findValue<Value, &Value::isInt>(key);
2✔
1149
}
1150
Value const* Value::findInt64(const String& key) const {
2✔
1151
  return findValue<Value, &Value::isInt64>(key);
2✔
1152
}
1153
Value const* Value::findUInt(const String& key) const {
2✔
1154
  return findValue<Value, &Value::isUInt>(key);
2✔
1155
}
1156
Value const* Value::findUInt64(const String& key) const {
2✔
1157
  return findValue<Value, &Value::isUInt64>(key);
2✔
1158
}
1159
Value const* Value::findIntegral(const String& key) const {
2✔
1160
  return findValue<Value, &Value::isIntegral>(key);
2✔
1161
}
1162
Value const* Value::findDouble(const String& key) const {
2✔
1163
  return findValue<Value, &Value::isDouble>(key);
2✔
1164
}
1165
Value const* Value::findNumeric(const String& key) const {
2✔
1166
  return findValue<Value, &Value::isNumeric>(key);
2✔
1167
}
1168
Value const* Value::findString(const String& key) const {
2✔
1169
  return findValue<Value, &Value::isString>(key);
2✔
1170
}
1171
Value const* Value::findArray(const String& key) const {
2✔
1172
  return findValue<Value, &Value::isArray>(key);
2✔
1173
}
UNCOV
1174
Value const* Value::findObject(const String& key) const {
×
UNCOV
1175
  return findValue<Value, &Value::isObject>(key);
×
1176
}
1177

1178
Value* Value::demand(char const* begin, char const* end) {
1✔
1179
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
1!
1180
                      "in Json::Value::demand(begin, end): requires "
1181
                      "objectValue or nullValue");
1182
  return &resolveReference(begin, end);
1✔
1183
}
1184
const Value& Value::operator[](const char* key) const {
16,094✔
1185
  Value const* found = find(key, key + strlen(key));
16,094✔
1186
  if (!found)
16,094✔
1187
    return nullSingleton();
1✔
1188
  return *found;
1189
}
1190
Value const& Value::operator[](const String& key) const {
872✔
1191
  Value const* found = find(key);
872✔
1192
  if (!found)
872✔
1193
    return nullSingleton();
3✔
1194
  return *found;
1195
}
1196

1197
Value& Value::operator[](const char* key) {
17,760✔
1198
  return resolveReference(key, key + strlen(key));
17,760✔
1199
}
1200

1201
Value& Value::operator[](const String& key) {
1,864✔
1202
  return resolveReference(key.data(), key.data() + key.length());
1,864✔
1203
}
1204

1205
Value& Value::operator[](const StaticString& key) {
1✔
1206
  return resolveReference(key.c_str());
1✔
1207
}
1208

1209
Value& Value::append(const Value& value) { return append(Value(value)); }
1✔
1210

1211
Value& Value::append(Value&& value) {
53✔
1212
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
53!
1213
                      "in Json::Value::append: requires arrayValue, but found " << valueTypeToString(type()));
1214
  if (type() == nullValue) {
53✔
1215
    *this = Value(arrayValue);
43✔
1216
  }
1217
  return this->value_.map_->emplace(size(), std::move(value)).first->second;
53✔
1218
}
1219

1220
bool Value::insert(ArrayIndex index, const Value& newValue) {
1✔
1221
  return insert(index, Value(newValue));
1✔
1222
}
1223

1224
bool Value::insert(ArrayIndex index, Value&& newValue) {
4✔
1225
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
4!
1226
                      "in Json::Value::insert: requires arrayValue");
1227
  ArrayIndex length = size();
4✔
1228
  if (index > length) {
4✔
1229
    return false;
1230
  }
1231
  for (ArrayIndex i = length; i > index; i--) {
8✔
1232
    (*this)[i] = std::move((*this)[i - 1]);
5✔
1233
  }
1234
  (*this)[index] = std::move(newValue);
3✔
1235
  return true;
3✔
1236
}
1237

1238
Value Value::get(char const* begin, char const* end,
15✔
1239
                 Value const& defaultValue) const {
1240
  Value const* found = find(begin, end);
15✔
1241
  return !found ? defaultValue : *found;
29✔
1242
}
1243
Value Value::get(char const* key, Value const& defaultValue) const {
10✔
1244
  return get(key, key + strlen(key), defaultValue);
10✔
1245
}
1246
Value Value::get(String const& key, Value const& defaultValue) const {
5✔
1247
  return get(key.data(), key.data() + key.length(), defaultValue);
5✔
1248
}
1249

1250
bool Value::removeMember(const char* begin, const char* end, Value* removed) {
9✔
1251
  if (type() != objectValue) {
9!
1252
    return false;
1253
  }
1254
  CZString actualKey(begin, static_cast<unsigned>(end - begin),
9✔
1255
                     CZString::noDuplication);
9✔
1256
  auto it = value_.map_->find(actualKey);
9✔
1257
  if (it == value_.map_->end())
9✔
1258
    return false;
1259
  if (removed)
5✔
1260
    *removed = std::move(it->second);
4✔
1261
  value_.map_->erase(it);
5✔
1262
  return true;
5✔
1263
}
9✔
1264
bool Value::removeMember(const char* key, Value* removed) {
3✔
1265
  return removeMember(key, key + strlen(key), removed);
3✔
1266
}
1267
bool Value::removeMember(String const& key, Value* removed) {
2✔
1268
  return removeMember(key.data(), key.data() + key.length(), removed);
2✔
1269
}
1270

1271
void Value::removeMember(const char* key) {
4✔
1272
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
13!
1273
                      "in Json::Value::removeMember(): requires objectValue, but found " << valueTypeToString(type()));
1274
  if (type() == nullValue)
1!
UNCOV
1275
    return;
×
1276

1277
  CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication);
1✔
1278
  value_.map_->erase(actualKey);
1✔
1279
}
1✔
1280
void Value::removeMember(const String& key) { removeMember(key.c_str()); }
1✔
1281

1282
bool Value::removeIndex(ArrayIndex index, Value* removed) {
2✔
1283
  if (type() != arrayValue) {
2!
1284
    return false;
1285
  }
1286
  CZString key(index);
2✔
1287
  auto it = value_.map_->find(key);
2✔
1288
  if (it == value_.map_->end()) {
2✔
1289
    return false;
1290
  }
1291
  if (removed)
1!
1292
    *removed = std::move(it->second);
1✔
1293
  ArrayIndex oldSize = size();
1✔
1294
  // shift left all items left, into the place of the "removed"
1295
  for (ArrayIndex i = index; i < (oldSize - 1); ++i) {
1!
UNCOV
1296
    CZString keey(i);
×
UNCOV
1297
    (*value_.map_)[keey] = (*this)[i + 1];
×
UNCOV
1298
  }
×
1299
  // erase the last one ("leftover")
1300
  CZString keyLast(oldSize - 1);
1✔
1301
  auto itLast = value_.map_->find(keyLast);
1✔
1302
  value_.map_->erase(itLast);
1✔
1303
  return true;
1304
}
2✔
1305

1306
bool Value::isMember(char const* begin, char const* end) const {
10✔
1307
  Value const* value = find(begin, end);
10✔
1308
  return nullptr != value;
10✔
1309
}
1310
bool Value::isMember(char const* key) const {
5✔
1311
  return isMember(key, key + strlen(key));
5✔
1312
}
1313
bool Value::isMember(String const& key) const {
5✔
1314
  return isMember(key.data(), key.data() + key.length());
5✔
1315
}
1316

1317
Value::Members Value::getMemberNames() const {
1,130✔
1318
  JSON_ASSERT_MESSAGE(
1,136!
1319
      type() == nullValue || type() == objectValue,
1320
      "in Json::Value::getMemberNames(), value must be objectValue");
1321
  if (type() == nullValue)
1,127!
UNCOV
1322
    return Value::Members();
×
1323
  Members members;
1324
  members.reserve(value_.map_->size());
1,127✔
1325
  ObjectValues::const_iterator it = value_.map_->begin();
1,127✔
1326
  ObjectValues::const_iterator itEnd = value_.map_->end();
1327
  for (; it != itEnd; ++it) {
2,792✔
1328
    members.push_back(String((*it).first.data(), (*it).first.length()));
3,330✔
1329
  }
1330
  return members;
1331
}
1,127✔
1332

1333
static bool IsIntegral(double d) {
1334
  double integral_part;
1335
  return modf(d, &integral_part) == 0.0;
58✔
1336
}
1337

1338
bool Value::isNull() const { return type() == nullValue; }
83✔
1339

1340
bool Value::isBool() const { return type() == booleanValue; }
50✔
1341

1342
bool Value::isInt() const {
104✔
1343
  switch (type()) {
104✔
1344
  case intValue:
34✔
1345
#if defined(JSON_HAS_INT64)
1346
    return value_.int_ >= minInt && value_.int_ <= maxInt;
34✔
1347
#else
1348
    return true;
1349
#endif
1350
  case uintValue:
22✔
1351
    return value_.uint_ <= UInt(maxInt);
22✔
1352
  case realValue:
28✔
1353
    return value_.real_ >= minInt && value_.real_ <= maxInt &&
28✔
1354
           IsIntegral(value_.real_);
1355
  default:
1356
    break;
1357
  }
1358
  return false;
1359
}
1360

1361
bool Value::isUInt() const {
1,656✔
1362
  switch (type()) {
1,656✔
1363
  case intValue:
1,587✔
1364
#if defined(JSON_HAS_INT64)
1365
    return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
1,587✔
1366
#else
1367
    return value_.int_ >= 0;
1368
#endif
1369
  case uintValue:
21✔
1370
#if defined(JSON_HAS_INT64)
1371
    return value_.uint_ <= maxUInt;
21✔
1372
#else
1373
    return true;
1374
#endif
1375
  case realValue:
28✔
1376
    return value_.real_ >= 0 && value_.real_ <= maxUInt &&
28✔
1377
           IsIntegral(value_.real_);
1378
  default:
1379
    break;
1380
  }
1381
  return false;
1382
}
1383

1384
bool Value::isInt64() const {
56✔
1385
#if defined(JSON_HAS_INT64)
1386
  switch (type()) {
56✔
1387
  case intValue:
1388
    return true;
1389
  case uintValue:
13✔
1390
    return value_.uint_ <= UInt64(maxInt64);
13✔
1391
  case realValue:
15✔
1392
    // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
1393
    // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
1394
    // require the value to be strictly less than the limit.
1395
    // minInt64 is -2^63 which can be represented as a double, but since double
1396
    // values in its proximity are also rounded to -2^63, we require the value
1397
    // to be strictly greater than the limit to avoid returning 'true' for
1398
    // values that are not in the range
1399
    return value_.real_ > double(minInt64) && value_.real_ < double(maxInt64) &&
15✔
1400
           IsIntegral(value_.real_);
1401
  default:
1402
    break;
1403
  }
1404
#endif // JSON_HAS_INT64
1405
  return false;
1406
}
1407

1408
bool Value::isUInt64() const {
57✔
1409
#if defined(JSON_HAS_INT64)
1410
  switch (type()) {
57✔
1411
  case intValue:
20✔
1412
    return value_.int_ >= 0;
20✔
1413
  case uintValue:
1414
    return true;
1415
  case realValue:
15✔
1416
    // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
1417
    // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
1418
    // require the value to be strictly less than the limit.
1419
    return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&
15✔
1420
           IsIntegral(value_.real_);
1421
  default:
1422
    break;
1423
  }
1424
#endif // JSON_HAS_INT64
1425
  return false;
1426
}
1427

1428
bool Value::isIntegral() const {
42✔
1429
  switch (type()) {
42✔
1430
  case intValue:
1431
  case uintValue:
1432
    return true;
1433
  case realValue:
14✔
1434
#if defined(JSON_HAS_INT64)
1435
    // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
1436
    // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
1437
    // require the value to be strictly less than the limit.
1438
    // minInt64 is -2^63 which can be represented as a double, but since double
1439
    // values in its proximity are also rounded to -2^63, we require the value
1440
    // to be strictly greater than the limit to avoid returning 'true' for
1441
    // values that are not in the range
1442
    return value_.real_ > double(minInt64) &&
13✔
1443
           value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);
26✔
1444
#else
1445
    return value_.real_ >= minInt && value_.real_ <= maxUInt &&
1446
           IsIntegral(value_.real_);
1447
#endif // JSON_HAS_INT64
1448
  default:
1449
    break;
1450
  }
1451
  return false;
1452
}
1453

1454
bool Value::isDouble() const {
169✔
1455
  return type() == intValue || type() == uintValue || type() == realValue;
169✔
1456
}
1457

1458
bool Value::isNumeric() const { return isDouble(); }
119✔
1459

1460
bool Value::isString() const { return type() == stringValue; }
52✔
1461

1462
bool Value::isArray() const { return type() == arrayValue; }
501✔
1463

1464
bool Value::isObject() const { return type() == objectValue; }
432✔
1465

UNCOV
1466
Value::Comments::Comments(const Comments& that)
×
UNCOV
1467
    : ptr_{cloneUnique(that.ptr_)} {}
×
1468

1469
Value::Comments::Comments(Comments&& that) noexcept
125,214✔
1470
    : ptr_{std::move(that.ptr_)} {}
125,214✔
1471

1472
Value::Comments& Value::Comments::operator=(const Comments& that) {
245,138✔
1473
  ptr_ = cloneUnique(that.ptr_);
245,138✔
1474
  return *this;
245,138✔
1475
}
1476

1477
Value::Comments& Value::Comments::operator=(Comments&& that) noexcept {
489,835!
1478
  ptr_ = std::move(that.ptr_);
1479
  return *this;
489,835✔
1480
}
1481

1482
bool Value::Comments::has(CommentPlacement slot) const {
377,785✔
1483
  return ptr_ && !(*ptr_)[slot].empty();
377,785!
1484
}
1485

1486
String Value::Comments::get(CommentPlacement slot) const {
1,282!
1487
  if (!ptr_)
1,282!
1488
    return {};
1489
  return (*ptr_)[slot];
1,282!
1490
}
1491

1492
void Value::Comments::set(CommentPlacement slot, String comment) {
955✔
1493
  if (slot >= CommentPlacement::numberOfCommentPlacement)
955!
1494
    return;
1495
  if (!ptr_)
955✔
1496
    ptr_ = std::unique_ptr<Array>(new Array());
893✔
1497
  (*ptr_)[slot] = std::move(comment);
1,910!
1498
}
1499

1500
void Value::setComment(String comment, CommentPlacement placement) {
955!
1501
  if (!comment.empty() && (comment.back() == '\n')) {
955!
1502
    // Always discard trailing newline, to aid indentation.
1503
    comment.pop_back();
790✔
1504
  }
1505
  JSON_ASSERT_MESSAGE(
955!
1506
      comment.empty() || comment[0] == '/',
1507
      "in Json::Value::setComment(): Comments must start with /");
1508
  comments_.set(placement, std::move(comment));
955✔
1509
}
955✔
1510

1511
bool Value::hasComment(CommentPlacement placement) const {
377,785✔
1512
  return comments_.has(placement);
377,785✔
1513
}
1514

1515
String Value::getComment(CommentPlacement placement) const {
1,282✔
1516
  return comments_.get(placement);
1,282✔
1517
}
1518

1519
void Value::setOffsetStart(ptrdiff_t start) { start_ = start; }
109,614✔
1520

1521
void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; }
107,821✔
1522

1523
ptrdiff_t Value::getOffsetStart() const { return start_; }
19✔
1524

1525
ptrdiff_t Value::getOffsetLimit() const { return limit_; }
19✔
1526

1527
String Value::toStyledString() const {
5✔
1528
  StreamWriterBuilder builder;
5✔
1529

1530
  String out = this->hasComment(commentBefore) ? "\n" : "";
8✔
1531
  out += Json::writeString(builder, *this);
10✔
1532
  out += '\n';
1533

1534
  return out;
5✔
1535
}
5✔
1536

1537
Value::const_iterator Value::begin() const {
23✔
1538
  switch (type()) {
23✔
1539
  case arrayValue:
10✔
1540
  case objectValue:
1541
    if (value_.map_)
10!
1542
      return const_iterator(value_.map_->begin());
10✔
1543
    break;
1544
  default:
1545
    break;
1546
  }
1547
  return {};
13✔
1548
}
1549

1550
Value::const_iterator Value::end() const {
64✔
1551
  switch (type()) {
64✔
1552
  case arrayValue:
52✔
1553
  case objectValue:
1554
    if (value_.map_)
52!
1555
      return const_iterator(value_.map_->end());
52✔
1556
    break;
1557
  default:
1558
    break;
1559
  }
1560
  return {};
12✔
1561
}
1562

1563
Value::iterator Value::begin() {
39✔
1564
  switch (type()) {
39✔
1565
  case arrayValue:
26✔
1566
  case objectValue:
1567
    if (value_.map_)
26!
1568
      return iterator(value_.map_->begin());
26✔
1569
    break;
1570
  default:
1571
    break;
1572
  }
1573
  return iterator();
13✔
1574
}
1575

1576
Value::iterator Value::end() {
44✔
1577
  switch (type()) {
44✔
1578
  case arrayValue:
29✔
1579
  case objectValue:
1580
    if (value_.map_)
29!
1581
      return iterator(value_.map_->end());
29✔
1582
    break;
1583
  default:
1584
    break;
1585
  }
1586
  return iterator();
15✔
1587
}
1588

1589
// class PathArgument
1590
// //////////////////////////////////////////////////////////////////
1591

1592
PathArgument::PathArgument() = default;
36✔
1593

1594
PathArgument::PathArgument(ArrayIndex index)
4✔
1595
    : index_(index), kind_(kindIndex) {}
4✔
1596

1597
PathArgument::PathArgument(const char* key) : key_(key), kind_(kindKey) {}
2✔
1598

1599
PathArgument::PathArgument(String key) : key_(std::move(key)), kind_(kindKey) {}
10✔
1600

1601
// class Path
1602
// //////////////////////////////////////////////////////////////////
1603

1604
Path::Path(const String& path, const PathArgument& a1, const PathArgument& a2,
8✔
1605
           const PathArgument& a3, const PathArgument& a4,
1606
           const PathArgument& a5) {
1607
  InArgs in;
1608
  in.reserve(5);
8✔
1609
  in.push_back(&a1);
8✔
1610
  in.push_back(&a2);
8✔
1611
  in.push_back(&a3);
8✔
1612
  in.push_back(&a4);
8✔
1613
  in.push_back(&a5);
8✔
1614
  makePath(path, in);
8✔
1615
}
8✔
1616

1617
void Path::makePath(const String& path, const InArgs& in) {
8✔
1618
  const char* current = path.c_str();
1619
  const char* end = current + path.length();
8✔
1620
  auto itInArg = in.begin();
8✔
1621
  while (current != end) {
42✔
1622
    if (*current == '[') {
34✔
1623
      ++current;
4✔
1624
      if (*current == '%')
4✔
1625
        addPathInArg(path, in, itInArg, PathArgument::kindIndex);
2✔
1626
      else {
1627
        ArrayIndex index = 0;
1628
        for (; current != end && *current >= '0' && *current <= '9'; ++current)
4!
1629
          index = index * 10 + ArrayIndex(*current - '0');
2✔
1630
        args_.push_back(index);
4✔
1631
      }
1632
      if (current == end || *++current != ']')
4!
1633
        invalidPath(path, int(current - path.c_str()));
2✔
1634
    } else if (*current == '%') {
30✔
1635
      addPathInArg(path, in, itInArg, PathArgument::kindKey);
2✔
1636
      ++current;
2✔
1637
    } else if (*current == '.' || *current == ']') {
28✔
1638
      ++current;
18✔
1639
    } else {
1640
      const char* beginName = current;
1641
      while (current != end && !strchr("[.", *current))
88✔
1642
        ++current;
78✔
1643
      args_.push_back(String(beginName, current));
20✔
1644
    }
1645
  }
1646
}
8✔
1647

1648
void Path::addPathInArg(const String& /*path*/, const InArgs& in,
4!
1649
                        InArgs::const_iterator& itInArg,
1650
                        PathArgument::Kind kind) {
1651
  if (itInArg == in.end()) {
4!
1652
    // Error: missing argument %d
1653
  } else if ((*itInArg)->kind_ != kind) {
4!
1654
    // Error: bad argument type
1655
  } else {
1656
    args_.push_back(**itInArg++);
4✔
1657
  }
1658
}
4✔
1659

1660
void Path::invalidPath(const String& /*path*/, int /*location*/) {
2✔
1661
  // Error: invalid path.
1662
}
2✔
1663

1664
const Value& Path::resolve(const Value& root) const {
6✔
1665
  const Value* node = &root;
1666
  for (const auto& arg : args_) {
14✔
1667
    if (arg.kind_ == PathArgument::kindIndex) {
12✔
1668
      if (!node->isArray() || !node->isValidIndex(arg.index_)) {
2!
1669
        // Error: unable to resolve path (array value expected at position... )
1670
        return Value::nullSingleton();
1✔
1671
      }
1672
      node = &((*node)[arg.index_]);
1✔
1673
    } else if (arg.kind_ == PathArgument::kindKey) {
10!
1674
      if (!node->isObject()) {
10✔
1675
        // Error: unable to resolve path (object value expected at position...)
1676
        return Value::nullSingleton();
1✔
1677
      }
1678
      node = &((*node)[arg.key_]);
9✔
1679
      if (node == &Value::nullSingleton()) {
9✔
1680
        // Error: unable to resolve path (object has no member named '' at
1681
        // position...)
1682
        return Value::nullSingleton();
2✔
1683
      }
1684
    }
1685
  }
1686
  return *node;
1687
}
1688

1689
Value Path::resolve(const Value& root, const Value& defaultValue) const {
6✔
1690
  const Value* node = &root;
1691
  for (const auto& arg : args_) {
14✔
1692
    if (arg.kind_ == PathArgument::kindIndex) {
12✔
1693
      if (!node->isArray() || !node->isValidIndex(arg.index_))
3✔
1694
        return defaultValue;
2✔
1695
      node = &((*node)[arg.index_]);
1✔
1696
    } else if (arg.kind_ == PathArgument::kindKey) {
9!
1697
      if (!node->isObject())
9✔
1698
        return defaultValue;
1✔
1699
      node = &((*node)[arg.key_]);
8✔
1700
      if (node == &Value::nullSingleton())
8✔
1701
        return defaultValue;
1✔
1702
    }
1703
  }
1704
  return *node;
2✔
1705
}
1706

1707
Value& Path::make(Value& root) const {
2✔
1708
  Value* node = &root;
1709
  for (const auto& arg : args_) {
6✔
1710
    if (arg.kind_ == PathArgument::kindIndex) {
4✔
1711
      if (!node->isArray()) {
1✔
1712
        // Error: node is not an array at position ...
1713
      }
1714
      node = &((*node)[arg.index_]);
1✔
1715
    } else if (arg.kind_ == PathArgument::kindKey) {
3!
1716
      if (!node->isObject()) {
3✔
1717
        // Error: node is not an object at position...
1718
      }
1719
      node = &((*node)[arg.key_]);
3✔
1720
    }
1721
  }
1722
  return *node;
2✔
1723
}
1724

1725
const char* version() { return JSONCPP_VERSION_STRING; }
1✔
1726

1727
} // namespace Json
1728

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc