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

bblanchon / ArduinoJson / 10680315983

03 Sep 2024 09:30AM CUT coverage: 99.497%. First build
10680315983

push

github

bblanchon
Fu

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

3957 of 3977 relevant lines covered (99.5%)

10631.34 hits per line

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

98.95
/src/ArduinoJson/Variant/VariantData.hpp
1
// ArduinoJson - https://arduinojson.org
2
// Copyright © 2014-2024, 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,670✔
28
    return p;
74,670✔
29
  }
30

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

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

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

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

43
  template <typename TVisitor>
44
  typename TVisitor::result_type accept(
139,241✔
45
      TVisitor& visit, const ResourceManager* resources) const {
46
    (void)resources;  // silence warning
47
    switch (type_) {
139,241✔
48
      case VariantType::Float:
61✔
49
        return visit.visit(content_.asFloat);
61✔
50

51
#if ARDUINOJSON_USE_DOUBLE
52
      case VariantType::Double:
76✔
53
        return visit.visit(getExtension(resources)->asDouble);
76✔
54
#endif
55

56
      case VariantType::Array:
967✔
57
        return visit.visit(content_.asArray);
967✔
58

59
      case VariantType::Object:
2,661✔
60
        return visit.visit(content_.asObject);
2,661✔
61

62
      case VariantType::LinkedString:
1,160✔
63
        return visit.visit(JsonString(content_.asLinkedString));
1,160✔
64

65
      case VariantType::OwnedString:
917✔
66
        return visit.visit(JsonString(content_.asOwnedString->data,
917✔
67
                                      content_.asOwnedString->length,
917✔
68
                                      JsonString::Copied));
917✔
69

70
      case VariantType::RawString:
125✔
71
        return visit.visit(RawString(content_.asOwnedString->data,
125✔
72
                                     content_.asOwnedString->length));
125✔
73

74
      case VariantType::Int32:
1,173✔
75
        return visit.visit(static_cast<JsonInteger>(content_.asInt32));
1,173✔
76

77
      case VariantType::Uint32:
254✔
78
        return visit.visit(static_cast<JsonUInt>(content_.asUint32));
254✔
79

80
#if ARDUINOJSON_USE_LONG_LONG
81
      case VariantType::Int64:
7✔
82
        return visit.visit(getExtension(resources)->asInt64);
7✔
83

84
      case VariantType::Uint64:
8✔
85
        return visit.visit(getExtension(resources)->asUint64);
8✔
86
#endif
87

88
      case VariantType::Boolean:
606✔
89
        return visit.visit(content_.asBoolean != 0);
606✔
90

91
      default:
131,226✔
92
        return visit.visit(nullptr);
131,226✔
93
    }
94
  }
95

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

106
  VariantData* addElement(ResourceManager* resources) {
157✔
107
    auto array = isNull() ? &toArray() : asArray();
157✔
108
    return detail::ArrayData::addElement(array, resources);
157✔
109
  }
110

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

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

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

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

158
  ArrayData* asArray() {
760✔
159
    return isArray() ? &content_.asArray : 0;
760✔
160
  }
161

162
  const ArrayData* asArray() const {
481✔
163
    return const_cast<VariantData*>(this)->asArray();
481✔
164
  }
165

166
  CollectionData* asCollection() {
69,359✔
167
    return isCollection() ? &content_.asCollection : 0;
69,359✔
168
  }
169

170
  const CollectionData* asCollection() const {
44✔
171
    return const_cast<VariantData*>(this)->asCollection();
44✔
172
  }
173

174
  template <typename T>
175
  T asFloat(const ResourceManager* resources) const {
47✔
176
    static_assert(is_floating_point<T>::value, "T must be a floating point");
177
    (void)resources;  // silence warning
178
    switch (type_) {
47✔
179
      case VariantType::Boolean:
2✔
180
        return static_cast<T>(content_.asBoolean);
2✔
181
      case VariantType::Uint32:
2✔
182
        return static_cast<T>(content_.asUint32);
2✔
183
      case VariantType::Int32:
4✔
184
        return static_cast<T>(content_.asInt32);
4✔
185
#if ARDUINOJSON_USE_LONG_LONG
186
      case VariantType::Uint64:
1✔
187
        return static_cast<T>(getExtension(resources)->asUint64);
1✔
188
      case VariantType::Int64:
1✔
189
        return static_cast<T>(getExtension(resources)->asInt64);
1✔
190
#endif
191
      case VariantType::LinkedString:
1✔
192
      case VariantType::OwnedString:
193
        return parseNumber<T>(content_.asOwnedString->data);
1✔
194
      case VariantType::Float:
15✔
195
        return static_cast<T>(content_.asFloat);
15✔
196
#if ARDUINOJSON_USE_DOUBLE
197
      case VariantType::Double:
19✔
198
        return static_cast<T>(getExtension(resources)->asDouble);
19✔
199
#endif
200
      default:
2✔
201
        return 0;
2✔
202
    }
203
  }
