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

open-source-parsers / jsoncpp / 23129739262

16 Mar 2026 05:44AM UTC coverage: 90.093% (+0.2%) from 89.937%
23129739262

Pull #1662

github

web-flow
Merge 1d4d1173e into 9a5bbec0d
Pull Request #1662: Fix number parsing failing under non-C locales

2183 of 2589 branches covered (84.32%)

Branch coverage included in aggregate %.

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

66 existing lines in 2 files now uncovered.

2573 of 2690 relevant lines covered (95.65%)

23748.16 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,134✔
57
  std::unique_ptr<T> r;
245,134✔
58
  if (p) {
245,134✔
59
    r = std::unique_ptr<T>(new T(*p));
6✔
60
  }
61
  return r;
245,134✔
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,414✔
75
  static Value const nullStatic;
123,414!
76
  return nullStatic;
123,414✔
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,541✔
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,541✔
125
    length = Value::maxInt - 1;
126

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

137
/* Record the length as a prefix.
138
 */
139
static inline char* duplicateAndPrefixStringValue(const char* value,
2,657✔
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,657!
144
                                    sizeof(unsigned) - 1U,
145
                      "in Json::Value::duplicateAndPrefixStringValue(): "
146
                      "length too big for prefixing");
147
  size_t actualLength = sizeof(length) + length + 1;
2,657✔
148
  auto newString = static_cast<char*>(malloc(actualLength));
2,657✔
149
  if (newString == nullptr) {
2,657!
150
    throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): "
×
151
                      "Failed to allocate string value buffer");
152
  }
153
  *reinterpret_cast<unsigned*>(newString) = length;
2,657✔
154
  memcpy(newString + sizeof(unsigned), value, length);
2,657✔
155
  newString[actualLength - 1U] =
2,657✔
156
      0; // to avoid buffer over-run accidents by users later
157
  return newString;
2,657✔
158
}
159
inline static void decodePrefixedString(bool isPrefixed, char const* prefixed,
160
                                        unsigned* length, char const** value) {
161
  if (!isPrefixed) {
4,025!
162
    *length = static_cast<unsigned>(strlen(prefixed));
3✔
163
    *value = prefixed;
×
164
  } else {
165
    *length = *reinterpret_cast<unsigned const*>(prefixed);
4,158✔
166
    *value = prefixed + sizeof(unsigned);
4,022✔
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,540✔
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,650✔
245
                          DuplicationPolicy allocate)
36,650✔
246
    : cstr_(str) {
36,650✔
247
  // allocate != duplicate
248
  storage_.policy_ = allocate & 0x3;
36,650✔
249
  storage_.length_ = length & 0x3FFFFFFF;
36,650✔
250
}
36,650✔
251

252
Value::CZString::CZString(const CZString& other) {
244,833✔
253
  cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr
188,027✔
254
               ? duplicateStringValue(other.cstr_, other.storage_.length_)
432,860✔
255
               : other.cstr_);
256
  if (other.cstr_) {
244,833✔
257
    storage_.policy_ =
30,544✔
258
        static_cast<unsigned>(
259
            other.cstr_
260
                ? (static_cast<DuplicationPolicy>(other.storage_.policy_) ==
30,544✔
261
                           noDuplication
262
                       ? noDuplication
30,544✔
263
                       : duplicate)
264
                : static_cast<DuplicationPolicy>(other.storage_.policy_)) &
30,544✔
265
        3U;
266
    storage_.length_ = other.storage_.length_;
30,544✔
267
  } else {
268
    index_ = other.index_;
214,289✔
269
  }
270
}
244,833✔
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,820✔
283
  if (cstr_ && storage_.policy_ == duplicate) {
546,820✔
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,820✔
291

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

297
Value::CZString& Value::CZString::operator=(const CZString& other) {
×
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,045✔
319
  if (!cstr_)
3,942,045✔
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,387✔
324
  unsigned other_len = other.storage_.length_;
159,387✔
325
  unsigned min_len = std::min<unsigned>(this_len, other_len);
159,387✔
326
  JSON_ASSERT(this->cstr_ && other.cstr_);
159,387!
327
  int comp = memcmp(this->cstr_, other.cstr_, min_len);
159,387✔
328
  if (comp < 0)
159,387✔
329
    return true;
330
  if (comp > 0)
81,304✔
331
    return false;
332
  return (this_len < other_len);
40,623✔
333
}
334

335
bool Value::CZString::operator==(const CZString& other) const {
120,414✔
336
  if (!cstr_)
120,414✔
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,479✔
341
  unsigned other_len = other.storage_.length_;
15,479✔
342
  if (this_len != other_len)
15,479✔
343
    return false;
344
  JSON_ASSERT(this->cstr_ && other.cstr_);
5,417!
345
  int comp = memcmp(this->cstr_, other.cstr_, this_len);
5,417✔
346
  return comp == 0;
5,417✔
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,730✔
353
unsigned Value::CZString::length() const { return storage_.length_; }
1,711✔
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,573✔
371
  static char const emptyString[] = "";
372
  initBasic(type);
114,573✔
373
  switch (type) {
114,573!
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,939✔
388
  case objectValue:
389
    value_.map_ = new ObjectValues();
4,939✔
390
    break;
4,939✔
UNCOV
391
  case booleanValue:
×
UNCOV
392
    value_.bool_ = false;
×
UNCOV
393
    break;
×
UNCOV
394
  default:
×
UNCOV
395
    JSON_ASSERT_UNREACHABLE;
×
396
  }
397
}
114,573✔
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,257✔
425
  initBasic(stringValue, true);
1,257✔
426
  JSON_ASSERT_MESSAGE(value != nullptr,
1,257!
427
                      "Null Value Passed to Value Constructor");
428
  value_.string_ = duplicateAndPrefixStringValue(
2,514✔
429
      value, static_cast<unsigned>(strlen(value)));
1,257✔
430
}
1,257✔
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
#ifdef JSONCPP_HAS_STRING_VIEW
445
Value::Value(std::string_view value) {
446
  initBasic(stringValue, true);
447
  value_.string_ = duplicateAndPrefixStringValue(
448
      value.data(), static_cast<unsigned>(value.length()));
449
}
450
#endif
451

