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

bblanchon / ArduinoJson / 4466978960

pending completion
4466978960

push

github

Benoit Blanchon
Merge `DynamicJsonDocument` with `JsonDocument`

72 of 72 new or added lines in 1 file covered. (100.0%)

3279 of 3296 relevant lines covered (99.48%)

6214.2 hits per line

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

99.34
/src/ArduinoJson/Document/JsonDocument.hpp
1
// ArduinoJson - https://arduinojson.org
2
// Copyright © 2014-2023, Benoit BLANCHON
3
// MIT License
4

5
#pragma once
6

7
#include <ArduinoJson/Array/ElementProxy.hpp>
8
#include <ArduinoJson/Memory/Allocator.hpp>
9
#include <ArduinoJson/Memory/MemoryPool.hpp>
10
#include <ArduinoJson/Object/JsonObject.hpp>
11
#include <ArduinoJson/Object/MemberProxy.hpp>
12
#include <ArduinoJson/Strings/StoragePolicy.hpp>
13
#include <ArduinoJson/Variant/JsonVariantConst.hpp>
14
#include <ArduinoJson/Variant/VariantTo.hpp>
15

16
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
17

18
// A JSON document.
19
// https://arduinojson.org/v6/api/jsondocument/
20
class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
21
  friend class detail::VariantAttorney;
22

23
 public:
24
  explicit JsonDocument(size_t capa,
1,977✔
25
                        Allocator* alloc = DefaultAllocator::instance())
26
      : _allocator(alloc), _pool(allocPool(capa)) {}
1,977✔
27

28
  // Copy-constructor
29
  JsonDocument(const JsonDocument& src)
5✔
30
      : JsonDocument(src.capacity(), src._allocator) {
5✔
31
    set(src);
5✔
32
  }
5✔
33

34
  // Move-constructor
35
  JsonDocument(JsonDocument&& src) : _allocator(src._allocator), _pool(0, 0) {
2✔
36
    // TODO: use the copy and swap idiom
37
    moveAssignFrom(src);
2✔
38
  }
2✔
39

40
  // Construct from variant, array, or object
41
  template <typename T>
42
  JsonDocument(const T& src,
2✔
43
               typename detail::enable_if<
44
                   detail::is_same<T, JsonVariant>::value ||
45
                   detail::is_same<T, JsonVariantConst>::value ||
46
                   detail::is_same<T, JsonArray>::value ||
47
                   detail::is_same<T, JsonArrayConst>::value ||
48
                   detail::is_same<T, JsonObject>::value ||
49
                   detail::is_same<T, JsonObjectConst>::value>::type* = 0)
50
      : JsonDocument(src.memoryUsage()) {
4✔
51
    set(src);
2✔
52
  }
2✔
53

54
  // disambiguate
55
  // TODO: still needed?
56
  JsonDocument(JsonVariant src) : JsonDocument(src.memoryUsage()) {
2✔
57
    set(src);
1✔
58
  }
1✔
59

60
  ~JsonDocument() {
3,958✔
61
    freePool();
1,979✔
62
  }
1,979✔
63

64
  JsonDocument& operator=(const JsonDocument& src) {
5✔
65
    // TODO: use the copy and swap idiom
66
    copyAssignFrom(src);
5✔
67
    return *this;
5✔
68
  }
69

70
  JsonDocument& operator=(JsonDocument&& src) {
3✔
71
    // TODO: use the copy and swap idiom
72
    moveAssignFrom(src);
3✔
73
    return *this;
3✔
74
  }
75

76
  template <typename T>
77
  JsonDocument& operator=(const T& src) {
5✔
78
    size_t requiredSize = src.memoryUsage();
5✔
79
    if (requiredSize > capacity())
5✔
80
      reallocPool(requiredSize);
×
81
    set(src);
5✔
82
    return *this;
5✔
83
  }
84

85
  // Reduces the capacity of the memory pool to match the current usage.
86
  // https://arduinojson.org/v6/api/JsonDocument/shrinktofit/
87
  void shrinkToFit() {
29✔
88
    ptrdiff_t bytes_reclaimed = _pool.squash();
29✔
89
    if (bytes_reclaimed == 0)
29✔
90
      return;
15✔
91

92
    void* old_ptr = _pool.buffer();
14✔
93
    void* new_ptr = _allocator->reallocate(old_ptr, _pool.capacity());
14✔
94

95
    ptrdiff_t ptr_offset =
14✔
96
        static_cast<char*>(new_ptr) - static_cast<char*>(old_ptr);
97

98
    _pool.movePointers(ptr_offset);
14✔
99
    _data.movePointers(ptr_offset, ptr_offset - bytes_reclaimed);
14✔
100
  }
