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

bblanchon / ArduinoJson / 13696030297

06 Mar 2025 10:00AM CUT coverage: 99.309%. Remained the same
13696030297

push

github

bblanchon
Fix CLang Tidy error

4023 of 4051 relevant lines covered (99.31%)

10751.08 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-2025, 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,105✔
29

30
  ~MemoryPoolList() {
2,105✔
31
    ARDUINOJSON_ASSERT(count_ == 0);
32
  }
2,105✔
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,918✔
83
    // try to allocate from free list
84
    if (freeList_ != NULL_SLOT) {
74,918✔
85
      return allocFromFreeList();
262✔
86
    }
87

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

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

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

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

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

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

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

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

140
  void shrinkToFit(Allocator* allocator) {
1,350✔
141
    if (count_ > 0)
1,350✔
142
      pools_[count_ - 1].shrinkToFit(allocator);
524✔
143
    if (pools_ != preallocatedPools_ && count_ != capacity_) {
1,350✔
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,350✔
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,954✔
161
    ARDUINOJSON_ASSERT(count_ > 0);
162
    auto poolIndex = SlotId(count_ - 1);
74,954✔
163
    auto slot = pools_[poolIndex].allocSlot();
74,954✔
164
    if (!slot)
74,954✔
165
      return {};
346✔
166
    return {slot.ptr(),
167
            SlotId(poolIndex * ARDUINOJSON_POOL_CAPACITY + slot.id())};
74,608✔
168
  }
169

170
  Pool* addPool(Allocator* allocator) {
1,593✔
171
    if (count_ == capacity_ && !increaseCapacity(allocator))
1,593✔
172
      return nullptr;
10✔
173
    auto pool = &pools_[count_++];
1,583✔
174
    SlotCount poolCapacity = ARDUINOJSON_POOL_CAPACITY;
1,583✔
175
    if (count_ == maxPools)  // last pool is smaller because of NULL_SLOT
1,583✔
176
      poolCapacity--;
1✔
177
    pool->create(poolCapacity, allocator);
1,583✔
178
    return pool;
1,583✔
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