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

bblanchon / ArduinoJson / 6770901880

06 Nov 2023 12:24PM CUT coverage: 99.545%. Remained the same
6770901880

push

github

bblanchon
CI: always use libc++ with clang

3497 of 3513 relevant lines covered (99.54%)

10637.15 hits per line

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

97.85
/src/ArduinoJson/Memory/VariantPoolList.hpp
1
// ArduinoJson - https://arduinojson.org
2
// Copyright © 2014-2023, Benoit BLANCHON
3
// MIT License
4

5
#pragma once
6

7
#include <ArduinoJson/Memory/VariantPool.hpp>
8
#include <ArduinoJson/Polyfills/assert.hpp>
9

10
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
11

12
using PoolCount = SlotId;
13

14
class VariantPoolList {
15
 public:
16
  VariantPoolList() = default;
1,842✔
17

18
  ~VariantPoolList() {
1,842✔
19
    ARDUINOJSON_ASSERT(count_ == 0);
20
  }
1,842✔
21

22
  friend void swap(VariantPoolList& a, VariantPoolList& b) {
11✔
23
    bool aUsedPreallocated = a.pools_ == a.preallocatedPools_;
11✔
24
    bool bUsedPreallocated = b.pools_ == b.preallocatedPools_;
11✔
25

26
    // Who is using preallocated pools?
27
    if (aUsedPreallocated && bUsedPreallocated) {
11✔
28
      // both of us => swap preallocated pools
29
      for (PoolCount i = 0; i < ARDUINOJSON_INITIAL_POOL_COUNT; i++)
40✔
30
        swap_(a.preallocatedPools_[i], b.preallocatedPools_[i]);
40✔
31
    } else if (bUsedPreallocated) {
3✔
32
      // only b => copy b's preallocated pools and give him a's pointer
33
      for (PoolCount i = 0; i < b.count_; i++)
2✔
34
        a.preallocatedPools_[i] = b.preallocatedPools_[i];
1✔
35
      b.pools_ = a.pools_;
1✔
36
      a.pools_ = a.preallocatedPools_;
1✔
37
    } else if (aUsedPreallocated) {
2✔
38
      // only a => copy a's preallocated pools and give him b's pointer
39
      for (PoolCount i = 0; i < a.count_; i++)
2✔
40
        b.preallocatedPools_[i] = a.preallocatedPools_[i];
1✔
41
      a.pools_ = b.pools_;
1✔
42
      b.pools_ = b.preallocatedPools_;
1✔
43
    } else {
44
      // neither => swap pointers
45
      swap_(a.pools_, b.pools_);
1✔
46
    }
47

48
    swap_(a.count_, b.count_);
11✔
49
    swap_(a.capacity_, b.capacity_);
11✔
50
    swap_(a.freeList_, b.freeList_);
11✔
51
  }
11✔
52

53
  VariantPoolList& operator=(VariantPoolList&& src) {
54
    ARDUINOJSON_ASSERT(count_ == 0);
55
    if (src.pools_ == src.preallocatedPools_) {
56
      memcpy(preallocatedPools_, src.preallocatedPools_,
57
             sizeof(preallocatedPools_));
58
      pools_ = preallocatedPools_;
59
    } else {
60
      pools_ = src.pools_;
61
      src.pools_ = nullptr;
62
    }
63
    count_ = src.count_;
64
    capacity_ = src.capacity_;
65
    src.count_ = 0;
66
    src.capacity_ = 0;
67
    return *this;
68
  }
69

70
  SlotWithId allocSlot(Allocator* allocator) {
71,755✔
71
    // try to allocate from free list
72
    if (freeList_ != NULL_SLOT) {
71,755✔
73
      return allocFromFreeList();
131✔
74
    }
75

76
    // try to allocate from last pool (other pools are full)
77
    if (count_) {
71,624✔
78
      auto slot = allocFromLastPool();
70,493✔
79
      if (slot)
70,493✔
80
        return slot;
69,930✔
81
    }
82

83
    // create a new pool and try again
84
    auto pool = addPool(allocator);
1,694✔
85
    if (!pool)
1,694✔
86
      return {};
10✔
87

88
    return allocFromLastPool();
1,684✔
89
  }
90

91
  void freeSlot(SlotWithId slot);
92

93
  VariantSlot* getSlot(SlotId id) const {
351,953✔
94
    if (id == NULL_SLOT)
351,953✔
95
      return nullptr;
5,202✔
96
    auto poolIndex = SlotId(id / ARDUINOJSON_POOL_CAPACITY);
346,751✔
97
    auto indexInPool = SlotId(id % ARDUINOJSON_POOL_CAPACITY);
346,751✔
98
    ARDUINOJSON_ASSERT(poolIndex < count_);
99
    return pools_[poolIndex].getSlot(indexInPool);
346,751✔
100
  }
101

102
  void clear(Allocator* allocator) {
3,563✔
103
    for (PoolCount i = 0; i < count_; i++)
5,247✔
104
      pools_[i].destroy(allocator);
1,684✔
105
    count_ = 0;
3,563✔
106
    if (pools_ != preallocatedPools_) {
3,563✔
107
      allocator->deallocate(pools_);
7✔
108
      pools_ = preallocatedPools_;
7✔
109
      capacity_ = ARDUINOJSON_INITIAL_POOL_COUNT;
7✔
110
    }
111
  }
3,563✔
112

113
  SlotCount usage() const {
14✔
114
    SlotCount total = 0;
14✔
115
    for (PoolCount i = 0; i < count_; i++)
17✔
116
      total = SlotCount(total + pools_[i].usage());
3✔
117
    return total;
14✔
118
  }
119

120
  void shrinkToFit(Allocator* allocator) {
1,298✔
121
    if (count_ > 0)
1,298✔
122
      pools_[count_ - 1].shrinkToFit(allocator);
511✔
123
    if (pools_ != preallocatedPools_ && count_ != capacity_) {
1,298✔
124
      pools_ = static_cast<VariantPool*>(
1✔
125
          allocator->reallocate(pools_, count_ * sizeof(VariantPool)));
1✔
126
      ARDUINOJSON_ASSERT(pools_ != nullptr);  // realloc to smaller can't fail
127
      capacity_ = count_;
1✔
128
    }
129
  }
1,298✔
130

131
 private:
132
  SlotWithId allocFromFreeList();
133

134
  SlotWithId allocFromLastPool() {
72,177✔
135
    ARDUINOJSON_ASSERT(count_ > 0);
136
    auto poolIndex = SlotId(count_ - 1);
72,177✔
137
    auto slot = pools_[poolIndex].allocSlot();
72,177✔
138
    if (!slot)
72,177✔
139
      return {};
586✔
140
    return {slot, SlotId(poolIndex * ARDUINOJSON_POOL_CAPACITY + slot.id())};
71,591✔
141
  }
142

143
  VariantPool* addPool(Allocator* allocator) {
1,694✔
144
    if (count_ == capacity_ && !increaseCapacity(allocator))
1,694✔
145
      return nullptr;
10✔
146
    auto pool = &pools_[count_++];
1,684✔
147
    SlotCount poolCapacity = ARDUINOJSON_POOL_CAPACITY;
1,684✔
148
    if (count_ == maxPools)  // last pool is smaller because of NULL_SLOT
1,684✔
149
      poolCapacity--;
1✔
150
    pool->create(poolCapacity, allocator);
1,684✔
151
    return pool;
1,684✔
152
  }
153

154
  bool increaseCapacity(Allocator* allocator) {
24✔
155
    if (capacity_ == maxPools)
24✔
156
      return false;
10✔
157
    void* newPools;
158
    auto newCapacity = PoolCount(capacity_ * 2);
14✔
159

160
    if (pools_ == preallocatedPools_) {
14✔
161
      newPools = allocator->allocate(newCapacity * sizeof(VariantPool));
7✔
162
      if (!newPools)
7✔
163
        return false;
×
164
      memcpy(newPools, preallocatedPools_, sizeof(preallocatedPools_));
7✔
165
    } else {
166
      newPools =
167
          allocator->reallocate(pools_, newCapacity * sizeof(VariantPool));
7✔
168
      if (!newPools)
7✔
169
        return false;
×
170
    }
171

172
    pools_ = static_cast<VariantPool*>(newPools);
14✔
173
    capacity_ = newCapacity;
14✔
174
    return true;
14✔
175
  }
176

177
  VariantPool preallocatedPools_[ARDUINOJSON_INITIAL_POOL_COUNT];
178
  VariantPool* pools_ = preallocatedPools_;
179
  PoolCount count_ = 0;
180
  PoolCount capacity_ = ARDUINOJSON_INITIAL_POOL_COUNT;
181
  SlotId freeList_ = NULL_SLOT;
182

183
 public:
184
  static const PoolCount maxPools =
185
      PoolCount(NULL_SLOT / ARDUINOJSON_POOL_CAPACITY + 1);
186
};
187

188
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