101

102
  // Reclaims the memory leaked when removing and replacing values.
103
  // https://arduinojson.org/v6/api/jsondocument/garbagecollect/
104
  bool garbageCollect() {
3✔
105
    // make a temporary clone and move assign
106
    JsonDocument tmp(*this);
6✔
107
    if (!tmp.capacity())
3✔
108
      return false;
1✔
109
    tmp.set(*this);
2✔
110
    moveAssignFrom(tmp);
2✔
111
    return true;
2✔
112
  }
113

114
  // Casts the root to the specified type.
115
  // https://arduinojson.org/v6/api/jsondocument/as/
116
  template <typename T>
117
  T as() {
483✔
118
    return getVariant().template as<T>();
966✔
119
  }
120

121
  // Casts the root to the specified type.
122
  // https://arduinojson.org/v6/api/jsondocument/as/
123
  template <typename T>
124
  T as() const {
15✔
125
    return getVariant().template as<T>();
30✔
126
  }
127

128
  // Empties the document and resets the memory pool
129
  // https://arduinojson.org/v6/api/jsondocument/clear/
130
  void clear() {
1,779✔
131
    _pool.clear();
1,779✔
132
    _data.setNull();
1,779✔
133
  }
1,779✔
134

135
  // Returns true if the root is of the specified type.
136
  // https://arduinojson.org/v6/api/jsondocument/is/
137
  template <typename T>
138
  bool is() {
93✔
139
    return getVariant().template is<T>();
186✔
140
  }
141

142
  // Returns true if the root is of the specified type.
143
  // https://arduinojson.org/v6/api/jsondocument/is/
144
  template <typename T>
145
  bool is() const {
146
    return getVariant().template is<T>();
147
  }
148

149
  // Returns true if the root is null.
150
  // https://arduinojson.org/v6/api/jsondocument/isnull/
151
  bool isNull() const {
12✔
152
    return getVariant().isNull();
24✔
153
  }
154

155
  // Returns the number of used bytes in the memory pool.
156
  // https://arduinojson.org/v6/api/jsondocument/memoryusage/
157
  size_t memoryUsage() const {
297✔
158
    return _pool.size();
297✔
159
  }
160

161
  // Returns trues if the memory pool was too small.
162
  // https://arduinojson.org/v6/api/jsondocument/overflowed/
163
  bool overflowed() const {
18✔
164
    return _pool.overflowed();
18✔
165
  }
166

167
  // Returns the depth (nesting level) of the array.
168
  // https://arduinojson.org/v6/api/jsondocument/nesting/
169
  size_t nesting() const {
4✔
170
    return variantNesting(&_data);
4✔
171
  }
172

173
  // Returns the capacity of the memory pool.
174
  // https://arduinojson.org/v6/api/jsondocument/capacity/
175
  size_t capacity() const {
75✔
176
    return _pool.capacity();
75✔
177
  }
178

179
  // Returns the number of elements in the root array or object.
180
  // https://arduinojson.org/v6/api/jsondocument/size/
181
  size_t size() const {
11✔
182
    return _data.size();
11✔
183
  }
184

185
  // Copies the specified document.
186
  // https://arduinojson.org/v6/api/jsondocument/set/
187
  bool set(const JsonDocument& src) {
12✔
188
    return to<JsonVariant>().set(src.as<JsonVariantConst>());
24✔
189
  }
190

191
  // Replaces the root with the specified value.
192
  // https://arduinojson.org/v6/api/jsondocument/set/
193
  template <typename T>
194
  typename detail::enable_if<!detail::is_base_of<JsonDocument, T>::value,
195
                             bool>::type
196
  set(const T& src) {
43✔
197
    return to<JsonVariant>().set(src);
86✔
198
  }
199

200
  // Clears the document and converts it to the specified type.
201
  // https://arduinojson.org/v6/api/jsondocument/to/
202
  template <typename T>
203
  typename detail::VariantTo<T>::type to() {
723✔
204
    clear();
723✔
205
    return getVariant().template to<T>();
1,446✔
206
  }
207

208
  // Creates an array and appends it to the root array.
209
  // https://arduinojson.org/v6/api/jsondocument/createnestedarray/
210
  JsonArray createNestedArray() {
25✔
211
    return add().to<JsonArray>();
50✔
212
  }