452
Value::Value(const StaticString& value) {
2✔
453
  initBasic(stringValue);
2✔
454
  value_.string_ = const_cast<char*>(value.c_str());
2✔
455
}
2✔
456

457
Value::Value(bool value) {
14,711✔
458
  initBasic(booleanValue);
14,711✔
459
  value_.bool_ = value;
14,711✔
460
}
14,711✔
461

462
Value::Value(const Value& other) {
245,126✔
463
  dupPayload(other);
245,126✔
464
  dupMeta(other);
245,126✔
465
}
245,126✔
466

467
Value::Value(Value&& other) noexcept {
55✔
468
  initBasic(nullValue);
55✔
469
  swap(other);
55✔
470
}
55✔
471

472
Value::~Value() {
484,527✔
473
  releasePayload();
484,527✔
474
  value_.uint_ = 0;
484,527✔
475
}
484,527✔
476

477
Value& Value::operator=(const Value& other) {
18✔
478
  Value(other).swap(*this);
18✔
479
  return *this;
18✔
480
}
481

482
Value& Value::operator=(Value&& other) noexcept {
125,135✔
483
  other.swap(*this);
125,135✔
484
  return *this;
125,135✔
485
}
486

487
void Value::swapPayload(Value& other) {
234,781✔
488
  std::swap(bits_, other.bits_);
489
  std::swap(value_, other.value_);
490
}
234,781✔
491

492
void Value::copyPayload(const Value& other) {
8✔
493
  releasePayload();
8✔
494
  dupPayload(other);
8✔
495
}
8✔
496

497
void Value::swap(Value& other) {
125,209✔
498
  swapPayload(other);
125,209✔
499
  std::swap(comments_, other.comments_);
125,209✔
500
  std::swap(start_, other.start_);
501
  std::swap(limit_, other.limit_);
502
}
125,209✔
503

504
void Value::copy(const Value& other) {
8✔
505
  copyPayload(other);
8✔
506
  dupMeta(other);
8✔
507
}
8✔
508

509
ValueType Value::type() const {
2,229,701✔
510
  return static_cast<ValueType>(bits_.value_type_);
2,229,701✔
511
}
512

513
int Value::compare(const Value& other) const {
120✔
514
  if (*this < other)
120✔
515
    return -1;
516
  if (*this > other)
89✔
517
    return 1;
31✔
518
  return 0;
519
}
520

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

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

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

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

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

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

621
const char* Value::asCString() const {
4✔
622
  JSON_ASSERT_MESSAGE(type() == stringValue,
6✔
623
                      "in Json::Value::asCString(): requires stringValue");
624
  if (value_.string_ == nullptr)
3!
625
    return nullptr;
626
  unsigned this_len;
627
  char const* this_str;
628
  decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
629
                       &this_str);
630
  return this_str;
631
}
632

633
#if JSONCPP_USE_SECURE_MEMORY
634
unsigned Value::getCStringLength() const {
635
  JSON_ASSERT_MESSAGE(type() == stringValue,
636
                      "in Json::Value::asCString(): requires stringValue");
637
  if (value_.string_ == 0)
638
    return 0;
639
  unsigned this_len;
640
  char const* this_str;
641
  decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
642
                       &this_str);
643
  return this_len;
644
}
645
#endif
646

647
bool Value::getString(char const** begin, char const** end) const {
782✔
648
  if (type() != stringValue)
782!
649
    return false;
650
  if (value_.string_ == nullptr)
782!
651
    return false;
652
  unsigned length;
653
  decodePrefixedString(this->isAllocated(), this->value_.string_, &length,
654
                       begin);
655
  *end = *begin + length;
782✔
656
  return true;
782✔
657
}
658

659
#ifdef JSONCPP_HAS_STRING_VIEW
660
bool Value::getString(std::string_view* str) const {
661
  if (type() != stringValue)
662
    return false;
663
  if (value_.string_ == nullptr)
664
    return false;
665
  const char* begin;
666
  unsigned length;
667
  decodePrefixedString(this->isAllocated(), this->value_.string_, &length,
668
                       &begin);
669
  *str = std::string_view(begin, length);
670
  return true;
671
}
672
#endif
673

674
String Value::asString() const {
2,750✔
675
  switch (type()) {
2,750!
676
  case nullValue:
677
    return "";
2✔
678
  case stringValue: {
2,708✔
679
    if (value_.string_ == nullptr)
2,708!
UNCOV
680
      return "";
×
681
    unsigned this_len;
682
    char const* this_str;
683
    decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
684
                         &this_str);
685
    return String(this_str, this_len);
2,708✔
686
  }
687
  case booleanValue:
UNCOV
688
    return value_.bool_ ? "true" : "false";
×
689
  case intValue:
13✔
690
    return valueToString(value_.int_);
13✔
691
  case uintValue:
7✔
692
    return valueToString(value_.uint_);
7✔
693
  case realValue:
18✔
694
    return valueToString(value_.real_);
18✔
695
  default:
2✔
696
    JSON_FAIL_MESSAGE("Type is not convertible to string");
6✔
697
  }
698
}
699

700
Value::Int Value::asInt() const {
30✔
701
  switch (type()) {
30✔
702
  case intValue:
11✔
703
    JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
11!
704
    return Int(value_.int_);
11✔
705
  case uintValue:
8✔
706
    JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
8!
707
    return Int(value_.uint_);
8✔
708
  case realValue:
5✔
709
    JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
5!
710
                        "double out of Int range");
711
    return Int(value_.real_);
712
  case nullValue:
713
    return 0;
714
  case booleanValue:
2✔
715
    return value_.bool_ ? 1 : 0;
2✔
716
  default:
717
    break;
718
  }
