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

open-source-parsers / jsoncpp / 24208766526

09 Apr 2026 07:17PM UTC coverage: 90.145% (+0.05%) from 90.095%
24208766526

Pull #1679

github

baylesj
feat: add .members() iterator adapter for range-based for loops (#288)

This adds a zero-allocation iterator adapter to `Json::Value` that enables idiomatic range-based for loops over object members. This allows iterating over key-value pairs without allocating a vector of keys via `getMemberNames()`, and cleanly supports C++17 structured bindings (e.g. `for (const auto& [name, val] : obj.members())`).

Fixes #288
Pull Request #1679: feat: add .members() iterator adapter for range-based for loops (#288)

2194 of 2600 branches covered (84.38%)

Branch coverage included in aggregate %.

20 of 20 new or added lines in 1 file covered. (100.0%)

42 existing lines in 1 file now uncovered.

2590 of 2707 relevant lines covered (95.68%)

23599.37 hits per line

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

87.96
/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
#ifdef JSONCPP_HAS_STRING_VIEW
21
#include <string_view>
22
#endif
23

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

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

47
// Disable warning C4702 : unreachable code
48
#if defined(_MSC_VER)
49
#pragma warning(disable : 4702)
50
#endif
51

52
#define JSON_ASSERT_UNREACHABLE assert(false)
53

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

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

73
// static
74
Value const& Value::nullSingleton() {
123,416✔
75
  static Value const nullStatic;
123,416!
76
  return nullStatic;
123,416✔
77
}
78

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

85
// static
86
Value const& Value::nullRef = Value::nullSingleton();
87
#endif
88

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

103
template <typename T> static inline double integerToDouble(T value) {
104
  return static_cast<double>(value);
105
}
106

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

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

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

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

192
} // namespace Json
193

194
// //////////////////////////////////////////////////////////////////
195
// //////////////////////////////////////////////////////////////////
196
// //////////////////////////////////////////////////////////////////
197
// ValueInternals...
198
// //////////////////////////////////////////////////////////////////
199
// //////////////////////////////////////////////////////////////////
200
// //////////////////////////////////////////////////////////////////
201
#if !defined(JSON_IS_AMALGAMATION)
202

203
#include "json_valueiterator.inl"
204
#endif // if !defined(JSON_IS_AMALGAMATION)
205

206
namespace Json {
207

208
#if JSON_USE_EXCEPTION
209
Exception::Exception(String msg) : msg_(std::move(msg)) {}
49✔
210
Exception::~Exception() noexcept = default;
49✔
211
char const* Exception::what() const noexcept { return msg_.c_str(); }
6✔
212
RuntimeError::RuntimeError(String const& msg) : Exception(msg) {}
18✔
213
LogicError::LogicError(String const& msg) : Exception(msg) {}
80✔
214
JSONCPP_NORETURN void throwRuntimeError(String const& msg) {
9✔
215
  throw RuntimeError(msg);
9✔
216
}
217
JSONCPP_NORETURN void throwLogicError(String const& msg) {
40✔
218
  throw LogicError(msg);
40✔
219
}
220
#else // !JSON_USE_EXCEPTION
221
JSONCPP_NORETURN void throwRuntimeError(String const& msg) {
222
  std::cerr << msg << std::endl;
223
  abort();
224
}
225
JSONCPP_NORETURN void throwLogicError(String const& msg) {
226
  std::cerr << msg << std::endl;
227
  abort();
228
}
229
#endif
230

231
// //////////////////////////////////////////////////////////////////
232
// //////////////////////////////////////////////////////////////////
233
// //////////////////////////////////////////////////////////////////
234
// class Value::CZString
235
// //////////////////////////////////////////////////////////////////
236
// //////////////////////////////////////////////////////////////////
237
// //////////////////////////////////////////////////////////////////
238

239
// Notes: policy_ indicates if the string was allocated when
240
// a string is stored.
241

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

244
Value::CZString::CZString(char const* str, unsigned length,
36,653✔
245
                          DuplicationPolicy allocate)
36,653✔
246
    : cstr_(str) {
36,653✔
247
  // allocate != duplicate
248
  storage_.policy_ = allocate & 0x3;
36,653✔
249
  storage_.length_ = length & 0x3FFFFFFF;
36,653✔
250
}
36,653✔
251

252
Value::CZString::CZString(const CZString& other) {
244,837✔
253
  cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr
188,031✔
254
               ? duplicateStringValue(other.cstr_, other.storage_.length_)
432,868✔
255
               : other.cstr_);
256
  if (other.cstr_) {
244,837✔
257
    storage_.policy_ =
30,548✔
258
        static_cast<unsigned>(
259
            other.cstr_
260
                ? (static_cast<DuplicationPolicy>(other.storage_.policy_) ==
30,548✔
261
                           noDuplication
262
                       ? noDuplication
30,548✔
263
                       : duplicate)
264
                : static_cast<DuplicationPolicy>(other.storage_.policy_)) &
30,548✔
265
        3U;
266
    storage_.length_ = other.storage_.length_;
30,548✔
267
  } else {
268
    index_ = other.index_;
214,289✔
269
  }
270
}
244,837✔
271

272
Value::CZString::CZString(CZString&& other) noexcept : cstr_(other.cstr_) {
2✔
273
  if (other.cstr_) {
2✔
274
    storage_.policy_ = other.storage_.policy_;
1✔
275
    storage_.length_ = other.storage_.length_;
1✔
276
  } else {
277
    index_ = other.index_;
1✔
278
  }
279
  other.cstr_ = nullptr;
2✔
280
}
2✔
281

282
Value::CZString::~CZString() {
546,827✔
283
  if (cstr_ && storage_.policy_ == duplicate) {
546,827✔
284
    releaseStringValue(const_cast<char*>(cstr_),
285
                       storage_.length_ + 1U); // +1 for null terminating
286
                                               // character for sake of
287
                                               // completeness but not actually
288
                                               // necessary
289
  }
290
}
546,827✔
291

UNCOV
292
void Value::CZString::swap(CZString& other) {
×
293
  std::swap(cstr_, other.cstr_);
294
  std::swap(index_, other.index_);
295
}
×
296

UNCOV
297
Value::CZString& Value::CZString::operator=(const CZString& other) {
×
UNCOV
298
  cstr_ = other.cstr_;
×
UNCOV
299
  index_ = other.index_;
×
UNCOV
300
  return *this;
×
301
}
302

303
Value::CZString& Value::CZString::operator=(CZString&& other) noexcept {
2✔
304
  if (cstr_ && storage_.policy_ == duplicate) {
2!
305
    releasePrefixedStringValue(const_cast<char*>(cstr_));
306
  }
307
  cstr_ = other.cstr_;
2✔
308
  if (other.cstr_) {
2✔
309
    storage_.policy_ = other.storage_.policy_;
1✔
310
    storage_.length_ = other.storage_.length_;
1✔
311
  } else {
312
    index_ = other.index_;
1✔
313
  }
314
  other.cstr_ = nullptr;
2✔
315
  return *this;
2✔
316
}
317

318
bool Value::CZString::operator<(const CZString& other) const {
3,942,049✔
319
  if (!cstr_)
3,942,049✔
320
    return index_ < other.index_;
3,782,658✔
321
  // return strcmp(cstr_, other.cstr_) < 0;
322
  // Assume both are strings.
323
  unsigned this_len = this->storage_.length_;
159,391✔
324
  unsigned other_len = other.storage_.length_;
159,391✔
325
  unsigned min_len = std::min<unsigned>(this_len, other_len);
159,391✔
326
  JSON_ASSERT(this->cstr_ && other.cstr_);
159,391!
327
  int comp = memcmp(this->cstr_, other.cstr_, min_len);
159,391✔
328
  if (comp < 0)
159,391✔
329
    return true;
330
  if (comp > 0)
81,306✔
331
    return false;
332
  return (this_len < other_len);
40,624✔
333
}
334

