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

bblanchon / ArduinoJson / 10537406384

24 Aug 2024 09:18AM UTC coverage: 99.511% (+0.03%) from 99.484%
10537406384

push

github

bblanchon
Rename `flags_` to `type_`

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

4 existing lines in 3 files now uncovered.

3863 of 3882 relevant lines covered (99.51%)

10873.43 hits per line

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

99.03
/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/StringNode.hpp>
8
#include <ArduinoJson/Misc/SerializedValue.hpp>
9
#include <ArduinoJson/Numbers/convertNumber.hpp>
10
#include <ArduinoJson/Strings/JsonString.hpp>
11
#include <ArduinoJson/Strings/StringAdapters.hpp>
12
#include <ArduinoJson/Variant/VariantContent.hpp>
13
#include <ArduinoJson/Variant/VariantSlot.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

24
 public:
25
  VariantData() : type_(VALUE_IS_NULL) {}
2,090✔
26

27
  template <typename TVisitor>
28
  typename TVisitor::result_type accept(TVisitor& visit) const {
139,239✔
29
    switch (type_) {
139,239✔
30
      case VALUE_IS_FLOAT:
135✔
31
        return visit.visit(content_.asFloat);
135✔
32

33
      case VALUE_IS_ARRAY:
967✔
34
        return visit.visit(content_.asArray);
967✔
35

36
      case VALUE_IS_OBJECT:
2,661✔
37
        return visit.visit(content_.asObject);
2,661✔
38

39
      case VALUE_IS_LINKED_STRING:
1,160✔
40
        return visit.visit(JsonString(content_.asLinkedString));
1,160✔
41

42
      case VALUE_IS_OWNED_STRING:
917✔
43
        return visit.visit(JsonString(content_.asOwnedString->data,
917✔
44
                                      content_.asOwnedString->length,
917✔
45
                                      JsonString::Copied));
917✔
46

47
      case VALUE_IS_RAW_STRING:
125✔
48
        return visit.visit(RawString(content_.asOwnedString->data,
125✔
49
                                     content_.asOwnedString->length));
125✔
50

51
      case VALUE_IS_SIGNED_INTEGER:
1,181✔
52
        return visit.visit(content_.asSignedInteger);
1,181✔
53

54
      case VALUE_IS_UNSIGNED_INTEGER:
261✔
55
        return visit.visit(content_.asUnsignedInteger);
261✔
56

57
      case VALUE_IS_BOOLEAN:
606✔
58
        return visit.visit(content_.asBoolean != 0);
606✔
59

60
      default:
131,226✔
61
        return visit.visit(nullptr);
131,226✔
62
    }
63
  }
64

65
  template <typename TVisitor>
66
  static typename TVisitor::result_type accept(const VariantData* var,
698✔
67
                                               TVisitor& visit) {
68
    if (var != 0)
698✔
69
      return var->accept(visit);
695✔
70
    else
71
      return visit.visit(nullptr);
3✔
72
  }
73

74
  VariantData* addElement(ResourceManager* resources) {
157✔
75
    auto array = isNull() ? &toArray() : asArray();
157✔
76
    return detail::ArrayData::addElement(array, resources);
157✔
77
  }
78

79
  static VariantData* addElement(VariantData* var, ResourceManager* resources) {
41✔
80
    if (!var)
41✔
81
      return nullptr;
6✔
82
    return var->addElement(resources);
35✔
83
  }
84

85
  template <typename T>
86
  bool addValue(T&& value, ResourceManager* resources) {
124✔
87
    auto array = isNull() ? &toArray() : asArray();
124✔
88
    return detail::ArrayData::addValue(array, detail::forward<T>(value),
124✔
89
                                       resources);
124✔
90
  }
91

92
  template <typename T>
93
  static bool addValue(VariantData* var, T&& value,
43✔
94
                       ResourceManager* resources) {
95
    if (!var)
43✔
96
      return false;
6✔
97
    return var->addValue(value, resources);
37✔
98
  }
99