719
  JSON_FAIL_MESSAGE("Value is not convertible to Int.");
9✔
720
}
721

722
Value::UInt Value::asUInt() const {
1,582✔
723
  switch (type()) {
1,582✔
724
  case intValue:
1,565✔
725
    JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
1,565!
726
    return UInt(value_.int_);
1,565✔
727
  case uintValue:
6✔
728
    JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
6!
729
    return UInt(value_.uint_);
6✔
730
  case realValue:
5✔
731
    JSON_ASSERT_MESSAGE(InRange(value_.real_, 0u, maxUInt),
5!
732
                        "double out of UInt range");
733
    return UInt(value_.real_);
734
  case nullValue:
735
    return 0;
736
  case booleanValue:
2✔
737
    return value_.bool_ ? 1 : 0;
2✔
738
  default:
739
    break;
740
  }
741
  JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
9✔
742
}
743

744
#if defined(JSON_HAS_INT64)
745

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

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

794
LargestInt Value::asLargestInt() const {
157,448✔
795
#if defined(JSON_NO_INT64)
796
  return asInt();
797
#else
798
  return asInt64();
157,448✔
799
#endif
800
}
801

802
LargestUInt Value::asLargestUInt() const {
248✔
803
#if defined(JSON_NO_INT64)
804
  return asUInt();
805
#else
806
  return asUInt64();
248✔
807
#endif
808
}
809

810
double Value::asDouble() const {
528✔
811
  switch (type()) {
528✔
812
  case intValue:
20✔
813
    return static_cast<double>(value_.int_);
20✔
814
  case uintValue:
14✔
815
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
816
    return static_cast<double>(value_.uint_);
817
#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
818
    return integerToDouble(value_.uint_);
14✔
819
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
820
  case realValue:
488✔
821
    return value_.real_;
488✔
822
  case nullValue:
823
    return 0.0;
824
  case booleanValue:
2✔
825
    return value_.bool_ ? 1.0 : 0.0;
2✔
826
  default:
827
    break;
828
  }
829
  JSON_FAIL_MESSAGE("Value is not convertible to double.");
9✔
830
}
831

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

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

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

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

933
bool Value::empty() const {
36✔
934
  if (isNull() || isArray() || isObject())
36!
935
    return size() == 0U;
36✔
936
  return false;
937
}
938

939
Value::operator bool() const { return !isNull(); }
4✔
940

941
void Value::clear() {
3✔
942
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue ||
5!
943
                          type() == objectValue,
944
                      "in Json::Value::clear(): requires complex value");
945
  start_ = 0;
2✔
946
  limit_ = 0;
2✔
947
  switch (type()) {
2!
948
  case arrayValue:
2✔
949
  case objectValue:
950
    value_.map_->clear();
2✔
951
    break;
952
  default:
953
    break;
954
  }
955
}
2✔
956

957
void Value::resize(ArrayIndex newSize) {
7✔
958
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
13✔
959
                      "in Json::Value::resize(): requires arrayValue");
960
  if (type() == nullValue)
4✔
961
    *this = Value(arrayValue);
1✔
962
  ArrayIndex oldSize = size();
4✔
963
  if (newSize == 0)
4✔
964
    clear();
1✔
965
  else if (newSize > oldSize)
3✔
966
    for (ArrayIndex i = oldSize; i < newSize; ++i)
17✔
967
      (*this)[i];
15✔
968
  else {
969
    for (ArrayIndex index = newSize; index < oldSize; ++index) {
11✔
970
      value_.map_->erase(index);
20✔
971
    }
972
    JSON_ASSERT(size() == newSize);
1!
973
  }
974
}
4✔
975

976
Value& Value::operator[](ArrayIndex index) {
212,045✔
977
  JSON_ASSERT_MESSAGE(
212,051✔
978
      type() == nullValue || type() == arrayValue,
979
      "in Json::Value::operator[](ArrayIndex): requires arrayValue");
980
  if (type() == nullValue)
212,042✔
981
    *this = Value(arrayValue);
16✔
982
  CZString key(index);
212,042✔
983
  auto it = value_.map_->lower_bound(key);
212,042✔
984
  if (it != value_.map_->end() && (*it).first == key)
212,042✔
985
    return (*it).second;
104,910✔
986

987
  ObjectValues::value_type defaultValue(key, nullSingleton());
107,132✔
988
  it = value_.map_->insert(it, defaultValue);
107,132✔
989
  return (*it).second;
107,132✔
990
}
212,042✔
991

992
Value& Value::operator[](int index) {
107,037✔
993
  JSON_ASSERT_MESSAGE(
107,037!
994
      index >= 0,
995
      "in Json::Value::operator[](int index): index cannot be negative");
996
  return (*this)[ArrayIndex(index)];
107,037✔
997
}
998

