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

bblanchon / ArduinoJson / 13566673611

27 Feb 2025 12:42PM UTC coverage: 99.33% (+0.001%) from 99.329%
13566673611

push

github

bblanchon
Fix overflowed()

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

3 existing lines in 1 file now uncovered.

4005 of 4032 relevant lines covered (99.33%)

10853.67 hits per line

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

98.98
/src/ArduinoJson/Variant/VariantData.hpp
1
// ArduinoJson - https://arduinojson.org
2
// Copyright © 2014-2025, Benoit BLANCHON
3
// MIT License
4

5
#pragma once
6

7
#include <ArduinoJson/Memory/MemoryPool.hpp>
8
#include <ArduinoJson/Memory/StringNode.hpp>
9
#include <ArduinoJson/Misc/SerializedValue.hpp>
10
#include <ArduinoJson/Numbers/convertNumber.hpp>
11
#include <ArduinoJson/Strings/JsonString.hpp>
12
#include <ArduinoJson/Strings/StringAdapters.hpp>
13
#include <ArduinoJson/Variant/VariantContent.hpp>
14

15
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
16

17
template <typename T>
18
T parseNumber(const char* s);
19

20
class VariantData {
21
  VariantContent content_;  // must be first to allow cast from array to variant
22
  VariantType type_;
23
  SlotId next_;
24

25
 public:
26
  // Placement new
27
  static void* operator new(size_t, void* p) noexcept {
74,794✔
28
    return p;
74,794✔
29
  }
30

31
  static void operator delete(void*, void*) noexcept {}
32

33
  VariantData() : type_(VariantType::Null), next_(NULL_SLOT) {}
76,848✔
34

35
  SlotId next() const {
292,483✔
36
    return next_;
292,483✔
37
  }
38

39
  void setNext(SlotId slot) {
71,925✔
40
    next_ = slot;
71,925✔
41
  }
71,925✔
42

43
  template <typename TVisitor>
44
  typename TVisitor::result_type accept(
139,334✔
45
      TVisitor& visit, const ResourceManager* resources) const {
46
#if ARDUINOJSON_USE_EXTENSIONS
47
    auto extension = getExtension(resources);
139,334✔
48
#else
49
    (void)resources;  // silence warning
50
#endif
51
    switch (type_) {
139,334✔
52
      case VariantType::Float:
121✔
53
        return visit.visit(content_.asFloat);
121✔
54

55
#if ARDUINOJSON_USE_DOUBLE
56
      case VariantType::Double:
16✔
57
        return visit.visit(extension->asDouble);
16✔
58
#endif
59

60
      case VariantType::Array:
983✔
61
        return visit.visit(content_.asArray);
983✔
62

63
      case VariantType::Object:
2,677✔
64
        return visit.visit(content_.asObject);
2,677✔
65

66
      case VariantType::LinkedString:
1,153✔
67
        return visit.visit(JsonString(asLinkedString(resources), true));
1,153✔
68

69
      case VariantType::OwnedString:
967✔
70
        return visit.visit(JsonString(content_.asOwnedString->data,
967✔
71
                                      content_.asOwnedString->length));
967✔
72

73
      case VariantType::RawString:
129✔
74
        return visit.visit(RawString(content_.asOwnedString->data,
129✔
75
                                     content_.asOwnedString->length));
129✔
76

77
      case VariantType::Int32:
1,183✔
78
        return visit.visit(static_cast<JsonInteger>(content_.asInt32));
1,183✔
79

80
      case VariantType::Uint32:
256✔
81
        return visit.visit(static_cast<JsonUInt>(content_.asUint32));
256✔
82

83
#if ARDUINOJSON_USE_LONG_LONG
84
      case VariantType::Int64:
7✔
85
        return visit.visit(extension->asInt64);
7✔
86

87
      case VariantType::Uint64:
8✔
88
        return visit.visit(extension->asUint64);
8✔
89
#endif
90

91
      case VariantType::Boolean:
607✔
92
        return visit.visit(content_.asBoolean != 0);
607✔
93

94
      default:
131,227✔
95
        return visit.visit(nullptr);
131,227✔
96
    }
97
  }
98

99
  template <typename TVisitor>
100
  static typename TVisitor::result_type accept(const VariantData* var,
726✔
101
                                               const ResourceManager* resources,
102
                                               TVisitor& visit) {
103
    if (var != 0)
726✔
104
      return var->accept(visit, resources);
723✔
105
    else
106
      return visit.visit(nullptr);
3✔
107
  }
108

109
  VariantData* addElement(ResourceManager* resources) {
159✔
110
    auto array = isNull() ? &toArray() : asArray();
159✔
111
    return detail::ArrayData::addElement(array, resources);
159✔
112
  }
113

114
  static VariantData* addElement(VariantData* var, ResourceManager* resources) {
41✔
115
    if (!var)
41✔
116
      return nullptr;
6✔
117
    return var->addElement(resources);
35✔
118
  }
119

120
  template <typename T>
121
  bool addValue(const T& value, ResourceManager* resources) {
133✔
122
    auto array = isNull() ? &toArray() : asArray();
133✔
123
    return detail::ArrayData::addValue(array, value, resources);
133✔
124
  }
125

126
  template <typename T>
127
  static bool addValue(VariantData* var, const T& value,
49✔
128
                       ResourceManager* resources) {
129
    if (!var)
49✔
130
      return false;
6✔
131
    return var->addValue(value, resources);
43✔
132
  }
133

134
  bool asBoolean(const ResourceManager* resources) const {
554✔
135
#if ARDUINOJSON_USE_EXTENSIONS
136
    auto extension = getExtension(resources);
554✔
137
#else
138
    (void)resources;  // silence warning
139
#endif
140
    switch (type_) {
554✔
141
      case VariantType::Boolean:
305✔
142
        return content_.asBoolean;
305✔
143
      case VariantType::Uint32:
6✔
144
      case VariantType::Int32:
145
        return content_.asUint32 != 0;
6✔
146
      case VariantType::Float:
2✔
147
        return content_.asFloat != 0;
2✔
148
#if ARDUINOJSON_USE_DOUBLE
149
      case VariantType::Double:
4✔
150
        return extension->asDouble != 0;
4✔
151
#endif
152
      case VariantType::Null:
6✔
153
        return false;
6✔
154
#if ARDUINOJSON_USE_LONG_LONG
155
      case VariantType::Uint64:
2✔
156
      case VariantType::Int64:
157
        return extension->asUint64 != 0;
2✔
158
#endif
159
      default:
229✔
160
        return true;
229✔
161
    }
162
  }
163

164
  ArrayData* asArray() {
776✔
165
    return isArray() ? &content_.asArray : 0;
776✔
166
  }
167

168
  const ArrayData* asArray() const {
496✔
169
    return const_cast<VariantData*>(this)->asArray();
496✔
170
  }
171

172
  CollectionData* asCollection() {
69,466✔
173
    return isCollection() ? &content_.asCollection : 0;
69,466✔
174
  }
175

176
  const CollectionData* asCollection() const {
44✔
177
    return const_cast<VariantData*>(this)->asCollection();
44✔
178
  }
179

180
  template <typename T>
181
  T asFloat(const ResourceManager* resources) const {
53✔
182
    static_assert(is_floating_point<T>::value, "T must be a floating point");
183
#if ARDUINOJSON_USE_EXTENSIONS
184
    auto extension = getExtension(resources);
53✔
185
#else
186
    (void)resources;  // silence warning
187
#endif
188
    const char* str = nullptr;
53✔
189
    switch (type_) {
53✔
190
      case VariantType::Boolean:
2✔
191
        return static_cast<T>(content_.asBoolean);
2✔
192
      case VariantType::Uint32:
2✔
193
        return static_cast<T>(content_.asUint32);
2✔
194
      case VariantType::Int32:
4✔
195
        return static_cast<T>(content_.asInt32);
4✔
196
#if ARDUINOJSON_USE_LONG_LONG
197
      case VariantType::Uint64:
1✔
198
        return static_cast<T>(extension->asUint64);
1✔
199
      case VariantType::Int64:
1✔
200
        return static_cast<T>(extension->asInt64);
1✔
201
#endif
202
      case VariantType::LinkedString:
1✔
203
        str = asLinkedString(resources);
1✔
204
        break;
1✔
205
      case VariantType::OwnedString:
1✔
206
        str = content_.asOwnedString->data;
1✔
207
        break;
1✔
208
      case VariantType::Float:
18✔
209
        return static_cast<T>(content_.asFloat);
18✔
210
#if ARDUINOJSON_USE_DOUBLE
211
      case VariantType::Double:
21✔
212
        return static_cast<T>(extension->asDouble);
21✔
213
#endif
214
      default:
2✔
215
        return 0.0;
2✔
216
    }
217

218
    ARDUINOJSON_ASSERT(str != nullptr);
219
    return parseNumber<T>(str);
2✔
220
  }
221

222
  template <typename T>
223
  T asIntegral(const ResourceManager* resources) const {
197✔
224
    static_assert(is_integral<T>::value, "T must be an integral type");
225
#if ARDUINOJSON_USE_EXTENSIONS
226
    auto extension = getExtension(resources);
197✔
227
#else
228
    (void)resources;  // silence warning
229
#endif
230
    const char* str = nullptr;
197✔
231
    switch (type_) {
197✔
232
      case VariantType::Boolean:
2✔
233
        return content_.asBoolean;
2✔
234
      case VariantType::Uint32:
66✔
235
        return convertNumber<T>(content_.asUint32);
66✔
236
      case VariantType::Int32:
83✔
237
        return convertNumber<T>(content_.asInt32);
83✔
238
#if ARDUINOJSON_USE_LONG_LONG
239
      case VariantType::Uint64:
10✔
240
        return convertNumber<T>(extension->asUint64);
10✔
241
      case VariantType::Int64:
11✔
242
        return convertNumber<T>(extension->asInt64);
11✔
243
#endif
244
      case VariantType::LinkedString:
6✔
245
        str = asLinkedString(resources);
6✔
246
        break;
6✔
247
      case VariantType::OwnedString:
2✔
248
        str = content_.asOwnedString->data;
2✔
249
        break;
2✔
250
      case VariantType::Float:
5✔
251
        return convertNumber<T>(content_.asFloat);
5✔
252
#if ARDUINOJSON_USE_DOUBLE
253
      case VariantType::Double:
10✔
254
        return convertNumber<T>(extension->asDouble);
10✔
255
#endif
256
      default:
2✔
257
        return 0;
2✔
258
    }
259

260
    ARDUINOJSON_ASSERT(str != nullptr);
261
    return parseNumber<T>(str);
8✔
262
  }
263

264
  ObjectData* asObject() {
2,936✔
265
    return isObject() ? &content_.asObject : 0;
2,936✔
266
  }
267

268
  const ObjectData* asObject() const {
2,230✔
269
    return const_cast<VariantData*>(this)->asObject();
2,230✔
270
  }
271

272
  JsonString asRawString() const {
46✔
273
    switch (type_) {
46✔
274
      case VariantType::RawString:
26✔
275
        return JsonString(content_.asOwnedString->data,
26✔
276
                          content_.asOwnedString->length);
26✔
277
      default:
20✔
278
        return JsonString();
20✔
279
    }
280
  }
281

282
  const char* asLinkedString(const ResourceManager* resources) const;
283

284
  JsonString asString(const ResourceManager* resources) const {
12,746✔
285
    switch (type_) {
12,746✔
286
      case VariantType::LinkedString:
4,663✔
287
        return JsonString(asLinkedString(resources), true);
4,663✔
288
      case VariantType::OwnedString:
7,653✔
289
        return JsonString(content_.asOwnedString->data,
7,653✔
290
                          content_.asOwnedString->length);
7,653✔
291
      default:
430✔
292
        return JsonString();
430✔
293
    }
294
  }
295

296
#if ARDUINOJSON_USE_EXTENSIONS
297
  const VariantExtension* getExtension(const ResourceManager* resources) const;
298
#endif
299

300
  VariantData* getElement(size_t index,
463✔
301
                          const ResourceManager* resources) const {
302
    return ArrayData::getElement(asArray(), index, resources);
463✔
303
  }
304

305
  static VariantData* getElement(const VariantData* var, size_t index,
466✔
306
                                 const ResourceManager* resources) {
307
    return var != 0 ? var->getElement(index, resources) : 0;
466✔
308
  }
309

310
  template <typename TAdaptedString>
311
  VariantData* getMember(TAdaptedString key,
2,196✔
312
                         const ResourceManager* resources) const {
313
    return ObjectData::getMember(asObject(), key, resources);
2,196✔
314
  }
315

316
  template <typename TAdaptedString>
317
  static VariantData* getMember(const VariantData* var, TAdaptedString key,
2,185✔
318
                                const ResourceManager* resources) {
319
    if (!var)
2,185✔
320
      return 0;
13✔
321
    return var->getMember(key, resources);
2,172✔
322
  }
323

324
  VariantData* getOrAddElement(size_t index, ResourceManager* resources) {
152✔
325
    auto array = isNull() ? &toArray() : asArray();
152✔
326
    if (!array)
152✔
327
      return nullptr;
1✔
328
    return array->getOrAddElement(index, resources);
151✔
329
  }
330

331
  template <typename TAdaptedString>
332
  VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources) {
956✔
333
    if (key.isNull())
956✔
334
      return nullptr;
1✔
335
    auto obj = isNull() ? &toObject() : asObject();
955✔
336
    if (!obj)
955✔
UNCOV
337
      return nullptr;
×
338
    return obj->getOrAddMember(key, resources);
955✔
339
  }
