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

bblanchon / ArduinoJson / 10546949766

25 Aug 2024 12:30PM UTC coverage: 99.51%. First build
10546949766

push

github

bblanchon
Remove VariantSlot

4 of 4 new or added lines in 2 files covered. (100.0%)

3862 of 3881 relevant lines covered (99.51%)

10845.49 hits per line

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

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

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

33
  VariantData() : type_(VALUE_IS_NULL), next_(NULL_SLOT) {}
76,248✔
34

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

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

43
  template <typename TVisitor>
44
  typename TVisitor::result_type accept(TVisitor& visit) const {
139,239✔
45
    switch (type_) {
139,239✔
46
      case VALUE_IS_FLOAT:
135✔
47
        return visit.visit(content_.asFloat);
135✔
48

49
      case VALUE_IS_ARRAY:
967✔
50
        return visit.visit(content_.asArray);
967✔
51

52
      case VALUE_IS_OBJECT:
2,661✔
53
        return visit.visit(content_.asObject);
2,661✔
54

55
      case VALUE_IS_LINKED_STRING:
1,160✔
56
        return visit.visit(JsonString(content_.asLinkedString));
1,160✔
57

58
      case VALUE_IS_OWNED_STRING:
917✔
59
        return visit.visit(JsonString(content_.asOwnedString->data,
917✔
60
                                      content_.asOwnedString->length,
917✔
61
                                      JsonString::Copied));
917✔
62

63
      case VALUE_IS_RAW_STRING:
125✔
64
        return visit.visit(RawString(content_.asOwnedString->data,
125✔
65
                                     content_.asOwnedString->length));
125✔
66

67
      case VALUE_IS_SIGNED_INTEGER:
1,181✔
68
        return visit.visit(content_.asSignedInteger);
1,181✔
69

70
      case VALUE_IS_UNSIGNED_INTEGER:
261✔
71
        return visit.visit(content_.asUnsignedInteger);
261✔
72

73
      case VALUE_IS_BOOLEAN:
606✔
74
        return visit.visit(content_.asBoolean != 0);
606✔
75

76
      default:
131,226✔
77
        return visit.visit(nullptr);
131,226✔
78
    }
79
  }
80

81
  template <typename TVisitor>
82
  static typename TVisitor::result_type accept(const VariantData* var,
698✔
83
                                               TVisitor& visit) {
84
    if (var != 0)
698✔
85
      return var->accept(visit);
695✔
86
    else
87
      return visit.visit(nullptr);
3✔
88
  }
89

90
  VariantData* addElement(ResourceManager* resources) {
157✔
91
    auto array = isNull() ? &toArray() : asArray();
157✔
92
    return detail::ArrayData::addElement(array, resources);
157✔
93
  }
94

95
  static VariantData* addElement(VariantData* var, ResourceManager* resources) {
41✔
96
    if (!var)
41✔
97
      return nullptr;
6✔
98
    return var->addElement(resources);
35✔
99
  }
100

101
  template <typename T>
102
  bool addValue(T&& value, ResourceManager* resources) {
124✔
103
    auto array = isNull() ? &toArray() : asArray();
124✔
104
    return detail::ArrayData::addValue(array, detail::forward<T>(value),
124✔
105
                                       resources);
124✔
106
  }
107

108
  template <typename T>
109
  static bool addValue(VariantData* var, T&& value,
43✔
110
                       ResourceManager* resources) {
111
    if (!var)
43✔
112
      return false;
6✔
113
    return var->addValue(value, resources);
37✔
114
  }
115

116
  bool asBoolean() const {
551✔
117
    switch (type_) {
551✔
118
      case VALUE_IS_BOOLEAN:
304✔
119
        return content_.asBoolean;
304✔
120
      case VALUE_IS_SIGNED_INTEGER:
7✔
121
      case VALUE_IS_UNSIGNED_INTEGER:
122
        return content_.asUnsignedInteger != 0;
7✔
123
      case VALUE_IS_FLOAT:
5✔
124
        return content_.asFloat != 0;
5✔
125
      case VALUE_IS_NULL:
6✔
126
        return false;
6✔
127
      default:
229✔
128
        return true;
229✔
129
    }
130
  }
131

132
  ArrayData* asArray() {
760✔
133
    return isArray() ? &content_.asArray : 0;
760✔
134
  }
135

136
  const ArrayData* asArray() const {
481✔
137
    return const_cast<VariantData*>(this)->asArray();
481✔
138
  }
139

140
  CollectionData* asCollection() {
69,631✔
141
    return isCollection() ? &content_.asCollection : 0;
69,631✔
142
  }
143

144
  const CollectionData* asCollection() const {
44✔
145
    return const_cast<VariantData*>(this)->asCollection();
44✔
146
  }