999
const Value& Value::operator[](ArrayIndex index) const {
53,225✔
1000
  JSON_ASSERT_MESSAGE(
53,225!
1001
      type() == nullValue || type() == arrayValue,
1002
      "in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
1003
  if (type() == nullValue)
53,225!
UNCOV
1004
    return nullSingleton();
×
1005
  CZString key(index);
53,225✔
1006
  ObjectValues::const_iterator it = value_.map_->find(key);
53,225✔
1007
  if (it == value_.map_->end())
53,225✔
1008
    return nullSingleton();
1✔
1009
  return (*it).second;
53,224✔
1010
}
53,225✔
1011

1012
const Value& Value::operator[](int index) const {
4✔
1013
  JSON_ASSERT_MESSAGE(
4!
1014
      index >= 0,
1015
      "in Json::Value::operator[](int index) const: index cannot be negative");
1016
  return (*this)[ArrayIndex(index)];
4✔
1017
}
1018

1019
void Value::initBasic(ValueType type, bool allocated) {
239,401✔
1020
  setType(type);
1021
  setIsAllocated(allocated);
1022
  comments_ = Comments{};
239,401✔
1023
  start_ = 0;
239,401✔
1024
  limit_ = 0;
239,401✔
1025
}
239,401✔
1026

1027
void Value::dupPayload(const Value& other) {
245,134✔
1028
  setType(other.type());
245,134✔
1029
  setIsAllocated(false);
1030
  switch (type()) {
245,134!
1031
  case nullValue:
244,940✔
1032
  case intValue:
1033
  case uintValue:
1034
  case realValue:
1035
  case booleanValue:
1036
    value_ = other.value_;
244,940✔
1037
    break;
244,940✔
1038
  case stringValue:
139✔
1039
    if (other.value_.string_ && other.isAllocated()) {
139!
1040
      unsigned len;
1041
      char const* str;
1042
      decodePrefixedString(other.isAllocated(), other.value_.string_, &len,
1043
                           &str);
1044
      value_.string_ = duplicateAndPrefixStringValue(str, len);
139✔
1045
      setIsAllocated(true);
1046
    } else {
UNCOV
1047
      value_.string_ = other.value_.string_;
×
1048
    }
1049
    break;
1050
  case arrayValue:
55✔
1051
  case objectValue:
1052
    value_.map_ = new ObjectValues(*other.value_.map_);
55✔
1053
    break;
55✔
UNCOV
1054
  default:
×
UNCOV
1055
    JSON_ASSERT_UNREACHABLE;
×
1056
  }
1057
}
245,134✔
1058

1059
void Value::releasePayload() {
484,535✔
1060
  switch (type()) {
484,535!
1061
  case nullValue:
1062
  case intValue:
1063
  case uintValue:
1064
  case realValue:
1065
  case booleanValue:
1066
    break;
1067
  case stringValue:
1068
    if (isAllocated())
2,659✔
1069
      releasePrefixedStringValue(value_.string_);
2,657✔
1070
    break;
1071
  case arrayValue:
4,994✔
1072
  case objectValue:
1073
    delete value_.map_;
9,988!
1074
    break;
UNCOV
1075
  default:
×
UNCOV
1076
    JSON_ASSERT_UNREACHABLE;
×
1077
  }
1078
}
484,535✔
1079

1080
void Value::dupMeta(const Value& other) {
245,134✔
1081
  comments_ = other.comments_;
245,134✔
1082
  start_ = other.start_;
245,134✔
1083
  limit_ = other.limit_;
245,134✔
1084
}
245,134✔
1085

1086
// Access an object value by name, create a null member if it does not exist.
1087
// @pre Type of '*this' is object or null.
1088
// @param key is null-terminated.
1089
Value& Value::resolveReference(const char* key) {
1✔
1090
  JSON_ASSERT_MESSAGE(
1!
1091
      type() == nullValue || type() == objectValue,
1092
      "in Json::Value::resolveReference(): requires objectValue");
1093
  if (type() == nullValue)
1!
1094
    *this = Value(objectValue);
1✔
1095
  CZString actualKey(key, static_cast<unsigned>(strlen(key)),
1✔
1096
                     CZString::noDuplication); // NOTE!
1✔
1097
  auto it = value_.map_->lower_bound(actualKey);
1✔
1098
  if (it != value_.map_->end() && (*it).first == actualKey)
1!
UNCOV
1099
    return (*it).second;
×
1100

1101
  ObjectValues::value_type defaultValue(actualKey, nullSingleton());
1✔
1102
  it = value_.map_->insert(it, defaultValue);
1✔
1103
  Value& value = (*it).second;
1✔
1104
  return value;
1105
}
1✔
1106

1107
// @param key is not null-terminated.
1108
Value& Value::resolveReference(char const* key, char const* end) {
19,622✔
1109
  JSON_ASSERT_MESSAGE(
19,628✔
1110
      type() == nullValue || type() == objectValue,
1111
      "in Json::Value::resolveReference(key, end): requires objectValue");
1112
  if (type() == nullValue)
19,619✔
1113
    *this = Value(objectValue);
1,693✔
1114
  CZString actualKey(key, static_cast<unsigned>(end - key),
19,619✔
1115
                     CZString::duplicateOnCopy);
19,619✔
1116
  auto it = value_.map_->lower_bound(actualKey);
19,619✔
1117
  if (it != value_.map_->end() && (*it).first == actualKey)
19,619✔
1118
    return (*it).second;
4,369✔
1119

1120
  ObjectValues::value_type defaultValue(actualKey, nullSingleton());
15,250✔
1121
  it = value_.map_->insert(it, defaultValue);
15,250✔
1122
  Value& value = (*it).second;
15,250✔
1123
  return value;
1124
}
19,619✔
1125

1126
Value Value::get(ArrayIndex index, const Value& defaultValue) const {
6✔
1127
  const Value* value = &((*this)[index]);
6✔
1128
  return value == &nullSingleton() ? defaultValue : *value;
11✔
1129
}
1130

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

1133
Value const* Value::find(char const* begin, char const* end) const {
17,018✔
1134
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
17,018!
1135
                      "in Json::Value::find(begin, end): requires "
1136
                      "objectValue or nullValue");
1137
  if (type() == nullValue)
17,018!
1138
    return nullptr;
1139
  CZString actualKey(begin, static_cast<unsigned>(end - begin),
17,018✔
1140
                     CZString::noDuplication);
17,018✔
1141
  ObjectValues::const_iterator it = value_.map_->find(actualKey);
17,018✔
1142
  if (it == value_.map_->end())
17,018✔
1143
    return nullptr;
1144
  return &(*it).second;
17,003✔
1145
}
17,018✔
1146
Value const* Value::find(const String& key) const {
896✔
1147
  return find(key.data(), key.data() + key.length());
896✔
1148
}
1149

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