335
bool Value::CZString::operator==(const CZString& other) const {
120,415✔
336
  if (!cstr_)
120,415✔
337
    return index_ == other.index_;
104,935✔
338
  // return strcmp(cstr_, other.cstr_) == 0;
339
  // Assume both are strings.
340
  unsigned this_len = this->storage_.length_;
15,480✔
341
  unsigned other_len = other.storage_.length_;
15,480✔
342
  if (this_len != other_len)
15,480✔
343
    return false;
344
  JSON_ASSERT(this->cstr_ && other.cstr_);
5,418!
345
  int comp = memcmp(this->cstr_, other.cstr_, this_len);
5,418✔
346
  return comp == 0;
5,418✔
347
}
348

349
ArrayIndex Value::CZString::index() const { return index_; }
724✔
350

351
// const char* Value::CZString::c_str() const { return cstr_; }
352
const char* Value::CZString::data() const { return cstr_; }
1,736✔
353
unsigned Value::CZString::length() const { return storage_.length_; }
1,717✔
354
bool Value::CZString::isStaticString() const {
3✔
355
  return storage_.policy_ == noDuplication;
3✔
356
}
357

358
// //////////////////////////////////////////////////////////////////
359
// //////////////////////////////////////////////////////////////////
360
// //////////////////////////////////////////////////////////////////
361
// class Value::Value
362
// //////////////////////////////////////////////////////////////////
363
// //////////////////////////////////////////////////////////////////
364
// //////////////////////////////////////////////////////////////////
365

366
/*! \internal Default constructor initialization must be equivalent to:
367
 * memset( this, 0, sizeof(Value) )
368
 * This optimization is used in ValueInternalMap fast allocator.
369
 */
370
Value::Value(ValueType type) {
114,575✔
371
  static char const emptyString[] = "";
372
  initBasic(type);
114,575✔
373
  switch (type) {
114,575!
374
  case nullValue:
375
    break;
376
  case intValue:
2✔
377
  case uintValue:
378
    value_.int_ = 0;
2✔
379
    break;
2✔
380
  case realValue:
1✔
381
    value_.real_ = 0.0;
1✔
382
    break;
1✔
UNCOV
383
  case stringValue:
×
384
    // allocated_ == false, so this is safe.
UNCOV
385
    value_.string_ = const_cast<char*>(static_cast<char const*>(emptyString));
×
UNCOV
386
    break;
×
387
  case arrayValue:
4,940✔
388
  case objectValue:
389
    value_.map_ = new ObjectValues();
4,940✔
390
    break;
4,940✔
391
  case booleanValue:
×
UNCOV
392
    value_.bool_ = false;
×
UNCOV
393
    break;
×
UNCOV
394
  default:
×
UNCOV
395
    JSON_ASSERT_UNREACHABLE;
×
396
  }
397
}
114,575✔
398

399
Value::Value(Int value) {
1,507✔
400
  initBasic(intValue);
1,507✔
401
  value_.int_ = value;
1,507✔
402
}
1,507✔
403

404
Value::Value(UInt value) {
216✔
405
  initBasic(uintValue);
216✔
406
  value_.uint_ = value;
216✔
407
}
216✔
408
#if defined(JSON_HAS_INT64)
409
Value::Value(Int64 value) {
105,106✔
410
  initBasic(intValue);
105,106✔
411
  value_.int_ = value;
105,106✔
412
}
105,106✔
413
Value::Value(UInt64 value) {
126✔
414
  initBasic(uintValue);
126✔
415
  value_.uint_ = value;
126✔
416
}
126✔
417
#endif // defined(JSON_HAS_INT64)
418

419
Value::Value(double value) {
587✔
420
  initBasic(realValue);
587✔
421
  value_.real_ = value;
587✔
422
}
587✔
423

424
Value::Value(const char* value) {
1,261✔
425
  initBasic(stringValue, true);
1,261✔
426
  JSON_ASSERT_MESSAGE(value != nullptr,
1,261!
427
                      "Null Value Passed to Value Constructor");
428
  value_.string_ = duplicateAndPrefixStringValue(
2,522✔
429
      value, static_cast<unsigned>(strlen(value)));
1,261✔
430
}
1,261✔
431

432
Value::Value(const char* begin, const char* end) {
2✔
433
  initBasic(stringValue, true);
2✔
434
  value_.string_ =
2✔
435
      duplicateAndPrefixStringValue(begin, static_cast<unsigned>(end - begin));
2✔
436
}
2✔
437

438
Value::Value(const String& value) {
1,259✔
439
  initBasic(stringValue, true);
1,259✔
440
  value_.string_ = duplicateAndPrefixStringValue(
1,259✔
441
      value.data(), static_cast<unsigned>(value.length()));
442
}
1,259✔
443

444
Value::Value(const StaticString& value) {
2✔
445
  initBasic(stringValue);
2✔
446
  value_.string_ = const_cast<char*>(value.c_str());
2✔
447
}
2✔
448

449
Value::Value(bool value) {
14,711✔
450
  initBasic(booleanValue);
14,711✔
451
  value_.bool_ = value;
14,711✔
452
}
14,711✔
453

454
Value::Value(const Value& other) {
245,130✔
455
  dupPayload(other);
245,130✔
456
  dupMeta(other);
245,130✔
457
}
245,130✔
458

459
Value::Value(Value&& other) noexcept {
55✔
460
  initBasic(nullValue);
55✔
461
  swap(other);
55✔
462
}
55✔
463

464
Value::~Value() {
484,537✔
465
  releasePayload();
484,537✔
466
  value_.uint_ = 0;
484,537✔
467
}
484,537✔
468

469
Value& Value::operator=(const Value& other) {
18✔
470
  Value(other).swap(*this);
18✔
471
  return *this;
18✔
472
}
473

474
Value& Value::operator=(Value&& other) noexcept {
125,140✔
475
  other.swap(*this);
125,140✔
476
  return *this;
125,140✔
477
}
478

479
void Value::swapPayload(Value& other) {
234,786✔
480
  std::swap(bits_, other.bits_);
481
  std::swap(value_, other.value_);
482
}
234,786✔
483

484
void Value::copyPayload(const Value& other) {
8✔
485
  releasePayload();
8✔
486
  dupPayload(other);
8✔
487
}
8✔
488

489
void Value::swap(Value& other) {
125,214✔
490
  swapPayload(other);
125,214✔
491
  std::swap(comments_, other.comments_);
125,214✔
492
  std::swap(start_, other.start_);
493
  std::swap(limit_, other.limit_);
494
}
125,214✔
495

496
void Value::copy(const Value& other) {
8✔
497
  copyPayload(other);
8✔
498
  dupMeta(other);
8✔
499
}
8✔
500

501
ValueType Value::type() const {
2,229,738✔
502
  return static_cast<ValueType>(bits_.value_type_);
2,229,738✔
503
}
504

505
int Value::compare(const Value& other) const {
120✔
506
  if (*this < other)
120✔
507
    return -1;
508
  if (*this > other)
89✔
509
    return 1;
31✔
510
  return 0;
511
}
512

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

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

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

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