204

205
  template <typename T>
206
  T asIntegral(const ResourceManager* resources) const {
197✔
207
    static_assert(is_integral<T>::value, "T must be an integral type");
208
    (void)resources;  // silence warning
209
    switch (type_) {
197✔
210
      case VariantType::Boolean:
2✔
211
        return content_.asBoolean;
2✔
212
      case VariantType::Uint32:
66✔
213
        return convertNumber<T>(content_.asUint32);
66✔
214
      case VariantType::Int32:
83✔
215
        return convertNumber<T>(content_.asInt32);
83✔
216
#if ARDUINOJSON_USE_LONG_LONG
217
      case VariantType::Uint64:
10✔
218
        return convertNumber<T>(getExtension(resources)->asUint64);
10✔
219
      case VariantType::Int64:
11✔
220
        return convertNumber<T>(getExtension(resources)->asInt64);
11✔
221
#endif
222
      case VariantType::LinkedString:
6✔
223
        return parseNumber<T>(content_.asLinkedString);
6✔
224
      case VariantType::OwnedString:
2✔
225
        return parseNumber<T>(content_.asOwnedString->data);
2✔
226
      case VariantType::Float:
5✔
227
        return convertNumber<T>(content_.asFloat);
5✔
228
#if ARDUINOJSON_USE_DOUBLE
229
      case VariantType::Double:
10✔
230
        return convertNumber<T>(getExtension(resources)->asDouble);
10✔
231
#endif
232
      default:
2✔
233
        return 0;
2✔
234
    }
235
  }
236

237
  ObjectData* asObject() {
2,845✔
238
    return isObject() ? &content_.asObject : 0;
2,845✔
239
  }
240

241
  const ObjectData* asObject() const {
2,175✔
242
    return const_cast<VariantData*>(this)->asObject();
2,175✔
243
  }
244

245
  JsonString asRawString() const {
46✔
246
    switch (type_) {
46✔
247
      case VariantType::RawString:
26✔
248
        return JsonString(content_.asOwnedString->data,
26✔
249
                          content_.asOwnedString->length, JsonString::Copied);
26✔
250
      default:
20✔
251
        return JsonString();
20✔
252
    }
253
  }
254

255
  JsonString asString() const {
12,371✔
256
    switch (type_) {
12,371✔
257
      case VariantType::LinkedString:
4,512✔
258
        return JsonString(content_.asLinkedString, JsonString::Linked);
4,512✔
259
      case VariantType::OwnedString:
7,453✔
260
        return JsonString(content_.asOwnedString->data,
7,453✔
261
                          content_.asOwnedString->length, JsonString::Copied);
7,453✔
262
      default:
406✔
263
        return JsonString();
406✔
264
    }
265
  }
266

267
#if ARDUINOJSON_USE_EXTENSIONS
268
  const VariantExtension* getExtension(const ResourceManager* resources) const;
269
#endif
270

271
  VariantData* getElement(size_t index,
448✔
272
                          const ResourceManager* resources) const {
273
    return ArrayData::getElement(asArray(), index, resources);
448✔
274
  }
275

276
  static VariantData* getElement(const VariantData* var, size_t index,
451✔
277
                                 const ResourceManager* resources) {
278
    return var != 0 ? var->getElement(index, resources) : 0;
451✔
279
  }
280

281
  template <typename TAdaptedString>
282
  VariantData* getMember(TAdaptedString key,
2,141✔
283
                         const ResourceManager* resources) const {
284
    return ObjectData::getMember(asObject(), key, resources);
2,141✔
285
  }
286

287
  template <typename TAdaptedString>
288
  static VariantData* getMember(const VariantData* var, TAdaptedString key,
2,141✔
289
                                const ResourceManager* resources) {
290
    if (!var)
2,141✔
291
      return 0;
13✔
292
    return var->getMember(key, resources);
2,128✔
293
  }
294

295
  VariantData* getOrAddElement(size_t index, ResourceManager* resources) {
150✔
296
    auto array = isNull() ? &toArray() : asArray();
150✔
297
    if (!array)
150✔
298
      return nullptr;
1✔
299
    return array->getOrAddElement(index, resources);
149✔
300
  }
301