100
  bool asBoolean() const {
551✔
101
    switch (type_) {
551✔
102
      case VALUE_IS_BOOLEAN:
304✔
103
        return content_.asBoolean;
304✔
104
      case VALUE_IS_SIGNED_INTEGER:
7✔
105
      case VALUE_IS_UNSIGNED_INTEGER:
106
        return content_.asUnsignedInteger != 0;
7✔
107
      case VALUE_IS_FLOAT:
5✔
108
        return content_.asFloat != 0;
5✔
109
      case VALUE_IS_NULL:
6✔
110
        return false;
6✔
111
      default:
229✔
112
        return true;
229✔
113
    }
114
  }
115

116
  ArrayData* asArray() {
760✔
117
    return isArray() ? &content_.asArray : 0;
760✔
118
  }
119

120
  const ArrayData* asArray() const {
481✔
121
    return const_cast<VariantData*>(this)->asArray();
481✔
122
  }
123

124
  CollectionData* asCollection() {
69,631✔
125
    return isCollection() ? &content_.asCollection : 0;
69,631✔
126
  }
127

128
  const CollectionData* asCollection() const {
44✔
129
    return const_cast<VariantData*>(this)->asCollection();
44✔
130
  }
131

132
  template <typename T>
133
  T asFloat() const {
117✔
134
    static_assert(is_floating_point<T>::value, "T must be a floating point");
135
    switch (type_) {
117✔
136
      case VALUE_IS_BOOLEAN:
2✔
137
        return static_cast<T>(content_.asBoolean);
2✔
138
      case VALUE_IS_UNSIGNED_INTEGER:
3✔
139
        return static_cast<T>(content_.asUnsignedInteger);
3✔
140
      case VALUE_IS_SIGNED_INTEGER:
6✔
141
        return static_cast<T>(content_.asSignedInteger);
6✔
142
      case VALUE_IS_LINKED_STRING:
1✔
143
      case VALUE_IS_OWNED_STRING:
144
        return parseNumber<T>(content_.asOwnedString->data);
1✔
145
      case VALUE_IS_FLOAT:
103✔
146
        return static_cast<T>(content_.asFloat);
103✔
147
      default:
2✔
148
        return 0;
2✔
149
    }
150
  }
151

152
  template <typename T>
153
  T asIntegral() const {
224✔
154
    static_assert(is_integral<T>::value, "T must be an integral type");
155
    switch (type_) {
224✔
156
      case VALUE_IS_BOOLEAN:
2✔
157
        return content_.asBoolean;
2✔
158
      case VALUE_IS_UNSIGNED_INTEGER:
89✔
159
        return convertNumber<T>(content_.asUnsignedInteger);
89✔
160
      case VALUE_IS_SIGNED_INTEGER:
96✔
161
        return convertNumber<T>(content_.asSignedInteger);
96✔
162
      case VALUE_IS_LINKED_STRING:
6✔
163
        return parseNumber<T>(content_.asLinkedString);
6✔
164
      case VALUE_IS_OWNED_STRING:
2✔
165
        return parseNumber<T>(content_.asOwnedString->data);
2✔
166
      case VALUE_IS_FLOAT:
19✔
167
        return convertNumber<T>(content_.asFloat);
19✔
168
      default:
10✔
169
        return 0;
10✔
170
    }
171
  }
172

173
  ObjectData* asObject() {
2,845✔
174
    return isObject() ? &content_.asObject : 0;
2,845✔
175
  }
176

177
  const ObjectData* asObject() const {
2,175✔
178
    return const_cast<VariantData*>(this)->asObject();
2,175✔
179
  }
180

181
  JsonString asRawString() const {
38✔
182
    switch (type_) {
38✔
183
      case VALUE_IS_RAW_STRING:
26✔
184
        return JsonString(content_.asOwnedString->data,
26✔
185
                          content_.asOwnedString->length, JsonString::Copied);
26✔
186
      default:
12✔
187
        return JsonString();
12✔
188
    }
189
  }
190