569
bool Value::operator==(const Value& other) const {
317✔
570
  if (type() != other.type())
317✔
571
    return false;
572
  switch (type()) {
302!
573
  case nullValue:
574
    return true;
575
  case intValue:
79✔
576
    return value_.int_ == other.value_.int_;
79✔
577
  case uintValue:
10✔
578
    return value_.uint_ == other.value_.uint_;
10✔
579
  case realValue:
14✔
580
    return value_.real_ == other.value_.real_;
14✔
581
  case booleanValue:
15✔
582
    return value_.bool_ == other.value_.bool_;
15✔
583
  case stringValue: {
91✔
584
    if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
91!
UNCOV
585
      return (value_.string_ == other.value_.string_);
×
586
    }
587
    unsigned this_len;
588
    unsigned other_len;
589
    char const* this_str;
590
    char const* other_str;
591
    decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
592
                         &this_str);
593
    decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
594
                         &other_str);
595
    if (this_len != other_len)
91✔
596
      return false;
597
    JSON_ASSERT(this_str && other_str);
598
    int comp = memcmp(this_str, other_str, this_len);
84✔
599
    return comp == 0;
84✔
600
  }
601
  case arrayValue:
60✔
602
  case objectValue:
603
    return value_.map_->size() == other.value_.map_->size() &&
107✔
604
           (*value_.map_) == (*other.value_.map_);
UNCOV
605
  default:
×
UNCOV
606
    JSON_ASSERT_UNREACHABLE;
×
607
  }
608
  return false; // unreachable
609
}
610

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

613
const char* Value::asCString() const {
4✔
614
  JSON_ASSERT_MESSAGE(type() == stringValue,
6✔
615
                      "in Json::Value::asCString(): requires stringValue");
616
  if (value_.string_ == nullptr)
3!
617
    return nullptr;
618
  unsigned this_len;
619
  char const* this_str;
620
  decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
621
                       &this_str);
622
  return this_str;
623
}
624

625
#if JSONCPP_USE_SECURE_MEMORY
626
unsigned Value::getCStringLength() const {
627
  JSON_ASSERT_MESSAGE(type() == stringValue,
628
                      "in Json::Value::asCString(): requires stringValue");
629
  if (value_.string_ == 0)
630
    return 0;
631
  unsigned this_len;
632
  char const* this_str;
633
  decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
634
                       &this_str);
635
  return this_len;
636
}
637
#endif
638

639
bool Value::getString(char const** begin, char const** end) const {
782✔
640
  if (type() != stringValue)
782!
641
    return false;
642
  if (value_.string_ == nullptr)
782!
643
    return false;
644
  unsigned length;
645
  decodePrefixedString(this->isAllocated(), this->value_.string_, &length,
646
                       begin);
647
  *end = *begin + length;
782✔
648
  return true;
782✔
649
}
650

651
String Value::asString() const {
2,755✔
652
  switch (type()) {
2,755!
653
  case nullValue:
654
    return "";
2✔
655
  case stringValue: {
2,713✔
656
    if (value_.string_ == nullptr)
2,713!
UNCOV
657
      return "";
×
658
    unsigned this_len;
659
    char const* this_str;
660
    decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
661
                         &this_str);
662
    return String(this_str, this_len);
2,713✔
663
  }
664
  case booleanValue:
UNCOV
665
    return value_.bool_ ? "true" : "false";
×
666
  case intValue:
13✔
667
    return valueToString(value_.int_);
13✔
668
  case uintValue:
7✔
669
    return valueToString(value_.uint_);
7✔
670
  case realValue:
18✔
671
    return valueToString(value_.real_);
18✔
672
  default:
2✔
673
    JSON_FAIL_MESSAGE("Type is not convertible to string");
6✔
674
  }
675
}
676

677
Value::Int Value::asInt() const {
30✔
678
  switch (type()) {
30✔
679
  case intValue:
11✔
680
    JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
11!
681
    return Int(value_.int_);
11✔
682
  case uintValue:
8✔
683
    JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
8!
684
    return Int(value_.uint_);
8✔
685
  case realValue:
5✔
686
    JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
5!
687
                        "double out of Int range");
688
    return Int(value_.real_);
689
  case nullValue:
690
    return 0;
691
  case booleanValue:
2✔
692
    return value_.bool_ ? 1 : 0;
2✔
693
  default:
694
    break;
695
  }
696
  JSON_FAIL_MESSAGE("Value is not convertible to Int.");
9✔
697
}
698

699
Value::UInt Value::asUInt() const {
1,582✔
700
  switch (type()) {
1,582✔
701
  case intValue:
1,565✔
702
    JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
1,565!
703
    return UInt(value_.int_);
1,565✔
704
  case uintValue:
6✔
705
    JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
6!
706
    return UInt(value_.uint_);
6✔
707
  case realValue:
5✔
708
    JSON_ASSERT_MESSAGE(InRange(value_.real_, 0u, maxUInt),
5!
709
                        "double out of UInt range");
710
    return UInt(value_.real_);
711
  case nullValue:
712
    return 0;
713
  case booleanValue:
2✔
714
    return value_.bool_ ? 1 : 0;
2✔
715
  default:
716
    break;
717
  }
718
  JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
9✔
719
}
720

721
#if defined(JSON_HAS_INT64)
722

723
Value::Int64 Value::asInt64() const {
157,460✔
724
  switch (type()) {
157,460✔
725
  case intValue:
157,438✔
726
    return Int64(value_.int_);
157,438✔
727
  case uintValue:
6✔
728
    JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
6!
729
    return Int64(value_.uint_);
6✔
730
  case realValue:
10✔
731
    // If the double value is in proximity to minInt64, it will be rounded to
732
    // minInt64. The correct value in this scenario is indeterminable
733
    JSON_ASSERT_MESSAGE(
10!
734
        value_.real_ != minInt64,
735
        "Double value is minInt64, precise value cannot be determined");
UNCOV
736
    JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
×
737
                        "double out of Int64 range");
738
    return Int64(value_.real_);
739
  case nullValue:
740
    return 0;
741
  case booleanValue:
2✔
742
    return value_.bool_ ? 1 : 0;
2✔
743
  default:
744
    break;
745
  }
746
  JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
9✔
747
}
748

749
Value::UInt64 Value::asUInt64() const {
261✔
750
  switch (type()) {
261✔
751
  case intValue:
8✔
752
    JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
8!
753
    return UInt64(value_.int_);
8✔
754
  case uintValue:
237✔
755
    return UInt64(value_.uint_);
237✔
756
  case realValue:
10✔
757
    JSON_ASSERT_MESSAGE(InRange(value_.real_, 0u, maxUInt64),
10!
758
                        "double out of UInt64 range");
759
    return UInt64(value_.real_);
760
  case nullValue:
761
    return 0;
762
  case booleanValue:
2✔
763
    return value_.bool_ ? 1 : 0;
2✔
764
  default:
765
    break;
766
  }
767
  JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
9✔
768
}
769
#endif // if defined(JSON_HAS_INT64)
770

771
LargestInt Value::asLargestInt() const {
157,448✔
772
#if defined(JSON_NO_INT64)
773
  return asInt();
774
#else
775
  return asInt64();
157,448✔
776
#endif
777
}
778

779
LargestUInt Value::asLargestUInt() const {
248✔
780
#if defined(JSON_NO_INT64)
781
  return asUInt();
782
#else
783
  return asUInt64();
248✔
784
#endif
785
}
786

