GCC Code Coverage Report


Directory: Fw/DataStructures/
File: ArraySetOrMapImpl.hpp
Date: 2026-09-03 21:14:50
Exec Total Coverage
Lines: 95 96 99.0%
Functions: 48 48 100.0%
Branches: 48 58 82.8%

Line Branch Exec Source
1 // ======================================================================
2 // \title ArraySetOrMapImpl
3 // \author bocchino
4 // \brief An array-based implementation of a set or map
5 // ======================================================================
6
7 #ifndef Fw_ArraySetOrMapImpl_HPP
8 #define Fw_ArraySetOrMapImpl_HPP
9
10 #include "Fw/DataStructures/ExternalArray.hpp"
11 #include "Fw/DataStructures/SetOrMapImplConstIterator.hpp"
12 #include "Fw/DataStructures/SetOrMapImplEntry.hpp"
13 #include "Fw/Types/Assert.hpp"
14 #include "Fw/Types/SuccessEnumAc.hpp"
15
16 namespace Fw {
17
18 template <typename KE, typename VN>
19 class ArraySetOrMapImpl final {
20 // ----------------------------------------------------------------------
21 // Friend class for testing
22 // ----------------------------------------------------------------------
23
24 template <typename KK, typename VV>
25 friend class ArraySetOrMapImplTester;
26
27 public:
28 // ----------------------------------------------------------------------
29 // Public types
30 // ----------------------------------------------------------------------
31
32 //! The type of an entry in the set or map
33 using Entry = SetOrMapImplEntry<KE, VN>;
34
35 //! Const iterator
36 class ConstIterator final : public SetOrMapImplConstIterator<KE, VN> {
37 public:
38 using ImplKind = typename SetOrMapImplConstIterator<KE, VN>::ImplKind;
39
40 public:
41 //! Default constructor
42 2 ConstIterator() {}
43
44 //! Constructor providing the implementation
45 1657 ConstIterator(const ArraySetOrMapImpl<KE, VN>& impl) : SetOrMapImplConstIterator<KE, VN>(), m_impl(&impl) {}
46
47 //! Copy constructor
48 5703 ConstIterator(const ConstIterator& it)
49 5703 : SetOrMapImplConstIterator<KE, VN>(), m_impl(it.m_impl), m_index(it.m_index) {}
50
51 //! Destructor
52 3318 ~ConstIterator() override = default;
53
54 public:
55 //! Copy assignment operator
56 ConstIterator& operator=(const ConstIterator& it) {
57 this->m_impl = it.m_impl;
58 this->m_index = it.m_index;
59 return *this;
60 }
61
62 //! Equality comparison operator
63 840 bool compareEqual(const ConstIterator& it) const {
64 840 bool result = false;
65
3/4
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 839 times.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
840 if ((this->m_impl == nullptr) && (it.m_impl == nullptr)) {
66 1 result = true;
67
1/2
✓ Branch 8 taken 839 times.
✗ Branch 9 not taken.
839 } else if (this->m_impl == it.m_impl) {
68 839 result |= (this->m_index == it.m_index);
69
3/4
✓ Branch 4 taken 330 times.
✓ Branch 5 taken 509 times.
✓ Branch 10 taken 330 times.
✗ Branch 11 not taken.
839 result |= (!this->isInRange() and !it.isInRange());
70 }
71 840 return result;
72 }
73
74 //! Return the impl kind
75 //! \return The impl kind
76 6012 ImplKind implKind() const override { return ImplKind::ARRAY; }
77
78 //! Get the set or map impl entry pointed to by this iterator
79 //! \return The set or map impl entry
80 7699 const Entry& getEntry() const override {
81 7699 FW_ASSERT(this->m_impl != nullptr);
82 7699 FW_ASSERT(this->isInRange(), static_cast<FwAssertArgType>(this->m_index),
83 static_cast<FwAssertArgType>(this->m_impl->m_size));
84 7699 return this->m_impl->m_entries[this->m_index];
85 }
86
87 //! Increment operator
88 4927 void increment() override {
89
1/2
✓ Branch 4 taken 4927 times.
✗ Branch 5 not taken.
4927 if (this->isInRange()) {
90 4927 this->m_index++;
91 }
92 4927 }
93
94 //! Check whether the iterator is in range
95 15053 bool isInRange() const override {
96 15053 FW_ASSERT(this->m_impl != nullptr);
97 15053 return this->m_index < this->m_impl->m_size;
98 }
99
100 //! Set the iterator to the end value
101 330 void setToEnd() {
102 330 FW_ASSERT(this->m_impl != nullptr);
103 330 this->m_index = this->m_impl->m_size;
104 330 }
105
106 private:
107 //! The implementation over which to iterate
108 const ArraySetOrMapImpl<KE, VN>* m_impl = nullptr;
109
110 //! The current iteration index
111 FwSizeType m_index = 0;
112 };
113
114 public:
115 // ----------------------------------------------------------------------
116 // Public constructors and destructors
117 // ----------------------------------------------------------------------
118
119 //! Zero-argument constructor
120 79 ArraySetOrMapImpl() = default;
121
122 //! Constructor providing typed backing storage.
123 //! entries must point to at least capacity elements of type Entry.
124 12 ArraySetOrMapImpl(Entry* entries, //!< The entries
125 FwSizeType capacity //!< The capacity
126 12 ) {
127
1/1
✓ Branch 2 taken 12 times.
12 this->setStorage(entries, capacity);
128 12 }
129
130 //! Constructor providing untyped backing storage.
131 //! data must be aligned according to getByteArrayAlignment().
132 //! data must contain at least getByteArraySize(capacity) bytes.
133 1 ArraySetOrMapImpl(ByteArray data, //!< The data
134 FwSizeType capacity //!< The capacity
135 1 ) {
136
1/1
✓ Branch 2 taken 1 times.
1 this->setStorage(data, capacity);
137 1 }
138
139 //! Copy constructor
140
1/1
✓ Branch 6 taken 1 times.
1 ArraySetOrMapImpl(const ArraySetOrMapImpl<KE, VN>& impl) { *this = impl; }
141
142 //! Destructor
143 93 ~ArraySetOrMapImpl() = default;
144
145 public:
146 // ----------------------------------------------------------------------
147 // Public member functions
148 // ----------------------------------------------------------------------
149
150 //! operator=
151 6 ArraySetOrMapImpl<KE, VN>& operator=(const ArraySetOrMapImpl<KE, VN>& impl) {
152
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (&impl != this) {
153 6 m_entries = impl.m_entries;
154 6 m_size = impl.m_size;
155 }
156 6 return *this;
157 }
158
159 //! Get the begin iterator
160 1656 ConstIterator begin() const { return ConstIterator(*this); }
161
162 //! Clear the set or map
163 515 void clear() { this->m_size = 0; }
164
165 //! Get the end iterator
166 330 ConstIterator end() const {
167 330 auto it = begin();
168
1/1
✓ Branch 3 taken 330 times.
330 it.setToEnd();
169 330 return it;
170 }
171
172 //! Find a value associated with a key in the map or an element in a set
173 //! \return SUCCESS if the item was found
174 5908 Success find(const KE& keyOrElement, //!< The key or element
175 VN& valueOrNil //!< The value or Nil
176 ) const {
177 5908 auto status = Success::FAILURE;
178
2/2
✓ Branch 2 taken 1576695 times.
✓ Branch 3 taken 1150 times.
1577845 for (FwSizeType i = 0; i < this->m_size; i++) {
179
1/1
✓ Branch 4 taken 1576695 times.
1576695 const auto& e = this->m_entries[i];
180
2/2
✓ Branch 6 taken 4758 times.
✓ Branch 7 taken 1571937 times.
1576695 if (e.getKey() == keyOrElement) {
181 4758 valueOrNil = e.getValue();
182 4758 status = Success::SUCCESS;
183 4758 break;
184 }
185 }
186
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 5908 times.
✓ Branch 3 taken 5908 times.
11816 return status;
187 }
188
189 //! Get the capacity of the set or map (max number of entries)
190 //! \return The capacity
191 22171 FwSizeType getCapacity() const { return this->m_entries.getSize(); }
192
193 //! Get the size (number of entries)
194 //! \return The size
195 31808 FwSizeType getSize() const { return this->m_size; }
196
197 //! Insert an element in the set or a (key, value) pair in the map
198 //! \return SUCCESS if there is room in the set or map
199 16010 Success insert(const KE& keyOrElement, //!< The key or element
200 const VN& valueOrNil //!< The value or Nil
201 ) {
202 16010 auto status = Success::FAILURE;
203
2/2
✓ Branch 2 taken 6553119 times.
✓ Branch 3 taken 15573 times.
6568692 for (FwSizeType i = 0; i < this->m_size; i++) {
204
1/1
✓ Branch 3 taken 6553119 times.
6553119 auto& e = this->m_entries[i];
205
2/2
✓ Branch 6 taken 437 times.
✓ Branch 7 taken 6552682 times.
6553119 if (e.getKey() == keyOrElement) {
206 437 e.setValueOrNil(valueOrNil);
207 437 status = Success::SUCCESS;
208 437 break;
209 }
210 }
211
8/10
✗ Branch 0 not taken.
✓ Branch 1 taken 16010 times.
✓ Branch 2 taken 15573 times.
✓ Branch 3 taken 437 times.
✓ Branch 8 taken 15573 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 15568 times.
✓ Branch 11 taken 5 times.
✓ Branch 12 taken 15568 times.
✓ Branch 13 taken 442 times.
16010 if ((status == Success::FAILURE) && (this->m_size < this->getCapacity())) {
212
1/1
✓ Branch 8 taken 15568 times.
15568 this->m_entries[this->m_size] = Entry(keyOrElement, valueOrNil);
213 15568 this->m_size++;
214 15568 status = Success::SUCCESS;
215 }
216
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 16010 times.
✓ Branch 3 taken 16010 times.
32020 return status;
217 }
218
219 //! Remove an element from the set or a (key, value) pair from the map
220 //! \return SUCCESS if the key or element was there
221 1515 Success remove(const KE& keyOrElement, //!< The key or element
222 VN& valueOrNil //!< The value or Nil
223 ) {
224 1515 auto status = Success::FAILURE;
225 // Loop over a fixed bound; the loop exits immediately after m_size is modified
226 1515 const FwSizeType size = this->m_size;
227
2/2
✓ Branch 0 taken 1275 times.
✓ Branch 1 taken 1073 times.
2348 for (FwSizeType i = 0; i < size; i++) {
228
3/3
✓ Branch 3 taken 1275 times.
✓ Branch 11 taken 442 times.
✓ Branch 12 taken 833 times.
1275 if (this->m_entries[i].getKey() == keyOrElement) {
229
1/1
✓ Branch 3 taken 442 times.
442 valueOrNil = this->m_entries[i].getValue();
230
2/2
✓ Branch 2 taken 112 times.
✓ Branch 3 taken 330 times.
442 if (i < this->m_size - 1) {
231
2/2
✓ Branch 5 taken 112 times.
✓ Branch 11 taken 112 times.
112 this->m_entries[i] = this->m_entries[this->m_size - 1];
232 }
233 442 this->m_size--;
234 442 status = Success::SUCCESS;
235 442 break;
236 }
237 }
238
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1515 times.
✓ Branch 3 taken 1515 times.
3030 return status;
239 }
240
241 //! Set the backing storage (typed data)
242 //! entries must point to at least capacity elements of type Entry.
243 80 void setStorage(Entry* entries, //!< The entries
244 FwSizeType capacity //!< The capacity
245 ) {
246 80 this->m_entries.setStorage(entries, capacity);
247 80 this->clear();
248 80 }
249
250 //! Set the backing storage (untyped data)
251 //! data must be aligned according to getByteArrayAlignment().
252 //! data must contain at least getByteArraySize(capacity) bytes.
253 3 void setStorage(ByteArray data, //!< The data
254 FwSizeType capacity //!< The capacity
255 ) {
256 3 this->m_entries.setStorage(data, capacity);
257 3 this->clear();
258 3 }
259
260 public:
261 // ----------------------------------------------------------------------
262 // Public static functions
263 // ----------------------------------------------------------------------
264
265 //! Get the alignment of the storage for an ArraySetOrMapImpl
266 //! \return The alignment
267 static constexpr U8 getByteArrayAlignment() { return ExternalArray<Entry>::getByteArrayAlignment(); }
268
269 //! Get the size of the storage for an ExternalArray of the specified capacity,
270 //! as a byte array
271 //! \return The byte array size
272 static constexpr FwSizeType getByteArraySize(FwSizeType capacity //!< The capacity
273 ) {
274 return ExternalArray<Entry>::getByteArraySize(capacity);
275 }
276
277 private:
278 // ----------------------------------------------------------------------
279 // Private member variables
280 // ----------------------------------------------------------------------
281
282 //! The array for storing the set or map entries
283 ExternalArray<Entry> m_entries = {};
284
285 //! The number of entries in the set or map
286 FwSizeType m_size = 0;
287 };
288
289 } // namespace Fw
290
291 #endif
292