GCC Code Coverage Report


Directory: ./
File: Fw/DataStructures/ExternalArray.hpp
Date: 2026-09-03 21:13:48
Exec Total Coverage
Lines: 57 57 100.0%
Functions: 150 152 98.7%
Branches: 19 26 73.1%

Line Branch Exec Source
1 // ======================================================================
2 // \file ExternalArray.hpp
3 // \author bocchino
4 // \brief A bounds-checked array with external memory
5 // ======================================================================
6
7 #ifndef Fw_ExternalArray_HPP
8 #define Fw_ExternalArray_HPP
9
10 #include <cstdint>
11 #include <new>
12 #include <type_traits>
13
14 #include "Fw/FPrimeBasicTypes.hpp"
15 #include "Fw/Types/Assert.hpp"
16 #include "Fw/Types/ByteArray.hpp"
17
18 namespace Fw {
19
20 template <typename T>
21 class ExternalArray final {
22 // ----------------------------------------------------------------------
23 // Static assertions
24 // ----------------------------------------------------------------------
25
26 static_assert(std::is_assignable<T&, T>::value, "T must be assignable to T&");
27
28 public:
29 // ----------------------------------------------------------------------
30 // Public constructors and destructors
31 // ----------------------------------------------------------------------
32
33 //! Zero-argument constructor
34 2951 ExternalArray() {}
35
36 //! Constructor providing typed backing storage.
37 //! elements must point to at least size elements of type T.
38 711 ExternalArray(T* elements, //!< The elements
39 FwSizeType size //!< The array size
40 )
41 711 : m_elements(elements), m_size(size) {}
42
43 //! Constructor providing untyped backing storage.
44 //! data must be aligned according to getByteArrayAlignment().
45 //! data must contain at least getByteArraySize(size) bytes.
46 1 ExternalArray(ByteArray data, //!< The data
47 FwSizeType size //!< The array size
48 1 ) {
49 1 this->setStorage(data, size);
50 1 }
51
52 //! Copy constructor
53 12 ExternalArray(const ExternalArray<T>& a) : m_elements(a.m_elements), m_size(a.m_size) {}
54
55 //! Destructor
56 4300 ~ExternalArray() { this->releaseStorage(); }
57
58 public:
59 // ----------------------------------------------------------------------
60 // Public member functions
61 // ----------------------------------------------------------------------
62
63 //! Subscript operator
64 //! \return The element at index i
65 16078389 T& operator[](const FwSizeType i //!< The subscript index
66 ) {
67 16078389 FW_ASSERT(this->m_elements != nullptr);
68 16078389 FW_ASSERT(i < this->m_size, static_cast<FwAssertArgType>(i));
69 16078389 return this->m_elements[i];
70 }
71
72 //! Const subscript operator
73 //! \return The element at index i
74 41773608 const T& operator[](const FwSizeType i //!< The subscript index
75 ) const {
76 41773608 FW_ASSERT(this->m_elements != nullptr);
77 41773608 FW_ASSERT(i < this->m_size, static_cast<FwAssertArgType>(i));
78 41773608 return this->m_elements[i];
79 }
80
81 //! Copy assignment operator
82 //! \return *this
83 36 ExternalArray<T>& operator=(const ExternalArray<T>& a) {
84
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
36 if (&a != this) {
85 36 this->setStorage(a.m_elements, a.m_size);
86 }
87 36 return *this;
88 }
89
90 //! Copy the data from a
91 3 void copyDataFrom(const ExternalArray<T>& a) {
92
2/2
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 2 times.
3 const FwSizeType size = FW_MIN(this->m_size, a.m_size);
93
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 3 times.
23 for (FwSizeType i = 0; i < size; i++) {
94 20 (*this)[i] = a[i];
95 }
96 3 }
97
98 //! Get a mutable pointer to the elements
99 //! \return A mutable pointer to the elements
100 134 T* getElements() { return this->m_elements; }
101
102 //! Get a const pointer to the elements
103 //! \return A const pointer to the elements
104 45 const T* getElements() const { return this->m_elements; }
105
106 //! Get the size
107 //! \return The size
108 10420225 FwSizeType getSize() const { return this->m_size; }
109
110 //! Set the backing storage (typed data)
111 2909 void setStorage(T* elements, //!< The array elements
112 FwSizeType size //!< The size
113 ) {
114 // Check that elements is not null if the array is nonempty
115 2909 FW_ASSERT((elements != nullptr) || (size == 0), static_cast<FwAssertArgType>(size));
116
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1551 times.
2909 if (elements == this->m_elements) {
117 // The incoming pointer aliases the existing storage, so do not
118 // release the storage or change the ownership flag
119 1 this->m_size = size;
120 } else {
121 2908 this->releaseStorage();
122 2908 this->m_elements = elements;
123 2908 this->m_size = size;
124 2908 this->m_destroyElementsOnRelease = false;
125 }
126 2909 }
127
128 //! Set the backing storage (untyped data)
129 //! Data must be aligned for T and must contain at least getByteArraySize(size) bytes.
130 23 void setStorage(ByteArray data, //!< The data
131 FwSizeType size //!< The array size
132 ) {
133 // Check that data.bytes is not null
134 23 FW_ASSERT(data.bytes != nullptr);
135 // Check that data.bytes is properly aligned
136 23 FW_ASSERT(reinterpret_cast<uintptr_t>(data.bytes) % alignof(T) == 0);
137 // Check that data.size is large enough to hold the array
138 // The division form is used because size * sizeof(T) can overflow FwSizeType
139 23 FW_ASSERT(size <= data.size / sizeof(T));
140 // Release the backing storage
141 23 this->releaseStorage();
142 // Initialize the array members
143 23 this->m_elements = reinterpret_cast<T*>(data.bytes);
144 // Construct the array members in place
145 // This step ensures that each array element holds a valid object
146 // into which we can assign data
147
2/2
✓ Branch 0 taken 11277 times.
✓ Branch 1 taken 13 times.
19505 for (FwSizeType i = 0; i < size; i++) {
148 // This code trips an alignment check in clang-tidy
149 // However the alignment has been checked by FW_ASSERT above
150
3/8
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 2048 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 15 taken 1024 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
19482 (void)new (&this->m_elements[i]) T(); // NOLINT
151 }
152 // Set the size
153 23 this->m_size = size;
154 // Destroy elements on release of storage
155 23 this->m_destroyElementsOnRelease = true;
156 23 }
157
158 public:
159 // ----------------------------------------------------------------------
160 // Public static functions
161 // ----------------------------------------------------------------------
162
163 //! Get the alignment of the storage for an ExternalArray
164 //! \return The alignment
165 static constexpr U8 getByteArrayAlignment() { return alignof(T); }
166
167 //! Get the size of the storage for an ExternalArray of the specified size,
168 //! as a byte array
169 //! \return The byte array size
170 12 static constexpr FwSizeType getByteArraySize(FwSizeType size //!< The size
171 ) {
172 12 return size * sizeof(T);
173 }
174
175 private:
176 // ----------------------------------------------------------------------
177 // Private member functions
178 // ----------------------------------------------------------------------
179
180 //! Release the backing storage
181 7228 void releaseStorage() {
182
5/6
✓ Branch 1 taken 2287 times.
✓ Branch 2 taken 1581 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2287 times.
✓ Branch 6 taken 13 times.
✓ Branch 7 taken 2274 times.
7228 if ((this->m_elements != nullptr) && this->m_destroyElementsOnRelease) {
183
2/2
✓ Branch 2 taken 11277 times.
✓ Branch 3 taken 13 times.
17444 for (FwSizeType i = 0; i < this->m_size; i++) {
184 17424 this->m_elements[i].~T();
185 }
186 20 this->m_destroyElementsOnRelease = false;
187 }
188 7228 }
189
190 private:
191 // ----------------------------------------------------------------------
192 // Private member variables
193 // ----------------------------------------------------------------------
194
195 //! The array elements
196 T* m_elements = nullptr;
197
198 //! The size
199 FwSizeType m_size = 0;
200
201 //! Whether to destroy the array elements when the backing storage is released
202 bool m_destroyElementsOnRelease = false;
203 };
204
205 } // namespace Fw
206
207 #endif
208