Line | Branch | Exec | Source |
---|---|---|---|
1 | /** | ||
2 | * @file lib.Heap.hpp | ||
3 | * @author Sergey Baigudin, sergey@baigudin.software | ||
4 | * @copyright 2014-2022, Sergey Baigudin, Baigudin Software | ||
5 | */ | ||
6 | #ifndef LIB_HEAP_HPP_ | ||
7 | #define LIB_HEAP_HPP_ | ||
8 | |||
9 | #include "api.Heap.hpp" | ||
10 | #include "lib.MutexGuard.hpp" | ||
11 | |||
12 | namespace eoos | ||
13 | { | ||
14 | namespace lib | ||
15 | { | ||
16 | |||
17 | /** | ||
18 | * @class Heap | ||
19 | * @brief Heap memory. | ||
20 | * | ||
21 | * Hardware address for system heap memory has to be aligned to eight. | ||
22 | */ | ||
23 | class Heap : public api::Heap | ||
24 | { | ||
25 | typedef Heap Self; | ||
26 | |||
27 | class NoAllocator; | ||
28 | |||
29 | public: | ||
30 | |||
31 | /** | ||
32 | * @brief Constructor. | ||
33 | * | ||
34 | * @param size Total heap size. | ||
35 | * @param mutex A mutex to protect memory allocation. | ||
36 | */ | ||
37 | 7 | Heap(size_t size, api::Mutex& mutex) | |
38 | 7 | : api::Heap() | |
39 | 7 | , data_(size, mutex) | |
40 | 7 | , temp_() { | |
41 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | bool_t const isConstructed( construct() ); |
42 | 7 | setConstructed( isConstructed ); | |
43 | 7 | } | |
44 | |||
45 | /** | ||
46 | * @brief Destructor. | ||
47 | */ | ||
48 | ✗ | virtual ~Heap() ///< UT Justified Branch: Language dependency | |
49 | { | ||
50 | ✗ | data_.key = 0; | |
51 | } | ||
52 | |||
53 | /** | ||
54 | * @copydoc eoos::api::Object::isConstructed() | ||
55 | */ | ||
56 | 102 | virtual bool_t isConstructed() const | |
57 | { | ||
58 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
|
102 | if( data_.key != HEAP_KEY ) |
59 | { ///< UT Justified Branch: HW dependency | ||
60 | ✗ | return false; | |
61 | } | ||
62 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 102 times.
|
102 | if( !getFirstHeapBlock()->isConstructed() ) |
63 | { ///< UT Justified Branch: HW dependency | ||
64 | ✗ | return false; | |
65 | } | ||
66 | 102 | return true; | |
67 | } | ||
68 | |||
69 | /** | ||
70 | * @copydoc eoos::api::Heap::allocate(size_t,void*) | ||
71 | */ | ||
72 | 47 | virtual void* allocate(size_t const size, void* ptr) | |
73 | { | ||
74 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 46 times.
|
47 | if( !isConstructed() ) |
75 | { | ||
76 | 1 | return NULLPTR; | |
77 | } | ||
78 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | if( ptr == NULLPTR ) |
79 | { | ||
80 |
1/2✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
|
46 | MutexGuard<NoAllocator> guard( *data_.mutex ); |
81 |
1/2✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
|
46 | ptr = getFirstHeapBlock()->alloc(size); |
82 | 46 | } | |
83 | 46 | return ptr; | |
84 | } | ||
85 | |||
86 | /** | ||
87 | * @copydoc eoos::api::Heap::free(void*) | ||
88 | */ | ||
89 | 29 | virtual void free(void* ptr) | |
90 | { | ||
91 |
3/4✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 28 times.
|
29 | if( !isConstructed() ) |
92 | { | ||
93 | 2 | return; | |
94 | } | ||
95 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 27 times.
|
28 | if( ptr == NULLPTR ) |
96 | { | ||
97 | 1 | return; | |
98 | } | ||
99 |
1/2✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
|
27 | MutexGuard<NoAllocator> guard( *data_.mutex ); |
100 |
1/2✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
|
27 | getHeapBlock(ptr)->free(); |
101 | 27 | } | |
102 | |||
103 | /** | ||
104 | * @brief Operator new. | ||
105 | * | ||
106 | * Function initiates a building of heap memory | ||
107 | * checks and tests self memory structure data | ||
108 | * and leads to call the class constructor. | ||
109 | * | ||
110 | * @param size Unused. | ||
111 | * @param ptr Aligned to eight memory address. | ||
112 | * @return Address of memory or NULLPTR. | ||
113 | */ | ||
114 | 8 | static void* operator new(size_t, uintptr_t const ptr) EOOS_KEYWORD_NOEXCEPT | |
115 | { | ||
116 | void* memory; | ||
117 | 8 | void* address( reinterpret_cast< void* >(ptr) ); ///< SCA MISRA-C++:2008 Justified Rule 5-2-8 | |
118 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
|
8 | if(address == NULLPTR) |
119 | { | ||
120 | // No class constructor call | ||
121 | 1 | memory = address; | |
122 | } | ||
123 | else | ||
124 | { | ||
125 | // Create the heap | ||
126 | 7 | memory = create(address); | |
127 | } | ||
128 | 8 | return memory; | |
129 | } | ||
130 | |||
131 | /** | ||
132 | * @brief Operator delete. | ||
133 | */ | ||
134 | ✗ | static void operator delete(void*, uintptr_t) {} ///< UT Justified Branch: Language dependency | |
135 | |||
136 | /** | ||
137 | * @brief Operator delete. | ||
138 | */ | ||
139 | ✗ | static void operator delete(void*) {} ///< UT Justified Branch: Language dependency | |
140 | |||
141 | private: | ||
142 | |||
143 | class HeapBlock; | ||
144 | |||
145 | /** | ||
146 | * @copydoc eoos::lib::Object::setConstructed(bool_t) | ||
147 | */ | ||
148 | 7 | void setConstructed(bool_t const flag) | |
149 | { | ||
150 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | if(data_.key == HEAP_KEY) |
151 | { | ||
152 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | data_.key = flag ? HEAP_KEY : 0; |
153 | } | ||
154 | 7 | } | |
155 | |||
156 | /** | ||
157 | * @brief Constructor. | ||
158 | * | ||
159 | * @return True if object has been constructed successfully. | ||
160 | */ | ||
161 | 7 | bool_t construct() | |
162 | { | ||
163 | // Crop a size to multiple of eight | ||
164 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if( (sizeof(HeapBlock) + 16UL) > data_.size ) |
165 | { ///< UT Justified Branch: HW dependency | ||
166 | ✗ | return false; | |
167 | } | ||
168 | // Test Heap and HeapBlock structures sizes witch has to be multipled to eight | ||
169 | if( (sizeof(Heap) & 0x7UL) != 0UL ) | ||
170 | { ///< UT Justified Branch: HW dependency | ||
171 | return false; | ||
172 | } | ||
173 | if( (sizeof(HeapBlock) & 0x7UL) != 0UL ) | ||
174 | { ///< UT Justified Branch: HW dependency | ||
175 | return false; | ||
176 | } | ||
177 | // Test memory | ||
178 | 7 | uintptr_t const addr( reinterpret_cast<uintptr_t>(this) + sizeof(Heap) ); ///< SCA MISRA-C++:2008 Justified Rule 5-2-9 | |
179 | 7 | void* ptr ( reinterpret_cast<void*>(addr) ); ///< SCA MISRA-C++:2008 Justified Rule 5-2-8 | |
180 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
|
7 | if( !isMemoryAvailable(ptr, data_.size) ) |
181 | { ///< UT Justified Branch: HW dependency | ||
182 | ✗ | return false; | |
183 | } | ||
184 | // Alloc first heap block | ||
185 | 7 | data_.block = new ( getFirstHeapBlock() ) HeapBlock(this, data_.size); | |
186 | 7 | return (data_.block != NULLPTR) ? true : false; | |
187 | } | ||
188 | |||
189 | /** | ||
190 | * @brief Returns a first heap block address. | ||
191 | * | ||
192 | * @return Pointer to heap block. | ||
193 | */ | ||
194 | 155 | HeapBlock* getFirstHeapBlock() const | |
195 | { | ||
196 | 155 | uintptr_t const addr( reinterpret_cast<uintptr_t>(this) + sizeof(Heap) ); ///< SCA MISRA-C++:2008 Justified Rule 5-2-9 | |
197 | 155 | return reinterpret_cast<HeapBlock*>(addr); ///< SCA MISRA-C++:2008 Justified Rule 5-2-8 | |
198 | } | ||
199 | |||
200 | /** | ||
201 | * @brief Returns a heap block by user data address. | ||
202 | * | ||
203 | * @return Pointer to heap block. | ||
204 | */ | ||
205 | 27 | static HeapBlock* getHeapBlock(void* const data) | |
206 | { | ||
207 | 27 | uintptr_t const addr( reinterpret_cast<uintptr_t>(data) - sizeof(HeapBlock) ); ///< SCA MISRA-C++:2008 Justified Rule 5-2-9 | |
208 | 27 | return reinterpret_cast<HeapBlock*>(addr); ///< SCA MISRA-C++:2008 Justified Rule 5-2-8 | |
209 | } | ||
210 | |||
211 | /** | ||
212 | * @brief Allocates memory for heap. | ||
213 | * | ||
214 | * Function initiates a building of heap memory | ||
215 | * checks and tests self memory structure data | ||
216 | * and leads to call the class constructor. | ||
217 | * | ||
218 | * @param ptr Aligned to eight memory address. | ||
219 | * @return Address of memory or NULLPTR. | ||
220 | */ | ||
221 | 7 | static void* create(void* ptr) | |
222 | { | ||
223 | // Size of this class has to be multipled to eight | ||
224 | if( (sizeof(Heap) & 0x7UL) != 0UL ) | ||
225 | { ///< UT Justified Branch: HW dependency | ||
226 | ptr = NULLPTR; | ||
227 | } | ||
228 | // Testing memory for self structure data | ||
229 | // | ||
230 | // @todo copy constructor of the Heap class for | ||
231 | // temporary copying the tested memory to that | ||
232 | // class. This way would help to restore original | ||
233 | // memory data if the test were failed. | ||
234 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
|
7 | if( !isMemoryAvailable(ptr, sizeof(Heap)) ) |
235 | { ///< UT Justified Branch: HW dependency | ||
236 | ✗ | ptr = NULLPTR; | |
237 | } | ||
238 | // Memory address has to be aligned to eight | ||
239 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if( (reinterpret_cast<uintptr_t>(ptr) & 0x7UL) != 0UL ) ///< SCA MISRA-C++:2008 Justified Rule 5-2-9 |
240 | { ///< UT Justified Branch: HW dependency | ||
241 | ✗ | ptr = NULLPTR; | |
242 | } | ||
243 | 7 | return ptr; | |
244 | } | ||
245 | |||
246 | /** | ||
247 | * @brief Tests memory. | ||
248 | * | ||
249 | * @todo normal type casts should be done. | ||
250 | * | ||
251 | * @param addr Memory address pointer. | ||
252 | * @param size Size in byte. | ||
253 | * @return True if test complete. | ||
254 | */ | ||
255 | 14 | static bool_t isMemoryAvailable(void* const addr, size_t const size) | |
256 | { | ||
257 | 14 | size_t mask( static_cast<ucell_t>(-1) ); | |
258 | 14 | ucell_t* ptr( reinterpret_cast<ucell_t*>(addr) ); ///< SCA MISRA-C++:2008 Justified Rule 5-2-8 | |
259 | // Value test | ||
260 |
2/2✓ Branch 0 taken 25600 times.
✓ Branch 1 taken 14 times.
|
25614 | for( size_t i(0UL); i<size; i++) |
261 | { | ||
262 | 25600 | ptr[i] = static_cast<ucell_t>(i & mask); | |
263 | } | ||
264 |
2/2✓ Branch 0 taken 25600 times.
✓ Branch 1 taken 14 times.
|
25614 | for( size_t i(0UL); i<size; i++) |
265 | { | ||
266 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25600 times.
|
25600 | if(ptr[i] != static_cast<ucell_t>(i & mask)) |
267 | { ///< UT Justified Branch: HW dependency | ||
268 | ✗ | return false; | |
269 | } | ||
270 | } | ||
271 | // 0x55 test | ||
272 |
2/2✓ Branch 0 taken 25600 times.
✓ Branch 1 taken 14 times.
|
25614 | for( size_t i(0UL); i<size; i++) |
273 | { | ||
274 | 25600 | ptr[i] = static_cast<ucell_t>(0x55555555UL & mask); | |
275 | } | ||
276 |
2/2✓ Branch 0 taken 25600 times.
✓ Branch 1 taken 14 times.
|
25614 | for( size_t i(0UL); i<size; i++) |
277 | { | ||
278 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25600 times.
|
25600 | if(ptr[i] != static_cast<ucell_t>(0x55555555UL & mask)) |
279 | { ///< UT Justified Branch: HW dependency | ||
280 | ✗ | return false; | |
281 | } | ||
282 | } | ||
283 | // 0xAA test | ||
284 |
2/2✓ Branch 0 taken 25600 times.
✓ Branch 1 taken 14 times.
|
25614 | for( size_t i(0UL); i<size; i++) |
285 | { | ||
286 | 25600 | ptr[i] = static_cast<ucell_t>(0xAAAAAAAAUL & mask); | |
287 | } | ||
288 |
2/2✓ Branch 0 taken 25600 times.
✓ Branch 1 taken 14 times.
|
25614 | for( size_t i(0UL); i<size; i++) |
289 | { | ||
290 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25600 times.
|
25600 | if(ptr[i] != static_cast<ucell_t>(0xAAAAAAAAUL & mask)) |
291 | { ///< UT Justified Branch: HW dependency | ||
292 | ✗ | return false; | |
293 | } | ||
294 | } | ||
295 | // Zero test | ||
296 |
2/2✓ Branch 0 taken 25600 times.
✓ Branch 1 taken 14 times.
|
25614 | for( size_t i(0UL); i<size; i++) |
297 | { | ||
298 | 25600 | ptr[i] = 0x00U; | |
299 | } | ||
300 |
2/2✓ Branch 0 taken 25600 times.
✓ Branch 1 taken 14 times.
|
25614 | for( size_t i(0UL); i<size; i++) |
301 | { | ||
302 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25600 times.
|
25600 | if(ptr[i] != 0x00U) |
303 | { ///< UT Justified Branch: HW dependency | ||
304 | ✗ | return false; | |
305 | } | ||
306 | } | ||
307 | 14 | return true; | |
308 | } | ||
309 | |||
310 | /** | ||
311 | * @copydoc eoos::Object::Object(Object const&) | ||
312 | */ | ||
313 | Heap(Heap const&); ///< SCA MISRA-C++:2008 Justified Rule 3-2-2 and Rule 3-2-4 | ||
314 | |||
315 | /** | ||
316 | * @copydoc eoos::Object::operator=(Object const&) | ||
317 | */ | ||
318 | Heap& operator=(Heap const&); ///< SCA MISRA-C++:2008 Justified Rule 3-2-2 and Rule 3-2-4 | ||
319 | |||
320 | #if EOOS_CPP_STANDARD >= 2011 | ||
321 | |||
322 | /** | ||
323 | * @copydoc eoos::Object::Object(Object&&) | ||
324 | */ | ||
325 | Heap(Heap&&) noexcept = delete; | ||
326 | |||
327 | /** | ||
328 | * @copydoc eoos::Object::operator=(Object&&) | ||
329 | */ | ||
330 | Heap& operator=(Heap&&) & noexcept = delete; | ||
331 | |||
332 | #endif // EOOS_CPP_STANDARD >= 2011 | ||
333 | |||
334 | /** | ||
335 | * @class NoAllocator | ||
336 | * @brief No allocator for creating MutexGuard on stack. | ||
337 | */ | ||
338 | class NoAllocator | ||
339 | { | ||
340 | |||
341 | public: | ||
342 | |||
343 | /** | ||
344 | * @copydoc eoos::lib::Allocator::allocate(size_t) | ||
345 | */ | ||
346 | static void* allocate(size_t) | ||
347 | { | ||
348 | return NULLPTR; | ||
349 | } | ||
350 | |||
351 | /** | ||
352 | * @copydoc eoos::lib::Allocator::allocate(size_t). | ||
353 | */ | ||
354 | ✗ | static void free(void*) ///< UT Justified Branch: Language dependency | |
355 | { | ||
356 | } | ||
357 | }; | ||
358 | |||
359 | /** | ||
360 | * @struct Aligner<S> | ||
361 | * @brief Heap class aligner aligns that to eight. | ||
362 | * | ||
363 | * @note If given S is already multiple 8, the class size will be 8 bytes. | ||
364 | * | ||
365 | * @tparam S Size of Heap class. | ||
366 | */ | ||
367 | template <size_t S> | ||
368 | struct Aligner | ||
369 | { | ||
370 | |||
371 | public: | ||
372 | |||
373 | /** | ||
374 | * @brief Constructor. | ||
375 | */ | ||
376 | 7 | Aligner() | |
377 | { | ||
378 | #ifdef EOOS_DEBUG | ||
379 | for(size_t i(0U); i<SIZE; i++) | ||
380 | { | ||
381 | val_[i] = 0x0AUL; | ||
382 | } | ||
383 | #endif | ||
384 | 7 | } | |
385 | |||
386 | private: | ||
387 | |||
388 | /** | ||
389 | * @brief Aligning data size. | ||
390 | */ | ||
391 | static const size_t SIZEOF = S; | ||
392 | |||
393 | /** | ||
394 | * @brief Aligning data size. | ||
395 | */ | ||
396 | static const size_t MASK = ~0x7UL; | ||
397 | |||
398 | /** | ||
399 | * @brief Aligning data size. | ||
400 | */ | ||
401 | static const size_t SIZE = ( ( SIZEOF & MASK ) + 0x8UL ) - SIZEOF; | ||
402 | |||
403 | /** | ||
404 | * @brief Temp array. | ||
405 | */ | ||
406 | ucell_t val_[SIZE]; | ||
407 | |||
408 | }; | ||
409 | |||
410 | /** | ||
411 | * @class VirtualTable | ||
412 | * @brief Contains a Virtual Function Table only. | ||
413 | * | ||
414 | * Probably, the solution of using this empty class | ||
415 | * is not delicate, but it works for understanding | ||
416 | * about size of a virtual function table of this Heap class. | ||
417 | * | ||
418 | * @note This uint64_t variable of the class is used, because some compilers | ||
419 | * might put 64 bit variable to aligned 8 memory address. Therefore, size of classes | ||
420 | * with 32 bit pointer to virtual table and one 64 bit variable is 16 bytes. | ||
421 | */ | ||
422 | class VirtualTable : public api::Heap{uint64_t temp;}; | ||
423 | |||
424 | /** | ||
425 | * @class HeapBlock | ||
426 | * @brief Heap memory block. | ||
427 | * | ||
428 | * The class data has to be aligned to 8. | ||
429 | */ | ||
430 | class HeapBlock | ||
431 | { | ||
432 | |||
433 | public: | ||
434 | |||
435 | /** | ||
436 | * @brief Constructor. | ||
437 | * | ||
438 | * @param heap Pointer to heap class. | ||
439 | * @param size Size of byte given to this new block. | ||
440 | */ | ||
441 | 49 | HeapBlock(api::Heap* heap, size_t size) | |
442 | 49 | : heap_(heap) | |
443 | 49 | , prev_(NULLPTR) | |
444 | 49 | , next_(NULLPTR) | |
445 | 49 | , attr_(0) | |
446 | 49 | , size_(size - sizeof(HeapBlock)) | |
447 | 49 | , key_(BLOCK_KEY) { | |
448 | 49 | } | |
449 | |||
450 | /** | ||
451 | * @brief Destructor. | ||
452 | */ | ||
453 | ~HeapBlock() | ||
454 | { | ||
455 | } | ||
456 | |||
457 | /** | ||
458 | * @brief Tests if this object has been constructed. | ||
459 | * | ||
460 | * @return True if object has been constructed successfully. | ||
461 | */ | ||
462 | 129 | bool_t isConstructed() const | |
463 | { | ||
464 | 129 | return (key_ == BLOCK_KEY) ? true : false; | |
465 | } | ||
466 | |||
467 | /** | ||
468 | * @brief Allocates a memory block. | ||
469 | * | ||
470 | * @param size Size in byte. | ||
471 | * @return Pointer to an allocated memory. | ||
472 | */ | ||
473 | 46 | void* alloc(size_t size) | |
474 | { | ||
475 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 45 times.
|
46 | if(size == 0UL) |
476 | { | ||
477 | 1 | return NULLPTR; | |
478 | } | ||
479 | // Align a size to 8 byte boudary | ||
480 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 44 times.
|
45 | if((size & 0x7UL) != 0UL) |
481 | { | ||
482 | 1 | size = (size & ~0x7UL) + 0x8UL; | |
483 | } | ||
484 | 45 | HeapBlock* curr( this ); | |
485 |
2/2✓ Branch 0 taken 335 times.
✓ Branch 1 taken 1 times.
|
336 | while(curr != NULLPTR) |
486 | { | ||
487 |
6/6✓ Branch 1 taken 46 times.
✓ Branch 2 taken 289 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 44 times.
✓ Branch 5 taken 291 times.
✓ Branch 6 taken 44 times.
|
335 | if(curr->isUsed() || (curr->size_ < size) ) |
488 | { | ||
489 | 291 | curr = curr->next_; | |
490 | } | ||
491 | else | ||
492 | { | ||
493 | 44 | break; | |
494 | } | ||
495 | } | ||
496 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 44 times.
|
45 | if(curr == NULLPTR) |
497 | { | ||
498 | 1 | return NULLPTR; | |
499 | } | ||
500 | // Has required memory size for data and a new heap block | ||
501 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 2 times.
|
44 | if( curr->size_ >= (size + sizeof(HeapBlock)) ) |
502 | { | ||
503 | 42 | HeapBlock* next( new ( curr->next(size) ) HeapBlock(heap_, curr->size_ - size) ); | |
504 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
|
42 | if(next == NULLPTR) |
505 | { ///< UT Justified Branch: HW dependency | ||
506 | ✗ | return NULLPTR; | |
507 | } | ||
508 | 42 | next->next_ = curr->next_; | |
509 | 42 | next->prev_ = curr; | |
510 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 41 times.
|
42 | if(next->next_ != NULLPTR) |
511 | { | ||
512 | 1 | next->next_->prev_ = next; | |
513 | } | ||
514 | 42 | curr->next_ = next; | |
515 | 42 | curr->size_ = size; | |
516 | } | ||
517 | 44 | curr->attr_ |= ATTR_USED; | |
518 | 44 | return curr->data(); | |
519 | } | ||
520 | |||
521 | /** | ||
522 | * @brief Frees allocated memory by this block. | ||
523 | */ | ||
524 | 27 | void free() | |
525 | { | ||
526 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
|
27 | if( !canDelete() ) |
527 | { ///< UT Justified Branch: HW dependency | ||
528 | ✗ | return; | |
529 | } | ||
530 | 27 | uint32_t sibling( 0UL ); | |
531 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 3 times.
|
27 | if( prev_ != NULLPTR ) |
532 | { | ||
533 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 18 times.
|
24 | if( !prev_->isUsed() ) |
534 | { | ||
535 | 6 | sibling |= PREV_FREE; | |
536 | } | ||
537 | } | ||
538 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 1 times.
|
27 | if( next_ != NULLPTR ) |
539 | { | ||
540 |
2/2✓ Branch 1 taken 18 times.
✓ Branch 2 taken 8 times.
|
26 | if( !next_->isUsed() ) |
541 | { | ||
542 | 18 | sibling |= NEXT_FREE; | |
543 | } | ||
544 | } | ||
545 |
4/4✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 7 times.
|
27 | switch(sibling) |
546 | { | ||
547 | 4 | case PREV_FREE | NEXT_FREE: | |
548 | { | ||
549 | 4 | prev_->size_ += ( 2UL * sizeof(HeapBlock) ) + size_ + next_->size_; | |
550 | 4 | prev_->next_ = next_->next_; | |
551 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
|
4 | if(prev_->next_ != NULLPTR) |
552 | { | ||
553 | 1 | prev_->next_->prev_ = prev_; | |
554 | } | ||
555 | 4 | break; | |
556 | } | ||
557 | 2 | case PREV_FREE: | |
558 | { | ||
559 | 2 | prev_->size_ += sizeof(HeapBlock) + size_; | |
560 | 2 | prev_->next_ = next_; | |
561 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if(next_ != NULLPTR) |
562 | { | ||
563 | 2 | next_->prev_ = prev_; | |
564 | } | ||
565 | 2 | break; | |
566 | } | ||
567 | 14 | case NEXT_FREE: | |
568 | { | ||
569 | 14 | size_ += sizeof(HeapBlock) + next_->size_; | |
570 | 14 | next_ = next_->next_; | |
571 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 10 times.
|
14 | if(next_ != NULLPTR) |
572 | { | ||
573 | 4 | next_->prev_ = this; | |
574 | } | ||
575 | 14 | attr_ &= MASK_UNUSED; | |
576 | 14 | break; | |
577 | } | ||
578 | 7 | default: | |
579 | { | ||
580 | 7 | attr_ &= MASK_UNUSED; | |
581 | 7 | break; | |
582 | } | ||
583 | } | ||
584 | } | ||
585 | |||
586 | /** | ||
587 | * @brief Operator new. | ||
588 | * | ||
589 | * @param size Unused. | ||
590 | * @param ptr Address of memory. | ||
591 | * @return Address of memory. | ||
592 | */ | ||
593 | 49 | static void* operator new(size_t, void* const ptr) | |
594 | { | ||
595 | 49 | void* memory( NULLPTR ); | |
596 | do | ||
597 | { | ||
598 | // Size of this class must be multipled to eight | ||
599 | if((sizeof(HeapBlock) & 0x7UL) != 0UL) | ||
600 | { ///< UT Justified Branch: HW dependency | ||
601 | break; | ||
602 | } | ||
603 | // The passed address must be multipled to eight | ||
604 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 49 times.
|
49 | if((reinterpret_cast<uintptr_t>(ptr) & 0x7UL) != 0UL) ///< SCA MISRA-C++:2008 Justified Rule 5-2-9 |
605 | { ///< UT Justified Branch: HW dependency | ||
606 | ✗ | break; | |
607 | } | ||
608 | 49 | memory = ptr; | |
609 | } | ||
610 | while(false); | ||
611 | 49 | return memory; | |
612 | } | ||
613 | |||
614 | /** | ||
615 | * @brief Operator delete. | ||
616 | */ | ||
617 | static void operator delete(void*, void*) {} ///< UT Justified Branch: Language dependency | ||
618 | |||
619 | private: | ||
620 | |||
621 | /** | ||
622 | * @brief Tests if this memory block is available for deleting. | ||
623 | * | ||
624 | * @return True if it may be deleted. | ||
625 | */ | ||
626 | 27 | bool_t canDelete() const | |
627 | { | ||
628 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
|
27 | if( !isConstructed() ) |
629 | { ///< UT Justified Branch: HW dependency | ||
630 | ✗ | return false; | |
631 | } | ||
632 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
|
27 | if( !heap_->isConstructed() ) |
633 | { ///< UT Justified Branch: HW dependency | ||
634 | ✗ | return false; | |
635 | } | ||
636 | 27 | return true; | |
637 | } | ||
638 | |||
639 | /** | ||
640 | * @brief Tests if this memory block is available. | ||
641 | * | ||
642 | * @return True if memory block is available. | ||
643 | */ | ||
644 | 385 | bool_t isUsed() const | |
645 | { | ||
646 | 385 | return ( (attr_ & ATTR_USED) != 0UL ) ? true : false; | |
647 | } | ||
648 | |||
649 | /** | ||
650 | * @brief Returns an address to data of this block. | ||
651 | * | ||
652 | * @return Pointer to memory. | ||
653 | */ | ||
654 | 44 | void* data() | |
655 | { | ||
656 | 44 | uintptr_t const addr( reinterpret_cast<uintptr_t>(this) + sizeof(HeapBlock) ); ///< SCA MISRA-C++:2008 Justified Rule 5-2-9 | |
657 | 44 | return reinterpret_cast<void*>(addr); ///< SCA MISRA-C++:2008 Justified Rule 5-2-8 | |
658 | } | ||
659 | |||
660 | /** | ||
661 | * @brief Returns an address to next block. | ||
662 | * | ||
663 | * @return PSinter to memory. | ||
664 | */ | ||
665 | 42 | void* next(size_t const size) | |
666 | { | ||
667 | 42 | uintptr_t const addr( reinterpret_cast<uintptr_t>(this) + sizeof(HeapBlock) + size ); ///< SCA MISRA-C++:2008 Justified Rule 5-2-9 | |
668 | 42 | return reinterpret_cast<void*>(addr); ///< SCA MISRA-C++:2008 Justified Rule 5-2-8 | |
669 | } | ||
670 | |||
671 | /** | ||
672 | * @copydoc eoos::Object::Object(Object const&) | ||
673 | */ | ||
674 | HeapBlock(HeapBlock const&); ///< SCA MISRA-C++:2008 Justified Rule 3-2-2 and Rule 3-2-4 | ||
675 | |||
676 | /** | ||
677 | * @copydoc eoos::Object::operator=(Object const&) | ||
678 | */ | ||
679 | HeapBlock& operator=(HeapBlock const&); ///< SCA MISRA-C++:2008 Justified Rule 3-2-2 and Rule 3-2-4 | ||
680 | |||
681 | #if EOOS_CPP_STANDARD >= 2011 | ||
682 | |||
683 | /** | ||
684 | * @copydoc eoos::Object::Object(Object&&) | ||
685 | */ | ||
686 | HeapBlock(HeapBlock&&) noexcept = delete; | ||
687 | |||
688 | /** | ||
689 | * @copydoc eoos::Object::operator=(Object&&) | ||
690 | */ | ||
691 | HeapBlock& operator=(HeapBlock&&) & noexcept = delete; | ||
692 | |||
693 | #endif // EOOS_CPP_STANDARD >= 2011 | ||
694 | |||
695 | /** | ||
696 | * @brief Heap block definition key. | ||
697 | */ | ||
698 | static const size_t BLOCK_KEY = 0x20140515UL; | ||
699 | |||
700 | /** | ||
701 | * @brief Block is used. | ||
702 | */ | ||
703 | static const uint32_t ATTR_USED = 0x00000001UL; | ||
704 | |||
705 | /** | ||
706 | * @brief Next block is free. | ||
707 | */ | ||
708 | static const uint32_t NEXT_FREE = 0x00000001UL; | ||
709 | |||
710 | /** | ||
711 | * @brief Previous block is free. | ||
712 | */ | ||
713 | static const uint32_t PREV_FREE = 0x00000002UL; | ||
714 | |||
715 | /** | ||
716 | * @brief Mask block is unused. | ||
717 | */ | ||
718 | static const uint32_t MASK_UNUSED = 0xFFFFFFFEUL; | ||
719 | |||
720 | /** | ||
721 | * @brief Heap page of this block. | ||
722 | */ | ||
723 | api::Heap* heap_; | ||
724 | |||
725 | /** | ||
726 | * @brief Next block. | ||
727 | */ | ||
728 | HeapBlock* prev_; | ||
729 | |||
730 | /** | ||
731 | * @brief Previous block. | ||
732 | */ | ||
733 | HeapBlock* next_; | ||
734 | |||
735 | /** | ||
736 | * @brief Attributes of this block. | ||
737 | */ | ||
738 | uint32_t attr_; | ||
739 | |||
740 | /** | ||
741 | * @brief Size in byte of this block. | ||
742 | */ | ||
743 | size_t size_; | ||
744 | |||
745 | /** | ||
746 | * @brief Heap block definition key. | ||
747 | */ | ||
748 | size_t key_; | ||
749 | |||
750 | }; | ||
751 | |||
752 | /** | ||
753 | * @struct HeapData | ||
754 | * @brief Heap data. | ||
755 | * | ||
756 | * This structure is needed for aligning heap data or otherwise | ||
757 | * this Heap class can not de aligned because it is incompleted. | ||
758 | */ | ||
759 | struct HeapData | ||
760 | { | ||
761 | /** | ||
762 | * @brief Constructor. | ||
763 | * | ||
764 | * @param isize Total heap size. | ||
765 | * @param mutex A mutex to protect memory allocation. | ||
766 | */ | ||
767 | 7 | HeapData(size_t isize, api::Mutex& imutex) | |
768 | 7 | : block(NULLPTR) | |
769 | 7 | , mutex(&imutex) | |
770 | 7 | , size(0) | |
771 | 7 | , key(HEAP_KEY) { | |
772 | 7 | size = (isize & ~0x7UL) - sizeof(Heap); | |
773 | 7 | } | |
774 | |||
775 | /** | ||
776 | * @brief First memory block of heap page memory. | ||
777 | */ | ||
778 | HeapBlock* block; ///< SCA MISRA-C++:2008 Justified Rule 11-0-1 | ||
779 | |||
780 | /** | ||
781 | * @brief Thread allocation protection. | ||
782 | */ | ||
783 | api::Mutex* mutex; ///< SCA MISRA-C++:2008 Justified Rule 11-0-1 | ||
784 | |||
785 | /** | ||
786 | * @brief Actual size of heap. | ||
787 | */ | ||
788 | size_t size; ///< SCA MISRA-C++:2008 Justified Rule 11-0-1 | ||
789 | |||
790 | /** | ||
791 | * @brief Heap page memory definition key. | ||
792 | */ | ||
793 | int32_t key; ///< SCA MISRA-C++:2008 Justified Rule 11-0-1 | ||
794 | |||
795 | private: | ||
796 | |||
797 | /** | ||
798 | * @copydoc eoos::Object::Object(Object const&) | ||
799 | */ | ||
800 | HeapData(HeapData const&); ///< SCA MISRA-C++:2008 Justified Rule 3-2-2 and Rule 3-2-4 | ||
801 | |||
802 | /** | ||
803 | * @copydoc eoos::Object::operator=(Object const&) | ||
804 | */ | ||
805 | HeapData& operator=(HeapData const&); ///< SCA MISRA-C++:2008 Justified Rule 3-2-2 and Rule 3-2-4 | ||
806 | |||
807 | #if EOOS_CPP_STANDARD >= 2011 | ||
808 | |||
809 | /** | ||
810 | * @copydoc eoos::Object::Object(Object&&) | ||
811 | */ | ||
812 | HeapData(HeapData&&) noexcept = delete; | ||
813 | |||
814 | /** | ||
815 | * @copydoc eoos::Object::operator=(Object&&) | ||
816 | */ | ||
817 | HeapData& operator=(HeapData&&) & noexcept = delete; | ||
818 | |||
819 | #endif // EOOS_CPP_STANDARD >= 2011 | ||
820 | |||
821 | }; | ||
822 | |||
823 | /** | ||
824 | * @brief Size of this Heap class without aligned data. | ||
825 | */ | ||
826 | static const size_t SIZEOF_HEAP = ( sizeof(HeapData) + sizeof(VirtualTable) ) - sizeof(uint64_t); | ||
827 | |||
828 | /** | ||
829 | * @brief Heap page memory definition key. | ||
830 | */ | ||
831 | static const int32_t HEAP_KEY = 0x19820401; | ||
832 | |||
833 | /** | ||
834 | * @brief Data of this heap. | ||
835 | */ | ||
836 | HeapData data_; | ||
837 | |||
838 | /** | ||
839 | * @brief Aligning data. | ||
840 | */ | ||
841 | Aligner<SIZEOF_HEAP> temp_; | ||
842 | |||
843 | }; | ||
844 | |||
845 | } // namespace lib | ||
846 | } // namespace eoos | ||
847 | #endif // LIB_HEAP_HPP_ | ||
848 |