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

bblanchon / ArduinoJson / 5377130425

pending completion
5377130425

push

github

bblanchon
Convert "variant functions" to static member functions

126 of 126 new or added lines in 16 files covered. (100.0%)

3385 of 3408 relevant lines covered (99.33%)

6305.9 hits per line

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

99.44
/src/ArduinoJson/Variant/VariantData.hpp
1
// ArduinoJson - https://arduinojson.org
2
// Copyright © 2014-2023, 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
void slotRelease(VariantSlot* slot, ResourceManager* resources);
20

21
class VariantData {
22
  VariantContent content_;  // must be first to allow cast from array to variant
23
  uint8_t flags_;
24

25
 public:
26
  VariantData() : flags_(VALUE_IS_NULL) {}
2,082✔
27

28
  template <typename TVisitor>
29
  typename TVisitor::result_type accept(TVisitor& visitor) const {
138,239✔
30
    switch (type()) {
138,239✔
31
      case VALUE_IS_FLOAT:
135✔
32
        return visitor.visitFloat(content_.asFloat);
135✔
33

34
      case VALUE_IS_ARRAY:
897✔
35
        return visitor.visitArray(content_.asArray);
1,107✔
36

37
      case VALUE_IS_OBJECT:
2,588✔
38
        return visitor.visitObject(content_.asObject);
2,588✔
39

40
      case VALUE_IS_LINKED_STRING:
898✔
41
        return visitor.visitString(content_.asLinkedString,
898✔
42
                                   strlen(content_.asLinkedString));
898✔
43

44
      case VALUE_IS_OWNED_STRING:
282✔
45
        return visitor.visitString(content_.asOwnedString->data,
282✔
46
                                   content_.asOwnedString->length);
282✔
47

48
      case VALUE_IS_RAW_STRING:
55✔
49
        return visitor.visitRawString(content_.asOwnedString->data,
55✔
50
                                      content_.asOwnedString->length);
55✔
51

52
      case VALUE_IS_SIGNED_INTEGER:
1,271✔
53
        return visitor.visitSignedInteger(content_.asSignedInteger);
1,271✔
54

55
      case VALUE_IS_UNSIGNED_INTEGER:
257✔
56
        return visitor.visitUnsignedInteger(content_.asUnsignedInteger);
257✔
57

58
      case VALUE_IS_BOOLEAN:
616✔
59
        return visitor.visitBoolean(content_.asBoolean != 0);
616✔
60

61
      default:
131,240✔
62
        return visitor.visitNull();
131,240✔
63
    }
64
  }
65

66
  template <typename TVisitor>
67
  static typename TVisitor::result_type accept(const VariantData* var,
5,986✔
68
                                               TVisitor& visitor) {
69
    if (var != 0)
5,986✔
70
      return var->accept(visitor);
5,835✔
71
    else
72
      return visitor.visitNull();
151✔
73
  }
74

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

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

86
  bool asBoolean() const {
554✔
87
    switch (type()) {
554✔
88
      case VALUE_IS_BOOLEAN:
307✔
89
        return content_.asBoolean;
307✔
90
      case VALUE_IS_SIGNED_INTEGER:
7✔
91
      case VALUE_IS_UNSIGNED_INTEGER:
92
        return content_.asUnsignedInteger != 0;
7✔
93
      case VALUE_IS_FLOAT:
5✔
94
        return content_.asFloat != 0;
5✔
95
      case VALUE_IS_NULL:
6✔
96
        return false;
6✔
97
      default:
229✔
98
        return true;
229✔
99
    }
100
  }
101

102
  ArrayData* asArray() {
706✔
103
    return isArray() ? &content_.asArray : 0;
706✔
104
  }
105

106
  const ArrayData* asArray() const {
459✔
107
    return const_cast<VariantData*>(this)->asArray();
459✔
108
  }
109

110
  const CollectionData* asCollection() const {
67,927✔
111
    return isCollection() ? &content_.asCollection : 0;
67,927✔
112
  }
113

114
  template <typename T>
115
  T asFloat() const {
117✔
116
    static_assert(is_floating_point<T>::value, "T must be a floating point");
117
    switch (type()) {
117✔
118
      case VALUE_IS_BOOLEAN:
2✔
119
        return static_cast<T>(content_.asBoolean);
2✔
120
      case VALUE_IS_UNSIGNED_INTEGER:
3✔
121
        return static_cast<T>(content_.asUnsignedInteger);
3✔
122
      case VALUE_IS_SIGNED_INTEGER:
6✔
123
        return static_cast<T>(content_.asSignedInteger);
6✔
124
      case VALUE_IS_LINKED_STRING:
1✔
125
      case VALUE_IS_OWNED_STRING:
126
        return parseNumber<T>(content_.asOwnedString->data);
1✔
127
      case VALUE_IS_FLOAT:
103✔
128
        return static_cast<T>(content_.asFloat);
103✔
129
      default:
2✔
130
        return 0;
2✔
131
    }
132
  }
133

134
  template <typename T>
135
  T asIntegral() const {
210✔
136
    static_assert(is_integral<T>::value, "T must be an integral type");
137
    switch (type()) {
210✔
138
      case VALUE_IS_BOOLEAN:
2✔
139
        return content_.asBoolean;
2✔
140
      case VALUE_IS_UNSIGNED_INTEGER:
87✔
141
        return convertNumber<T>(content_.asUnsignedInteger);
87✔
142
      case VALUE_IS_SIGNED_INTEGER:
84✔
143
        return convertNumber<T>(content_.asSignedInteger);
84✔
144
      case VALUE_IS_LINKED_STRING:
6✔
145
        return parseNumber<T>(content_.asLinkedString);
6✔
146
      case VALUE_IS_OWNED_STRING:
2✔
147
        return parseNumber<T>(content_.asOwnedString->data);
2✔
148
      case VALUE_IS_FLOAT:
19✔
149
        return convertNumber<T>(content_.asFloat);
19✔
150
      default:
10✔
151
        return 0;
10✔
152
    }
153
  }
154

155
  ObjectData* asObject() {
2,744✔
156
    return isObject() ? &content_.asObject : 0;
2,744✔
157
  }
158

159
  const ObjectData* asObject() const {
2,152✔
160
    return const_cast<VariantData*>(this)->asObject();
2,152✔
161
  }
162

163
  JsonString asRawString() const {
4✔
164
    switch (type()) {
4✔
165
      case VALUE_IS_RAW_STRING:
4✔
166
        return JsonString(content_.asOwnedString->data,
4✔
167
                          content_.asOwnedString->length, JsonString::Copied);
4✔
168
      default:
×
169
        return JsonString();
×
170
    }
171
  }
172

173
  JsonString asString() const {
444✔
174
    switch (type()) {
444✔
175
      case VALUE_IS_LINKED_STRING:
30✔
176
        return JsonString(content_.asLinkedString, JsonString::Linked);
30✔
177
      case VALUE_IS_OWNED_STRING:
76✔
178
        return JsonString(content_.asOwnedString->data,
76✔
179
                          content_.asOwnedString->length, JsonString::Copied);
76✔
180
      default:
338✔
181
        return JsonString();
338✔
182
    }
183
  }
184

185
  bool copyFrom(const VariantData* src, ResourceManager* resources) {
71✔
186
    release(resources);
71✔
187
    if (!src) {
71✔
188
      setNull();
4✔
189
      return true;
4✔
190
    }
191
    switch (src->type()) {
67✔
192
      case VALUE_IS_ARRAY:
12✔
193
        return toArray().copyFrom(*src->asArray(), resources);
12✔
194
      case VALUE_IS_OBJECT:
17✔
195
        return toObject().copyFrom(*src->asObject(), resources);
17✔
196
      case VALUE_IS_OWNED_STRING: {
11✔
197
        auto str = adaptString(src->asString());
11✔
198
        auto dup = resources->saveString(str);
11✔
199
        if (!dup)
11✔
200
          return false;
1✔
201
        setOwnedString(dup);
10✔
202
        return true;
10✔
203
      }
204
      case VALUE_IS_RAW_STRING: {
4✔
205
        auto str = adaptString(src->asRawString());
4✔
206
        auto dup = resources->saveString(str);
4✔
207
        if (!dup)
4✔
208
          return false;
1✔
209
        setRawString(dup);
3✔
210
        return true;
3✔
211
      }
212
      default:
23✔
213
        content_ = src->content_;
23✔
214
        flags_ = src->flags_;
23✔
215
        return true;
23✔
216
    }
217
  }
218

219
  static bool copy(VariantData* dst, const VariantData* src,
50✔
220
                   ResourceManager* resources) {
221
    if (!dst)
50✔
222
      return false;
1✔
223
    return dst->copyFrom(src, resources);
49✔
224
  }
225

226
  VariantData* getElement(size_t index) const {
424✔
227
    auto array = asArray();
424✔
228
    if (!array)
424✔
229
      return nullptr;
15✔
230
    return array->getElement(index);
409✔
231
  }
232

233
  static VariantData* getElement(const VariantData* var, size_t index) {
429✔
234
    return var != 0 ? var->getElement(index) : 0;
429✔
235
  }
236

237
  template <typename TAdaptedString>
238
  VariantData* getMember(TAdaptedString key) const {
2,135✔
239
    auto object = asObject();
2,135✔
240
    if (!object)
2,135✔
241
      return nullptr;
44✔
242
    return object->getMember(key);
2,091✔
243
  }
244

245
  template <typename TAdaptedString>
246
  static VariantData* getMember(const VariantData* var, TAdaptedString key) {
2,140✔
247
    if (!var)
2,140✔
248
      return 0;
13✔
249
    return var->getMember(key);
2,127✔
250
  }
251

252
  VariantData* getOrAddElement(size_t index, ResourceManager* resources) {
136✔
253
    auto array = isNull() ? &toArray() : asArray();
136✔
254
    if (!array)
136✔
255
      return nullptr;
1✔
256
    return array->getOrAddElement(index, resources);
135✔
257
  }
258

259
  template <typename TAdaptedString>
260
  VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources) {
799✔
261
    if (key.isNull())
799✔
262
      return nullptr;
1✔
263
    auto obj = isNull() ? &toObject() : asObject();
798✔
264
    if (!obj)
798✔
265
      return nullptr;
1✔
266
    return obj->getOrAddMember(key, resources);
797✔
267
  }
