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

bblanchon / ArduinoJson / 13565547901

27 Feb 2025 10:13AM UTC coverage: 99.325% (+0.002%) from 99.323%
13565547901

push

github

bblanchon
Reduce code size

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

3 existing lines in 1 file now uncovered.

3974 of 4001 relevant lines covered (99.33%)

10896.33 hits per line

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

99.0
/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,798✔
28
    return p;
74,798✔
29
  }
30

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

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

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

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

43
  template <typename TVisitor>
44
  typename TVisitor::result_type accept(
139,338✔
45
      TVisitor& visit, const ResourceManager* resources) const {
46
#if ARDUINOJSON_USE_EXTENSIONS
47
    auto extension = getExtension(resources);
139,338✔
48
#else
49
    (void)resources;  // silence warning
50
#endif
51
    switch (type_) {
139,338✔
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,158✔
67
        return visit.visit(JsonString(content_.asLinkedString, true));
1,158✔
68

69
      case VariantType::OwnedString:
966✔
70
        return visit.visit(JsonString(content_.asOwnedString->data,
966✔
71
                                      content_.asOwnedString->length));
966✔
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 = content_.asLinkedString;
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 = content_.asLinkedString;
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,941✔
265
    return isObject() ? &content_.asObject : 0;
2,941✔
266
  }
267

268
  const ObjectData* asObject() const {
2,233✔
269
    return const_cast<VariantData*>(this)->asObject();
2,233✔
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
  JsonString asString() const {
12,753✔
283
    switch (type_) {
12,753✔
284
      case VariantType::LinkedString:
4,663✔
285
        return JsonString(content_.asLinkedString, true);
4,663✔
286
      case VariantType::OwnedString:
7,660✔
287
        return JsonString(content_.asOwnedString->data,
7,660✔
288
                          content_.asOwnedString->length);
7,660✔
289
      default:
430✔
290
        return JsonString();
430✔
291
    }
292
  }
293

294
#if ARDUINOJSON_USE_EXTENSIONS
295
  const VariantExtension* getExtension(const ResourceManager* resources) const;
296
#endif
297

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

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

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

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

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

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

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

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

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

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

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

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

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

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

377
      default:
68✔
378
        return false;
68✔
379
    }
380
  }
381

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

386
  static bool isNull(const VariantData* var) {
1,288✔
387
    if (!var)
1,288✔
388
      return true;
737✔
389
    return var->isNull();
551✔
390
  }
391

392
  bool isObject() const {
3,328✔
393
    return type_ == VariantType::Object;
3,328✔
394
  }
395

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

505
  void setLinkedString(const char* s) {
1,165✔
506
    ARDUINOJSON_ASSERT(type_ == VariantType::Null);  // must call clear() first
507
    ARDUINOJSON_ASSERT(s);
508
    type_ = VariantType::LinkedString;
1,165✔
509
    content_.asLinkedString = s;
1,165✔
510
  }
1,165✔
511

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

519
  size_t size(const ResourceManager* resources) const {
42✔
520
    if (isObject())
42✔
521
      return content_.asObject.size(resources);
14✔
522

523
    if (isArray())
28✔
524
      return content_.asArray.size(resources);
15✔
525

526
    return 0;
13✔
527
  }
528

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

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

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

547
  ObjectData& toObject() {
1,346✔
548
    ARDUINOJSON_ASSERT(type_ == VariantType::Null);  // must call clear() first
549
    type_ = VariantType::Object;
1,346✔
550
    new (&content_.asObject) ObjectData();
2,692✔
551
    return content_.asObject;
1,346✔
552
  }
553

554
  static ObjectData* toObject(VariantData* var, ResourceManager* resources) {
318✔
555
    if (!var)
318✔
UNCOV
556
      return 0;
×
557
    var->clear(resources);
318✔
558
    return &var->toObject();
318✔
559
  }
560

561
  VariantType type() const {
562
    return type_;
563
  }
564

565
  // Release the resources used by this variant and set it to null.
566
  void clear(ResourceManager* resources);
567

568
  static void clear(VariantData* var, ResourceManager* resources) {
539✔
569
    if (!var)
539✔
570
      return;
1✔
571
    var->clear(resources);
538✔
572
  }
573
};
574

575
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

© 2025 Coveralls, Inc