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

bblanchon / ArduinoJson / 10572597112

27 Aug 2024 06:03AM UTC coverage: 99.194% (-0.3%) from 99.512%
10572597112

push

github

bblanchon
Merge conf_test for linux and windows

This reverts commit 83516e174.

3940 of 3972 relevant lines covered (99.19%)

10537.46 hits per line

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

96.84
/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
  uint8_t 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_(VALUE_IS_NULL), next_(NULL_SLOT) {}
76,637✔
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,239✔
45
      TVisitor& visit, const ResourceManager* resources) const {
46
    (void)resources;  // silence warning
47
    switch (type_) {
139,239✔
48
      case VALUE_IS_FLOAT:
59✔
49
        return visit.visit(static_cast<JsonFloat>(content_.asFloat));
59✔
50

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

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

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

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

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

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

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

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

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

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

88
      case VALUE_IS_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,
698✔
98
                                               const ResourceManager* resources,
99
                                               TVisitor& visit) {
100
    if (var != 0)
698✔
101
      return var->accept(visit, resources);
695✔
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 {
551✔
133
    (void)resources;  // silence warning
134
    switch (type_) {
551✔
135
      case VALUE_IS_BOOLEAN:
304✔
136
        return content_.asBoolean;
304✔
137
      case VALUE_IS_UINT32:
7✔
138
      case VALUE_IS_INT32:
139
        return content_.asUint32 != 0;
7✔
140
      case VALUE_IS_FLOAT:
1✔
141
        return content_.asFloat != 0;
1✔
142
#if ARDUINOJSON_USE_DOUBLE
143
      case VALUE_IS_DOUBLE:
4✔
144
        return getExtension(resources)->asDouble != 0;
4✔
145
#endif
146
      case VALUE_IS_NULL:
6✔
147
        return false;
6✔
148
#if ARDUINOJSON_USE_LONG_LONG
149
      case VALUE_IS_UINT64:
×
150
      case VALUE_IS_INT64:
151
        return getExtension(resources)->asUint64 != 0;
×
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,322✔
167
    return isCollection() ? &content_.asCollection : 0;
69,322✔
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 {
43✔
176
    static_assert(is_floating_point<T>::value, "T must be a floating point");
177
    (void)resources;  // silence warning
178
    switch (type_) {
43✔
179
      case VALUE_IS_BOOLEAN:
2✔
180
        return static_cast<T>(content_.asBoolean);
2✔
181
      case VALUE_IS_UINT32:
2✔
182
        return static_cast<T>(content_.asUint32);
2✔
183
      case VALUE_IS_INT32:
6✔
184
        return static_cast<T>(content_.asInt32);
6✔
185
#if ARDUINOJSON_USE_LONG_LONG
186
      case VALUE_IS_UINT64:
×
187
        return static_cast<T>(getExtension(resources)->asUint64);
×
188
      case VALUE_IS_INT64:
×
189
        return static_cast<T>(getExtension(resources)->asInt64);
×
190
#endif
191
      case VALUE_IS_LINKED_STRING:
1✔
192
      case VALUE_IS_OWNED_STRING:
193
        return parseNumber<T>(content_.asOwnedString->data);
1✔
194
      case VALUE_IS_FLOAT:
13✔
195
        return static_cast<T>(content_.asFloat);
13✔
196
#if ARDUINOJSON_USE_DOUBLE
197
      case VALUE_IS_DOUBLE:
17✔
198
        return static_cast<T>(getExtension(resources)->asDouble);
17✔
199
#endif
200
      default:
2✔
201
        return 0;
2✔
202
    }
203
  }
204

205
  template <typename T>
206
  T asIntegral(const ResourceManager* resources) const {
179✔
207
    static_assert(is_integral<T>::value, "T must be an integral type");
208
    (void)resources;  // silence warning
209
    switch (type_) {
179✔
210
      case VALUE_IS_BOOLEAN:
2✔
211
        return content_.asBoolean;
2✔
212
      case VALUE_IS_UINT32:
62✔
213
        return convertNumber<T>(content_.asUint32);
62✔
214
      case VALUE_IS_INT32:
80✔
215
        return convertNumber<T>(content_.asInt32);
80✔
216
#if ARDUINOJSON_USE_LONG_LONG
217
      case VALUE_IS_UINT64:
6✔
218
        return convertNumber<T>(getExtension(resources)->asUint64);
6✔
219
      case VALUE_IS_INT64:
6✔
220
        return convertNumber<T>(getExtension(resources)->asInt64);
6✔
221
#endif
222
      case VALUE_IS_LINKED_STRING:
6✔
223
        return parseNumber<T>(content_.asLinkedString);
6✔
224
      case VALUE_IS_OWNED_STRING:
2✔
225
        return parseNumber<T>(content_.asOwnedString->data);
2✔
226
      case VALUE_IS_FLOAT:
3✔
227
        return convertNumber<T>(content_.asFloat);
3✔
228
#if ARDUINOJSON_USE_DOUBLE
229
      case VALUE_IS_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 {
38✔
246
    switch (type_) {
38✔
247
      case VALUE_IS_RAW_STRING:
26✔
248
        return JsonString(content_.asOwnedString->data,
26✔
249
                          content_.asOwnedString->length, JsonString::Copied);
26✔
250
      default:
12✔
251
        return JsonString();
12✔
252
    }
253
  }
254

255
  JsonString asString() const {
12,368✔
256
    switch (type_) {
12,368✔
257
      case VALUE_IS_LINKED_STRING:
4,512✔
258
        return JsonString(content_.asLinkedString, JsonString::Linked);
4,512✔
259
      case VALUE_IS_OWNED_STRING:
7,453✔
260
        return JsonString(content_.asOwnedString->data,
7,453✔
261
                          content_.asOwnedString->length, JsonString::Copied);
7,453✔
262
      default:
403✔
263
        return JsonString();
403✔
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_ == VALUE_IS_ARRAY;
877✔
314
  }
315

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

320
  bool isCollection() const {
69,322✔
321
    return (type_ & COLLECTION_MASK) != 0;
69,322✔
322
  }
323

324
  bool isFloat() const {
402✔
325
    return (type_ & NUMBER_BIT) != 0;
402✔
326
  }
327

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

335
      case VALUE_IS_INT32:
62✔
336
        return canConvertNumber<T>(content_.asInt32);
62✔
337

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

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

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

351
  bool isNull() const {
1,878✔
352
    return type_ == VALUE_IS_NULL;
1,878✔
353
  }
354

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

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

365
  bool isString() const {
71✔
366
    return type_ == VALUE_IS_LINKED_STRING || type_ == VALUE_IS_OWNED_STRING;
71✔
367
  }
368

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

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

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

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

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

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

408
  void reset() {  // TODO: remove
1,882✔
409
    type_ = VALUE_IS_NULL;
1,882✔
410
  }
1,882✔
411

412
  void setBoolean(bool value) {
329✔
413
    ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL);  // must call clear() first
414
    type_ = VALUE_IS_BOOLEAN;
329✔
415
    content_.asBoolean = value;
329✔
416
  }
329✔
417

418
  template <typename T>
419
  typename enable_if<sizeof(T) == 4>::type setFloat(T value, ResourceManager*) {
11✔
420
    ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL);  // must call clear() first
421
    type_ = VALUE_IS_FLOAT;
11✔
422
    content_.asFloat = value;
11✔
423
  }
11✔
424

425
  template <typename T>
426
  typename enable_if<sizeof(T) == 8>::type setFloat(T value, ResourceManager*);
427

428
  template <typename T>
429
  enable_if_t<is_signed<T>::value> setInteger(T value,
430
                                              ResourceManager* resources);
431

432
  template <typename T>
433
  enable_if_t<is_unsigned<T>::value> setInteger(T value,
434
                                                ResourceManager* resources);
435

436
  void setRawString(StringNode* s) {
87✔
437
    ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL);  // must call clear() first
438
    ARDUINOJSON_ASSERT(s);
439
    type_ = VALUE_IS_RAW_STRING;
87✔
440
    content_.asOwnedString = s;
87✔
441
  }
87✔
442

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

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

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

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

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

472
  void setLinkedString(const char* s) {
1,152✔
473
    ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL);  // must call clear() first
474
    ARDUINOJSON_ASSERT(s);
475
    type_ = VALUE_IS_LINKED_STRING;
1,152✔
476
    content_.asLinkedString = s;
1,152✔
477
  }
1,152✔
478

479
  void setOwnedString(StringNode* s) {
1,929✔
480
    ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL);  // must call clear() first
481
    ARDUINOJSON_ASSERT(s);
482
    type_ = VALUE_IS_OWNED_STRING;
1,929✔
483
    content_.asOwnedString = s;
1,929✔
484
  }
1,929✔
485

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

490
    if (isArray())
28✔
491
      return content_.asArray.size(resources);
15✔
492

493
    return 0;
13✔
494
  }
495

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

500
  ArrayData& toArray() {
1,260✔
501
    ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL);  // must call clear() first
502
    type_ = VALUE_IS_ARRAY;
1,260✔
503
    new (&content_.asArray) ArrayData();
2,520✔
504
    return content_.asArray;
1,260✔
505
  }
506

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

514
  ObjectData& toObject() {
1,324✔
515
    ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL);  // must call clear() first
516
    type_ = VALUE_IS_OBJECT;
1,324✔
517
    new (&content_.asObject) ObjectData();
2,648✔
518
    return content_.asObject;
1,324✔
519
  }
520

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

528
  uint8_t type() const {
529
    return type_;
530
  }
531

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

535
  static void clear(VariantData* var, ResourceManager* resources) {
485✔
536
    if (!var)
485✔
537
      return;
1✔
538
    var->clear(resources);
484✔
539
  }
540
};
541

542
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