213

214
  // Creates an array and adds it to the root object.
215
  // https://arduinojson.org/v6/api/jsondocument/createnestedarray/
216
  template <typename TChar>
217
  JsonArray createNestedArray(TChar* key) {
1✔
218
    return operator[](key).template to<JsonArray>();
1✔
219
  }
220

221
  // Creates an array and adds it to the root object.
222
  // https://arduinojson.org/v6/api/jsondocument/createnestedarray/
223
  template <typename TString>
224
  JsonArray createNestedArray(const TString& key) {
1✔
225
    return operator[](key).template to<JsonArray>();
1✔
226
  }
227

228
  // Creates an object and appends it to the root array.
229
  // https://arduinojson.org/v6/api/jsondocument/createnestedobject/
230
  JsonObject createNestedObject() {
25✔
231
    return add().to<JsonObject>();
50✔
232
  }
233

234
  // Creates an object and adds it to the root object.
235
  // https://arduinojson.org/v6/api/jsondocument/createnestedobject/
236
  template <typename TChar>
237
  JsonObject createNestedObject(TChar* key) {
1✔
238
    return operator[](key).template to<JsonObject>();
1✔
239
  }
240

241
  // Creates an object and adds it to the root object.
242
  // https://arduinojson.org/v6/api/jsondocument/createnestedobject/
243
  template <typename TString>
244
  JsonObject createNestedObject(const TString& key) {
1✔
245
    return operator[](key).template to<JsonObject>();
1✔
246
  }
247

248
  // Returns true if the root object contains the specified key.
249
  // https://arduinojson.org/v6/api/jsondocument/containskey/
250
  template <typename TChar>
251
  bool containsKey(TChar* key) const {
5✔
252
    return _data.getMember(detail::adaptString(key)) != 0;
5✔
253
  }
254

255
  // Returns true if the root object contains the specified key.
256
  // https://arduinojson.org/v6/api/jsondocument/containskey/
257
  template <typename TString>
258
  bool containsKey(const TString& key) const {
1✔
259
    return _data.getMember(detail::adaptString(key)) != 0;
1✔
260
  }
261

262
  // Gets or sets a root object's member.
263
  // https://arduinojson.org/v6/api/jsondocument/subscript/
264
  template <typename TString>
265
  FORCE_INLINE typename detail::enable_if<
266
      detail::IsString<TString>::value,
267
      detail::MemberProxy<JsonDocument&, TString>>::type
268
  operator[](const TString& key) {
269
    return {*this, key};
16✔
270
  }
271

272
  // Gets or sets a root object's member.
273
  // https://arduinojson.org/v6/api/jsondocument/subscript/
274
  template <typename TChar>
275
  FORCE_INLINE typename detail::enable_if<
276
      detail::IsString<TChar*>::value,
277
      detail::MemberProxy<JsonDocument&, TChar*>>::type
278
  operator[](TChar* key) {
279
    return {*this, key};
421✔
280
  }
281

282
  // Gets a root object's member.
283
  // https://arduinojson.org/v6/api/jsondocument/subscript/
284
  template <typename TString>
285
  FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value,
286
                                          JsonVariantConst>::type
287
  operator[](const TString& key) const {
288
    return JsonVariantConst(_data.getMember(detail::adaptString(key)));
1✔
289
  }
290

291
  // Gets a root object's member.
292
  // https://arduinojson.org/v6/api/jsondocument/subscript/
293
  template <typename TChar>
294
  FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value,
295
                                          JsonVariantConst>::type
296
  operator[](TChar* key) const {
297
    return JsonVariantConst(_data.getMember(detail::adaptString(key)));
1✔
298
  }
299

300
  // Gets or sets a root array's element.
301
  // https://arduinojson.org/v6/api/jsondocument/subscript/
302
  FORCE_INLINE detail::ElementProxy<JsonDocument&> operator[](size_t index) {
303
    return {*this, index};
152✔
304
  }
305

306
  // Gets a root array's member.
307
  // https://arduinojson.org/v6/api/jsondocument/subscript/
308
  FORCE_INLINE JsonVariantConst operator[](size_t index) const {
309
    return JsonVariantConst(_data.getElement(index));
1✔
310
  }
311

312
  // Appends a new (null) element to the root array.
313
  // Returns a reference to the new element.
314
  // https://arduinojson.org/v6/api/jsondocument/add/
315
  FORCE_INLINE JsonVariant add() {
316
    return JsonVariant(&_pool, _data.addElement(&_pool));
176✔
317
  }