147

148
  template <typename T>
149
  T asFloat() const {
117✔
150
    static_assert(is_floating_point<T>::value, "T must be a floating point");
151
    switch (type_) {
117✔
152
      case VALUE_IS_BOOLEAN:
2✔
153
        return static_cast<T>(content_.asBoolean);
2✔
154
      case VALUE_IS_UNSIGNED_INTEGER:
3✔
155
        return static_cast<T>(content_.asUnsignedInteger);
3✔
156
      case VALUE_IS_SIGNED_INTEGER:
6✔
157
        return static_cast<T>(content_.asSignedInteger);
6✔
158
      case VALUE_IS_LINKED_STRING:
1✔
159
      case VALUE_IS_OWNED_STRING:
160
        return parseNumber<T>(content_.asOwnedString->data);
1✔
161
      case VALUE_IS_FLOAT:
103✔
162
        return static_cast<T>(content_.asFloat);
103✔
163
      default:
2✔
164
        return 0;
2✔
165
    }
166
  }
167

168
  template <typename T>
169
  T asIntegral() const {
224✔
170
    static_assert(is_integral<T>::value, "T must be an integral type");
171
    switch (type_) {
224✔
172
      case VALUE_IS_BOOLEAN:
2✔
173
        return content_.asBoolean;
2✔
174
      case VALUE_IS_UNSIGNED_INTEGER:
89✔
175
        return convertNumber<T>(content_.asUnsignedInteger);
89✔
176
      case VALUE_IS_SIGNED_INTEGER:
96✔
177
        return convertNumber<T>(content_.asSignedInteger);
96✔
178
      case VALUE_IS_LINKED_STRING:
6✔
179
        return parseNumber<T>(content_.asLinkedString);
6✔
180
      case VALUE_IS_OWNED_STRING:
2✔
181
        return parseNumber<T>(content_.asOwnedString->data);
2✔
182
      case VALUE_IS_FLOAT:
19✔
183
        return convertNumber<T>(content_.asFloat);
19✔
184
      default:
10✔
185
        return 0;
10✔
186
    }
187
  }
188

189
  ObjectData* asObject() {
2,845✔
190
    return isObject() ? &content_.asObject : 0;
2,845✔
191
  }
192

193
  const ObjectData* asObject() const {
2,175✔
194
    return const_cast<VariantData*>(this)->asObject();
2,175✔
195
  }
196

197
  JsonString asRawString() const {
38✔
198
    switch (type_) {
38✔
199
      case VALUE_IS_RAW_STRING:
26✔
200
        return JsonString(content_.asOwnedString->data,
26✔
201
                          content_.asOwnedString->length, JsonString::Copied);
26✔
202
      default:
12✔
203
        return JsonString();
12✔
204
    }
205
  }
206

207
  JsonString asString() const {
12,368✔
208
    switch (type_) {
12,368✔
209
      case VALUE_IS_LINKED_STRING:
4,512✔
210
        return JsonString(content_.asLinkedString, JsonString::Linked);
4,512✔
211
      case VALUE_IS_OWNED_STRING:
7,453✔
212
        return JsonString(content_.asOwnedString->data,
7,453✔
213
                          content_.asOwnedString->length, JsonString::Copied);
7,453✔
214
      default:
403✔
215
        return JsonString();
403✔
216
    }
217
  }
218

219
  VariantData* getElement(size_t index,
448✔
220
                          const ResourceManager* resources) const {
221
    return ArrayData::getElement(asArray(), index, resources);
448✔
222
  }
223

224
  static VariantData* getElement(const VariantData* var, size_t index,
451✔
225
                                 const ResourceManager* resources) {
226
    return var != 0 ? var->getElement(index, resources) : 0;
451✔
227
  }
228

229
  template <typename TAdaptedString>
230
  VariantData* getMember(TAdaptedString key,
2,141✔
231
                         const ResourceManager* resources) const {
232
    return ObjectData::getMember(asObject(), key, resources);
2,141✔
233
  }
234

235
  template <typename TAdaptedString>
236
  static VariantData* getMember(const VariantData* var, TAdaptedString key,
2,141✔
237
                                const ResourceManager* resources) {
238
    if (!var)
2,141✔
239
      return 0;
13✔
240
    return var->getMember(key, resources);
2,128✔
241
  }
242

243
  VariantData* getOrAddElement(size_t index, ResourceManager* resources) {
150✔
244
    auto array = isNull() ? &toArray() : asArray();
150✔
245
    if (!array)
150✔
246
      return nullptr;
1✔
247
    return array->getOrAddElement(index, resources);
149✔
248
  }
249

