GCC Code Coverage Report


Directory: codebase/
File: codebase/library/include/public/lib.Memory.hpp
Date: 2023-03-16 04:37:09
Exec Total Coverage
Lines: 168 168 100.0%
Functions: 26 26 100.0%
Branches: 116 124 93.5%

Line Branch Exec Source
1 /**
2 * @file lib.Memory.hpp
3 * @author Sergey Baigudin, sergey@baigudin.software
4 * @copyright 2016-2022, Sergey Baigudin, Baigudin Software
5 */
6 #ifndef LIB_MEMORY_HPP_
7 #define LIB_MEMORY_HPP_
8
9 #include "lib.Types.hpp"
10
11 namespace eoos
12 {
13 namespace lib
14 {
15
16 /**
17 * @class Memory
18 * @brief Memory manipulator class.
19 */
20 class Memory
21 {
22
23 public:
24
25 /**
26 * @brief Copies a block of memory.
27 *
28 * @param dst A destination array where the content would be copied.
29 * @param src A source array to be copied.
30 * @param len A number of bytes to copy.
31 * @return A pointer to the destination array, or NULLPTR if an error has been occurred.
32 */
33 5 static void* memcpy(void* const dst, void const* const src, size_t len)
34 {
35 5 void* res( NULLPTR );
36
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
5 if( (dst != NULLPTR) && (src != NULLPTR) )
37 {
38 2 ucell_t const* sp( static_cast<ucell_t const*>(src) ); ///< SCA MISRA-C++:2008 Justified Rule 5-2-8
39 2 ucell_t* dp( static_cast<ucell_t*>(dst) ); ///< SCA MISRA-C++:2008 Justified Rule 5-2-8
40
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 while(len-- != 0U) ///< SCA MISRA-C++:2008 Justified Rule 5-2-10
41 {
42 4 *dp++ = *sp++; ///< SCA MISRA-C++:2008 Justified Rule 5-0-15 and Rule 5-2-10
43 }
44 2 res = dst;
45 }
46 5 return res;
47 }
48
49 /**
50 * @brief Fills a block of memory.
51 *
52 * @param dst A destination block of memory would be filled.
53 * @param val A least significant byte of value to be set.
54 * @param len A number of bytes to be set to the value.
55 * @return A pointer to the destination memory, or NULLPTR if an error has been occurred.
56 */
57 27 static void* memset(void* const dst, int32_t const val, size_t len)
58 {
59 27 void* res( NULLPTR );
60
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 1 times.
27 if(dst != NULLPTR)
61 {
62 26 ucell_t* dp( static_cast<ucell_t*>(dst) ); ///< SCA MISRA-C++:2008 Justified Rule 5-2-8
63 26 ucell_t const uc( static_cast<ucell_t>(val) );
64
2/2
✓ Branch 0 taken 28812 times.
✓ Branch 1 taken 26 times.
28838 while(len-- != 0U) ///< SCA MISRA-C++:2008 Justified Rule 5-2-10
65 {
66 28812 *dp++ = uc; ///< SCA MISRA-C++:2008 Justified Rule 5-0-15 and Rule 5-2-10
67 }
68 26 res = dst;
69 }
70 27 return res;
71 }
72
73 /**
74 * @brief Returns the length of a passed string .
75 *
76 * @param str A character string would be measured.
77 * @return The length of the passed string, and zero if NULLPTR given.
78 */
79 3 static size_t strlen(char_t const* str)
80 {
81 3 size_t len( 0U );
82
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if(str != NULLPTR)
83 {
84
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 2 times.
15 while( *str != '\0' )
85 {
86 13 len++;
87 13 str++; ///< SCA MISRA-C++:2008 Justified Rule 5-0-15
88 }
89 }
90 3 return len;
91 }
92
93 /**
94 * @brief Copies one string to another .
95 *
96 * @param dst A destination array where the content would be copied.
97 * @param src A character string to be copied.
98 * @return A pointer to the destination string, or NULLPTR if an error has been occurred.
99 */
100 111 static char_t* strcpy(char_t* const dst, char_t const* src)
101 {
102 111 char_t* res( NULLPTR );
103
4/4
✓ Branch 0 taken 109 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 108 times.
✓ Branch 3 taken 1 times.
111 if( (dst != NULLPTR) && (src != NULLPTR) )
104 {
105 108 char_t* d( dst - 1 ); ///< SCA MISRA-C++:2008 Justified Rule 5-0-15
106 108 char_t const* s( src - 1 ); ///< SCA MISRA-C++:2008 Justified Rule 5-0-15
107
2/2
✓ Branch 0 taken 821 times.
✓ Branch 1 taken 108 times.
929 while( (*++d = *++s) != '\0' ) {} ///< SCA MISRA-C++:2008 Justified Rule 5-0-15, Rule 5-2-10 and Rule 6-2-1
108 108 res = dst;
109
110 }
111 111 return res;
112 }
113
114
115 /**
116 * @brief Concatenates two strings.
117 *
118 * @param dst A destination character string where the content would be appended.
119 * @param src A character string to be appended.
120 * @return A pointer to the destination string, or NULLPTR if an error has been occurred.
121 */
122 4 static char_t* strcat(char_t* const dst, char_t const* src)
123 {
124 4 char_t* res( NULLPTR );
125
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
4 if( (dst != NULLPTR) && (src != NULLPTR) )
126 {
127 1 char_t* d( dst - 1 ); ///< SCA MISRA-C++:2008 Justified Rule 5-0-15
128
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 while( *++d != '\0' ) {} ///< SCA MISRA-C++:2008 Justified Rule 5-0-15 and Rule 5-2-10
129 1 d--; ///< SCA MISRA-C++:2008 Justified Rule 5-0-15
130 1 char_t const* s( src - 1 ); ///< SCA MISRA-C++:2008 Justified Rule 5-0-15
131
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 while( (*++d = *++s) != '\0' ) {} ///< SCA MISRA-C++:2008 Justified Rule 5-0-15, Rule 5-2-10 and Rule 6-2-1
132 1 res = dst;
133 }
134 4 return res;
135 }
136
137 /**
138 * @brief Compares two strings.
139 *
140 * @param str1 Character string to be compared.
141 * @param str2 Character string to be compared.
142 * @return The value 0 if the string 1 is equal to the string 2;
143 * a value less than 0 if the first not match character of string 1 has lower value than in string 2;
144 * a value greater than 0 if the first not match character of string 1 has greater value than in string 2;
145 * or the minimum possible value if an error has been occurred.
146 */
147 8 static int32_t strcmp(char_t const* str1, char_t const* str2)
148 {
149 8 int32_t res( static_cast<int32_t>( 0x80000000U ) );
150
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 1 times.
8 if( (str1 != NULLPTR) && (str2 != NULLPTR) )
151 {
152 while(true)
153 {
154 18 int32_t ch1( static_cast<int32_t>(*str1++) ); ///< SCA MISRA-C++:2008 Justified Rule 5-0-15 and Rule 5-2-10
155 18 int32_t ch2( static_cast<int32_t>(*str2++) ); ///< SCA MISRA-C++:2008 Justified Rule 5-0-15 and Rule 5-2-10
156 18 res = ch1 - ch2;
157
4/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 3 times.
18 if( (ch1 == 0) || (res != 0) )
158 {
159 break;
160 }
161 13 }
162 }
163 8 return res;
164 }
165
166 /**
167 * @brief Converts an integer number to a string.
168 *
169 * The function converts an integer value into a character string using the base parameter,
170 * which has to be 2, 8, 10, or 16 based numerals for converting to an appropriate numeral system.
171 *
172 * @note See exceptions below:
173 *
174 * Exception 1: Minimum negative value can be `T_MIN + 1` or greater.
175 *
176 * Exception 2: Only if the base is decimal, a passed number is available to be negative value,
177 * and the resulting string of these values is preceded with a minus sign.
178 *
179 * Exception 3: A hexadecimal number includes lower case characters, and any resulting strings
180 * do not contain any suffixes or prefixes for identifying a numeral system.
181 *
182 * @todo Rework the implementation to avoid the exceptions.
183 *
184 * @param val A value that would be converted to a string.
185 * @param str A character string for a result of the conversion.
186 * @param base A numerical base used to represent a value as a string.
187 * @return True if the conversion has been completed successfully.
188 */
189 template <typename T>
190 208 static bool_t itoa(T const val, char_t* str, Number::Base const base = Number::BASE_10)
191 {
192 208 const int32_t LENGTH( ( static_cast<int32_t>( sizeof(T) ) * 8) + 1 );
193 208 bool_t res( false );
194
1/2
✓ Branch 0 taken 104 times.
✗ Branch 1 not taken.
208 if(str != NULLPTR)
195 {
196 char_t temp[LENGTH];
197 bool_t isNegative;
198 208 int32_t index( LENGTH - 1 );
199 208 res = true;
200 208 temp[index--] = '\0'; ///< SCA MISRA-C++:2008 Justified Rule 5-0-11 and Rule 5-2-10
201 do
202 {
203 // Test for available base
204
3/3
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 8 times.
208 switch(base)
205 {
206 112 case Number::BASE_2:
207 case Number::BASE_8:
208 case Number::BASE_16:
209 {
210 112 isNegative = false;
211 112 break;
212 }
213 80 case Number::BASE_10:
214 {
215
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 28 times.
80 isNegative = ( !isPositive(val) ) ? true : false;
216 80 break;
217 }
218 16 default:
219 {
220 16 res = false;
221 16 break;
222 }
223 }
224 // If the base is not available
225
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 96 times.
208 if(res == false)
226 {
227 16 break;
228 }
229 // Prepare absolute value
230
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 84 times.
192 T module( isNegative ? (0 - val) : val );
231
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 80 times.
192 if( !isPositive(module) )
232 {
233 32 res = false;
234 32 break;
235 }
236 // Do the conversion
237 // @todo Revise possibility to declare index of size_t underlying type.
238 // But in the case index will always more than or equal zero.
239 // Thus, algorithm shall be re-worked.
240
1/2
✓ Branch 0 taken 781 times.
✗ Branch 1 not taken.
1562 while(index >= 0)
241 {
242 char_t ch;
243 1562 T digit( module % static_cast<T>(base) );
244
4/4
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 643 times.
✓ Branch 2 taken 116 times.
✓ Branch 3 taken 22 times.
1562 if( (base == Number::BASE_16) && (digit > 9) )
245 {
246 232 ch = 'a';
247 232 digit -= 10;
248 }
249 else
250 {
251 1330 ch = '0';
252 }
253 1562 temp[index--] = static_cast<char_t>(digit + ch); ///< SCA MISRA-C++:2008 Justified Rule 3-9-2, Rule 5-0-11 and Rule 5-2-10
254 1562 module = module / static_cast<T>(base);
255
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 701 times.
1562 if(module == 0)
256 {
257 160 break;
258 }
259 }
260 // Add minus
261
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 72 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
160 if( isNegative && (index >= 0) )
262 {
263 16 temp[index--] = '-'; ///< SCA MISRA-C++:2008 Justified Rule 5-0-11 and Rule 5-2-10
264 }
265 160 res = true;
266 }
267 while(false);
268 // Copy the temp string to the destination string
269 // @todo Replace this with strncpy
270 208 strcpy(str, &temp[++index]); ///< SCA MISRA-C++:2008 Justified Rule 5-2-10
271 }
272 208 return res;
273 }
274
275 /**
276 * @brief Converts a string to an integer number.
277 *
278 * @param str A character string that would be converted to a number.
279 * @param base A numerical base used to parse the string.
280 * @return The resulting number, 0 if an error is occurred.
281 */
282 template <typename T>
283 18 static T atoi(char_t const* str, Number::Base const base = Number::BASE_10)
284 {
285 18 bool_t isBase( false );
286
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 1 times.
18 switch(base)
287 {
288 17 case Number::BASE_2:
289 case Number::BASE_8:
290 case Number::BASE_10:
291 case Number::BASE_16:
292 {
293 17 isBase = true;
294 17 break;
295 }
296 1 default:
297 {
298 1 isBase = false;
299 1 break;
300 }
301 }
302 18 T result( 0 );
303
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 1 times.
18 if( isBase )
304 {
305 17 T const multiplier( static_cast<T>(base) );
306 17 int32_t index( 0 );
307 17 bool_t isNegative( false );
308 // Look for whitespaces
309
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 17 times.
23 while( isSpace(str[index]) )
310 {
311 6 index++;
312 }
313 // Test a character if the number is negative for decimal base
314
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 8 times.
17 if(base == Number::BASE_10)
315 {
316
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7 times.
9 if( str[index] == '-' )
317 {
318 2 isNegative = true;
319 2 index++;
320 }
321
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
7 else if( str[index] == '+' )
322 {
323 2 isNegative = false;
324 2 index++;
325 }
326 else
327 {
328 5 isNegative = false;
329 }
330 }
331 // Do fast calculation for no hexadecimal base
332
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 4 times.
17 if(base != Number::BASE_16)
333 {
334
2/2
✓ Branch 1 taken 141 times.
✓ Branch 2 taken 13 times.
154 while( isDigit(str[index], base) )
335 {
336 141 result *= multiplier;
337 141 result += static_cast<T>( str[index++] - '0' ); ///< SCA MISRA-C++:2008 Justified Rule 5-2-10
338 }
339 }
340 else
341 {
342 char_t subtrahend;
343 int32_t addend;
344
2/2
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 4 times.
36 while( isDigit(str[index], base) )
345 {
346 32 detectMathOperands(str[index], subtrahend, addend);
347 32 result *= static_cast<T>( base );
348 32 result += static_cast<T>( str[index++] - subtrahend ); ///< SCA MISRA-C++:2008 Justified Rule 4-5-3, Rule 5-0-11 and Rule 5-2-10
349 32 result += static_cast<T>( addend );
350 }
351 }
352
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 15 times.
17 result = isNegative ? (0 - result) : result;
353 }
354 18 return result;
355 }
356
357 private:
358
359 /**
360 * @brief Tests if a value is signed or unsigned.
361 *
362 * @param value A value that would be tested.
363 * @return True if the value has been negative.
364 *
365 * @note The `volatile` keyword added, as the GCC 7.5.0 compiler doesn't call this function optimizing it for Release build.
366 * This behavior is cause a bug in `itoa` function with -9223372036854775808 value of int64_t type trying to check module of the value.
367 * Partial specialization of the template function for int64_t also doesn't help.
368 */
369 template <typename T>
370 272 static bool_t isPositive(volatile T value)
371 {
372
4/4
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 92 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 28 times.
272 return ( (value > 0) || (value == 0) ) ? true : false;
373 }
374
375 /**
376 * @brief Tests if a character is a whitespace character.
377 *
378 * @param character A character code.
379 * @return True if the character is whitespace.
380 */
381 23 static bool_t isSpace(char_t const character)
382 {
383 23 bool_t result( true );
384
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 17 times.
23 switch(character)
385 {
386 6 case ' ':
387 case '\t':
388 case '\n':
389 case '\v':
390 case '\f':
391 case '\r':
392 {
393 6 break;
394 }
395 17 default:
396 {
397 17 result = false;
398 17 break;
399 }
400 }
401 23 return result;
402 }
403
404 /**
405 * @brief Tests if a character is a decimal number.
406 *
407 * @param character A character code.
408 * @param base A numerical base used to parse the character.
409 * @return True if the character is a decimal number.
410 */
411 190 static bool_t isDigit(char_t const character, Number::Base const base = Number::BASE_10)
412 {
413 190 bool_t res( false );
414 190 int32_t const ch( static_cast<int32_t>(character) );
415
4/5
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 68 times.
✗ Branch 4 not taken.
190 switch(base)
416 {
417 62 case Number::BASE_2:
418 {
419
3/4
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
62 res = ( (ch >= 0x30) && (ch <= 0x31) ) ? true : false;
420 62 break;
421 }
422 24 case Number::BASE_8:
423 {
424
3/4
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
24 res = ( (ch >= 0x30) && (ch <= 0x37) ) ? true : false;
425 24 break;
426 }
427 36 case Number::BASE_16:
428 {
429 36 res = (
430
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
32 ( (ch >= 0x30) && (ch <= 0x39) )
431
4/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 12 times.
28 || ( (ch >= 0x41) && (ch <= 0x46) )
432
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 || ( (ch >= 0x61) && (ch <= 0x66) )
433
4/4
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 4 times.
84 ) ? true : false;
434 36 break;
435 }
436 68 case Number::BASE_10:
437 {
438
4/4
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 59 times.
✓ Branch 3 taken 1 times.
68 res = ( (ch >= 0x30) && (ch <= 0x39) ) ? true : false;
439 68 break;
440 }
441 }
442 190 return res;
443 }
444
445 /**
446 * @brief Detects subtrahend and addend for hex numbers.
447 *
448 * @param ch A testing character code.
449 * @param subtrahend A resulting subtrahend.
450 * @param addend A resulting addend.
451 */
452 32 static void detectMathOperands(char_t const character, char_t& subtrahend, int32_t& addend)
453 {
454 32 int32_t const ch( static_cast<int32_t>(character) );
455 // Test for uppercase letter
456
4/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 12 times.
32 if( (ch >= 0x41) && (ch <= 0x46) )
457 {
458 12 subtrahend = 'A';
459 12 addend = 10;
460 }
461 // Test for lowercase letter
462
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
20 else if( (ch >= 0x61) && (ch <= 0x66) )
463 {
464 12 subtrahend = 'a';
465 12 addend = 10;
466 }
467 else
468 {
469 8 subtrahend = '0';
470 8 addend = 0;
471 }
472 32 }
473
474 };
475
476 } // namespace lib
477 } // namespace eoos
478 #endif // LIB_MEMORY_HPP_
479