787
double Value::asDouble() const {
528✔
788
  switch (type()) {
528✔
789
  case intValue:
20✔
790
    return static_cast<double>(value_.int_);
20✔
791
  case uintValue:
14✔
792
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
793
    return static_cast<double>(value_.uint_);
794
#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
795
    return integerToDouble(value_.uint_);
14✔
796
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
797
  case realValue:
488✔
798
    return value_.real_;
488✔
799
  case nullValue:
800
    return 0.0;
801
  case booleanValue:
2✔
802
    return value_.bool_ ? 1.0 : 0.0;
2✔
803
  default:
804
    break;
805
  }
806
  JSON_FAIL_MESSAGE("Value is not convertible to double.");
9✔
807
}
808

809
float Value::asFloat() const {
40✔
810
  switch (type()) {
40✔
811
  case intValue:
10✔
812
    return static_cast<float>(value_.int_);
10✔
813
  case uintValue:
7✔
814
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
815
    return static_cast<float>(value_.uint_);
816
#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
817
    // This can fail (silently?) if the value is bigger than MAX_FLOAT.
818
    return static_cast<float>(integerToDouble(value_.uint_));
7✔
819
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
820
  case realValue:
17✔
821
    return static_cast<float>(value_.real_);
17✔
822
  case nullValue:
823
    return 0.0;
824
  case booleanValue:
2✔
825
    return value_.bool_ ? 1.0F : 0.0F;
2✔
826
  default:
827
    break;
828
  }
829
  JSON_FAIL_MESSAGE("Value is not convertible to float.");
9✔
830
}
831

832
bool Value::asBool() const {
12,746✔
833
  switch (type()) {
12,746!
834
  case booleanValue:
12,713✔
835
    return value_.bool_;
12,713✔
836
  case nullValue:
837
    return false;
838
  case intValue:
10✔
839
    return value_.int_ != 0;
10✔
840
  case uintValue:
7✔
841
    return value_.uint_ != 0;
7✔
842
  case realValue: {
13✔
843
    // According to JavaScript language zero or NaN is regarded as false
844
    const auto value_classification = std::fpclassify(value_.real_);
13!
845
    return value_classification != FP_ZERO && value_classification != FP_NAN;
13✔
846
  }
847
  default:
848
    break;
849
  }
850
  JSON_FAIL_MESSAGE("Value is not convertible to bool.");
9✔
851
}
852

853
bool Value::isConvertibleTo(ValueType other) const {
173✔
854
  switch (other) {
173!
855
  case nullValue:
39✔
856
    return (isNumeric() && asDouble() == 0.0) ||
102✔
857
           (type() == booleanValue && !value_.bool_) ||
67✔
858
           (type() == stringValue && asString().empty()) ||
105!
859
           (type() == arrayValue && value_.map_->empty()) ||
63✔
860
           (type() == objectValue && value_.map_->empty()) ||
100✔
861
           type() == nullValue;
29✔
862
  case intValue:
35✔
863
    return isInt() ||
58✔
864
           (type() == realValue && InRange(value_.real_, minInt, maxInt)) ||
54✔
865
           type() == booleanValue || type() == nullValue;
76✔
866
  case uintValue:
35✔
867
    return isUInt() ||
59✔
868
           (type() == realValue && InRange(value_.real_, 0u, maxUInt)) ||
56✔
869
           type() == booleanValue || type() == nullValue;
78✔
870
  case realValue:
13✔
871
    return isNumeric() || type() == booleanValue || type() == nullValue;
13✔
872
  case booleanValue:
12✔
873
    return isNumeric() || type() == booleanValue || type() == nullValue;
12✔
874
  case stringValue:
13✔
875
    return isNumeric() || type() == booleanValue || type() == stringValue ||
16✔
876
           type() == nullValue;
3✔
877
  case arrayValue:
13✔
878
    return type() == arrayValue || type() == nullValue;
13✔
879
  case objectValue:
13✔
880
    return type() == objectValue || type() == nullValue;
13✔
881
  }
UNCOV
882
  JSON_ASSERT_UNREACHABLE;
×
883
  return false;
884
}
885

886
/// Number of values in array or object
887
ArrayIndex Value::size() const {
845✔
888
  switch (type()) {
845!
889
  case nullValue:
890
  case intValue:
891
  case uintValue:
892
  case realValue:
893
  case booleanValue:
894
  case stringValue:
895
    return 0;
896
  case arrayValue: // size of the array is highest index + 1
804✔
897
    if (!value_.map_->empty()) {
804✔
898
      ObjectValues::const_iterator itLast = value_.map_->end();
899
      --itLast;
900
      return (*itLast).first.index() + 1;
717✔
901
    }
902
    return 0;
903
  case objectValue:
28✔
904
    return ArrayIndex(value_.map_->size());
28✔
905
  }
UNCOV
906
  JSON_ASSERT_UNREACHABLE;
×
907
  return 0; // unreachable;
908
}
909

910
bool Value::empty() const {
36✔
911
  if (isNull() || isArray() || isObject())
36!
912
    return size() == 0U;
36✔
913
  return false;
914
}
915

916
Value::operator bool() const { return !isNull(); }
4✔
917

918
void Value::clear() {
3✔
919
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue ||
5!
920
                          type() == objectValue,
921
                      "in Json::Value::clear(): requires complex value");
922
  start_ = 0;
2✔
923
  limit_ = 0;
2✔
924
  switch (type()) {
2!
925
  case arrayValue:
2✔
926
  case objectValue:
927
    value_.map_->clear();
2✔
928
    break;
929
  default:
930
    break;
931
  }
932
}
2✔
933

934
void Value::resize(ArrayIndex newSize) {
7✔
935
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
13✔
936
                      "in Json::Value::resize(): requires arrayValue");
937
  if (type() == nullValue)
4✔
938
    *this = Value(arrayValue);
1✔
939
  ArrayIndex oldSize = size();
4✔
940
  if (newSize == 0)
4✔
941
    clear();
1✔
942
  else if (newSize > oldSize)
3✔
943
    for (ArrayIndex i = oldSize; i < newSize; ++i)
17✔
944
      (*this)[i];
15✔
945
  else {
946
    for (ArrayIndex index = newSize; index < oldSize; ++index) {
11✔
947
      value_.map_->erase(index);
20✔
948
    }
949
    JSON_ASSERT(size() == newSize);
1!
950
  }
951
}
4✔
952

953
Value& Value::operator[](ArrayIndex index) {
212,045✔
954
  JSON_ASSERT_MESSAGE(
212,051✔
955
      type() == nullValue || type() == arrayValue,
956
      "in Json::Value::operator[](ArrayIndex): requires arrayValue");
957
  if (type() == nullValue)
212,042✔
958
    *this = Value(arrayValue);
16✔
959
  CZString key(index);
212,042✔
960
  auto it = value_.map_->lower_bound(key);
212,042✔
961
  if (it != value_.map_->end() && (*it).first == key)
212,042✔
962
    return (*it).second;
104,910✔
963

964
  ObjectValues::value_type defaultValue(key, nullSingleton());
107,132✔
965
  it = value_.map_->insert(it, defaultValue);
107,132✔
966
  return (*it).second;
107,132✔
967
}
212,042✔
968

969
Value& Value::operator[](int index) {
107,037✔
970
  JSON_ASSERT_MESSAGE(
107,037!
971
      index >= 0,
972
      "in Json::Value::operator[](int index): index cannot be negative");
973
  return (*this)[ArrayIndex(index)];
107,037✔
974
}
975

