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

bblanchon / ArduinoJson / 11879748170

17 Nov 2024 02:40PM CUT coverage: 99.327%. Remained the same
11879748170

push

github

bblanchon
Fix support for NUL characters in `deserializeJson()`

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

3985 of 4012 relevant lines covered (99.33%)

10799.38 hits per line

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

98.1
/src/ArduinoJson/Memory/MemoryPoolList.hpp
1
// ArduinoJson - https://arduinojson.org
2
// Copyright © 2014-2024, Benoit BLANCHON
3
// MIT License
4

5
#pragma once
6

7
#include <ArduinoJson/Memory/MemoryPool.hpp>
8
#include <ArduinoJson/Polyfills/assert.hpp>
9
#include <ArduinoJson/Polyfills/utility.hpp>
10

11
#include <string.h>  // memcpy
12

13
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
14

15
using PoolCount = SlotId;
16

17
template <typename T>
18
class MemoryPoolList {
19
  struct FreeSlot {
20
    SlotId next;
21
  };
22

23
  static_assert(sizeof(FreeSlot) <= sizeof(T), "T is too small");
24

25
 public:
26
  using Pool = MemoryPool<T>;
27

28
  MemoryPoolList() = default;
2,069✔
29

30
  ~MemoryPoolList() {
2,069✔
31
    ARDUINOJSON_ASSERT(count_ == 0);
32
  }
2,069✔
33

34
  friend void swap(MemoryPoolList& a, MemoryPoolList& b) {
11✔
35
    bool aUsedPreallocated = a.pools_ == a.preallocatedPools_;
11✔
36
    bool bUsedPreallocated = b.pools_ == b.preallocatedPools_;
11✔
37

38
    // Who is using preallocated pools?
39
    if (aUsedPreallocated && bUsedPreallocated) {
11✔
40
      // both of us => swap preallocated pools
41
      for (PoolCount i = 0; i < ARDUINOJSON_INITIAL_POOL_COUNT; i++)
40✔
42
        swap_(a.preallocatedPools_[i], b.preallocatedPools_[i]);
40✔
43
    } else if (bUsedPreallocated) {
3✔
44
      // only b => copy b's preallocated pools and give him a's pointer
45
      for (PoolCount i = 0; i < b.count_; i++)
2✔
46
        a.preallocatedPools_[i] = b.preallocatedPools_[i];
1✔
47
      b.pools_ = a.pools_;
1✔
48
      a.pools_ = a.preallocatedPools_;
1✔
49
    } else if (aUsedPreallocated) {
2✔
50
      // only a => copy a's preallocated pools and give him b's pointer
51
      for (PoolCount i = 0; i < a.count_; i++)
2✔
52
        b.preallocatedPools_[i] = a.preallocatedPools_[i];
1✔
53
      a.pools_ = b.pools_;
1✔
54
      b.pools_ = b.preallocatedPools_;
1✔
55
    } else {
56
      // neither => swap pointers
57
      swap_(a.pools_, b.pools_);
1✔
58
    }
59

60
    swap_(a.count_, b.count_);
11✔
61
    swap_(a.capacity_, b.capacity_);
11✔
62
    swap_(a.freeList_, b.freeList_);
11✔
63
  }
11✔
64

65
  MemoryPoolList& operator=(MemoryPoolList&& src) {
66
    ARDUINOJSON_ASSERT(count_ == 0);
67
    if (src.pools_ == src.preallocatedPools_) {
68
      memcpy(preallocatedPools_, src.preallocatedPools_,
69
             sizeof(preallocatedPools_));
70
      pools_ = preallocatedPools_;
71
    } else {
72
      pools_ = src.pools_;
73
      src.pools_ = nullptr;
74
    }
75
    count_ = src.count_;
76
    capacity_ = src.capacity_;
77
    src.count_ = 0;
78
    src.capacity_ = 0;
79
    return *this;
80
  }
81

82
  Slot<T> allocSlot(Allocator* allocator) {
74,886✔
83
    // try to allocate from free list
84
    if (freeList_ != NULL_SLOT) {
74,886✔
85
      return allocFromFreeList();
262✔
86
    }
87

88
    // try to allocate from last pool (other pools are full)
89
    if (count_) {
74,624✔
90
      auto slot = allocFromLastPool();
73,347✔
91
      if (slot)
73,347✔
92
        return slot;
73,039✔
93
    }
94

95
    // create a new pool and try again
96
    auto pool = addPool(allocator);
1,585✔
97
    if (!pool)
1,585✔
98
      return {};
10✔
99

100
    return allocFromLastPool();
1,575✔
101
  }
102

103
  void freeSlot(Slot<T> slot) {
371✔
104
    reinterpret_cast<FreeSlot*>(slot.ptr())->next = freeList_;
371✔
105
    freeList_ = slot.id();
371✔
106
  }
371✔
107

108
  T* getSlot(SlotId id) const {
366,994✔
109
    if (id == NULL_SLOT)
366,994✔
110
      return nullptr;
4,567✔
111
    auto poolIndex = SlotId(id / ARDUINOJSON_POOL_CAPACITY);
362,427✔
112
    auto indexInPool = SlotId(id % ARDUINOJSON_POOL_CAPACITY);
362,427✔
113
    ARDUINOJSON_ASSERT(poolIndex < count_);
114
    return pools_[poolIndex].getSlot(indexInPool);
362,427✔
115
  }
116

117
  void clear(Allocator* allocator) {
3,997✔
118
    for (PoolCount i = 0; i < count_; i++)
5,572✔
119
      pools_[i].destroy(allocator);
1,575✔
120
    count_ = 0;
3,997✔
121
    freeList_ = NULL_SLOT;
3,997✔
122
    if (pools_ != preallocatedPools_) {
3,997✔
123
      allocator->deallocate(pools_);
7✔
124
      pools_ = preallocatedPools_;
7✔
125
      capacity_ = ARDUINOJSON_INITIAL_POOL_COUNT;
7✔
126
    }
127
  }
3,997✔
128

129
  SlotCount usage() const {
14✔
130
    SlotCount total = 0;
14✔
131
    for (PoolCount i = 0; i < count_; i++)
17✔
132
      total = SlotCount(total + pools_[i].usage());
3✔
133
    return total;
14✔
134
  }
135

136
  size_t size() const {
14✔
137
    return Pool::slotsToBytes(usage());
14✔
138
  }
139

140
  void shrinkToFit(Allocator* allocator) {
1,349✔
141
    if (count_ > 0)
1,349✔
142
      pools_[count_ - 1].shrinkToFit(allocator);
523✔
143
    if (pools_ != preallocatedPools_ && count_ != capacity_) {
1,349✔
144
      pools_ = static_cast<Pool*>(
2✔
145
          allocator->reallocate(pools_, count_ * sizeof(Pool)));
1✔
146
      ARDUINOJSON_ASSERT(pools_ != nullptr);  // realloc to smaller can't fail
147
      capacity_ = count_;
1✔
148
    }
149
  }
1,349✔
150

151
 private:
152
  Slot<T> allocFromFreeList() {
262✔
153
    ARDUINOJSON_ASSERT(freeList_ != NULL_SLOT);
154
    auto id = freeList_;
262✔
155
    auto slot = getSlot(freeList_);
262✔
156
    freeList_ = reinterpret_cast<FreeSlot*>(slot)->next;
262✔
157
    return {slot, id};
262✔
158
  }
159

160
  Slot<T> allocFromLastPool() {
74,922✔
161
    ARDUINOJSON_ASSERT(count_ > 0);
162
    auto poolIndex = SlotId(count_ - 1);
74,922✔
163
    auto slot = pools_[poolIndex].allocSlot();
74,922✔
164
    if (!slot)
74,922✔
165
      return {};
346✔
166
    return {slot.ptr(),
167
            SlotId(poolIndex * ARDUINOJSON_POOL_CAPACITY + slot.id())};
74,576✔
168
  }
169

170
  Pool* addPool(Allocator* allocator) {
1,585✔
171
    if (count_ == capacity_ && !increaseCapacity(allocator))
1,585✔
172
      return nullptr;
10✔
173
    auto pool = &pools_[count_++];
1,575✔
174
    SlotCount poolCapacity = ARDUINOJSON_POOL_CAPACITY;
1,575✔
175
    if (count_ == maxPools)  // last pool is smaller because of NULL_SLOT
1,575✔
176
      poolCapacity--;
1✔
177
    pool->create(poolCapacity, allocator);
1,575✔
178
    return pool;
1,575✔
179
  }
180

181
  bool increaseCapacity(Allocator* allocator) {
23✔
182
    if (capacity_ == maxPools)
23✔
183
      return false;
10✔
184
    void* newPools;
185
    auto newCapacity = PoolCount(capacity_ * 2);
13✔
186

187
    if (pools_ == preallocatedPools_) {
13✔
188
      newPools = allocator->allocate(newCapacity * sizeof(Pool));
7✔
189
      if (!newPools)
7✔
190
        return false;
×
191
      memcpy(newPools, preallocatedPools_, sizeof(preallocatedPools_));
7✔
192
    } else {
193
      newPools = allocator->reallocate(pools_, newCapacity * sizeof(Pool));
6✔
194
      if (!newPools)
6✔
195
        return false;
×
196
    }
197

198
    pools_ = static_cast<Pool*>(newPools);
13✔
199
    capacity_ = newCapacity;
13✔
200
    return true;
13✔
201
  }
202

203
  Pool preallocatedPools_[ARDUINOJSON_INITIAL_POOL_COUNT];
204
  Pool* pools_ = preallocatedPools_;
205
  PoolCount count_ = 0;
206
  PoolCount capacity_ = ARDUINOJSON_INITIAL_POOL_COUNT;
207
  SlotId freeList_ = NULL_SLOT;
208

209
 public:
210
  static const PoolCount maxPools =
211
      PoolCount(NULL_SLOT / ARDUINOJSON_POOL_CAPACITY + 1);
212
};
213

214
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