318

319
  // Appends a value to the root array.
320
  // https://arduinojson.org/v6/api/jsondocument/add/
321
  template <typename TValue>
322
  FORCE_INLINE bool add(const TValue& value) {
323
    return add().set(value);
96✔
324
  }
325

326
  // Appends a value to the root array.
327
  // https://arduinojson.org/v6/api/jsondocument/add/
328
  template <typename TChar>
329
  FORCE_INLINE bool add(TChar* value) {
330
    return add().set(value);
32✔
331
  }
332

333
  // Removes an element of the root array.
334
  // ⚠️ Doesn't release the memory associated with the removed element.
335
  // https://arduinojson.org/v6/api/jsondocument/remove/
336
  FORCE_INLINE void remove(size_t index) {
337
    _data.remove(index);
1✔
338
  }
1✔
339

340
  // Removes a member of the root object.
341
  // ⚠️ Doesn't release the memory associated with the removed element.
342
  // https://arduinojson.org/v6/api/jsondocument/remove/
343
  template <typename TChar>
344
  FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value>::type
345
  remove(TChar* key) {
346
    _data.remove(detail::adaptString(key));
4✔
347
  }
4✔
348

349
  // Removes a member of the root object.
350
  // ⚠️ Doesn't release the memory associated with the removed element.
351
  // https://arduinojson.org/v6/api/jsondocument/remove/
352
  template <typename TString>
353
  FORCE_INLINE
354
      typename detail::enable_if<detail::IsString<TString>::value>::type
355
      remove(const TString& key) {
356
    _data.remove(detail::adaptString(key));
1✔
357
  }
1✔
358

359
  FORCE_INLINE operator JsonVariant() {
360
    return getVariant();
1✔
361
  }
362

363
  FORCE_INLINE operator JsonVariantConst() const {
364
    return getVariant();
335✔
365
  }
366

367
 private:
368
  void replacePool(detail::MemoryPool pool) {
4✔
369
    _pool = pool;
4✔
370
  }
4✔
371

372
  JsonVariant getVariant() {
1,300✔
373
    return JsonVariant(&_pool, &_data);
1,300✔
374
  }
375

376
  JsonVariantConst getVariant() const {
362✔
377
    return JsonVariantConst(&_data);
362✔
378
  }
379

380
  detail::MemoryPool allocPool(size_t requiredSize) {
1,981✔
381
    size_t capa = detail::addPadding(requiredSize);
1,981✔
382
    return {reinterpret_cast<char*>(_allocator->allocate(capa)), capa};
1,981✔
383
  }
384

385
  void reallocPool(size_t requiredSize) {
5✔
386
    size_t capa = detail::addPadding(requiredSize);
5✔
387
    if (capa == _pool.capacity())
5✔
388
      return;
1✔
389
    freePool();
4✔
390
    replacePool(allocPool(detail::addPadding(requiredSize)));
4✔
391
  }
392

393
  void freePool() {
1,990✔
394
    auto p = getPool()->buffer();
1,990✔
395
    if (p)
1,990✔
396
      _allocator->deallocate(p);
1,980✔
397
  }
1,990✔
398

399
  void copyAssignFrom(const JsonDocument& src) {
5✔
400
    reallocPool(src.capacity());
5✔
401
    set(src);
5✔
402
  }
5✔
403

404
  void moveAssignFrom(JsonDocument& src) {
7✔
405
    freePool();
7✔
406
    _data = src._data;
7✔
407
    _pool = src._pool;
7✔
408
    src._data.setNull();
7✔
409
    src._pool = {0, 0};
7✔
410
  }
7✔
411

412
  detail::MemoryPool* getPool() {
4,372✔
413
    return &_pool;
4,372✔
414
  }
415

416
  detail::VariantData* getData() {
1,316✔
417
    return &_data;
1,316✔
418
  }
419

420
  const detail::VariantData* getData() const {
6✔
421
    return &_data;
6✔
422
  }
423

424
  detail::VariantData* getOrCreateData() {
398✔
425
    return &_data;
398✔
426
  }
427

428
  Allocator* _allocator;
429
  detail::MemoryPool _pool;
430
  detail::VariantData _data;
431
};
432

433
inline void convertToJson(const JsonDocument& src, JsonVariant dst) {
1✔
434
  dst.set(src.as<JsonVariantConst>());
1✔
435
}
1✔
436

437
ARDUINOJSON_END_PUBLIC_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