191
  JsonString asString() const {
12,368✔
192
    switch (type_) {
12,368✔
193
      case VALUE_IS_LINKED_STRING:
4,512✔
194
        return JsonString(content_.asLinkedString, JsonString::Linked);
4,512✔
195
      case VALUE_IS_OWNED_STRING:
7,453✔
196
        return JsonString(content_.asOwnedString->data,
7,453✔
197
                          content_.asOwnedString->length, JsonString::Copied);
7,453✔
198
      default:
403✔
199
        return JsonString();
403✔
200
    }
201
  }
202

203
  VariantData* getElement(size_t index,
448✔
204
                          const ResourceManager* resources) const {
205
    return ArrayData::getElement(asArray(), index, resources);
448✔
206
  }
207

208
  static VariantData* getElement(const VariantData* var, size_t index,
451✔
209
                                 const ResourceManager* resources) {
210
    return var != 0 ? var->getElement(index, resources) : 0;
451✔
211
  }
212

213
  template <typename TAdaptedString>
214
  VariantData* getMember(TAdaptedString key,
2,141✔
215
                         const ResourceManager* resources) const {
216
    return ObjectData::getMember(asObject(), key, resources);
2,141✔
217
  }
218

219
  template <typename TAdaptedString>
220
  static VariantData* getMember(const VariantData* var, TAdaptedString key,
2,141✔
221
                                const ResourceManager* resources) {
222
    if (!var)
2,141✔
223
      return 0;
13✔
224
    return var->getMember(key, resources);
2,128✔
225
  }
226

227
  VariantData* getOrAddElement(size_t index, ResourceManager* resources) {
150✔
228
    auto array = isNull() ? &toArray() : asArray();
150✔
229
    if (!array)
150✔
230
      return nullptr;
1✔
231
    return array->getOrAddElement(index, resources);
149✔
232
  }
233

234
  template <typename TAdaptedString>
235
  VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources) {
899✔
236
    if (key.isNull())
899✔
237
      return nullptr;
1✔
238
    auto obj = isNull() ? &toObject() : asObject();
898✔
239
    if (!obj)
898✔
240
      return nullptr;
×
241
    return obj->getOrAddMember(key, resources);
898✔
242
  }
243

244
  bool isArray() const {
877✔
245
    return type_ == VALUE_IS_ARRAY;
877✔
246
  }
247

248
  bool isBoolean() const {
35✔
249
    return type_ == VALUE_IS_BOOLEAN;
35✔
250
  }
251

252
  bool isCollection() const {
69,631✔
253
    return (type_ & COLLECTION_MASK) != 0;
69,631✔
254
  }
255

256
  bool isFloat() const {
402✔
257
    return (type_ & NUMBER_BIT) != 0;
402✔
258
  }
259

260
  template <typename T>
261
  bool isInteger() const {
135✔
262
    switch (type_) {
135✔
263
      case VALUE_IS_UNSIGNED_INTEGER:
12✔
264
        return canConvertNumber<T>(content_.asUnsignedInteger);
12✔
265

266
      case VALUE_IS_SIGNED_INTEGER:
65✔
267
        return canConvertNumber<T>(content_.asSignedInteger);
65✔
268

269
      default:
58✔
270
        return false;
58✔
271
    }
272
  }
273

274
  bool isNull() const {
1,877✔
275
    return type_ == VALUE_IS_NULL;
1,877✔
276
  }
277

278
  static bool isNull(const VariantData* var) {
1,276✔
279
    if (!var)
1,276✔
280
      return true;
731✔
281
    return var->isNull();
545✔
282
  }
283

284
  bool isObject() const {
3,229✔
285
    return type_ == VALUE_IS_OBJECT;
3,229✔
286
  }
287

288
  bool isString() const {
71✔
289
    return type_ == VALUE_IS_LINKED_STRING || type_ == VALUE_IS_OWNED_STRING;
71✔
290
  }
291

292
  size_t nesting(const ResourceManager* resources) const {
44✔
293
    auto collection = asCollection();
44✔
294
    if (collection)
44✔
295
      return collection->nesting(resources);
30✔
296
    else
297
      return 0;
14✔
298
  }
299