1187
Value* Value::demand(char const* begin, char const* end) {
1✔
1188
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
1!
1189
                      "in Json::Value::demand(begin, end): requires "
1190
                      "objectValue or nullValue");
1191
  return &resolveReference(begin, end);
1✔
1192
}
1193
#ifdef JSONCPP_HAS_STRING_VIEW
1194
const Value& Value::operator[](std::string_view key) const {
1195
  Value const* found = find(key.data(), key.data() + key.length());
1196
  if (!found)
1197
    return nullSingleton();
1198
  return *found;
1199
}
1200
Value& Value::operator[](std::string_view key) {
1201
  return resolveReference(key.data(), key.data() + key.length());
1202
}
1203
#else
1204
const Value& Value::operator[](const char* key) const {
16,094✔
1205
  Value const* found = find(key, key + strlen(key));
16,094✔
1206
  if (!found)
16,094✔
1207
    return nullSingleton();
1✔
1208
  return *found;
1209
}
1210
Value const& Value::operator[](const String& key) const {
872✔
1211
  Value const* found = find(key);
872✔
1212
  if (!found)
872✔
1213
    return nullSingleton();
3✔
1214
  return *found;
1215
}
1216

1217
Value& Value::operator[](const char* key) {
17,757✔
1218
  return resolveReference(key, key + strlen(key));
17,757✔
1219
}
1220

1221
Value& Value::operator[](const String& key) {
1,864✔
1222
  return resolveReference(key.data(), key.data() + key.length());
1,864✔
1223
}
1224
#endif
1225

1226
Value& Value::operator[](const StaticString& key) {
1✔
1227
  return resolveReference(key.c_str());
1✔
1228
}
1229

1230
Value& Value::append(const Value& value) { return append(Value(value)); }
1✔
1231

1232
Value& Value::append(Value&& value) {
53✔
1233
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
53!
1234
                      "in Json::Value::append: requires arrayValue");
1235
  if (type() == nullValue) {
53✔
1236
    *this = Value(arrayValue);
43✔
1237
  }
1238
  return this->value_.map_->emplace(size(), std::move(value)).first->second;
53✔
1239
}
1240

1241
bool Value::insert(ArrayIndex index, const Value& newValue) {
1✔
1242
  return insert(index, Value(newValue));
1✔
1243
}
1244

1245
bool Value::insert(ArrayIndex index, Value&& newValue) {
4✔
1246
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
4!
1247
                      "in Json::Value::insert: requires arrayValue");
1248
  ArrayIndex length = size();
4✔
1249
  if (index > length) {
4✔
1250
    return false;
1251
  }
1252
  for (ArrayIndex i = length; i > index; i--) {
8✔
1253
    (*this)[i] = std::move((*this)[i - 1]);
5✔
1254
  }
1255
  (*this)[index] = std::move(newValue);
3✔
1256
  return true;
3✔
1257
}
1258

1259
Value Value::get(char const* begin, char const* end,
15✔
1260
                 Value const& defaultValue) const {
1261
  Value const* found = find(begin, end);
15✔
1262
  return !found ? defaultValue : *found;
29✔
1263
}
1264
#ifdef JSONCPP_HAS_STRING_VIEW
1265
Value Value::get(std::string_view key, const Value& defaultValue) const {
1266
  return get(key.data(), key.data() + key.length(), defaultValue);
1267
}
1268
#else
1269
Value Value::get(char const* key, Value const& defaultValue) const {
10✔
1270
  return get(key, key + strlen(key), defaultValue);
10✔
1271
}
1272
Value Value::get(String const& key, Value const& defaultValue) const {
5✔
1273
  return get(key.data(), key.data() + key.length(), defaultValue);
5✔
1274
}
1275
#endif
1276

1277
bool Value::removeMember(const char* begin, const char* end, Value* removed) {
9✔
1278
  if (type() != objectValue) {
9!
1279
    return false;
1280
  }
1281
  CZString actualKey(begin, static_cast<unsigned>(end - begin),
9✔
1282
                     CZString::noDuplication);
9✔
1283
  auto it = value_.map_->find(actualKey);
9✔
1284
  if (it == value_.map_->end())
9✔
1285
    return false;
1286
  if (removed)
5✔
1287
    *removed = std::move(it->second);
4✔
1288
  value_.map_->erase(it);
5✔
1289
  return true;
5✔
1290
}
9✔
1291
#ifdef JSONCPP_HAS_STRING_VIEW
1292
bool Value::removeMember(std::string_view key, Value* removed) {
1293
  return removeMember(key.data(), key.data() + key.length(), removed);
1294
}
1295
#else
1296
bool Value::removeMember(const char* key, Value* removed) {
3✔
1297
  return removeMember(key, key + strlen(key), removed);
3✔
1298
}
1299
bool Value::removeMember(String const& key, Value* removed) {
2✔
1300
  return removeMember(key.data(), key.data() + key.length(), removed);
2✔
1301
}
1302
#endif
1303

1304
#ifdef JSONCPP_HAS_STRING_VIEW
1305
void Value::removeMember(std::string_view key) {
1306
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
1307
                      "in Json::Value::removeMember(): requires objectValue");
1308
  if (type() == nullValue)
1309
    return;
1310

1311
  CZString actualKey(key.data(), unsigned(key.length()),
1312
                     CZString::noDuplication);
1313
  value_.map_->erase(actualKey);
1314
}
1315
#else
1316
void Value::removeMember(const char* key) {
4✔
1317
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
10!
1318
                      "in Json::Value::removeMember(): requires objectValue");
1319
  if (type() == nullValue)
1!
UNCOV
1320
    return;
×
1321

1322
  CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication);