976
const Value& Value::operator[](ArrayIndex index) const {
53,225✔
977
  JSON_ASSERT_MESSAGE(
53,225!
978
      type() == nullValue || type() == arrayValue,
979
      "in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
980
  if (type() == nullValue)
53,225!
UNCOV
981
    return nullSingleton();
×
982
  CZString key(index);
53,225✔
983
  ObjectValues::const_iterator it = value_.map_->find(key);
53,225✔
984
  if (it == value_.map_->end())
53,225✔
985
    return nullSingleton();
1✔
986
  return (*it).second;
53,224✔
987
}
53,225✔
988

989
const Value& Value::operator[](int index) const {
4✔
990
  JSON_ASSERT_MESSAGE(
4!
991
      index >= 0,
992
      "in Json::Value::operator[](int index) const: index cannot be negative");
993
  return (*this)[ArrayIndex(index)];
4✔
994
}
995

996
void Value::initBasic(ValueType type, bool allocated) {
239,407✔
997
  setType(type);
998
  setIsAllocated(allocated);
999
  comments_ = Comments{};
239,407✔
1000
  start_ = 0;
239,407✔
1001
  limit_ = 0;
239,407✔
1002
}
239,407✔
1003

1004
void Value::dupPayload(const Value& other) {
245,138✔
1005
  setType(other.type());
245,138✔
1006
  setIsAllocated(false);
1007
  switch (type()) {
245,138!
1008
  case nullValue:
244,944✔
1009
  case intValue:
1010
  case uintValue:
1011
  case realValue:
1012
  case booleanValue:
1013
    value_ = other.value_;
244,944✔
1014
    break;
244,944✔
1015
  case stringValue:
139✔
1016
    if (other.value_.string_ && other.isAllocated()) {
139!
1017
      unsigned len;
1018
      char const* str;
1019
      decodePrefixedString(other.isAllocated(), other.value_.string_, &len,
1020
                           &str);
1021
      value_.string_ = duplicateAndPrefixStringValue(str, len);
139✔
1022
      setIsAllocated(true);
1023
    } else {
UNCOV
1024
      value_.string_ = other.value_.string_;
×
1025
    }
1026
    break;
1027
  case arrayValue:
55✔
1028
  case objectValue:
1029
    value_.map_ = new ObjectValues(*other.value_.map_);
55✔
1030
    break;
55✔
UNCOV
1031
  default:
×
UNCOV
1032
    JSON_ASSERT_UNREACHABLE;
×
1033
  }
1034
}
245,138✔
1035

1036
void Value::releasePayload() {
484,545✔
1037
  switch (type()) {
484,545!
1038
  case nullValue:
1039
  case intValue:
1040
  case uintValue:
1041
  case realValue:
1042
  case booleanValue:
1043
    break;
1044
  case stringValue:
1045
    if (isAllocated())
2,663✔
1046
      releasePrefixedStringValue(value_.string_);
2,661✔
1047
    break;
1048
  case arrayValue:
4,995✔
1049
  case objectValue:
1050
    delete value_.map_;
9,990!
1051
    break;
UNCOV
1052
  default:
×
UNCOV
1053
    JSON_ASSERT_UNREACHABLE;
×
1054
  }
1055
}
484,545✔
1056

1057
void Value::dupMeta(const Value& other) {
245,138✔
1058
  comments_ = other.comments_;
245,138✔
1059
  start_ = other.start_;
245,138✔
1060
  limit_ = other.limit_;
245,138✔
1061
}
245,138✔
1062

1063
// Access an object value by name, create a null member if it does not exist.
1064
// @pre Type of '*this' is object or null.
1065
// @param key is null-terminated.
1066
Value& Value::resolveReference(const char* key) {
1✔
1067
  JSON_ASSERT_MESSAGE(
1!
1068
      type() == nullValue || type() == objectValue,
1069
      "in Json::Value::resolveReference(): requires objectValue");
1070
  if (type() == nullValue)
1!
1071
    *this = Value(objectValue);
1✔
1072
  CZString actualKey(key, static_cast<unsigned>(strlen(key)),
1✔
1073
                     CZString::noDuplication); // NOTE!
1✔
1074
  auto it = value_.map_->lower_bound(actualKey);
1✔
1075
  if (it != value_.map_->end() && (*it).first == actualKey)
1!
UNCOV
1076
    return (*it).second;
×
1077

1078
  ObjectValues::value_type defaultValue(actualKey, nullSingleton());
1✔
1079
  it = value_.map_->insert(it, defaultValue);
1✔
1080
  Value& value = (*it).second;
1✔
1081
  return value;
1082
}
1✔
1083

1084
// @param key is not null-terminated.
1085
Value& Value::resolveReference(char const* key, char const* end) {
19,625✔
1086
  JSON_ASSERT_MESSAGE(
19,631✔
1087
      type() == nullValue || type() == objectValue,
1088
      "in Json::Value::resolveReference(key, end): requires objectValue");
1089
  if (type() == nullValue)
19,622✔
1090
    *this = Value(objectValue);
1,694✔
1091
  CZString actualKey(key, static_cast<unsigned>(end - key),
19,622✔
1092
                     CZString::duplicateOnCopy);
19,622✔
1093
  auto it = value_.map_->lower_bound(actualKey);
19,622✔
1094
  if (it != value_.map_->end() && (*it).first == actualKey)
19,622✔
1095
    return (*it).second;
4,370✔
1096

1097
  ObjectValues::value_type defaultValue(actualKey, nullSingleton());
15,252✔
1098
  it = value_.map_->insert(it, defaultValue);
15,252✔
1099
  Value& value = (*it).second;
15,252✔
1100
  return value;
1101
}
19,622✔
1102

1103
Value Value::get(ArrayIndex index, const Value& defaultValue) const {
6✔
1104
  const Value* value = &((*this)[index]);
6✔
1105
  return value == &nullSingleton() ? defaultValue : *value;
11✔
1106
}
1107

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

1110
Value const* Value::find(char const* begin, char const* end) const {
17,018✔
1111
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
17,018!
1112
                      "in Json::Value::find(begin, end): requires "
1113
                      "objectValue or nullValue");
1114
  if (type() == nullValue)
17,018!
1115
    return nullptr;
1116
  CZString actualKey(begin, static_cast<unsigned>(end - begin),
17,018✔
1117
                     CZString::noDuplication);
17,018✔
1118
  ObjectValues::const_iterator it = value_.map_->find(actualKey);
17,018✔
1119
  if (it == value_.map_->end())
17,018✔
1120
    return nullptr;
1121
  return &(*it).second;
17,003✔
1122
}
17,018✔
1123
Value const* Value::find(const String& key) const {
896✔
1124
  return find(key.data(), key.data() + key.length());
896✔
1125
}
1126