250
  template <typename TAdaptedString>
251
  VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources) {
899✔
252
    if (key.isNull())
899✔
253
      return nullptr;
1✔
254
    auto obj = isNull() ? &toObject() : asObject();
898✔
255
    if (!obj)
898✔
256
      return nullptr;
×
257
    return obj->getOrAddMember(key, resources);
898✔
258
  }
259

260
  bool isArray() const {
877✔
261
    return type_ == VALUE_IS_ARRAY;
877✔
262
  }
263

264
  bool isBoolean() const {
35✔
265
    return type_ == VALUE_IS_BOOLEAN;
35✔
266
  }
267

268
  bool isCollection() const {
69,631✔
269
    return (type_ & COLLECTION_MASK) != 0;
69,631✔
270
  }
271

272
  bool isFloat() const {
402✔
273
    return (type_ & NUMBER_BIT) != 0;
402✔
274
  }
275

276
  template <typename T>
277
  bool isInteger() const {
135✔
278
    switch (type_) {
135✔
279
      case VALUE_IS_UNSIGNED_INTEGER:
12✔
280
        return canConvertNumber<T>(content_.asUnsignedInteger);
12✔
281

282
      case VALUE_IS_SIGNED_INTEGER:
65✔
283
        return canConvertNumber<T>(content_.asSignedInteger);
65✔
284

285
      default:
58✔
286
        return false;
58✔
287
    }
288
  }
289

290
  bool isNull() const {
1,877✔
291
    return type_ == VALUE_IS_NULL;
1,877✔
292
  }
293

294
  static bool isNull(const VariantData* var) {
1,276✔
295
    if (!var)
1,276✔
296
      return true;
731✔
297
    return var->isNull();
545✔
298
  }
299

300
  bool isObject() const {
3,229✔
301
    return type_ == VALUE_IS_OBJECT;
3,229✔
302
  }
303

304
  bool isString() const {
71✔
305
    return type_ == VALUE_IS_LINKED_STRING || type_ == VALUE_IS_OWNED_STRING;
71✔
306
  }
307

308
  size_t nesting(const ResourceManager* resources) const {
44✔
309
    auto collection = asCollection();
44✔
310
    if (collection)
44✔
311
      return collection->nesting(resources);
30✔
312
    else
313
      return 0;
14✔
314
  }
315

316
  static size_t nesting(const VariantData* var,
28✔
317
                        const ResourceManager* resources) {
318
    if (!var)
28✔
319
      return 0;
6✔
320
    return var->nesting(resources);
22✔
321
  }
322

323
  void removeElement(size_t index, ResourceManager* resources) {
9✔
324
    ArrayData::removeElement(asArray(), index, resources);
9✔
325
  }
9✔
326

327
  static void removeElement(VariantData* var, size_t index,
10✔
328
                            ResourceManager* resources) {
329
    if (!var)
10✔
330
      return;
1✔
331
    var->removeElement(index, resources);
9✔
332
  }
333

334
  template <typename TAdaptedString>
335
  void removeMember(TAdaptedString key, ResourceManager* resources) {
14✔
336
    ObjectData::removeMember(asObject(), key, resources);
14✔
337
  }
14✔
338

339
  template <typename TAdaptedString>
340
  static void removeMember(VariantData* var, TAdaptedString key,
15✔
341
                           ResourceManager* resources) {
342
    if (!var)
15✔
343
      return;
1✔
344
    var->removeMember(key, resources);
14✔
345
  }
346

347
  void reset() {
1,882✔
348
    type_ = VALUE_IS_NULL;
1,882✔
349
  }
1,882✔
350

351
  void setBoolean(bool value) {
329✔
352
    type_ = VALUE_IS_BOOLEAN;
329✔
353
    content_.asBoolean = value;
329✔
354
  }
329✔
355

356
  void setBoolean(bool value, ResourceManager* resources) {
248✔
357
    release(resources);
248✔
358
    setBoolean(value);
248✔
359
  }
248✔
360

361
  void setFloat(JsonFloat value) {
231✔
362
    type_ = VALUE_IS_FLOAT;
231✔
363
    content_.asFloat = value;
231✔
364
  }
231✔
365

366
  void setFloat(JsonFloat value, ResourceManager* resources) {
61✔
367
    release(resources);
61✔
368
    setFloat(value);
61✔
369
  }
61✔
370

371
  template <typename T>
372
  enable_if_t<is_signed<T>::value> setInteger(T value) {
1,151✔
373
    type_ = VALUE_IS_SIGNED_INTEGER;
1,151✔
374
    content_.asSignedInteger = value;
1,151✔
375
  }
1,151✔
376

377
  template <typename T>