340

341
  bool isArray() const {
893✔
342
    return type_ == VariantType::Array;
893✔
343
  }
344

345
  bool isBoolean() const {
35✔
346
    return type_ == VariantType::Boolean;
35✔
347
  }
348

349
  bool isCollection() const {
69,466✔
350
    return type_ & VariantTypeBits::CollectionMask;
69,466✔
351
  }
352

353
  bool isFloat() const {
405✔
354
    return type_ & VariantTypeBits::NumberBit;
405✔
355
  }
356

357
  template <typename T>
358
  bool isInteger(const ResourceManager* resources) const {
151✔
359
#if ARDUINOJSON_USE_LONG_LONG
360
    auto extension = getExtension(resources);
148✔
361
#else
362
    (void)resources;  // silence warning
363
#endif
364
    switch (type_) {
151✔
365
      case VariantType::Uint32:
11✔
366
        return canConvertNumber<T>(content_.asUint32);
11✔
367

368
      case VariantType::Int32:
65✔
369
        return canConvertNumber<T>(content_.asInt32);
65✔
370

371
#if ARDUINOJSON_USE_LONG_LONG
372
      case VariantType::Uint64:
3✔
373
        return canConvertNumber<T>(extension->asUint64);
3✔
374

375
      case VariantType::Int64:
4✔
376
        return canConvertNumber<T>(extension->asInt64);
4✔
377
#endif
378

379
      default:
68✔
380
        return false;
68✔
381
    }
382
  }