1✔
1323
  value_.map_->erase(actualKey);
1✔
1324
}
1✔
1325
void Value::removeMember(const String& key) { removeMember(key.c_str()); }
1✔
1326
#endif
1327

1328
bool Value::removeIndex(ArrayIndex index, Value* removed) {
2✔
1329
  if (type() != arrayValue) {
2!
1330
    return false;
1331
  }
1332
  CZString key(index);
2✔
1333
  auto it = value_.map_->find(key);
2✔
1334
  if (it == value_.map_->end()) {
2✔
1335
    return false;
1336
  }
1337
  if (removed)
1!
1338
    *removed = std::move(it->second);
1✔
1339
  ArrayIndex oldSize = size();
1✔
1340
  // shift left all items left, into the place of the "removed"
1341
  for (ArrayIndex i = index; i < (oldSize - 1); ++i) {
1!
UNCOV
1342
    CZString keey(i);
×
UNCOV
1343
    (*value_.map_)[keey] = (*this)[i + 1];
×
UNCOV
1344
  }
×
1345
  // erase the last one ("leftover")
1346
  CZString keyLast(oldSize - 1);
1✔
1347
  auto itLast = value_.map_->find(keyLast);
1✔
1348
  value_.map_->erase(itLast);
1✔
1349
  return true;
1350
}
2✔
1351

1352
bool Value::isMember(char const* begin, char const* end) const {
10✔
1353
  Value const* value = find(begin, end);
10✔
1354
  return nullptr != value;
10✔
1355
}
1356
#ifdef JSONCPP_HAS_STRING_VIEW
1357
bool Value::isMember(std::string_view key) const {
1358
  return isMember(key.data(), key.data() + key.length());
1359
}
1360
#else
1361
bool Value::isMember(char const* key) const {
5✔
1362
  return isMember(key, key + strlen(key));
5✔
1363
}
1364
bool Value::isMember(String const& key) const {
5✔
1365
  return isMember(key.data(), key.data() + key.length());
5✔
1366
}
1367
#endif
1368

1369
Value::Members Value::getMemberNames() const {
1,130✔
1370
  JSON_ASSERT_MESSAGE(
1,136!
1371
      type() == nullValue || type() == objectValue,
1372
      "in Json::Value::getMemberNames(), value must be objectValue");
1373
  if (type() == nullValue)
1,127!
UNCOV
1374
    return Value::Members();
×
1375
  Members members;
1376
  members.reserve(value_.map_->size());
1,127✔
1377
  ObjectValues::const_iterator it = value_.map_->begin();
1,127✔
1378
  ObjectValues::const_iterator itEnd = value_.map_->end();
1379
  for (; it != itEnd; ++it) {
2,792✔
1380
    members.push_back(String((*it).first.data(), (*it).first.length()));
3,330✔
1381
  }
1382
  return members;
1383
}
1,127✔
1384

1385
static bool IsIntegral(double d) {
1386
  double integral_part;
1387
  return modf(d, &integral_part) == 0.0;
58✔
1388
}
1389

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

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

1394
bool Value::isInt() const {
104✔
1395
  switch (type()) {
104✔
1396
  case intValue:
34✔
1397
#if defined(JSON_HAS_INT64)
1398
    return value_.int_ >= minInt && value_.int_ <= maxInt;
34✔
1399
#else
1400
    return true;
1401
#endif
1402
  case uintValue:
22✔
1403
    return value_.uint_ <= UInt(maxInt);
22✔
1404
  case realValue:
28✔
1405
    return value_.real_ >= minInt && value_.real_ <= maxInt &&
28✔
1406
           IsIntegral(value_.real_);
1407
  default:
1408
    break;
1409
  }
1410
  return false;
1411
}
1412

1413
bool Value::isUInt() const {
1,656✔
1414
  switch (type()) {
1,656✔
1415
  case intValue:
1,587✔
1416
#if defined(JSON_HAS_INT64)
1417
    return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
1,587✔
1418
#else
1419
    return value_.int_ >= 0;
1420
#endif
1421
  case uintValue:
21✔
1422
#if defined(JSON_HAS_INT64)
1423
    return value_.uint_ <= maxUInt;
21✔
1424
#else
1425
    return true;
1426
#endif
1427
  case realValue:
28✔
1428
    return value_.real_ >= 0 && value_.real_ <= maxUInt &&
28✔
1429
           IsIntegral(value_.real_);
1430
  default:
1431
    break;
1432
  }
1433
  return false;
1434
}
1435

1436
bool Value::isInt64() const {
56✔
1437
#if defined(JSON_HAS_INT64)
1438
  switch (type()) {
56✔
1439
  case intValue:
1440
    return true;
1441
  case uintValue:
13✔
1442
    return value_.uint_ <= UInt64(maxInt64);
13✔
1443
  case realValue:
15✔
1444
    // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
1445
    // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
1446
    // require the value to be strictly less than the limit.
1447
    // minInt64 is -2^63 which can be represented as a double, but since double
1448
    // values in its proximity are also rounded to -2^63, we require the value
1449
    // to be strictly greater than the limit to avoid returning 'true' for
1450
    // values that are not in the range
1451
    return value_.real_ > double(minInt64) && value_.real_ < double(maxInt64) &&
15✔
1452
           IsIntegral(value_.real_);
1453
  default:
1454
    break;
1455
  }
1456
#endif // JSON_HAS_INT64
1457
  return false;
1458
}
1459

1460
bool Value::isUInt64() const {
57✔
1461
#if defined(JSON_HAS_INT64)
1462
  switch (type()) {
57✔
1463
  case intValue:
20✔
1464
    return value_.int_ >= 0;
20✔
1465
  case uintValue:
1466
    return true;
1467
  case realValue:
15✔
1468
    // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
1469
    // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
1470
    // require the value to be strictly less than the limit.
1471
    return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&
15✔
1472
           IsIntegral(value_.real_);
1473
  default:
1474
    break;
1475
  }
1476
#endif // JSON_HAS_INT64
1477
  return false;
1478
}
1479