268

269
  bool isArray() const {
802✔
270
    return (flags_ & VALUE_IS_ARRAY) != 0;
802✔
271
  }
272

273
  bool isBoolean() const {
35✔
274
    return type() == VALUE_IS_BOOLEAN;
35✔
275
  }
276

277
  bool isCollection() const {
67,966✔
278
    return (flags_ & COLLECTION_MASK) != 0;
67,966✔
279
  }
280

281
  bool isFloat() const {
402✔
282
    return (flags_ & NUMBER_BIT) != 0;
402✔
283
  }
284

285
  template <typename T>
286
  bool isInteger() const {
123✔
287
    switch (type()) {
123✔
288
      case VALUE_IS_UNSIGNED_INTEGER:
12✔
289
        return canConvertNumber<T>(content_.asUnsignedInteger);
12✔
290

291
      case VALUE_IS_SIGNED_INTEGER:
57✔
292
        return canConvertNumber<T>(content_.asSignedInteger);
57✔
293

294
      default:
54✔
295
        return false;
54✔
296
    }
297
  }
298

299
  bool isNull() const {
1,690✔
300
    return type() == VALUE_IS_NULL;
1,690✔
301
  }
302

303
  static bool isNull(const VariantData* var) {
1,237✔
304
    if (!var)
1,237✔
305
      return true;
726✔
306
    return var->isNull();
511✔
307
  }
