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

bblanchon / ArduinoJson / 9131102872

17 May 2024 03:10PM CUT coverage: 99.553% (-0.001%) from 99.554%
9131102872

push

github

bblanchon
Move `CollectionData::releaseSlot()` to `ResourceManager::freeSlot()`

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

3790 of 3807 relevant lines covered (99.55%)

10947.29 hits per line

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

98.99
/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 flags_;
23

24
 public:
25
  VariantData() : flags_(VALUE_IS_NULL) {}
2,042✔
26

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

109
  CollectionData* asCollection() {
68,675✔
110
    return isCollection() ? &content_.asCollection : 0;
68,675✔
111
  }
112

113
  const CollectionData* asCollection() const {
38✔
114
    return const_cast<VariantData*>(this)->asCollection();
38✔
115
  }
116

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

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

158
  ObjectData* asObject() {
2,825✔
159
    return isObject() ? &content_.asObject : 0;
2,825✔
160
  }
161

162
  const ObjectData* asObject() const {
2,169✔
163
    return const_cast<VariantData*>(this)->asObject();
2,169✔
164
  }
165

166
  JsonString asRawString() const {
13✔
167
    switch (type()) {
13✔
168
      case VALUE_IS_RAW_STRING:
7✔
169
        return JsonString(content_.asOwnedString->data,
7✔
170
                          content_.asOwnedString->length, JsonString::Copied);
7✔
171
      default:
6✔
172
        return JsonString();
6✔
173
    }
174
  }
175

176
  JsonString asString() const {
516✔
177
    switch (type()) {
516✔
178
      case VALUE_IS_LINKED_STRING:
44✔
179
        return JsonString(content_.asLinkedString, JsonString::Linked);
44✔
180
      case VALUE_IS_OWNED_STRING:
68✔
181
        return JsonString(content_.asOwnedString->data,
68✔
182
                          content_.asOwnedString->length, JsonString::Copied);
68✔
183
      default:
404✔
184
        return JsonString();
404✔
185
    }
186
  }
187

188
  VariantData* getElement(size_t index,
448✔
189
                          const ResourceManager* resources) const {
190
    return ArrayData::getElement(asArray(), index, resources);
448✔
191
  }
192

193
  static VariantData* getElement(const VariantData* var, size_t index,
451✔
194
                                 const ResourceManager* resources) {
195
    return var != 0 ? var->getElement(index, resources) : 0;
451✔
196
  }
197

198
  template <typename TAdaptedString>
199
  VariantData* getMember(TAdaptedString key,
2,141✔
200
                         const ResourceManager* resources) const {
201
    return ObjectData::getMember(asObject(), key, resources);
2,141✔
202
  }
203

204
  template <typename TAdaptedString>
205
  static VariantData* getMember(const VariantData* var, TAdaptedString key,
2,141✔
206
                                const ResourceManager* resources) {
207
    if (!var)
2,141✔
208
      return 0;
13✔
209
    return var->getMember(key, resources);
2,128✔
210
  }
211

212
  VariantData* getOrAddElement(size_t index, ResourceManager* resources) {
149✔
213
    auto array = isNull() ? &toArray() : asArray();
149✔
214
    if (!array)
149✔
215
      return nullptr;
1✔
216
    return array->getOrAddElement(index, resources);
148✔
217
  }
218

219
  template <typename TAdaptedString>
220
  VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources) {
883✔
221
    if (key.isNull())
883✔
222
      return nullptr;
1✔
223
    auto obj = isNull() ? &toObject() : asObject();
882✔
224
    if (!obj)
882✔
225
      return nullptr;
×
226
    return obj->getOrAddMember(key, resources);
882✔
227
  }
228

229
  bool isArray() const {
849✔
230
    return (flags_ & VALUE_IS_ARRAY) != 0;
849✔
231
  }
232

233
  bool isBoolean() const {
35✔
234
    return type() == VALUE_IS_BOOLEAN;
35✔
235
  }
236

237
  bool isCollection() const {
68,715✔
238
    return (flags_ & COLLECTION_MASK) != 0;
68,715✔
239
  }
240

241
  bool isFloat() const {
402✔
242
    return (flags_ & NUMBER_BIT) != 0;
402✔
243
  }
244

245
  template <typename T>
246
  bool isInteger() const {
135✔
247
    switch (type()) {
135✔
248
      case VALUE_IS_UNSIGNED_INTEGER:
12✔
249
        return canConvertNumber<T>(content_.asUnsignedInteger);
12✔
250

251
      case VALUE_IS_SIGNED_INTEGER:
65✔
252
        return canConvertNumber<T>(content_.asSignedInteger);
65✔
253

254
      default:
58✔
255
        return false;
58✔
256
    }
257
  }