300
  static size_t nesting(const VariantData* var,
28✔
301
                        const ResourceManager* resources) {
302
    if (!var)
28✔
303
      return 0;
6✔
304
    return var->nesting(resources);
22✔
305
  }
306

307
  void removeElement(size_t index, ResourceManager* resources) {
9✔
308
    ArrayData::removeElement(asArray(), index, resources);
9✔
309
  }
9✔
310

311
  static void removeElement(VariantData* var, size_t index,
10✔
312
                            ResourceManager* resources) {
313
    if (!var)
10✔
314
      return;
1✔
315
    var->removeElement(index, resources);
9✔
316
  }
317

318
  template <typename TAdaptedString>
319
  void removeMember(TAdaptedString key, ResourceManager* resources) {
14✔
320
    ObjectData::removeMember(asObject(), key, resources);
14✔
321
  }
14✔
322

323
  template <typename TAdaptedString>
324
  static void removeMember(VariantData* var, TAdaptedString key,
15✔
325
                           ResourceManager* resources) {
326
    if (!var)
15✔
327
      return;
1✔
328
    var->removeMember(key, resources);
14✔
329
  }
330

331
  void reset() {
1,882✔
332
    type_ = VALUE_IS_NULL;
1,882✔
333
  }
1,882✔
334

335
  void setBoolean(bool value) {
329✔
336
    type_ = VALUE_IS_BOOLEAN;
329✔
337
    content_.asBoolean = value;
329✔
338
  }
329✔
339

340
  void setBoolean(bool value, ResourceManager* resources) {
248✔
341
    release(resources);
248✔
342
    setBoolean(value);
248✔
343
  }
248✔
344

345
  void setFloat(JsonFloat value) {
231✔
346
    type_ = VALUE_IS_FLOAT;
231✔
347
    content_.asFloat = value;
231✔
348
  }
231✔
349

350
  void setFloat(JsonFloat value, ResourceManager* resources) {
61✔
351
    release(resources);
61✔
352
    setFloat(value);
61✔
353
  }
61✔
354

355
  template <typename T>
356
  enable_if_t<is_signed<T>::value> setInteger(T value) {
1,151✔
357
    type_ = VALUE_IS_SIGNED_INTEGER;
1,151✔
358
    content_.asSignedInteger = value;
1,151✔
359
  }
1,151✔
360

361
  template <typename T>
362
  enable_if_t<is_unsigned<T>::value> setInteger(T value) {
2,310✔
363
    type_ = VALUE_IS_UNSIGNED_INTEGER;
2,310✔
364
    content_.asUnsignedInteger = static_cast<JsonUInt>(value);
2,310✔
365
  }
2,310✔
366

367
  template <typename T>
368
  void setInteger(T value, ResourceManager* resources) {
1,008✔
369
    release(resources);
1,008✔
370
    setInteger(value);
1,008✔
371
  }
1,008✔
372

373
  void setNull() {
67,672✔
374
    type_ = VALUE_IS_NULL;
67,672✔
375
  }
67,672✔
376

377
  void setNull(ResourceManager* resources) {
67,660✔
378
    release(resources);
67,660✔
379
    setNull();
67,660✔
380
  }
67,660✔
381

382
  static void setNull(VariantData* var, ResourceManager* resources) {
485✔
383
    if (!var)
485✔
384
      return;
1✔
385
    var->setNull(resources);
484✔
386
  }
387

388
  void setRawString(StringNode* s) {
87✔
389
    ARDUINOJSON_ASSERT(s);
390
    type_ = VALUE_IS_RAW_STRING;
87✔
391
    content_.asOwnedString = s;
87✔
392
  }
87✔
393

394
  template <typename T>
395
  void setRawString(SerializedValue<T> value, ResourceManager* resources) {
34✔
396
    release(resources);
34✔
397
    auto dup = resources->saveString(adaptString(value.data(), value.size()));
34✔
398
    if (dup)
34✔
399
      setRawString(dup);
30✔
400
    else
401
      setNull();
4✔
402
  }
34✔
403

404
  template <typename T>