308

309
  bool isObject() const {
3,094✔
310
    return (flags_ & VALUE_IS_OBJECT) != 0;
3,094✔
311
  }
312

313
  bool isString() const {
62✔
314
    return type() == VALUE_IS_LINKED_STRING || type() == VALUE_IS_OWNED_STRING;
62✔
315
  }
316

317
  size_t memoryUsage() const {
34✔
318
    switch (type()) {
34✔
319
      case VALUE_IS_OWNED_STRING:
10✔
320
      case VALUE_IS_RAW_STRING:
321
        return sizeofString(content_.asOwnedString->length);
10✔
322
      case VALUE_IS_OBJECT:
6✔
323
      case VALUE_IS_ARRAY:
324
        return content_.asCollection.memoryUsage();
6✔
325
      default:
18✔
326
        return 0;
18✔
327
    }
328
  }
329

330
  void movePointers(ptrdiff_t variantDistance) {
22✔
331
    if (flags_ & COLLECTION_MASK)
22✔
332
      content_.asCollection.movePointers(variantDistance);
10✔
333
  }
22✔
334

335
  size_t nesting() const {
21✔
336
    auto collection = asCollection();
21✔
337
    if (!collection)
21✔
338
      return 0;
5✔
339

340
    size_t maxChildNesting = 0;
16✔
341
    for (const VariantSlot* s = collection->head(); s; s = s->next()) {
22✔
342
      size_t childNesting = s->data()->nesting();
6✔
343
      if (childNesting > maxChildNesting)
6✔
344
        maxChildNesting = childNesting;
4✔
345
    }
346
    return maxChildNesting + 1;
16✔
347
  }