258

259
  bool isNull() const {
1,850✔
260
    return type() == VALUE_IS_NULL;
1,850✔
261
  }
262

263
  static bool isNull(const VariantData* var) {
1,270✔
264
    if (!var)
1,270✔
265
      return true;
731✔
266
    return var->isNull();
539✔
267
  }
268

269
  bool isObject() const {
3,165✔
270
    return (flags_ & VALUE_IS_OBJECT) != 0;
3,165✔
271
  }
272

273
  bool isString() const {
71✔
274
    return type() == VALUE_IS_LINKED_STRING || type() == VALUE_IS_OWNED_STRING;
71✔
275
  }
276

277
  size_t nesting(const ResourceManager* resources) const {
38✔
278
    auto collection = asCollection();
38✔
279
    if (collection)
38✔
280
      return collection->nesting(resources);
30✔
281
    else
282
      return 0;
8✔
283
  }
284

285
  static size_t nesting(const VariantData* var,
28✔
286
                        const ResourceManager* resources) {
287
    if (!var)
28✔
288
      return 0;
6✔
289
    return var->nesting(resources);
22✔
290
  }
291

292
  void removeElement(size_t index, ResourceManager* resources) {
9✔
293
    ArrayData::removeElement(asArray(), index, resources);
9✔
294
  }
9✔
295

296
  static void removeElement(VariantData* var, size_t index,
10✔
297
                            ResourceManager* resources) {
298
    if (!var)
10✔
299
      return;
1✔
300
    var->removeElement(index, resources);
9✔
301
  }
302

303
  template <typename TAdaptedString>
304
  void removeMember(TAdaptedString key, ResourceManager* resources) {
14✔
305
    ObjectData::removeMember(asObject(), key, resources);
14✔
306
  }
14✔
307

308
  template <typename TAdaptedString>
309
  static void removeMember(VariantData* var, TAdaptedString key,
15✔
310
                           ResourceManager* resources) {
311
    if (!var)
15✔
312
      return;
1✔
313
    var->removeMember(key, resources);
14✔
314
  }
315

316
  void reset() {
1,847✔
317
    flags_ = VALUE_IS_NULL;
1,847✔
318
  }
1,847✔
319

320
  void setBoolean(bool value) {
329✔
321
    setType(VALUE_IS_BOOLEAN);
329✔
322
    content_.asBoolean = value;
329✔
323
  }
329✔
324

325
  void setBoolean(bool value, ResourceManager* resources) {
248✔
326
    release(resources);
248✔
327
    setBoolean(value);
248✔
328
  }
248✔
329

330
  void setFloat(JsonFloat value) {
231✔
331
    setType(VALUE_IS_FLOAT);
231✔
332
    content_.asFloat = value;
231✔
333
  }
231✔
334

335
  void setFloat(JsonFloat value, ResourceManager* resources) {
61✔
336
    release(resources);
61✔
337
    setFloat(value);
61✔
338
  }
61✔
339

340
  template <typename T>
341
  typename enable_if<is_signed<T>::value>::type setInteger(T value) {
1,155✔
342
    setType(VALUE_IS_SIGNED_INTEGER);
1,155✔
343
    content_.asSignedInteger = value;
1,155✔
344
  }
1,155✔
345

346
  template <typename T>
347
  typename enable_if<is_unsigned<T>::value>::type setInteger(T value) {
2,308✔
348
    setType(VALUE_IS_UNSIGNED_INTEGER);
2,308✔
349
    content_.asUnsignedInteger = static_cast<JsonUInt>(value);
2,308✔
350
  }
2,308✔
351

352
  template <typename T>
353
  void setInteger(T value, ResourceManager* resources) {
1,004✔
354
    release(resources);
1,004✔
355
    setInteger(value);
1,004✔
356
  }
1,004✔
357

358
  void setNull() {
66,732✔
359
    setType(VALUE_IS_NULL);
66,732✔
360
  }
66,732✔
361

362
  void setNull(ResourceManager* resources) {
66,722✔
363
    release(resources);
66,722✔
364
    setNull();
66,722✔
365
  }
66,722✔
366

367
  static void setNull(VariantData* var, ResourceManager* resources) {
465✔
368
    if (!var)
465✔
369
      return;
1✔
370
    var->setNull(resources);
464✔
371
  }
372