383

384
  bool isNull() const {
1,955✔
385
    return type_ == VariantType::Null;
1,955✔
386
  }
387

388
  static bool isNull(const VariantData* var) {
1,290✔
389
    if (!var)
1,290✔
390
      return true;
737✔
391
    return var->isNull();
553✔
392
  }
393

394
  bool isObject() const {
3,323✔
395
    return type_ == VariantType::Object;
3,323✔
396
  }
397

398
  bool isString() const {
80✔
399
    return type_ == VariantType::LinkedString ||
136✔
400
           type_ == VariantType::OwnedString;
136✔
401
  }
402

403
  size_t nesting(const ResourceManager* resources) const {
44✔
404
    auto collection = asCollection();
44✔
405
    if (collection)
44✔
406
      return collection->nesting(resources);
30✔
407
    else
408
      return 0;
14✔
409
  }
410

411
  static size_t nesting(const VariantData* var,
28✔
412
                        const ResourceManager* resources) {
413
    if (!var)
28✔
414
      return 0;
6✔
415
    return var->nesting(resources);
22✔
416
  }
417

418
  void removeElement(size_t index, ResourceManager* resources) {
9✔
419
    ArrayData::removeElement(asArray(), index, resources);
9✔
420
  }
9✔
421

422
  static void removeElement(VariantData* var, size_t index,
10✔
423
                            ResourceManager* resources) {
424
    if (!var)
10✔
425
      return;
1✔
426
    var->removeElement(index, resources);
9✔
427
  }