348

349
  static size_t nesting(const VariantData* var) {
14✔
350
    if (!var)
14✔
351
      return 0;
3✔
352
    return var->nesting();
11✔
353
  }
354

355
  void operator=(const VariantData& src) {
16✔
356
    content_ = src.content_;
16✔
357
    flags_ = uint8_t((flags_ & OWNED_KEY_BIT) | (src.flags_ & ~OWNED_KEY_BIT));
16✔
358
  }
16✔
359

360
  void removeElement(size_t index, ResourceManager* resources) {
7✔
361
    ArrayData::removeElement(asArray(), index, resources);
7✔
362
  }
7✔
363

364
  static void removeElement(VariantData* var, size_t index,
8✔
365
                            ResourceManager* resources) {
366
    if (!var)
8✔
367
      return;
1✔
368
    var->removeElement(index, resources);
7✔
369
  }
370

371
  template <typename TAdaptedString>
372
  void removeMember(TAdaptedString key, ResourceManager* resources) {
13✔
373
    ObjectData::removeMember(asObject(), key, resources);
13✔
374
  }
13✔
375

376
  template <typename TAdaptedString>
377
  static void removeMember(VariantData* var, TAdaptedString key,
14✔
378
                           ResourceManager* resources) {
379
    if (!var)
14✔
380
      return;
1✔
381
    var->removeMember(key, resources);
13✔
382
  }
383

384
  void reset() {
1,763✔
385
    flags_ = VALUE_IS_NULL;
1,763✔
386
  }
1,763✔
387

388
  void setBoolean(bool value) {
337✔
389
    setType(VALUE_IS_BOOLEAN);
337✔
390
    content_.asBoolean = value;
337✔
391
  }
337✔
392

393
  void setBoolean(bool value, ResourceManager* resources) {
249✔
394
    release(resources);
249✔
395
    setBoolean(value);
249✔
396
  }
249✔
397

398
  void setFloat(JsonFloat value) {
231✔
399
    setType(VALUE_IS_FLOAT);
231✔
400
    content_.asFloat = value;
231✔
401
  }
231✔
402

403
  void setFloat(JsonFloat value, ResourceManager* resources) {
61✔
404
    release(resources);
61✔
405
    setFloat(value);
61✔
406
  }
61✔
407

408
  template <typename T>
409
  typename enable_if<is_signed<T>::value>::type setInteger(T value) {
723✔
410
    setType(VALUE_IS_SIGNED_INTEGER);
723✔
411
    content_.asSignedInteger = value;
723✔
412
  }
723✔
413

414
  template <typename T>
415
  typename enable_if<is_unsigned<T>::value>::type setInteger(T value) {
2,313✔
416
    setType(VALUE_IS_UNSIGNED_INTEGER);
2,313✔
417
    content_.asUnsignedInteger = static_cast<JsonUInt>(value);
2,313✔
418
  }
2,313✔
419

420
  template <typename T>
421
  void setInteger(T value, ResourceManager* resources) {
571✔
422
    release(resources);
571✔
423
    setInteger(value);
571✔
424
  }
571✔
425

426
  void setNull() {
66,444✔
427
    setType(VALUE_IS_NULL);
66,444✔
428
  }
66,444✔
429

430
  void setNull(ResourceManager* resources) {
66,433✔
431
    release(resources);
66,433✔
432
    setNull();
66,433✔
433
  }
66,433✔
434

435
  static void setNull(VariantData* var, ResourceManager* resources) {
409✔
436
    if (!var)
409✔
437
      return;
1✔
438
    var->setNull(resources);
408✔
439
  }
440

441
  void setRawString(StringNode* s) {
30✔
442
    ARDUINOJSON_ASSERT(s);
443
    setType(VALUE_IS_RAW_STRING);
30✔
444
    content_.asOwnedString = s;
30✔
445
  }
30✔
446

447
  template <typename T>