1127
Value const* Value::findNull(const String& key) const {
2✔
1128
  return findValue<Value, &Value::isNull>(key);
2✔
1129
}
1130
Value const* Value::findBool(const String& key) const {
2✔
1131
  return findValue<Value, &Value::isBool>(key);
2✔
1132
}
1133
Value const* Value::findInt(const String& key) const {
2✔
1134
  return findValue<Value, &Value::isInt>(key);
2✔
1135
}
1136
Value const* Value::findInt64(const String& key) const {
2✔
1137
  return findValue<Value, &Value::isInt64>(key);
2✔
1138
}
1139
Value const* Value::findUInt(const String& key) const {
2✔
1140
  return findValue<Value, &Value::isUInt>(key);
2✔
1141
}
1142
Value const* Value::findUInt64(const String& key) const {
2✔
1143
  return findValue<Value, &Value::isUInt64>(key);
2✔
1144
}
1145
Value const* Value::findIntegral(const String& key) const {
2✔
1146
  return findValue<Value, &Value::isIntegral>(key);
2✔
1147
}
1148
Value const* Value::findDouble(const String& key) const {
2✔
1149
  return findValue<Value, &Value::isDouble>(key);
2✔
1150
}
1151
Value const* Value::findNumeric(const String& key) const {
2✔
1152
  return findValue<Value, &Value::isNumeric>(key);
2✔
1153
}
1154
Value const* Value::findString(const String& key) const {
2✔
1155
  return findValue<Value, &Value::isString>(key);
2✔
1156
}
1157
Value const* Value::findArray(const String& key) const {
2✔
1158
  return findValue<Value, &Value::isArray>(key);
2✔
1159
}
UNCOV
1160
Value const* Value::findObject(const String& key) const {
×
UNCOV
1161
  return findValue<Value, &Value::isObject>(key);
×
1162
}
1163

1164
Value* Value::demand(char const* begin, char const* end) {
1✔
1165
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
1!
1166
                      "in Json::Value::demand(begin, end): requires "
1167
                      "objectValue or nullValue");
1168
  return &resolveReference(begin, end);
1✔
1169
}
1170
const Value& Value::operator[](const char* key) const {
16,094✔
1171
  Value const* found = find(key, key + strlen(key));
16,094✔
1172
  if (!found)
16,094✔
1173
    return nullSingleton();
1✔
1174
  return *found;
1175
}
1176
Value const& Value::operator[](const String& key) const {
872✔
1177
  Value const* found = find(key);
872✔
1178
  if (!found)
872✔
1179
    return nullSingleton();
3✔
1180
  return *found;
1181
}
1182

1183
Value& Value::operator[](const char* key) {
17,760✔
1184
  return resolveReference(key, key + strlen(key));
17,760✔
1185
}
1186

1187
Value& Value::operator[](const String& key) {
1,864✔
1188
  return resolveReference(key.data(), key.data() + key.length());
1,864✔
1189
}
1190

1191
Value& Value::operator[](const StaticString& key) {
1✔
1192
  return resolveReference(key.c_str());
1✔
1193
}
1194

1195
Value& Value::append(const Value& value) { return append(Value(value)); }
1✔
1196

1197
Value& Value::append(Value&& value) {
53✔
1198
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
53!
1199
                      "in Json::Value::append: requires arrayValue");
1200
  if (type() == nullValue) {
53✔
1201
    *this = Value(arrayValue);
43✔
1202
  }
1203
  return this->value_.map_->emplace(size(), std::move(value)).first->second;
53✔
1204
}
1205

1206
bool Value::insert(ArrayIndex index, const Value& newValue) {
1✔
1207
  return insert(index, Value(newValue));
1✔
1208
}
1209

1210
bool Value::insert(ArrayIndex index, Value&& newValue) {
4✔
1211
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
4!
1212
                      "in Json::Value::insert: requires arrayValue");
1213
  ArrayIndex length = size();
4✔
1214
  if (index > length) {
4✔
1215
    return false;
1216
  }
1217
  for (ArrayIndex i = length; i > index; i--) {
8✔
1218
    (*this)[i] = std::move((*this)[i - 1]);
5✔
1219
  }
1220
  (*this)[index] = std::move(newValue);
3✔
1221
  return true;
3✔
1222
}
1223

1224
Value Value::get(char const* begin, char const* end,
15✔
1225
                 Value const& defaultValue) const {
1226
  Value const* found = find(begin, end);
15✔
1227
  return !found ? defaultValue : *found;
29✔
1228
}
1229
Value Value::get(char const* key, Value const& defaultValue) const {
10✔
1230
  return get(key, key + strlen(key), defaultValue);
10✔
1231
}
1232
Value Value::get(String const& key, Value const& defaultValue) const {
5✔
1233
  return get(key.data(), key.data() + key.length(), defaultValue);
5✔
1234
}
1235

1236
bool Value::removeMember(const char* begin, const char* end, Value* removed) {
9✔
1237
  if (type() != objectValue) {
9!
1238
    return false;
1239
  }
1240
  CZString actualKey(begin, static_cast<unsigned>(end - begin),
9✔
1241
                     CZString::noDuplication);
9✔
1242
  auto it = value_.map_->find(actualKey);
9✔
1243
  if (it == value_.map_->end())
9✔
1244
    return false;
1245
  if (removed)
5✔
1246
    *removed = std::move(it->second);
4✔
1247
  value_.map_->erase(it);
5✔
1248
  return true;
5✔
1249
}
9✔
1250
bool Value::removeMember(const char* key, Value* removed) {
3✔
1251
  return removeMember(key, key + strlen(key), removed);
3✔
1252
}
1253
bool Value::removeMember(String const& key, Value* removed) {
2✔
1254
  return removeMember(key.data(), key.data() + key.length(), removed);
2✔
1255
}
1256

1257
void Value::removeMember(const char* key) {
4✔
1258
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
10!
1259
                      "in Json::Value::removeMember(): requires objectValue");
1260
  if (type() == nullValue)
1!
UNCOV
1261
    return;
×
1262

1263
  CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication);
1✔
1264
  value_.map_->erase(actualKey);
1✔
1265
}
1✔
1266
void Value::removeMember(const String& key) { removeMember(key.c_str()); }
1✔
1267

1268
bool Value::removeIndex(ArrayIndex index, Value* removed) {
2✔
1269
  if (type() != arrayValue) {
2!
1270
    return false;
1271
  }
1272
  CZString key(index);
2✔
1273
  auto it = value_.map_->find(key);
2✔
1274
  if (it == value_.map_->end()) {
2✔
1275
    return false;
1276
  }
1277
  if (removed)
1!
1278
    *removed = std::move(it->second);
1✔
1279
  ArrayIndex oldSize = size();
1✔
1280
  // shift left all items left, into the place of the "removed"
1281
  for (ArrayIndex i = index; i < (oldSize - 1); ++i) {
1!
UNCOV
1282
    CZString keey(i);
×
UNCOV
1283
    (*value_.map_)[keey] = (*this)[i + 1];
×
UNCOV
1284
  }
×
1285
  // erase the last one ("leftover")
1286
  CZString keyLast(oldSize - 1);
1✔
1287
  auto itLast = value_.map_->find(keyLast);
1✔
1288
  value_.map_->erase(itLast);
1✔
1289
  return true;
1290
}
2✔
1291

1292
bool Value::isMember(char const* begin, char const* end) const {
10✔
1293
  Value const* value = find(begin, end);
10✔
1294
  return nullptr != value;
10✔
1295
}
1296
bool Value::isMember(char const* key) const {
5✔
1297
  return isMember(key, key + strlen(key));
5✔
1298
}
1299
bool Value::isMember(String const& key) const {
5✔
1300
  return isMember(key.data(), key.data() + key.length());
5✔
1301
}
1302

1303
Value::Members Value::getMemberNames() const {
1,130✔
1304
  JSON_ASSERT_MESSAGE(
1,136!
1305
      type() == nullValue || type() == objectValue,
1306
      "in Json::Value::getMemberNames(), value must be objectValue");
1307
  if (type() == nullValue)
1,127!
UNCOV
1308
    return Value::Members();
×
1309
  Members members;
1310
  members.reserve(value_.map_->size());
1,127✔
1311
  ObjectValues::const_iterator it = value_.map_->begin();
1,127✔
1312
  ObjectValues::const_iterator itEnd = value_.map_->end();
1313
  for (; it != itEnd; ++it) {
2,792✔
1314
    members.push_back(String((*it).first.data(), (*it).first.length()));
3,330✔
1315
  }
1316
  return members;
1317
}
1,127✔
1318