405
  static void setRawString(VariantData* var, SerializedValue<T> value,
36✔
406
                           ResourceManager* resources) {
407
    if (!var)
36✔
408
      return;
2✔
409
    var->setRawString(value, resources);
34✔
410
  }
411

412
  template <typename TAdaptedString>
413
  bool setString(TAdaptedString value, ResourceManager* resources) {
66,936✔
414
    setNull(resources);
66,936✔
415

416
    if (value.isNull())
66,936✔
417
      return false;
65,553✔
418

419
    if (value.isLinked()) {
1,383✔
420
      setLinkedString(value.data());
1,152✔
421
      return true;
1,152✔
422
    }
423

424
    auto dup = resources->saveString(value);
231✔
425
    if (dup) {
231✔
426
      setOwnedString(dup);
219✔
427
      return true;
219✔
428
    }
429

430
    return false;
12✔
431
  }
432

433
  bool setString(StringNode* s, ResourceManager*) {
1,332✔
434
    setOwnedString(s);
1,332✔
435
    return true;
1,332✔
436
  }
437

438
  template <typename TAdaptedString>
439
  static void setString(VariantData* var, TAdaptedString value,
66,080✔
440
                        ResourceManager* resources) {
441
    if (!var)
66,080✔
442
      return;
5✔
443
    var->setString(value, resources);
66,075✔
444
  }
445

446
  void setLinkedString(const char* s) {
1,152✔
447
    ARDUINOJSON_ASSERT(s);
448
    type_ = VALUE_IS_LINKED_STRING;
1,152✔
449
    content_.asLinkedString = s;
1,152✔
450
  }
1,152✔
451

452
  void setOwnedString(StringNode* s) {
1,929✔
453
    ARDUINOJSON_ASSERT(s);
454
    type_ = VALUE_IS_OWNED_STRING;
1,929✔
455
    content_.asOwnedString = s;
1,929✔
456
  }
1,929✔
457

458
  size_t size(const ResourceManager* resources) const {
42✔
459
    if (isObject())
42✔
460
      return content_.asObject.size(resources);
14✔
461

462
    if (isArray())
28✔
463
      return content_.asArray.size(resources);
15✔
464

465
    return 0;
13✔
466
  }
467

468
  static size_t size(const VariantData* var, const ResourceManager* resources) {
30✔
469
    return var != 0 ? var->size(resources) : 0;
30✔
470
  }
471

472
  ArrayData& toArray() {
1,260✔
473
    type_ = VALUE_IS_ARRAY;
1,260✔
474
    new (&content_.asArray) ArrayData();
2,520✔
475
    return content_.asArray;
1,260✔
476
  }
477

478
  ArrayData& toArray(ResourceManager* resources) {
261✔
479
    release(resources);
261✔
480
    return toArray();
261✔
481
  }
482

483
  static ArrayData* toArray(VariantData* var, ResourceManager* resources) {
261✔
484
    if (!var)
261✔
UNCOV
485
      return 0;
×
486
    return &var->toArray(resources);
261✔
487
  }
488

489
  ObjectData& toObject() {
1,324✔
490
    type_ = VALUE_IS_OBJECT;
1,324✔
491
    new (&content_.asObject) ObjectData();
2,648✔
492
    return content_.asObject;
1,324✔
493
  }
494

495
  ObjectData& toObject(ResourceManager* resources) {
315✔
496
    release(resources);
315✔
497
    return toObject();
315✔
498
  }
499

500
  static ObjectData* toObject(VariantData* var, ResourceManager* resources) {
315✔
501
    if (!var)
315✔
UNCOV
502
      return 0;
×
503
    return &var->toObject(resources);
315✔
504
  }
505

506
  uint8_t type() const {
5✔
507
    return type_;
5✔
508
  }
509

510
 private:
511
  void release(ResourceManager* resources) {
69,587✔
512
    if (type_ & OWNED_VALUE_BIT)
69,587✔
513
      resources->dereferenceString(content_.asOwnedString->data);
25✔
514

515
    auto collection = asCollection();
69,587✔
516
    if (collection)
69,587✔
517
      collection->clear(resources);
17✔
518
  }
69,587✔
519
};
520

521
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