448
  void setRawString(SerializedValue<T> value, ResourceManager* resources) {
30✔
449
    release(resources);
30✔
450
    auto dup = resources->saveString(adaptString(value.data(), value.size()));
30✔
451
    if (dup)
30✔
452
      setRawString(dup);
27✔
453
    else
454
      setNull();
3✔
455
  }
30✔
456

457
  template <typename T>
458
  static void setRawString(VariantData* var, SerializedValue<T> value,
33✔
459
                           ResourceManager* resources) {
460
    if (!var)
33✔
461
      return;
3✔
462
    var->setRawString(value, resources);
30✔
463
  }
464

465
  template <typename TAdaptedString>
466
  void setString(TAdaptedString value, ResourceManager* resources) {
65,954✔
467
    setNull(resources);
65,954✔
468

469
    if (value.isNull())
65,954✔
470
      return;
65,553✔
471

472
    if (value.isLinked()) {
401✔
473
      setLinkedString(value.data());
300✔
474
      return;
300✔
475
    }
476

477
    auto dup = resources->saveString(value);
101✔
478
    if (dup)
101✔
479
      setOwnedString(dup);
98✔
480
  }
481

482
  template <typename TAdaptedString>
483
  static void setString(VariantData* var, TAdaptedString value,
65,960✔
484
                        ResourceManager* resources) {
485
    if (!var)
65,960✔
486
      return;
6✔
487
    var->setString(value, resources);
65,954✔
488
  }
489

490
  void setLinkedString(const char* s) {
300✔
491
    ARDUINOJSON_ASSERT(s);
492
    setType(VALUE_IS_LINKED_STRING);
300✔
493
    content_.asLinkedString = s;
300✔
494
  }
300✔
495

496
  void setOwnedString(StringNode* s) {
469✔
497
    ARDUINOJSON_ASSERT(s);
498
    setType(VALUE_IS_OWNED_STRING);
469✔
499
    content_.asOwnedString = s;
469✔
500
  }
469✔
501

502
  size_t size() const {
39✔
503
    return isCollection() ? content_.asCollection.size() : 0;
39✔
504
  }
505

506
  static size_t size(const VariantData* var) {
30✔
507
    return var != 0 ? var->size() : 0;
30✔
508
  }
509

510
  ArrayData& toArray() {
1,217✔
511
    setType(VALUE_IS_ARRAY);
1,217✔
512
    new (&content_.asArray) ArrayData();
2,434✔
513
    return content_.asArray;
1,217✔
514
  }
515

516
  ArrayData& toArray(ResourceManager* resources) {
220✔
517
    release(resources);
220✔
518
    return toArray();
220✔
519
  }
520

521
  static ArrayData* toArray(VariantData* var, ResourceManager* resources) {
222✔
522
    if (!var)
222✔
523
      return 0;
2✔
524
    return &var->toArray(resources);
220✔
525
  }
526

527
  ObjectData& toObject() {
1,269✔
528
    setType(VALUE_IS_OBJECT);
1,269✔
529
    new (&content_.asObject) ObjectData();
2,538✔
530
    return content_.asObject;
1,269✔
531
  }
532

533
  ObjectData& toObject(ResourceManager* resources) {
271✔
534
    release(resources);
271✔
535
    return toObject();
271✔
536
  }
537

538
  static ObjectData* toObject(VariantData* var, ResourceManager* resources) {
273✔
539
    if (!var)
273✔
540
      return 0;
2✔
541
    return &var->toObject(resources);
271✔
542
  }
543

544
  uint8_t type() const {
141,630✔
545
    return flags_ & VALUE_MASK;
141,630✔
546
  }
547

548
 private:
549
  void release(ResourceManager* resources) {
67,906✔
550
    if (flags_ & OWNED_VALUE_BIT)
67,906✔
551
      resources->dereferenceString(content_.asOwnedString->data);
11✔
552

553
    auto c = asCollection();
67,906✔
554
    if (c) {
67,906✔
555
      for (auto slot = c->head(); slot; slot = slot->next())
29✔
556
        slotRelease(slot, resources);
14✔
557
    }
558
  }
67,906✔
559

560
  void setType(uint8_t t) {
73,333✔
561
    flags_ &= OWNED_KEY_BIT;
73,333✔
562
    flags_ |= t;
73,333✔
563
  }
73,333✔
564
};
565

566
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