302
  template <typename TAdaptedString>
303
  VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources) {
899✔
304
    if (key.isNull())
899✔
305
      return nullptr;
1✔
306
    auto obj = isNull() ? &toObject() : asObject();
898✔
307
    if (!obj)
898✔
308
      return nullptr;
×
309
    return obj->getOrAddMember(key, resources);
898✔
310
  }
311

312
  bool isArray() const {
877✔
313
    return type_ == VariantType::Array;
877✔
314
  }
315

316
  bool isBoolean() const {
35✔
317
    return type_ == VariantType::Boolean;
35✔
318
  }
319

320
  bool isCollection() const {
69,359✔
321
    return type_ & VariantTypeBits::CollectionMask;
69,359✔
322
  }
323

324
  bool isFloat() const {
405✔
325
    return type_ & VariantTypeBits::NumberBit;
405✔
326
  }
327

328
  template <typename T>
329
  bool isInteger(const ResourceManager* resources) const {
141✔
330
    (void)resources;  // silence warning
331
    switch (type_) {
141✔
332
      case VariantType::Uint32:
11✔
333
        return canConvertNumber<T>(content_.asUint32);
11✔
334

335
      case VariantType::Int32:
65✔
336
        return canConvertNumber<T>(content_.asInt32);
65✔
337

338
#if ARDUINOJSON_USE_LONG_LONG
339
      case VariantType::Uint64:
3✔
340
        return canConvertNumber<T>(getExtension(resources)->asUint64);
3✔
341

342
      case VariantType::Int64:
4✔
343
        return canConvertNumber<T>(getExtension(resources)->asInt64);
4✔
344
#endif
345

346
      default:
58✔
347
        return false;
58✔
348
    }
349
  }
350

351
  bool isNull() const {
1,881✔
352
    return type_ == VariantType::Null;
1,881✔
353
  }
354

355
  static bool isNull(const VariantData* var) {
1,280✔
356
    if (!var)
1,280✔
357
      return true;
731✔
358
    return var->isNull();
549✔
359
  }
360

361
  bool isObject() const {
3,229✔
362
    return type_ == VariantType::Object;
3,229✔
363
  }
364

365
  bool isString() const {
71✔
366
    return type_ == VariantType::LinkedString ||
120✔
367
           type_ == VariantType::OwnedString;
120✔
368
  }
369

370
  size_t nesting(const ResourceManager* resources) const {
44✔
371
    auto collection = asCollection();
44✔
372
    if (collection)
44✔
373
      return collection->nesting(resources);
30✔
374
    else
375
      return 0;
14✔
376
  }
377

378
  static size_t nesting(const VariantData* var,
28✔
379
                        const ResourceManager* resources) {
380
    if (!var)
28✔
381
      return 0;
6✔
382
    return var->nesting(resources);
22✔
383
  }
384

385
  void removeElement(size_t index, ResourceManager* resources) {
9✔
386
    ArrayData::removeElement(asArray(), index, resources);
9✔
387
  }
9✔
388

389
  static void removeElement(VariantData* var, size_t index,
10✔
390
                            ResourceManager* resources) {
391
    if (!var)
10✔
392
      return;
1✔
393
    var->removeElement(index, resources);
9✔
394
  }
395

396
  template <typename TAdaptedString>
397
  void removeMember(TAdaptedString key, ResourceManager* resources) {
14✔
398
    ObjectData::removeMember(asObject(), key, resources);
14✔
399
  }
14✔
400

401
  template <typename TAdaptedString>
402
  static void removeMember(VariantData* var, TAdaptedString key,
15✔
403
                           ResourceManager* resources) {
404
    if (!var)
15✔
405
      return;
1✔
406
    var->removeMember(key, resources);
14✔
407
  }
408

409
  void reset() {  // TODO: remove
1,899✔
410
    type_ = VariantType::Null;
1,899✔
411
  }
1,899✔
412

413
  void setBoolean(bool value) {
329✔
414
    ARDUINOJSON_ASSERT(type_ == VariantType::Null);  // must call clear() first
415
    type_ = VariantType::Boolean;
329✔
416
    content_.asBoolean = value;
329✔
417
  }
329✔
418

419
  template <typename T>
420
  enable_if_t<sizeof(T) == 4, bool> setFloat(T value, ResourceManager*) {
15✔
421
    ARDUINOJSON_ASSERT(type_ == VariantType::Null);  // must call clear() first
422
    type_ = VariantType::Float;
15✔
423
    content_.asFloat = value;
15✔
424
    return true;
15✔
425
  }
426

427
  template <typename T>