1319
static bool IsIntegral(double d) {
1320
  double integral_part;
1321
  return modf(d, &integral_part) == 0.0;
58✔
1322
}
1323

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

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

1328
bool Value::isInt() const {
104✔
1329
  switch (type()) {
104✔
1330
  case intValue:
34✔
1331
#if defined(JSON_HAS_INT64)
1332
    return value_.int_ >= minInt && value_.int_ <= maxInt;
34✔
1333
#else
1334
    return true;
1335
#endif
1336
  case uintValue:
22✔
1337
    return value_.uint_ <= UInt(maxInt);
22✔
1338
  case realValue:
28✔
1339
    return value_.real_ >= minInt && value_.real_ <= maxInt &&
28✔
1340
           IsIntegral(value_.real_);
1341
  default:
1342
    break;
1343
  }
1344
  return false;
1345
}
1346

1347
bool Value::isUInt() const {
1,656✔
1348
  switch (type()) {
1,656✔
1349
  case intValue:
1,587✔
1350
#if defined(JSON_HAS_INT64)
1351
    return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
1,587✔
1352
#else
1353
    return value_.int_ >= 0;
1354
#endif
1355
  case uintValue:
21✔
1356
#if defined(JSON_HAS_INT64)
1357
    return value_.uint_ <= maxUInt;
21✔
1358
#else
1359
    return true;
1360
#endif
1361
  case realValue:
28✔
1362
    return value_.real_ >= 0 && value_.real_ <= maxUInt &&
28✔
1363
           IsIntegral(value_.real_);
1364
  default:
1365
    break;
1366
  }
1367
  return false;
1368
}
1369

1370
bool Value::isInt64() const {
56✔
1371
#if defined(JSON_HAS_INT64)
1372
  switch (type()) {
56✔
1373
  case intValue:
1374
    return true;
1375
  case uintValue:
13✔
1376
    return value_.uint_ <= UInt64(maxInt64);
13✔
1377
  case realValue:
15✔
1378
    // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
1379
    // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
1380
    // require the value to be strictly less than the limit.
1381
    // minInt64 is -2^63 which can be represented as a double, but since double
1382
    // values in its proximity are also rounded to -2^63, we require the value
1383
    // to be strictly greater than the limit to avoid returning 'true' for
1384
    // values that are not in the range
1385
    return value_.real_ > double(minInt64) && value_.real_ < double(maxInt64) &&
15✔
1386
           IsIntegral(value_.real_);
1387
  default:
1388
    break;
1389
  }
1390
#endif // JSON_HAS_INT64
1391
  return false;
1392
}
1393

1394
bool Value::isUInt64() const {
57✔
1395
#if defined(JSON_HAS_INT64)
1396
  switch (type()) {
57✔
1397
  case intValue:
20✔
1398
    return value_.int_ >= 0;
20✔
1399
  case uintValue:
1400
    return true;
1401
  case realValue:
15✔
1402
    // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
1403
    // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
1404
    // require the value to be strictly less than the limit.
1405
    return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&
15✔
1406
           IsIntegral(value_.real_);
1407
  default:
1408
    break;
1409
  }
1410
#endif // JSON_HAS_INT64
1411
  return false;
1412
}
1413

1414
bool Value::isIntegral() const {
42✔
1415
  switch (type()) {
42✔
1416
  case intValue:
1417
  case uintValue:
1418
    return true;
1419
  case realValue:
14✔
1420
#if defined(JSON_HAS_INT64)
1421
    // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
1422
    // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
1423
    // require the value to be strictly less than the limit.
1424
    // minInt64 is -2^63 which can be represented as a double, but since double
1425
    // values in its proximity are also rounded to -2^63, we require the value
1426
    // to be strictly greater than the limit to avoid returning 'true' for
1427
    // values that are not in the range
1428
    return value_.real_ > double(minInt64) &&
13✔
1429
           value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);
26✔
1430
#else
1431
    return value_.real_ >= minInt && value_.real_ <= maxUInt &&
1432
           IsIntegral(value_.real_);
1433
#endif // JSON_HAS_INT64
1434
  default:
1435
    break;
1436
  }
1437
  return false;
1438
}
1439

1440
bool Value::isDouble() const {
169✔
1441
  return type() == intValue || type() == uintValue || type() == realValue;
169✔
1442
}
1443

1444
bool Value::isNumeric() const { return isDouble(); }
119✔
1445

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

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

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

UNCOV
1452
Value::Comments::Comments(const Comments& that)
×
UNCOV
1453
    : ptr_{cloneUnique(that.ptr_)} {}
×
1454

1455
Value::Comments::Comments(Comments&& that) noexcept
125,214✔
1456
    : ptr_{std::move(that.ptr_)} {}
125,214✔
1457

1458
Value::Comments& Value::Comments::operator=(const Comments& that) {
245,138✔
1459
  ptr_ = cloneUnique(that.ptr_);
245,138✔
1460
  return *this;
245,138✔
1461
}
1462

1463
Value::Comments& Value::Comments::operator=(Comments&& that) noexcept {
489,835!
1464
  ptr_ = std::move(that.ptr_);
1465
  return *this;
489,835✔
1466
}
1467

1468
bool Value::Comments::has(CommentPlacement slot) const {
377,785✔
1469
  return ptr_ && !(*ptr_)[slot].empty();
377,785!
1470
}
1471

1472
String Value::Comments::get(CommentPlacement slot) const {
1,282!
1473
  if (!ptr_)
1,282!
1474
    return {};
1475
  return (*ptr_)[slot];
1,282!
1476
}
1477

1478
void Value::Comments::set(CommentPlacement slot, String comment) {
955✔
1479
  if (slot >= CommentPlacement::numberOfCommentPlacement)
955!
1480
    return;
1481
  if (!ptr_)
955✔
1482
    ptr_ = std::unique_ptr<Array>(new Array());
893✔
1483
  (*ptr_)[slot] = std::move(comment);
1,910!
1484
}
1485

1486
void Value::setComment(String comment, CommentPlacement placement) {
955!
1487
  if (!comment.empty() && (comment.back() == '\n')) {
955!
1488
    // Always discard trailing newline, to aid indentation.
1489
    comment.pop_back();
790✔
1490
  }
1491
  JSON_ASSERT_MESSAGE(
955!
1492
      comment.empty() || comment[0] == '/',
1493
      "in Json::Value::setComment(): Comments must start with /");
1494
  comments_.set(placement, std::move(comment));
955✔
1495
}
955✔
1496

1497
bool Value::hasComment(CommentPlacement placement) const {
377,785✔
1498
  return comments_.has(placement);
377,785✔
1499
}
1500

1501
String Value::getComment(CommentPlacement placement) const {
1,282✔
1502
  return comments_.get(placement);
1,282✔
1503
}
1504

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

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

1509
ptrdiff_t Value::getOffsetStart() const { return start_; }
19✔
1510

1511
ptrdiff_t Value::getOffsetLimit() const { return limit_; }
19✔
1512