1480
bool Value::isIntegral() const {
42✔
1481
  switch (type()) {
42✔
1482
  case intValue:
1483
  case uintValue:
1484
    return true;
1485
  case realValue:
14✔
1486
#if defined(JSON_HAS_INT64)
1487
    // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
1488
    // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
1489
    // require the value to be strictly less than the limit.
1490
    // minInt64 is -2^63 which can be represented as a double, but since double
1491
    // values in its proximity are also rounded to -2^63, we require the value
1492
    // to be strictly greater than the limit to avoid returning 'true' for
1493
    // values that are not in the range
1494
    return value_.real_ > double(minInt64) &&
13✔
1495
           value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);
26✔
1496
#else
1497
    return value_.real_ >= minInt && value_.real_ <= maxUInt &&
1498
           IsIntegral(value_.real_);
1499
#endif // JSON_HAS_INT64
1500
  default:
1501
    break;
1502
  }
1503
  return false;
1504
}
1505

1506
bool Value::isDouble() const {
169✔
1507
  return type() == intValue || type() == uintValue || type() == realValue;
169✔
1508
}
1509

1510
bool Value::isNumeric() const { return isDouble(); }
119✔
1511

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

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

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

UNCOV
1518
Value::Comments::Comments(const Comments& that)
×
UNCOV
1519
    : ptr_{cloneUnique(that.ptr_)} {}
×
1520

1521
Value::Comments::Comments(Comments&& that) noexcept
125,209✔
1522
    : ptr_{std::move(that.ptr_)} {}
125,209✔
1523

1524
Value::Comments& Value::Comments::operator=(const Comments& that) {
245,134✔
1525
  ptr_ = cloneUnique(that.ptr_);
245,134✔
1526
  return *this;
245,134✔
1527
}
1528

1529
Value::Comments& Value::Comments::operator=(Comments&& that) noexcept {
489,819!
1530
  ptr_ = std::move(that.ptr_);
1531
  return *this;
489,819✔
1532
}
1533

1534
bool Value::Comments::has(CommentPlacement slot) const {
377,785✔
1535
  return ptr_ && !(*ptr_)[slot].empty();
377,785!
1536
}
1537

1538
String Value::Comments::get(CommentPlacement slot) const {
1,282!
1539
  if (!ptr_)
1,282!
1540
    return {};
1541
  return (*ptr_)[slot];
1,282!
1542
}
1543

1544
void Value::Comments::set(CommentPlacement slot, String comment) {
955✔
1545
  if (slot >= CommentPlacement::numberOfCommentPlacement)
955!
1546
    return;
1547
  if (!ptr_)
955✔
1548
    ptr_ = std::unique_ptr<Array>(new Array());
893✔
1549
  (*ptr_)[slot] = std::move(comment);
1,910!
1550
}
1551

1552
void Value::setComment(String comment, CommentPlacement placement) {
955!
1553
  if (!comment.empty() && (comment.back() == '\n')) {
955!
1554
    // Always discard trailing newline, to aid indentation.
1555
    comment.pop_back();
790✔
1556
  }
1557
  JSON_ASSERT_MESSAGE(
955!
1558
      comment.empty() || comment[0] == '/',
1559
      "in Json::Value::setComment(): Comments must start with /");
1560
  comments_.set(placement, std::move(comment));
955✔
1561
}
955✔
1562

1563
bool Value::hasComment(CommentPlacement placement) const {
377,785✔
1564
  return comments_.has(placement);
377,785✔
1565
}
1566

1567
String Value::getComment(CommentPlacement placement) const {
1,282✔
1568
  return comments_.get(placement);
1,282✔
1569
}
1570

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

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

1575
ptrdiff_t Value::getOffsetStart() const { return start_; }
19✔
1576

1577
ptrdiff_t Value::getOffsetLimit() const { return limit_; }
19✔
1578

1579
String Value::toStyledString() const {
5✔
1580
  StreamWriterBuilder builder;
5✔
1581

1582
  String out = this->hasComment(commentBefore) ? "\n" : "";
8✔
1583
  out += Json::writeString(builder, *this);
10✔
1584
  out += '\n';
1585

1586
  return out;
5✔
1587
}
5✔
1588

1589
Value::const_iterator Value::begin() const {
22✔
1590
  switch (type()) {
22✔
1591
  case arrayValue:
9✔
1592
  case objectValue:
1593
    if (value_.map_)
9!
1594
      return const_iterator(value_.map_->begin());
9✔
1595
    break;
1596
  default:
1597
    break;
1598
  }
1599
  return {};
13✔
1600
}
1601

1602
Value::const_iterator Value::end() const {
63✔
1603
  switch (type()) {
63✔
1604
  case arrayValue:
51✔
1605
  case objectValue:
1606
    if (value_.map_)
51!
1607
      return const_iterator(value_.map_->end());
51✔
1608
    break;
1609
  default:
1610
    break;
1611
  }
1612
  return {};
12✔
1613
}
1614

1615
Value::iterator Value::begin() {
37✔
1616
  switch (type()) {
37✔
1617
  case arrayValue:
24✔
1618
  case objectValue:
1619
    if (value_.map_)
24!
1620
      return iterator(value_.map_->begin());
24✔
1621
    break;
1622
  default:
1623
    break;
1624
  }
1625
  return iterator();
13✔
1626
}
1627

1628
Value::iterator Value::end() {
42✔
1629
  switch (type()) {
42✔
1630
  case arrayValue:
27✔
1631
  case objectValue:
1632
    if (value_.map_)
27!
1633
      return iterator(value_.map_->end());
27✔
1634
    break;
1635
  default:
1636
    break;
1637
  }
1638
  return iterator();
15✔
1639
}
1640