428

429
  template <typename TAdaptedString>
430
  void removeMember(TAdaptedString key, ResourceManager* resources) {
16✔
431
    ObjectData::removeMember(asObject(), key, resources);
16✔
432
  }
16✔
433

434
  template <typename TAdaptedString>
435
  static void removeMember(VariantData* var, TAdaptedString key,
17✔
436
                           ResourceManager* resources) {
437
    if (!var)
17✔
438
      return;
1✔
439
    var->removeMember(key, resources);
16✔
440
  }
441

442
  void reset() {  // TODO: remove
1,945✔
443
    type_ = VariantType::Null;
1,945✔
444
  }
1,945✔
445

446
  void setBoolean(bool value) {
330✔
447
    ARDUINOJSON_ASSERT(type_ == VariantType::Null);  // must call clear() first
448
    type_ = VariantType::Boolean;
330✔
449
    content_.asBoolean = value;
330✔
450
  }
330✔
451

452
  template <typename T>
453
  enable_if_t<sizeof(T) == 4, bool> setFloat(T value, ResourceManager*) {
89✔
454
    ARDUINOJSON_ASSERT(type_ == VariantType::Null);  // must call clear() first
455
    type_ = VariantType::Float;
89✔
456
    content_.asFloat = value;
89✔
457
    return true;
89✔
458
  }