1513
String Value::toStyledString() const {
5✔
1514
  StreamWriterBuilder builder;
5✔
1515

1516
  String out = this->hasComment(commentBefore) ? "\n" : "";
8✔
1517
  out += Json::writeString(builder, *this);
10✔
1518
  out += '\n';
1519

1520
  return out;
5✔
1521
}
5✔
1522

1523
Value::const_iterator Value::begin() const {
23✔
1524
  switch (type()) {
23✔
1525
  case arrayValue:
10✔
1526
  case objectValue:
1527
    if (value_.map_)
10!
1528
      return const_iterator(value_.map_->begin());
10✔
1529
    break;
1530
  default:
1531
    break;
1532
  }
1533
  return {};
13✔
1534
}
1535

1536
Value::const_iterator Value::end() const {
64✔
1537
  switch (type()) {
64✔
1538
  case arrayValue:
52✔
1539
  case objectValue:
1540
    if (value_.map_)
52!
1541
      return const_iterator(value_.map_->end());
52✔
1542
    break;
1543
  default:
1544
    break;
1545
  }
1546
  return {};
12✔
1547
}
1548

1549
Value::iterator Value::begin() {
39✔
1550
  switch (type()) {
39✔
1551
  case arrayValue:
26✔
1552
  case objectValue:
1553
    if (value_.map_)
26!
1554
      return iterator(value_.map_->begin());
26✔
1555
    break;
1556
  default:
1557
    break;
1558
  }
1559
  return iterator();
13✔
1560
}
1561

1562
Value::iterator Value::end() {
44✔
1563
  switch (type()) {
44✔
1564
  case arrayValue:
29✔
1565
  case objectValue:
1566
    if (value_.map_)
29!
1567
      return iterator(value_.map_->end());
29✔
1568
    break;
1569
  default:
1570
    break;
1571
  }
1572
  return iterator();
15✔
1573
}
1574

1575
// class PathArgument
1576
// //////////////////////////////////////////////////////////////////
1577

1578
PathArgument::PathArgument() = default;
36✔
1579

1580
PathArgument::PathArgument(ArrayIndex index)
4✔
1581
    : index_(index), kind_(kindIndex) {}
4✔
1582

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

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

1587
// class Path
1588
// //////////////////////////////////////////////////////////////////
1589

1590
Path::Path(const String& path, const PathArgument& a1, const PathArgument& a2,
8✔
1591
           const PathArgument& a3, const PathArgument& a4,
1592
           const PathArgument& a5) {
1593
  InArgs in;
1594
  in.reserve(5);
8✔
1595
  in.push_back(&a1);
8✔
1596
  in.push_back(&a2);
8✔
1597
  in.push_back(&a3);
8✔
1598
  in.push_back(&a4);
8✔
1599
  in.push_back(&a5);
8✔
1600
  makePath(path, in);
8✔
1601
}
8✔
1602

1603
void Path::makePath(const String& path, const InArgs& in) {
8✔
1604
  const char* current = path.c_str();
1605
  const char* end = current + path.length();
8✔
1606
  auto itInArg = in.begin();
8✔
1607
  while (current != end) {
42✔
1608
    if (*current == '[') {
34✔
1609
      ++current;
4✔
1610
      if (*current == '%')
4✔
1611
        addPathInArg(path, in, itInArg, PathArgument::kindIndex);
2✔
1612
      else {
1613
        ArrayIndex index = 0;
1614
        for (; current != end && *current >= '0' && *current <= '9'; ++current)
4!
1615
          index = index * 10 + ArrayIndex(*current - '0');
2✔
1616
        args_.push_back(index);
4✔
1617
      }
1618
      if (current == end || *++current != ']')
4!
1619
        invalidPath(path, int(current - path.c_str()));
2✔
1620
    } else if (*current == '%') {
30✔
1621
      addPathInArg(path, in, itInArg, PathArgument::kindKey);
2✔
1622
      ++current;
2✔
1623
    } else if (*current == '.' || *current == ']') {
28✔
1624
      ++current;
18✔
1625
    } else {
1626
      const char* beginName = current;
1627
      while (current != end && !strchr("[.", *current))
88✔
1628
        ++current;
78✔
1629
      args_.push_back(String(beginName, current));
20✔
1630
    }
1631
  }
1632
}
8✔
1633

1634
void Path::addPathInArg(const String& /*path*/, const InArgs& in,
4!
1635
                        InArgs::const_iterator& itInArg,
1636
                        PathArgument::Kind kind) {
1637
  if (itInArg == in.end()) {
4!
1638
    // Error: missing argument %d
1639
  } else if ((*itInArg)->kind_ != kind) {
4!
1640
    // Error: bad argument type
1641
  } else {
1642
    args_.push_back(**itInArg++);
4✔
1643
  }
1644
}
4✔
1645

1646
void Path::invalidPath(const String& /*path*/, int /*location*/) {
2✔
1647
  // Error: invalid path.
1648
}
2✔
1649

1650
const Value& Path::resolve(const Value& root) const {
6✔
1651
  const Value* node = &root;
1652
  for (const auto& arg : args_) {
14✔
1653
    if (arg.kind_ == PathArgument::kindIndex) {
12✔
1654
      if (!node->isArray() || !node->isValidIndex(arg.index_)) {
2!
1655
        // Error: unable to resolve path (array value expected at position... )
1656
        return Value::nullSingleton();
1✔
1657
      }
1658
      node = &((*node)[arg.index_]);
1✔
1659
    } else if (arg.kind_ == PathArgument::kindKey) {
10!
1660
      if (!node->isObject()) {
10✔
1661
        // Error: unable to resolve path (object value expected at position...)
1662
        return Value::nullSingleton();
1✔
1663
      }
1664
      node = &((*node)[arg.key_]);
9✔
1665
      if (node == &Value::nullSingleton()) {
9✔
1666
        // Error: unable to resolve path (object has no member named '' at
1667
        // position...)
1668
        return Value::nullSingleton();
2✔
1669
      }
1670
    }
1671
  }
1672
  return *node;
1673
}
1674

1675
Value Path::resolve(const Value& root, const Value& defaultValue) const {
6✔
1676
  const Value* node = &root;
1677
  for (const auto& arg : args_) {
14✔
1678
    if (arg.kind_ == PathArgument::kindIndex) {
12✔
1679
      if (!node->isArray() || !node->isValidIndex(arg.index_))
3✔
1680
        return defaultValue;
2✔
1681
      node = &((*node)[arg.index_]);
1✔
1682
    } else if (arg.kind_ == PathArgument::kindKey) {
9!
1683
      if (!node->isObject())
9✔
1684
        return defaultValue;
1✔
1685
      node = &((*node)[arg.key_]);
8✔
1686
      if (node == &Value::nullSingleton())
8✔
1687
        return defaultValue;
1✔
1688
    }
1689
  }
1690
  return *node;
2✔
1691
}
1692

1693
Value& Path::make(Value& root) const {
2✔
1694
  Value* node = &root;
1695
  for (const auto& arg : args_) {
6✔
1696
    if (arg.kind_ == PathArgument::kindIndex) {
4✔
1697
      if (!node->isArray()) {
1✔
1698
        // Error: node is not an array at position ...
1699
      }
1700
      node = &((*node)[arg.index_]);
1✔
1701
    } else if (arg.kind_ == PathArgument::kindKey) {
3!
1702
      if (!node->isObject()) {
3✔
1703
        // Error: node is not an object at position...
1704
      }
1705
      node = &((*node)[arg.key_]);
3✔
1706
    }
1707
  }
1708
  return *node;
2✔
1709
}
1710

1711
} // namespace Json
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