378
  enable_if_t<is_unsigned<T>::value> setInteger(T value) {
2,310✔
379
    type_ = VALUE_IS_UNSIGNED_INTEGER;
2,310✔
380
    content_.asUnsignedInteger = static_cast<JsonUInt>(value);
2,310✔
381
  }
2,310✔
382

383
  template <typename T>
384
  void setInteger(T value, ResourceManager* resources) {
1,008✔
385
    release(resources);
1,008✔
386
    setInteger(value);
1,008✔
387
  }
1,008✔
388

389
  void setNull() {
67,672✔
390
    type_ = VALUE_IS_NULL;
67,672✔
391
  }
67,672✔
392

393
  void setNull(ResourceManager* resources) {
67,660✔
394
    release(resources);
67,660✔
395
    setNull();
67,660✔
396
  }
67,660✔
397

398
  static void setNull(VariantData* var, ResourceManager* resources) {
485✔
399
    if (!var)
485✔
400
      return;
1✔
401
    var->setNull(resources);
484✔
402
  }
403

404
  void setRawString(StringNode* s) {
87✔
405
    ARDUINOJSON_ASSERT(s);
406
    type_ = VALUE_IS_RAW_STRING;
87✔
407
    content_.asOwnedString = s;
87✔
408
  }
87✔
409

410
  template <typename T>
411
  void setRawString(SerializedValue<T> value, ResourceManager* resources);
412

413
  template <typename T>
414
  static void setRawString(VariantData* var, SerializedValue<T> value,
36✔
415
                           ResourceManager* resources) {
416
    if (!var)
36✔
417
      return;
2✔
418
    var->setRawString(value, resources);
34✔
419
  }
420

421
  template <typename TAdaptedString>
422
  bool setString(TAdaptedString value, ResourceManager* resources);
423

424
  bool setString(StringNode* s, ResourceManager*) {
1,332✔
425
    setOwnedString(s);
1,332✔
426
    return true;
1,332✔
427
  }
428

429
  template <typename TAdaptedString>
430
  static void setString(VariantData* var, TAdaptedString value,
66,080✔
431
                        ResourceManager* resources) {
432
    if (!var)
66,080✔
433
      return;
5✔
434
    var->setString(value, resources);
66,075✔
435
  }
436

437
  void setLinkedString(const char* s) {
1,152✔
438
    ARDUINOJSON_ASSERT(s);
439
    type_ = VALUE_IS_LINKED_STRING;
1,152✔
440
    content_.asLinkedString = s;
1,152✔
441
  }
1,152✔
442

443
  void setOwnedString(StringNode* s) {
1,929✔
444
    ARDUINOJSON_ASSERT(s);
445
    type_ = VALUE_IS_OWNED_STRING;
1,929✔
446
    content_.asOwnedString = s;
1,929✔
447
  }
1,929✔
448

449
  size_t size(const ResourceManager* resources) const {
42✔
450
    if (isObject())
42✔
451
      return content_.asObject.size(resources);
14✔
452

453
    if (isArray())
28✔
454
      return content_.asArray.size(resources);
15✔
455

456
    return 0;
13✔
457
  }
458

459
  static size_t size(const VariantData* var, const ResourceManager* resources) {
30✔
460
    return var != 0 ? var->size(resources) : 0;
30✔
461
  }
462

463
  ArrayData& toArray() {
1,260✔
464
    type_ = VALUE_IS_ARRAY;
1,260✔
465
    new (&content_.asArray) ArrayData();
2,520✔
466
    return content_.asArray;
1,260✔
467
  }
468

469
  ArrayData& toArray(ResourceManager* resources) {
261✔
470
    release(resources);
261✔
471
    return toArray();
261✔
472
  }
473

474
  static ArrayData* toArray(VariantData* var, ResourceManager* resources) {
261✔
475
    if (!var)
261✔
476
      return 0;
×
477
    return &var->toArray(resources);
261✔
478
  }
479

480
  ObjectData& toObject() {
1,324✔
481
    type_ = VALUE_IS_OBJECT;
1,324✔
482
    new (&content_.asObject) ObjectData();
2,648✔
483
    return content_.asObject;
1,324✔
484
  }
485

486
  ObjectData& toObject(ResourceManager* resources) {
315✔
487
    release(resources);
315✔
488
    return toObject();
315✔
489
  }
490

491
  static ObjectData* toObject(VariantData* var, ResourceManager* resources) {
315✔
492
    if (!var)
315✔
493
      return 0;
×
494
    return &var->toObject(resources);
315✔
495
  }
496

497
  uint8_t type() const {
5✔
498
    return type_;
5✔
499
  }
500

501
 private:
502
  void release(ResourceManager* resources);
503
};
504

505
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