GCC Code Coverage Report


Directory: include/tts/
File: include/tts/tools/buffer.hpp
Date: 2026-10-14 16:28:14
Exec Total Coverage
Lines: 115 117 98.3%
Functions: 80 80 100.0%
Branches: 38 58 65.5%

Line Branch Exec Source
1 //======================================================================================================================
2 /*
3 TTS - Tiny Test System
4 Copyright : TTS Contributors & Maintainers
5 SPDX-License-Identifier: BSL-1.0
6 */
7 //======================================================================================================================
8 #pragma once
9
10 #include <tts/tools/preprocessor.hpp>
11
12 namespace tts
13 {
14 template<typename T> class buffer
15 {
16 // eve::wide and friends are over-aligned; malloc only promises alignof(std::max_align_t)
17 static constexpr bool over_aligned = alignof(T) > alignof(std::max_align_t);
18
19 // malloc keeps the test registry out of the operator new and delete a test may replace
20 229 static T* allocate(std::size_t n) noexcept
21 {
22 if constexpr(over_aligned)
23 return static_cast<T*>(
24 ::operator new(sizeof(T) * n, std::align_val_t {alignof(T)}, std::nothrow));
25 229 else return static_cast<T*>(malloc(sizeof(T) * n)); // NOSONAR - test may replace new
26 }
27
28 326 static void deallocate(T* p) noexcept
29 {
30 if constexpr(over_aligned) ::operator delete(p, std::align_val_t {alignof(T)});
31 326 else free(p); // NOSONAR - test may replace delete
32 326 }
33
34 public:
35 182 buffer()
36 182 : size_(0)
37 182 , capacity_(0)
38 182 , data_(nullptr)
39 {
40 182 }
41
42 49 explicit buffer(std::size_t n)
43 49 : buffer()
44 {
45
1/2
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
49 if(n > 0)
46 {
47 49 data_ = allocate(n);
48
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
49 assert(data_ && "tts::buffer out of memory");
49
50 49 size_ = n;
51 49 capacity_ = n;
52
2/2
✓ Branch 0 taken 65642 times.
✓ Branch 1 taken 25 times.
131269 for(std::size_t i = 0; i < n; ++i)
53
2/3
✗ Branch 1 not taken.
✓ Branch 2 taken 65641 times.
✓ Branch 3 taken 1 times.
131220 new(data_ + i) T();
54 }
55 49 }
56
57 16 buffer(std::size_t n, T val)
58 16 : buffer()
59 {
60
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
16 if(n > 0)
61 {
62 16 data_ = allocate(n);
63
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
16 assert(data_ && "tts::buffer out of memory");
64
65 16 size_ = n;
66 16 capacity_ = n;
67
2/2
✓ Branch 0 taken 152 times.
✓ Branch 1 taken 8 times.
320 for(std::size_t i = 0; i < n; ++i)
68
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 152 times.
304 new(data_ + i) T(val);
69 }
70 16 }
71
72 2 buffer(std::initializer_list<T> init)
73 2 : buffer()
74 {
75 2 std::size_t n = init.size();
76
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(n > 0)
77 {
78 2 data_ = allocate(n);
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 assert(data_ && "tts::buffer out of memory");
80
81 2 size_ = n;
82 2 capacity_ = n;
83 2 std::size_t i = 0;
84
2/2
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 2 times.
11 for(auto const& v: init)
85
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
9 new(data_ + (i++)) T(v);
86 }
87 2 }
88
89 182 ~buffer()
90 {
91
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 6 times.
182 if(data_)
92 {
93 if constexpr(!std::is_trivially_destructible_v<T>)
94 {
95
2/2
✓ Branch 0 taken 280 times.
✓ Branch 1 taken 96 times.
385 for(std::size_t i = 0; i < size_; ++i)
96 286 (data_ + i)->~T(); // NOSONAR - T may be non-trivial
97 }
98 171 deallocate(data_);
99 }
100 182 }
101
102 2 buffer(buffer const& other)
103 2 : buffer()
104 {
105
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(other.size_ > 0)
106 {
107 2 data_ = allocate(other.size_);
108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 assert(data_ && "tts::buffer out of memory");
109
110 2 size_ = other.size_;
111 2 capacity_ = other.size_;
112
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
16 for(std::size_t i = 0; i < size_; ++i)
113
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
14 new(data_ + i) T(other.data_[ i ]);
114 }
115 2 }
116
117 2 buffer(buffer&& other) noexcept
118 2 : buffer()
119 {
120 2 swap(other);
121 2 }
122
123 1 buffer& operator=(buffer const& other)
124 {
125 1 buffer local(other);
126 1 swap(local);
127 2 return *this;
128 1 }
129
130 1 buffer& operator=(buffer&& other) noexcept
131 {
132 1 buffer local(TTS_MOVE(other));
133 1 swap(local);
134 2 return *this;
135 1 }
136
137 void push_back(T const& value)
138 {
139 ensure_capacity(size_ + 1);
140 new(data_ + size_++) T(value);
141 }
142
143 1 void push_back(T&& value)
144 {
145 1 ensure_capacity(size_ + 1);
146
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 new(data_ + size_++) T(TTS_MOVE(value));
147 1 }
148
149 277 template<typename... Args> void emplace_back(Args&&... args)
150 {
151 277 ensure_capacity(size_ + 1);
152
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 277 times.
277 new(data_ + size_++) T(TTS_FWD(args)...);
153 277 }
154
155 6 T const& operator[](std::size_t i) const
156 {
157 6 return data_[ i ];
158 }
159 262722 T& operator[](std::size_t i)
160 {
161 262722 return data_[ i ];
162 }
163
164 16 T const* data() const
165 {
166 16 return data_;
167 }
168 8 T* data()
169 {
170 8 return data_;
171 }
172
173 decltype(auto) begin() const
174 {
175 return data_;
176 }
177 169 decltype(auto) begin()
178 {
179 169 return data_;
180 }
181 decltype(auto) end() const
182 {
183 return data_ + size_;
184 }
185 147 decltype(auto) end()
186 {
187 147 return data_ + size_;
188 }
189
190 bool empty() const noexcept
191 {
192 return size_ == 0;
193 }
194 65850 std::size_t size() const noexcept
195 {
196 65850 return size_;
197 }
198 22 std::size_t capacity() const noexcept
199 {
200 22 return capacity_;
201 }
202
203 5 void swap(buffer& other) noexcept
204 {
205 5 std::swap(size_, other.size_);
206 5 std::swap(capacity_, other.capacity_);
207 5 std::swap(data_, other.data_);
208 5 }
209
210 private:
211 std::size_t size_;
212 std::size_t capacity_;
213 T* data_;
214
215 281 void ensure_capacity(std::size_t new_capacity)
216 {
217
2/2
✓ Branch 0 taken 151 times.
✓ Branch 1 taken 127 times.
281 if(new_capacity > capacity_)
218 {
219
1/2
✓ Branch 1 taken 151 times.
✗ Branch 2 not taken.
154 assert(capacity_ <= std::numeric_limits<std::size_t>::max() / 2 &&
220 "tts::buffer requested capacity overflows size_t");
221
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 95 times.
154 std::size_t new_cap = capacity_ == 0 ? 1 : capacity_ * 2;
222
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 151 times.
154 while(new_cap < new_capacity)
223 {
224 ✗ assert(new_cap <= std::numeric_limits<std::size_t>::max() / 2 &&
225 "tts::buffer requested capacity overflows size_t");
226 ✗ new_cap *= 2;
227 }
228
229 154 auto new_data = allocate(new_cap);
230
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 151 times.
154 assert(new_data && "tts::buffer out of memory");
231
232
2/2
✓ Branch 0 taken 322 times.
✓ Branch 1 taken 151 times.
541 for(std::size_t i = 0; i < size_; ++i)
233 {
234
2/3
✗ Branch 1 not taken.
✓ Branch 2 taken 64 times.
✓ Branch 3 taken 258 times.
387 new(new_data + i) T(TTS_MOVE(data_[ i ]));
235 if constexpr(!std::is_trivially_destructible_v<T>)
236 259 (data_ + i)->~T(); // NOSONAR - T may be non-trivial
237 }
238
239 154 deallocate(data_);
240 154 data_ = new_data;
241 154 capacity_ = new_cap;
242 }
243 281 }
244 };
245 }
246