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

bblanchon / ArduinoJson / 8738040343

18 Apr 2024 12:39PM CUT coverage: 99.589%. Remained the same
8738040343

push

github

bblanchon
Fix error "pasting X and Y does not give a valid preprocessing token"

3639 of 3654 relevant lines covered (99.59%)

13017.28 hits per line

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

98.96
/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) {}
1,997✔
26

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

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

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

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

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

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

51
      case VALUE_IS_SIGNED_INTEGER:
1,182✔
52
        return visit.visit(content_.asSignedInteger);
1,182✔
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,238✔
61
        return visit.visit(nullptr);
131,238✔
62
    }
63
  }
64

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

74
  VariantData* addElement(ResourceManager* resources) {
268✔
75
    auto array = isNull() ? &toArray() : asArray();
268✔
76
    return detail::ArrayData::addElement(array, resources);
268✔
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() {
708✔
102
    return isArray() ? &content_.asArray : 0;
708✔
103
  }
104

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

109
  CollectionData* asCollection() {
68,577✔
110
    return isCollection() ? &content_.asCollection : 0;
68,577✔
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 {
212✔
139
    static_assert(is_integral<T>::value, "T must be an integral type");
140
    switch (type()) {
212✔
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:
86✔
146
        return convertNumber<T>(content_.asSignedInteger);
86✔
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,752✔
159
    return isObject() ? &content_.asObject : 0;
2,752✔
160
  }
161

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

273
  bool isString() const {
62✔
274
    return type() == VALUE_IS_LINKED_STRING || type() == VALUE_IS_OWNED_STRING;
62✔
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) {
7✔
293
    ArrayData::removeElement(asArray(), index, resources);
7✔
294
  }
7✔
295

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

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

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

316
  void reset() {
1,808✔
317
    flags_ = VALUE_IS_NULL;
1,808✔
318
  }
1,808✔
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,132✔
342
    setType(VALUE_IS_SIGNED_INTEGER);
1,132✔
343
    content_.asSignedInteger = value;
1,132✔
344
  }
1,132✔
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) {
978✔
354
    release(resources);
978✔
355
    setInteger(value);
978✔
356
  }
978✔
357

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

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

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

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

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

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

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

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

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

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

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

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

428
  void setOwnedString(StringNode* s) {
495✔
429
    ARDUINOJSON_ASSERT(s);
430
    setType(VALUE_IS_OWNED_STRING);
495✔
431
    content_.asOwnedString = s;
495✔
432
  }
495✔
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,249✔
443
    setType(VALUE_IS_ARRAY);
1,249✔
444
    new (&content_.asArray) ArrayData();
2,498✔
445
    return content_.asArray;
1,249✔
446
  }
447

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

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

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

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

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

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

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

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

490
  void setType(uint8_t t) {
74,085✔
491
    flags_ &= OWNED_KEY_BIT;
74,085✔
492
    flags_ |= t;
74,085✔
493
  }
74,085✔
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