GCC Code Coverage Report


Directory: codebase/
File: codebase/library/include/public/lib.AbstractBaseString.hpp
Date: 2023-03-16 04:37:09
Exec Total Coverage
Lines: 143 143 100.0%
Functions: 51 58 87.9%
Branches: 68 83 81.9%

Line Branch Exec Source
1 /**
2 * @file lib.AbstractBaseString.hpp
3 * @author Sergey Baigudin, sergey@baigudin.software
4 * @copyright 2017-2022, Sergey Baigudin, Baigudin Software
5 */
6 #ifndef LIB_ABSTRACTBASESTRING_HPP_
7 #define LIB_ABSTRACTBASESTRING_HPP_
8
9 #include "lib.Object.hpp"
10 #include "api.String.hpp"
11 #include "lib.CharTrait.hpp"
12
13 namespace eoos
14 {
15 namespace lib
16 {
17
18 /**
19 * @class AbstractBaseString<T,R,A>
20 * @brief Abstract base string class.
21 *
22 * @tparam T A data type of string characters.
23 * @tparam R A character traits.
24 * @tparam A A heap memory allocator class.
25 */
26 template <typename T, class R, class A = Allocator>
27 class AbstractBaseString : public Object<A>, public api::String<T>
28 {
29 typedef Object<A> Parent;
30
31 public:
32
33 using api::String<T>::getLength;
34
35 /**
36 * @brief Destructor.
37 */
38 632 virtual ~AbstractBaseString()
39 {
40 }
41
42 /**
43 * @copydoc eoos::api::Object::isConstructed()
44 */
45 1949 virtual bool_t isConstructed() const ///< SCA MISRA-C++:2008 Defected Rule 9-3-3
46 {
47 1949 return Parent::isConstructed();
48 }
49
50 /**
51 * @copydoc eoos::api::Collection::isEmpty()
52 */
53 140 virtual bool_t isEmpty() const ///< SCA MISRA-C++:2008 Defected Rule 9-3-3
54 {
55 bool_t res;
56 140 size_t const length( getLength() );
57
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 108 times.
140 if(length == 0U)
58 {
59 32 res = true;
60 }
61 else
62 {
63 108 res = false;
64 }
65 140 return res;
66 }
67
68 /**
69 * @copydoc eoos::api::String::copy(const api::String<T>&)
70 */
71 13 virtual bool_t copy(api::String<T> const& string)
72 {
73 bool_t res;
74
6/6
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 2 times.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 9 times.
✓ Branch 7 taken 4 times.
13 if( isConstructed() && string.isConstructed() )
75 {
76 9 T const* const str( string.getChar() );
77 9 res = copyRaw(str);
78 }
79 else
80 {
81 4 res = false;
82 }
83 13 return res;
84 }
85
86 /**
87 * @copydoc eoos::api::String::concatenate(const api::String<T>&)
88 */
89 24 virtual bool_t concatenate(api::String<T> const& string)
90 {
91 bool_t res;
92
6/6
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 2 times.
✓ Branch 4 taken 20 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 20 times.
✓ Branch 7 taken 4 times.
24 if( isConstructed() && string.isConstructed() )
93 {
94 20 T const* const str( string.getChar() );
95 20 res = concatenateRaw(str);
96 }
97 else
98 {
99 4 res = false;
100 }
101 24 return res;
102 }
103
104 /**
105 * @copydoc eoos::api::String::isEqualTo(const api::String<T>&)
106 */
107 28 virtual bool_t isEqualTo(api::String<T> const& string) const
108 {
109 bool_t res;
110
6/6
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 2 times.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 24 times.
✓ Branch 7 taken 4 times.
28 if( isConstructed() && string.isConstructed() )
111 {
112 24 T const* const str( string.getChar() );
113 24 res = isEqualToRaw(str);
114 }
115 else
116 {
117 4 res = false;
118 }
119 28 return res;
120 }
121
122 /**
123 * @brief Converts an integer number to this string.
124 *
125 * The function converts an integer value into a character string using the base parameter,
126 * which has to be 2, 8, 10, or 16 based numerals for converting to an appropriate numeral system.
127 *
128 * Mark that only if the base is decimal, a passed number is available to be negative values,
129 * and the resulting string of these values is preceded with a minus sign. In addition,
130 * a hexadecimal number includes lower case characters, and any resulting strings do not contain
131 * any suffixes or prefixes for identifying a numeral system.
132 *
133 * @note You need to use `AbstractBaseString.template convert<I>(value, base);` syntax,
134 * if you have to specify the template argument type explicitly.
135 *
136 * @param value A value that would be converted to this string.
137 * @param base A numerical base used to represent a value as this string.
138 * @return True if the conversion has been completed successfully.
139 */
140 template <typename I>
141 448 bool_t convert(I const value, Number::Base const base = Number::BASE_10) ///< SCA MISRA-C++:2008 Defected Rule 9-3-3
142 {
143 448 return convertToString(value, base);
144 }
145
146 /**
147 * @brief Assignment by sum operator.
148 *
149 * @param source A source object interface.
150 * @return Reference to this object.
151 */
152 10 AbstractBaseString& operator+=(api::String<T> const& source)
153 {
154 10 static_cast<void>( concatenate(source) );
155 10 return *this;
156 }
157
158 /**
159 * @brief Assignment by sum operator.
160 *
161 * @param source A source character string.
162 * @return Reference to this object.
163 */
164 4 AbstractBaseString& operator+=(T const* const source)
165 {
166 4 static_cast<void>( concatenateRaw(source) );
167 4 return *this;
168 }
169
170 protected:
171
172 /**
173 * @brief Constructor.
174 */
175 297 AbstractBaseString()
176 : Object<A>()
177 297 , api::String<T>() {
178 297 }
179
180 /**
181 * @copydoc eoos::Object::Object(Object const&)
182 */
183 18 AbstractBaseString(AbstractBaseString const& obj)
184 : Object<A>(obj)
185 18 , api::String<T>() {
186 18 }
187
188 /**
189 * @copydoc eoos::Object::operator=(Object const&)
190 */
191 6 AbstractBaseString& operator=(AbstractBaseString const& obj)
192 {
193
3/6
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
6 if( isConstructed() && (this != &obj) )
194 {
195 6 Parent::operator=(obj);
196 }
197 6 return *this;
198 }
199
200 #if EOOS_CPP_STANDARD >= 2011
201
202 /**
203 * @copydoc eoos::Object::Object(Object&&)
204 */
205 2 AbstractBaseString(AbstractBaseString&& obj) noexcept
206 2 : Object<A>( move(obj) )
207 2 , api::String<T>(){
208 2 }
209
210 /**
211 * @copydoc eoos::Object::operator=(Object&&)
212 */
213 20 AbstractBaseString& operator=(AbstractBaseString&& obj) & noexcept
214 {
215
3/6
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
20 if( isConstructed() && (this != &obj) )
216 {
217 20 Parent::operator=( move(obj) );
218 }
219 20 return *this;
220 }
221
222 #endif // EOOS_CPP_STANDARD >= 2011
223
224 /**
225 * @brief Returns a calculated string length.
226 *
227 * @param str A character string would be measured.
228 * @return A length of the passed string.
229 */
230 579 static size_t getLengthRaw(T const* str)
231 {
232 579 size_t len( 0U );
233 579 T const null( R::getTerminator() );
234
2/2
✓ Branch 0 taken 7220 times.
✓ Branch 1 taken 578 times.
7802 while( *str != null )
235 {
236 7223 ++str; ///< SCA MISRA-C++:2008 Justified Rule 5-0-15
237 7223 ++len;
238 }
239 579 return len;
240 }
241
242 /**
243 * @brief Copies a string to a string.
244 *
245 * @param dst A destination array where the content would be copied.
246 * @param src A character string to be copied.
247 * @param cnt Destination character string size.
248 */
249 485 static void copyRaw3(T* dst, T const* src, size_t cnt)
250 {
251
2/4
✓ Branch 0 taken 485 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 485 times.
✗ Branch 3 not taken.
485 if( (dst != NULLPTR) && (src != NULLPTR) )
252 {
253 485 T const null( R::getTerminator() );
254 while(true)
255 {
256
2/2
✓ Branch 0 taken 287 times.
✓ Branch 1 taken 4776 times.
5063 if( cnt == 0U )
257 {
258 287 *dst = null;
259 287 break;
260 }
261 4776 *dst = *src;
262 4776 --cnt;
263
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 4578 times.
4776 if( *dst == null )
264 {
265 198 break;
266 }
267 4578 ++dst;
268 4578 ++src;
269 }
270 }
271 485 }
272
273 /**
274 * @brief Concatenates two strings.
275 *
276 * @param dst A destination character string where the content would be appended.
277 * @param src An appended character string.
278 * @param cnt Destination character string length that cannot be less than dst string length.
279 */
280 24 static void concatenateRaw3(T* dst, T const* src, size_t cnt)
281 {
282
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
24 if( (dst != NULLPTR) && (src != NULLPTR) )
283 {
284 24 T const null( R::getTerminator() );
285 while(true)
286 {
287
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 208 times.
232 if(*dst == null)
288 {
289 24 break;
290 }
291 208 ++dst;
292 208 --cnt;
293 }
294 24 copyRaw3(dst, src, cnt);
295 }
296 24 }
297
298 /**
299 * @brief Compares two strings.
300 *
301 * @param string A string object interface to be compared with.
302 * @return true if strings equal to each other.
303 */
304 58 static bool_t isEqualRaw2(T const* str1, T const* str2)
305 {
306 58 bool_t res( false );
307
2/4
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 58 times.
✗ Branch 3 not taken.
58 if( (str1 != NULLPTR) && (str2 != NULLPTR) )
308 {
309 58 T const null( R::getTerminator() );
310 while(true)
311 {
312 454 res = *str1 == *str2;
313
4/4
✓ Branch 0 taken 420 times.
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 396 times.
✓ Branch 3 taken 24 times.
454 if( (*str1 == null) || (res == false) )
314 {
315 break;
316 }
317 396 ++str1; ///< SCA MISRA-C++:2008 Justified Rule 5-0-15
318 396 ++str2; ///< SCA MISRA-C++:2008 Justified Rule 5-0-15
319 }
320 }
321 58 return res;
322 }
323
324 private:
325
326 /**
327 * @brief Copies a passed string into this string.
328 *
329 * @param str A character string to be copied.
330 * @return True if a passed string has been copied successfully.
331 */
332 virtual bool_t copyRaw(T const* str) = 0;
333
334 /**
335 * @brief Concatenates a passed string to this string.
336 *
337 * @param str A character string to be appended.
338 * @return True if a passed string has been appended successfully.
339 */
340 virtual bool_t concatenateRaw(T const* str) = 0;
341
342 /**
343 * @brief Compares this string with a passed string lexicographically.
344 *
345 * @param string A string object interface to be compared with.
346 * @return true if this string equals to a given string.
347 */
348 virtual bool_t isEqualToRaw(T const* str) const = 0;
349
350 /**
351 * @brief Converts an integer number to a string.
352 *
353 * The function converts an integer value into a character string using the base parameter,
354 * which has to be 2, 8, 10, or 16 based numerals for converting to an appropriate numeral system.
355 *
356 * @note See exceptions below:
357 *
358 * Exception 1: Minimum negative value can be `T_MIN + 1` or greater.
359 *
360 * Exception 2: Only if the base is decimal, a passed number is available to be negative value,
361 * and the resulting string of these values is preceded with a minus sign.
362 *
363 * Exception 3: A hexadecimal number includes lower case characters, and any resulting strings
364 * do not contain any suffixes or prefixes for identifying a numeral system.
365 *
366 * @todo Rework the implementation to avoid the exceptions.
367 *
368 * @param val A value that would be converted to a string.
369 * @param base A numerical base used to represent a value as a string.
370 * @return True if the conversion has been completed successfully.
371 */
372 template <typename I>
373 448 bool_t convertToString(I const val, Number::Base const base)
374 {
375 448 const int32_t LENGTH( ( static_cast<int32_t>( sizeof(I) ) * 8) + 1 );
376 448 bool_t res( true );
377 448 bool_t isNegative( false );
378 448 int32_t index( LENGTH - 1 );
379 T temp[LENGTH];
380 448 temp[index] = R::getTerminator();
381 448 index -= 1;
382 do
383 {
384 // Test for available base
385
3/3
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 91 times.
✓ Branch 2 taken 18 times.
448 switch(base)
386 {
387 240 case Number::BASE_2:
388 case Number::BASE_8:
389 case Number::BASE_16:
390 {
391 240 isNegative = false;
392 240 break;
393 }
394 174 case Number::BASE_10:
395 {
396
2/2
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 67 times.
174 isNegative = ( !isPositive(val) ) ? true : false;
397 174 break;
398 }
399 34 default:
400 {
401 34 res = false;
402 34 break;
403 }
404 }
405 // If the base is not available
406
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 218 times.
448 if(res == false)
407 {
408 34 break;
409 }
410 // Prepare absolute value
411
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 194 times.
414 I module( isNegative ? (0 - val) : val );
412
2/2
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 186 times.
414 if( !isPositive(module) )
413 {
414 64 res = false;
415 64 break;
416 }
417 // Do the conversion
418 // @todo Revise possibility to declare index of size_t underlying type.
419 // But in the case index will always more than or equal zero.
420 // Thus, algorithm shall be re-worked.
421
1/2
✓ Branch 0 taken 1759 times.
✗ Branch 1 not taken.
3020 while(index >= 0)
422 {
423 3020 I digit( module % static_cast<I>(base) );
424 3020 temp[index] = R::convertDigitToChar(digit);
425 3020 index -= 1;
426 3020 module = module / static_cast<I>(base);
427
2/2
✓ Branch 0 taken 186 times.
✓ Branch 1 taken 1573 times.
3020 if(module == 0)
428 {
429 350 break;
430 }
431 }
432 // Add minus
433
3/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 170 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
350 if( isNegative && (index >= 0) )
434 {
435 32 temp[index] = R::getMinusSign();
436 32 index -= 1;
437 }
438 350 res = true;
439 }
440 while(false);
441
2/2
✓ Branch 0 taken 186 times.
✓ Branch 1 taken 50 times.
448 if(res == true)
442 {
443 350 index += 1;
444
1/2
✓ Branch 1 taken 186 times.
✗ Branch 2 not taken.
350 res = copyRaw(&temp[index]);
445 }
446 448 return res;
447 }
448
449 /**
450 * @brief Tests if a value is signed or unsigned.
451 *
452 * @param value A value that would be tested.
453 * @return True if the value has been negative.
454 *
455 * @note The `volatile` keyword added, as the GCC 7.5.0 compiler doesn't call this function optimizing it for Release build.
456 * This behavior is cause a bug in `itoa` function with -9223372036854775808 value of int64_t type trying to check module of the value.
457 * Partial specialization of the template function for int64_t also doesn't help.
458 */
459 template <typename I>
460 588 static bool_t isPositive(volatile I value)
461 {
462
4/4
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 221 times.
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 56 times.
588 return ( (value > 0) || (value == 0) ) ? true : false;
463 }
464
465 template <typename T0> friend bool_t operator==(api::String<T0> const&, T0 const* const);
466 template <typename T0> friend bool_t operator==(T0 const* const, api::String<T0> const&);
467 template <typename T0> friend bool_t operator!=(api::String<T0> const&, T0 const* const);
468 template <typename T0> friend bool_t operator!=(T0 const* const, api::String<T0> const&);
469 };
470
471 /**
472 * @brief Compares for equality of two strings.
473 *
474 * @param source1 A source object interface 1.
475 * @param source2 A source object interface 2.
476 * @return True if strings are equal.
477 */
478 template <typename T>
479 8 inline bool_t operator==(api::String<T> const& source1, api::String<T> const& source2)
480 {
481 8 return source1.isEqualTo(source2);
482 }
483
484 /**
485 * @brief Compares for equality of two strings.
486 *
487 * @param source1 A source object interface 1.
488 * @param source2 A source character string 2.
489 * @return True if strings are equal.
490 */
491 template <typename T>
492 10 inline bool_t operator==(api::String<T> const& source1, T const* const source2)
493 {
494 10 return AbstractBaseString< T,CharTrait<T> >::isEqualRaw2(source1.getChar(), source2);
495 }
496
497 /**
498 * @brief Compares for equality of two strings.
499 *
500 * @param source1 A source character string 1.
501 * @param source2 A source object interface 2.
502 * @return True if strings are equal.
503 */
504 template <typename T>
505 8 inline bool_t operator==(T const* const source1, api::String<T> const& source2)
506 {
507 8 return AbstractBaseString< T,CharTrait<T> >::isEqualRaw2(source1, source2.getChar());
508 }
509
510 /**
511 * @brief Compares for inequality of two strings.
512 *
513 * @param source1 A source object interface 1.
514 * @param source2 A source object interface 2.
515 * @return True if strings are not equal.
516 */
517 template <typename T>
518 8 inline bool_t operator!=(api::String<T> const& source1, api::String<T> const& source2)
519 {
520 8 return !source1.isEqualTo(source2);
521 }
522
523 /**
524 * @brief Compares for inequality of two strings.
525 *
526 * @param source1 A source object interface 1.
527 * @param source2 A source character string 2.
528 * @return True if strings are not equal.
529 */
530 template <typename T>
531 8 inline bool_t operator!=(api::String<T> const& source1, T const* const source2)
532 {
533 8 return !AbstractBaseString< T,CharTrait<T> >::isEqualRaw2(source1.getChar(), source2);
534 }
535
536 /**
537 * @brief Compares for inequality of two strings.
538 *
539 * @param source1 A source character string 1.
540 * @param source2 A source object interface 2.
541 * @return True if strings are not equal.
542 */
543 template <typename T>
544 8 inline bool_t operator!=(T const* const source1, api::String<T> const& source2)
545 {
546 8 return !AbstractBaseString< T,CharTrait<T> >::isEqualRaw2(source1, source2.getChar());
547 }
548
549 } // namespace lib
550 } // namespace eoos
551 #endif // LIB_ABSTRACTBASESTRING_HPP_
552