428
  enable_if_t<sizeof(T) == 8, bool> setFloat(T value, ResourceManager*);
429

430
  template <typename T>
431
  enable_if_t<is_signed<T>::value, bool> setInteger(T value,
432
                                                    ResourceManager* resources);
433

434
  template <typename T>
435
  enable_if_t<is_unsigned<T>::value, bool> setInteger(
436
      T value, ResourceManager* resources);
437

438
  void setRawString(StringNode* s) {
87✔
439
    ARDUINOJSON_ASSERT(type_ == VariantType::Null);  // must call clear() first
440
    ARDUINOJSON_ASSERT(s);
441
    type_ = VariantType::RawString;
87✔
442
    content_.asOwnedString = s;
87✔
443
  }
87✔
444

445
  template <typename T>
446
  void setRawString(SerializedValue<T> value, ResourceManager* resources);
447

448
  template <typename T>
449
  static void setRawString(VariantData* var, SerializedValue<T> value,
36✔
450
                           ResourceManager* resources) {
451
    if (!var)
36✔
452
      return;
2✔
453
    var->clear(resources);
34✔
454
    var->setRawString(value, resources);
34✔
455
  }
456

457
  template <typename TAdaptedString>
458
  bool setString(TAdaptedString value, ResourceManager* resources);
459

460
  bool setString(StringNode* s, ResourceManager*) {
1,332✔
461
    setOwnedString(s);
1,332✔
462
    return true;
1,332✔
463
  }
464

465
  template <typename TAdaptedString>
466
  static void setString(VariantData* var, TAdaptedString value,
66,080✔
467
                        ResourceManager* resources) {
468
    if (!var)
66,080✔
469
      return;
5✔
470
    var->clear(resources);
66,075✔
471
    var->setString(value, resources);
66,075✔
472
  }
473

474
  void setLinkedString(const char* s) {
1,152✔
475
    ARDUINOJSON_ASSERT(type_ == VariantType::Null);  // must call clear() first
476
    ARDUINOJSON_ASSERT(s);
477
    type_ = VariantType::LinkedString;
1,152✔
478
    content_.asLinkedString = s;
1,152✔
479
  }
1,152✔
480

481
  void setOwnedString(StringNode* s) {
1,929✔
482
    ARDUINOJSON_ASSERT(type_ == VariantType::Null);  // must call clear() first
483
    ARDUINOJSON_ASSERT(s);
484
    type_ = VariantType::OwnedString;
1,929✔
485
    content_.asOwnedString = s;
1,929✔
486
  }
1,929✔
487

488
  size_t size(const ResourceManager* resources) const {
42✔
489
    if (isObject())
42✔
490
      return content_.asObject.size(resources);
14✔
491

492
    if (isArray())
28✔
493
      return content_.asArray.size(resources);
15✔
494

495
    return 0;
13✔
496
  }
497

498
  static size_t size(const VariantData* var, const ResourceManager* resources) {
30✔
499
    return var != 0 ? var->size(resources) : 0;
30✔
500
  }
501

502
  ArrayData& toArray() {
1,260✔
503
    ARDUINOJSON_ASSERT(type_ == VariantType::Null);  // must call clear() first
504
    type_ = VariantType::Array;
1,260✔
505
    new (&content_.asArray) ArrayData();
2,520✔
506
    return content_.asArray;
1,260✔
507
  }
508

509
  static ArrayData* toArray(VariantData* var, ResourceManager* resources) {
261✔
510
    if (!var)
261✔
511
      return 0;
×
512
    var->clear(resources);
261✔
513
    return &var->toArray();
261✔
514
  }
515

516
  ObjectData& toObject() {
1,324✔
517
    ARDUINOJSON_ASSERT(type_ == VariantType::Null);  // must call clear() first
518
    type_ = VariantType::Object;
1,324✔
519
    new (&content_.asObject) ObjectData();
2,648✔
520
    return content_.asObject;
1,324✔
521
  }
522

523
  static ObjectData* toObject(VariantData* var, ResourceManager* resources) {
315✔
524
    if (!var)
315✔
525
      return 0;
×
526
    var->clear(resources);
315✔
527
    return &var->toObject();
315✔
528
  }
529

530
  VariantType type() const {
531
    return type_;
532
  }
533

534
  // Release the resources used by this variant and set it to null.
535
  void clear(ResourceManager* resources);
536

537
  static void clear(VariantData* var, ResourceManager* resources) {
502✔
538
    if (!var)
502✔
539
      return;
1✔
540
    var->clear(resources);
501✔
541
  }
542
};
543

544
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