373
  void setRawString(StringNode* s) {
51✔
374
    ARDUINOJSON_ASSERT(s);
375
    setType(VALUE_IS_RAW_STRING);
51✔
376
    content_.asOwnedString = s;
51✔
377
  }
51✔
378

379
  template <typename T>
380
  void setRawString(SerializedValue<T> value, ResourceManager* resources) {
34✔
381
    release(resources);
34✔
382
    auto dup = resources->saveString(adaptString(value.data(), value.size()));
34✔
383
    if (dup)
34✔
384
      setRawString(dup);
30✔
385
    else
386
      setNull();
4✔
387
  }
34✔
388

389
  template <typename T>
390
  static void setRawString(VariantData* var, SerializedValue<T> value,
37✔
391
                           ResourceManager* resources) {
392
    if (!var)
37✔
393
      return;
3✔
394
    var->setRawString(value, resources);
34✔
395
  }
396

397
  template <typename TAdaptedString>
398
  void setString(TAdaptedString value, ResourceManager* resources) {
66,062✔
399
    setNull(resources);
66,062✔
400

401
    if (value.isNull())
66,062✔
402
      return;
65,553✔
403

404
    if (value.isLinked()) {
509✔
405
      setLinkedString(value.data());
376✔
406
      return;
376✔
407
    }
408

409
    auto dup = resources->saveString(value);
133✔
410
    if (dup)
133✔
411
      setOwnedString(dup);
126✔
412
  }
413

414
  template <typename TAdaptedString>
415
  static void setString(VariantData* var, TAdaptedString value,
66,067✔
416
                        ResourceManager* resources) {
417
    if (!var)
66,067✔
418
      return;
5✔
419
    var->setString(value, resources);
66,062✔
420
  }
421

422
  void setLinkedString(const char* s) {
376✔
423
    ARDUINOJSON_ASSERT(s);
424
    setType(VALUE_IS_LINKED_STRING);
376✔
425
    content_.asLinkedString = s;
376✔
426
  }
376✔
427

428
  void setOwnedString(StringNode* s) {
504✔
429
    ARDUINOJSON_ASSERT(s);
430
    setType(VALUE_IS_OWNED_STRING);
504✔
431
    content_.asOwnedString = s;
504✔
432
  }
504✔
433

434
  size_t size(const ResourceManager* resources) const {
40✔
435
    return isCollection() ? content_.asCollection.size(resources) : 0;
40✔
436
  }
437

438
  static size_t size(const VariantData* var, const ResourceManager* resources) {
30✔
439
    return var != 0 ? var->size(resources) : 0;
30✔
440
  }
441

442
  ArrayData& toArray() {
1,259✔
443
    setType(VALUE_IS_ARRAY);
1,259✔
444
    new (&content_.asArray) ArrayData();
2,518✔
445
    return content_.asArray;
1,259✔
446
  }
447

448
  ArrayData& toArray(ResourceManager* resources) {
257✔
449
    release(resources);
257✔
450
    return toArray();
257✔
451
  }
452

453
  static ArrayData* toArray(VariantData* var, ResourceManager* resources) {
257✔
454
    if (!var)
257✔
455
      return 0;
×
456
    return &var->toArray(resources);
257✔
457
  }
458

459
  ObjectData& toObject() {
1,309✔
460
    setType(VALUE_IS_OBJECT);
1,309✔
461
    new (&content_.asObject) ObjectData();
2,618✔
462
    return content_.asObject;
1,309✔
463
  }
464

465
  ObjectData& toObject(ResourceManager* resources) {
311✔
466
    release(resources);
311✔
467
    return toObject();
311✔
468
  }
469

470
  static ObjectData* toObject(VariantData* var, ResourceManager* resources) {
311✔
471
    if (!var)
311✔
472
      return 0;
×
473
    return &var->toObject(resources);
311✔
474
  }
475

476
  uint8_t type() const {
141,857✔
477
    return flags_ & VALUE_MASK;
141,857✔
478
  }
479

480
 private:
481
  void release(ResourceManager* resources) {
68,637✔
482
    if (flags_ & OWNED_VALUE_BIT)
68,637✔
483
      resources->dereferenceString(content_.asOwnedString->data);
17✔
484

485
    auto collection = asCollection();
68,637✔
486
    if (collection)
68,637✔
487
      collection->clear(resources);
14✔
488
  }
68,637✔
489

490
  void setType(uint8_t t) {
74,254✔
491
    flags_ &= OWNED_KEY_BIT;
74,254✔
492
    flags_ |= t;
74,254✔
493
  }
74,254✔
494
};
495

496
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