1641
// class PathArgument
1642
// //////////////////////////////////////////////////////////////////
1643

1644
PathArgument::PathArgument() = default;
36✔
1645

1646
PathArgument::PathArgument(ArrayIndex index)
4✔
1647
    : index_(index), kind_(kindIndex) {}
4✔
1648

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

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

1653
// class Path
1654
// //////////////////////////////////////////////////////////////////
1655

1656
Path::Path(const String& path, const PathArgument& a1, const PathArgument& a2,
8✔
1657
           const PathArgument& a3, const PathArgument& a4,
1658
           const PathArgument& a5) {
1659
  InArgs in;
1660
  in.reserve(5);
8✔
1661
  in.push_back(&a1);
8✔
1662
  in.push_back(&a2);
8✔
1663
  in.push_back(&a3);
8✔
1664
  in.push_back(&a4);
8✔
1665
  in.push_back(&a5);
8✔
1666
  makePath(path, in);
8✔
1667
}
8✔
1668

1669
void Path::makePath(const String& path, const InArgs& in) {
8✔
1670
  const char* current = path.c_str();
1671
  const char* end = current + path.length();
8✔
1672
  auto itInArg = in.begin();
8✔
1673
  while (current != end) {
42✔
1674
    if (*current == '[') {
34✔
1675
      ++current;
4✔
1676
      if (*current == '%')
4✔
1677
        addPathInArg(path, in, itInArg, PathArgument::kindIndex);
2✔
1678
      else {
1679
        ArrayIndex index = 0;
1680
        for (; current != end && *current >= '0' && *current <= '9'; ++current)
4!
1681
          index = index * 10 + ArrayIndex(*current - '0');
2✔
1682
        args_.push_back(index);
4✔
1683
      }
1684
      if (current == end || *++current != ']')
4!
1685
        invalidPath(path, int(current - path.c_str()));
2✔
1686
    } else if (*current == '%') {
30✔
1687
      addPathInArg(path, in, itInArg, PathArgument::kindKey);
2✔
1688
      ++current;
2✔
1689
    } else if (*current == '.' || *current == ']') {
28✔
1690
      ++current;
18✔
1691
    } else {
1692
      const char* beginName = current;
1693
      while (current != end && !strchr("[.", *current))
88✔
1694
        ++current;
78✔
1695
      args_.push_back(String(beginName, current));
20✔
1696
    }
1697
  }
1698
}
8✔
1699

1700
void Path::addPathInArg(const String& /*path*/, const InArgs& in,
4!
1701
                        InArgs::const_iterator& itInArg,
1702
                        PathArgument::Kind kind) {
1703
  if (itInArg == in.end()) {
4!
1704
    // Error: missing argument %d
1705
  } else if ((*itInArg)->kind_ != kind) {
4!
1706
    // Error: bad argument type
1707
  } else {
1708
    args_.push_back(**itInArg++);
4✔
1709
  }
1710
}
4✔
1711

1712
void Path::invalidPath(const String& /*path*/, int /*location*/) {
2✔
1713
  // Error: invalid path.
1714
}
2✔
1715

1716
const Value& Path::resolve(const Value& root) const {
6✔
1717
  const Value* node = &root;
1718
  for (const auto& arg : args_) {
14✔
1719
    if (arg.kind_ == PathArgument::kindIndex) {
12✔
1720
      if (!node->isArray() || !node->isValidIndex(arg.index_)) {
2!
1721
        // Error: unable to resolve path (array value expected at position... )
1722
        return Value::nullSingleton();
1✔
1723
      }
1724
      node = &((*node)[arg.index_]);
1✔
1725
    } else if (arg.kind_ == PathArgument::kindKey) {
10!
1726
      if (!node->isObject()) {
10✔
1727
        // Error: unable to resolve path (object value expected at position...)
1728
        return Value::nullSingleton();
1✔
1729
      }
1730
      node = &((*node)[arg.key_]);
9✔
1731
      if (node == &Value::nullSingleton()) {
9✔
1732
        // Error: unable to resolve path (object has no member named '' at
1733
        // position...)
1734
        return Value::nullSingleton();
2✔
1735
      }
1736
    }
1737
  }
1738
  return *node;
1739
}
1740

1741
Value Path::resolve(const Value& root, const Value& defaultValue) const {
6✔
1742
  const Value* node = &root;
1743
  for (const auto& arg : args_) {
14✔
1744
    if (arg.kind_ == PathArgument::kindIndex) {
12✔
1745
      if (!node->isArray() || !node->isValidIndex(arg.index_))
3✔
1746
        return defaultValue;
2✔
1747
      node = &((*node)[arg.index_]);
1✔
1748
    } else if (arg.kind_ == PathArgument::kindKey) {
9!
1749
      if (!node->isObject())
9✔
1750
        return defaultValue;
1✔
1751
      node = &((*node)[arg.key_]);
8✔
1752
      if (node == &Value::nullSingleton())
8✔
1753
        return defaultValue;
1✔
1754
    }
1755
  }
1756
  return *node;
2✔
1757
}
1758

1759
Value& Path::make(Value& root) const {
2✔
1760
  Value* node = &root;
1761
  for (const auto& arg : args_) {
6✔
1762
    if (arg.kind_ == PathArgument::kindIndex) {
4✔
1763
      if (!node->isArray()) {
1✔
1764
        // Error: node is not an array at position ...
1765
      }
1766
      node = &((*node)[arg.index_]);
1✔
1767
    } else if (arg.kind_ == PathArgument::kindKey) {
3!
1768
      if (!node->isObject()) {
3✔
1769
        // Error: node is not an object at position...
1770
      }
1771
      node = &((*node)[arg.key_]);
3✔
1772
    }
1773
  }
1774
  return *node;
2✔
1775
}
1776

1777
} // 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