459

460
  template <typename T>
461
  enable_if_t<sizeof(T) == 8, bool> setFloat(T value, ResourceManager*);
462

463
  template <typename T>
464
  enable_if_t<is_signed<T>::value, bool> setInteger(T value,
465
                                                    ResourceManager* resources);
466

467
  template <typename T>
468
  enable_if_t<is_unsigned<T>::value, bool> setInteger(
469
      T value, ResourceManager* resources);
470

471
  void setRawString(StringNode* s) {
87✔
472
    ARDUINOJSON_ASSERT(type_ == VariantType::Null);  // must call clear() first
473
    ARDUINOJSON_ASSERT(s);
474
    type_ = VariantType::RawString;
87✔
475
    content_.asOwnedString = s;
87✔
476
  }
87✔
477

478
  template <typename T>
479
  void setRawString(SerializedValue<T> value, ResourceManager* resources);
480

481
  template <typename T>
482
  static void setRawString(VariantData* var, SerializedValue<T> value,
36✔
483
                           ResourceManager* resources) {
484
    if (!var)
36✔
485
      return;
2✔
486
    var->clear(resources);
34✔
487
    var->setRawString(value, resources);
34✔
488
  }
489

490
  template <typename TAdaptedString>
491
  bool setString(TAdaptedString value, ResourceManager* resources);
492

493
  bool setString(StringNode* s, ResourceManager*) {
1,331✔
494
    setOwnedString(s);
1,331✔
495
    return true;
1,331✔
496
  }
497

498
  template <typename TAdaptedString>
499
  static void setString(VariantData* var, TAdaptedString value,
66,129✔
500
                        ResourceManager* resources) {
501
    if (!var)
66,129✔
502
      return;
5✔
503
    var->clear(resources);
66,124✔
504
    var->setString(value, resources);
66,124✔
505
  }
506

507
  bool setLinkedString(const char* s, ResourceManager* resources);
508

509
  void setOwnedString(StringNode* s) {
2,024✔
510
    ARDUINOJSON_ASSERT(type_ == VariantType::Null);  // must call clear() first
511
    ARDUINOJSON_ASSERT(s);
512
    type_ = VariantType::OwnedString;
2,024✔
513
    content_.asOwnedString = s;
2,024✔
514
  }
2,024✔
515

516
  size_t size(const ResourceManager* resources) const {
42✔
517
    if (isObject())
42✔
518
      return content_.asObject.size(resources);
14✔
519

520
    if (isArray())
28✔
521
      return content_.asArray.size(resources);
15✔
522

523
    return 0;
13✔
524
  }
525

526
  static size_t size(const VariantData* var, const ResourceManager* resources) {
30✔
527
    return var != 0 ? var->size(resources) : 0;
30✔
528
  }
529

530
  ArrayData& toArray() {
1,269✔
531
    ARDUINOJSON_ASSERT(type_ == VariantType::Null);  // must call clear() first
532
    type_ = VariantType::Array;
1,269✔
533
    new (&content_.asArray) ArrayData();
2,538✔
534
    return content_.asArray;
1,269✔
535
  }
536

537
  static ArrayData* toArray(VariantData* var, ResourceManager* resources) {
256✔
538
    if (!var)
256✔
UNCOV
539
      return 0;
×
540
    var->clear(resources);
256✔
541
    return &var->toArray();
256✔
542
  }
543

544
  ObjectData& toObject() {
1,344✔
545
    ARDUINOJSON_ASSERT(type_ == VariantType::Null);  // must call clear() first
546
    type_ = VariantType::Object;
1,344✔
547
    new (&content_.asObject) ObjectData();
2,688✔
548
    return content_.asObject;
1,344✔
549
  }
550

551
  static ObjectData* toObject(VariantData* var, ResourceManager* resources) {
316✔
552
    if (!var)
316✔
UNCOV
553
      return 0;
×
554
    var->clear(resources);
316✔
555
    return &var->toObject();
316✔
556
  }
557

558
  VariantType type() const {
559
    return type_;
560
  }
561

562
  // Release the resources used by this variant and set it to null.
563
  void clear(ResourceManager* resources);
564

565
  static void clear(VariantData* var, ResourceManager* resources) {
541✔
566
    if (!var)
541✔
567
      return;
1✔
568
    var->clear(resources);
540✔
569
  }
570
};
571

572
ARDUINOJSON_END_PRIVATE_NAMESPACE
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