Embedded Template Library 1.0
Loading...
Searching...
No Matches
to_string_helper.h
Go to the documentation of this file.
1
2
3/******************************************************************************
4The MIT License(MIT)
5
6Embedded Template Library.
7https://github.com/ETLCPP/etl
8https://www.etlcpp.com
9
10Copyright(c) 2019 John Wellbelove
11
12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files(the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions :
18
19The above copyright notice and this permission notice shall be included in all
20copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28SOFTWARE.
29******************************************************************************/
30
31#ifndef ETL_TO_STRING_HELPER_INCLUDED
32#define ETL_TO_STRING_HELPER_INCLUDED
33
35
36#include "../platform.h"
37#include "../absolute.h"
38#include "../algorithm.h"
40#include "../container.h"
41#include "../iterator.h"
42#include "../limits.h"
43#include "../math.h"
44#include "../negative.h"
45#include "../type_traits.h"
46
47#include <math.h>
48
49#if ETL_USING_STL && ETL_USING_CPP11
50 #include <iterator> // For std::begin, std::end and std::size
51#endif
52
53namespace etl
54{
55 namespace private_to_string
56 {
57#if ETL_NOT_USING_64BIT_TYPES
58 typedef int32_t workspace_t;
59 typedef uint32_t uworkspace_t;
60#else
61 typedef int64_t workspace_t;
62 typedef uint64_t uworkspace_t;
63#endif
64
65 //***************************************************************************
67 //***************************************************************************
68 template <typename TIString>
69 void add_alignment(TIString& str, typename TIString::iterator position, const etl::basic_format_spec<TIString>& format)
70 {
71 uint32_t length = static_cast<uint32_t>(etl::distance(position, str.end()));
72
73 if (length < format.get_width())
74 {
75 uint32_t fill_length = format.get_width() - length;
76
77 if (format.is_left())
78 {
79 // Insert fill characters on the right.
80 str.insert(str.end(), fill_length, format.get_fill());
81 }
82 else
83 {
84 // Insert fill characters on the left.
85 str.insert(position, fill_length, format.get_fill());
86 }
87 }
88 }
89
90 //***************************************************************************
92 //***************************************************************************
93 template <typename TIString>
94 void add_boolean(const bool value, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append)
95 {
96 typedef typename TIString::value_type type;
97 typedef typename TIString::iterator iterator;
98
99 static const type t[] = {'t', 'r', 'u', 'e'};
100 static const type f[] = {'f', 'a', 'l', 's', 'e'};
101
102 if (!append)
103 {
104 str.clear();
105 }
106
107 iterator start = str.end();
108
109 if (format.is_boolalpha())
110 {
111 if (value)
112 {
113 str.insert(str.end(), ETL_OR_STD11::begin(t), ETL_OR_STD11::end(t));
114 }
115 else
116 {
117 str.insert(str.end(), ETL_OR_STD11::begin(f), ETL_OR_STD11::end(f));
118 }
119 }
120 else
121 {
122 if (value)
123 {
124 str.push_back(type('1'));
125 }
126 else
127 {
128 str.push_back(type('0'));
129 }
130 }
131
132 etl::private_to_string::add_alignment(str, start, format);
133 }
134
135 //***************************************************************************
137 //***************************************************************************
138 template <typename T, typename TIString>
139 void add_integral(T value, TIString& str, const etl::basic_format_spec<TIString>& format, bool append, const bool negative)
140 {
141 typedef typename TIString::value_type type;
142 typedef typename TIString::iterator iterator;
143
144 if (!append)
145 {
146 str.clear();
147 }
148
149 iterator start = str.end();
150
151 if (value == 0)
152 {
153 // If number is negative, append '-' (a negative zero might occur for
154 // fractional numbers > -1.0)
155 if ((format.get_base() == 10U) && negative)
156 {
157 str.push_back(type('-'));
158 }
159
160 str.push_back(type('0'));
161 }
162 else
163 {
164 // Extract the digits, in reverse order.
165 while (value != 0)
166 {
167 T remainder = etl::absolute(value % T(format.get_base()));
168 str.push_back((remainder > 9) ? (format.is_upper_case() ? type('A' + (remainder - 10)) : type('a' + (remainder - 10)))
169 : type('0' + remainder));
170 value = value / T(format.get_base());
171 }
172
173 // If number is negative, append '-'
174 if ((format.get_base() == 10U) && negative)
175 {
176 str.push_back(type('-'));
177 }
178
179 if (format.is_show_base())
180 {
181 switch (format.get_base())
182 {
183 case 2U:
184 {
185 str.push_back(format.is_upper_case() ? type('B') : type('b'));
186 str.push_back(type('0'));
187 break;
188 }
189
190 case 8U:
191 {
192 str.push_back(type('0'));
193 break;
194 }
195
196 case 16U:
197 {
198 str.push_back(format.is_upper_case() ? type('X') : type('x'));
199 str.push_back(type('0'));
200 break;
201 }
202
203 default:
204 {
205 break;
206 }
207 }
208 }
209
210 // Reverse the string we appended.
211 etl::reverse(start, str.end());
212 }
213
214 etl::private_to_string::add_alignment(str, start, format);
215 }
216
217 //***************************************************************************
219 //***************************************************************************
220 template <typename TIString>
221 void add_nan_inf(const bool not_a_number, const bool infinity, TIString& str)
222 {
223 typedef typename TIString::value_type type;
224
225 static const type n[] = {'n', 'a', 'n'};
226 static const type i[] = {'i', 'n', 'f'};
227
228 if (not_a_number)
229 {
230 str.insert(str.end(), ETL_OR_STD11::begin(n), ETL_OR_STD11::end(n));
231 }
232 else if (infinity)
233 {
234 str.insert(str.end(), ETL_OR_STD11::begin(i), ETL_OR_STD11::end(i));
235 }
236 }
237
238 //***************************************************************************
240 //***************************************************************************
241 template <typename TIString>
242 void add_integral_and_fractional(const uint32_t integral, const uint32_t fractional, TIString& str,
243 const etl::basic_format_spec<TIString>& integral_format,
244 const etl::basic_format_spec<TIString>& fractional_format, const bool negative)
245 {
246 typedef typename TIString::value_type type;
247
248 etl::private_to_string::add_integral(integral, str, integral_format, true, negative);
249
250 if (fractional_format.get_precision() > 0)
251 {
252 str.push_back(type('.'));
253 etl::private_to_string::add_integral(fractional, str, fractional_format, true, false);
254 }
255 }
256
257#if ETL_USING_64BIT_TYPES
258 //***************************************************************************
260 //***************************************************************************
261 template <typename TIString>
262 void add_integral_and_fractional(const uint64_t integral, const uint64_t fractional, TIString& str,
263 const etl::basic_format_spec<TIString>& integral_format,
264 const etl::basic_format_spec<TIString>& fractional_format, const bool negative)
265 {
266 typedef typename TIString::value_type type;
267
268 etl::private_to_string::add_integral(integral, str, integral_format, true, negative);
269
270 if (fractional_format.get_precision() > 0)
271 {
272 str.push_back(type('.'));
273 etl::private_to_string::add_integral(fractional, str, fractional_format, true, false);
274 }
275 }
276#endif
277
278 //***************************************************************************
280 //***************************************************************************
281 template <typename T, typename TIString>
282 void add_floating_point(const T value, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append)
283 {
284 typedef typename TIString::iterator iterator;
285 typedef typename TIString::value_type type;
286
287 if (!append)
288 {
289 str.clear();
290 }
291
292 iterator start = str.end();
293
294 if (isnan(value) || isinf(value))
295 {
296 etl::private_to_string::add_nan_inf(isnan(value), isinf(value), str);
297 }
298 else
299 {
300 // Make sure we format the two halves correctly.
301 uint32_t max_precision = etl::numeric_limits<T>::digits10;
302
303#if ETL_NOT_USING_64BIT_TYPES
304 if (max_precision > 9)
305 {
306 max_precision = 9;
307 }
308#endif
309
310 etl::basic_format_spec<TIString> integral_format = format;
311 integral_format.decimal().width(0).precision(format.get_precision() > max_precision ? max_precision : format.get_precision());
312
313 etl::basic_format_spec<TIString> fractional_format = integral_format;
314 fractional_format.width(integral_format.get_precision()).fill(type('0')).right();
315
316 uworkspace_t multiplier = 1U;
317
318 for (uint32_t i = 0U; i < fractional_format.get_precision(); ++i)
319 {
320 multiplier *= 10U;
321 }
322
323 // Find the integral part of the floating point
324 T f_integral = ::floor(etl::absolute(value));
325 uworkspace_t integral = static_cast<uworkspace_t>(f_integral);
326
327 // Find the fractional part of the floating point.
328 uworkspace_t fractional = static_cast<uworkspace_t>(::round((etl::absolute(value) - f_integral) * multiplier));
329
330 // Check for a rounding carry to the integral.
331 if (fractional == multiplier)
332 {
333 ++integral;
334 fractional = 0U;
335 }
336
337 etl::private_to_string::add_integral_and_fractional(integral, fractional, str, integral_format, fractional_format, etl::is_negative(value));
338 }
339
340 etl::private_to_string::add_alignment(str, start, format);
341 }
342
343 //***************************************************************************
345 //***************************************************************************
346 template <typename T, typename TIString>
347 void add_integral_denominated(const T value, const uint32_t denominator_exponent, TIString& str, const etl::basic_format_spec<TIString>& format,
348 const bool append = false)
349 {
350 typedef typename TIString::iterator iterator;
351 typedef typename TIString::value_type type;
352 typedef typename etl::make_unsigned<T>::type working_t;
353
354 if (!append)
355 {
356 str.clear();
357 }
358
359 iterator start = str.end();
360
361 // Calculate the denominator.
362 working_t denominator = 1U;
363
364 for (uint32_t i = 0U; i < denominator_exponent; ++i)
365 {
366 denominator *= 10U;
367 }
368
369 // Get the absolute value, taking care of minimum negative values.
370 working_t abs_value = etl::absolute_unsigned(value);
371
372 // Figure out how many decimal digits we have in the value.
373 const uint32_t& original_decimal_digits = denominator_exponent;
374
375 // How many decimal digits are we displaying.
376 const uint32_t displayed_decimal_digits = (format.get_precision() > original_decimal_digits) ? original_decimal_digits : format.get_precision();
377
378 // Format for the integral part.
379 etl::basic_format_spec<TIString> integral_format = format;
380 integral_format.decimal().width(0U);
381
382 // Format for the fractional part.
383 etl::basic_format_spec<TIString> fractional_format = integral_format;
384 fractional_format.precision(displayed_decimal_digits).width(displayed_decimal_digits).fill(type('0')).right();
385
386 // Do we need to check for rounding?
387 if (original_decimal_digits > displayed_decimal_digits)
388 {
389 // Which digit to adjust?
390 uint32_t count = original_decimal_digits - fractional_format.get_width();
391
392 // The 'round-away-from-zero' value.
393 uint32_t rounding = 5U;
394
395 while (count-- > 1U)
396 {
397 rounding *= 10U;
398 }
399
400 abs_value += rounding;
401 }
402
403 // Split the value into integral and fractional.
404 working_t integral = abs_value / denominator;
405 working_t fractional = abs_value % denominator;
406
407 // Move the fractional part to the right place.
408 uint32_t count = original_decimal_digits - fractional_format.get_width();
409 while (count-- > 0U)
410 {
411 fractional /= 10U;
412 }
413
414 // Create the string.
415 etl::private_to_string::add_integral_and_fractional(integral, fractional, str, integral_format, fractional_format, etl::is_negative(value));
416 etl::private_to_string::add_alignment(str, start, format);
417 }
418
419 //***************************************************************************
421 //***************************************************************************
422 template <typename TIString>
423 void add_pointer(const volatile void* value, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append)
424 {
425 uintptr_t p = reinterpret_cast<uintptr_t>(value);
426
427 return etl::private_to_string::add_integral(p, str, format, append, false);
428 }
429
430 //***************************************************************************
432 //***************************************************************************
433 template <typename TIString>
434 void add_string(const TIString& value, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append)
435 {
436 if (!append)
437 {
438 str.clear();
439 }
440
441 typename TIString::iterator start = str.end();
442
443 str.insert(str.end(), value.begin(), value.end());
444
445 etl::private_to_string::add_alignment(str, start, format);
446 }
447
448 //***************************************************************************
450 //***************************************************************************
451 template <typename TSringView, typename TIString>
452 void add_string_view(const TSringView& value, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append)
453 {
454 if (!append)
455 {
456 str.clear();
457 }
458
459 typename TIString::iterator start = str.end();
460
461 str.insert(str.end(), value.begin(), value.end());
462
463 etl::private_to_string::add_alignment(str, start, format);
464 }
465
466 //*********************************************************************************************************
467
468 //***************************************************************************
470 //***************************************************************************
471 template <typename TIString>
472 const TIString& to_string(const bool value, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append = false)
473 {
474 etl::private_to_string::add_boolean(value, str, format, append);
475
476 return str;
477 }
478
479 //***************************************************************************
481 //***************************************************************************
482 template <typename TIString>
483 const TIString& to_string(const volatile void* value, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append = false)
484 {
485 etl::private_to_string::add_pointer(value, str, format, append);
486
487 return str;
488 }
489
490#if ETL_USING_64BIT_TYPES
491 //***************************************************************************
493 //***************************************************************************
494 template <typename T, typename TIString>
495 typename etl::enable_if<etl::is_integral<T>::value && !etl::is_same<T, bool>::value && !etl::is_one_of<T, int64_t, uint64_t>::value,
496 const TIString&>::type
497 to_string(const T value, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append = false)
498 {
499 typedef typename etl::conditional<etl::is_signed<T>::value, int32_t, uint32_t>::type type;
500
501 etl::private_to_string::add_integral(type(value), str, format, append, etl::is_negative(value));
502
503 return str;
504 }
505
506 //***************************************************************************
508 //***************************************************************************
509 template <typename T, typename TIString>
510 typename etl::enable_if<etl::is_integral<T>::value && !etl::is_same<T, bool>::value && etl::is_one_of<T, int64_t, uint64_t>::value,
511 const TIString&>::type
512 to_string(const T value, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append = false)
513 {
514 etl::private_to_string::add_integral(value, str, format, append, etl::is_negative(value));
515
516 return str;
517 }
518
519 //***************************************************************************
521 //***************************************************************************
522 template <typename T, typename TIString>
523 typename etl::enable_if<etl::is_integral<T>::value && !etl::is_same<T, bool>::value && !etl::is_one_of<T, int64_t, uint64_t>::value,
524 const TIString&>::type
525 to_string(const T value, uint32_t denominator_exponent, TIString& str, const etl::basic_format_spec<TIString>& format,
526 const bool append = false)
527 {
528 typedef typename etl::conditional<etl::is_signed<T>::value, int32_t, uint32_t>::type type;
529
530 etl::private_to_string::add_integral_denominated(type(value), denominator_exponent, str, format, append);
531
532 return str;
533 }
534
535 //***************************************************************************
537 //***************************************************************************
538 template <typename T, typename TIString>
539 typename etl::enable_if<etl::is_integral<T>::value && !etl::is_same<T, bool>::value && etl::is_one_of<T, int64_t, uint64_t>::value,
540 const TIString&>::type
541 to_string(const T value, uint32_t denominator_exponent, TIString& str, const etl::basic_format_spec<TIString>& format,
542 const bool append = false)
543 {
544 etl::private_to_string::add_integral_denominated(value, denominator_exponent, str, format, append);
545
546 return str;
547 }
548#else
549 //***************************************************************************
551 //***************************************************************************
552 template <typename T, typename TIString>
553 typename etl::enable_if<etl::is_integral<T>::value && !etl::is_same<T, bool>::value>::value,
554 const TIString& > ::type to_string(const T value, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append = false)
555 {
556 typedef typename etl::conditional<etl::is_signed<T>::value, int32_t, uint32_t>::type type;
557
558 etl::private_to_string::add_integral(type(value), str, format, append, false);
559
560 return str;
561 }
562
563 //***************************************************************************
565 //***************************************************************************
566 template <typename T, typename TIString>
567 typename etl::enable_if<etl::is_integral<T>::value && !etl::is_same<T, bool>::value>::value,
568 const TIString& > ::type to_string(const T value, uint32_t denominator_exponent, TIString& str, const etl::basic_format_spec<TIString>& format,
569 const bool append = false)
570 {
571 etl::private_to_string::add_integral_denominated(type(value), denominator_exponent, str, format, append, false);
572
573 return str;
574 }
575#endif
576
577 //***************************************************************************
579 //***************************************************************************
580 template <typename T, typename TIString>
581 typename etl::enable_if<etl::is_floating_point<T>::value, const TIString&>::type
582 to_string(const T value, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append = false)
583 {
584 etl::private_to_string::add_floating_point(value, str, format, append);
585
586 return str;
587 }
588 } // namespace private_to_string
589} // namespace etl
590
591#endif
basic_format_spec
Definition basic_format_spec.h:204
ETL_CONSTEXPR14 basic_format_spec & right() ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT
Definition basic_format_spec.h:514
ETL_CONSTEXPR14 basic_format_spec & fill(typename TString::value_type c) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT
Definition basic_format_spec.h:460
ETL_CONSTEXPR uint32_t get_base() const ETL_NOEXCEPT
Gets the base.
Definition basic_format_spec.h:343
ETL_CONSTEXPR14 basic_format_spec & width(uint32_t w) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT
Definition basic_format_spec.h:379
ETL_CONSTEXPR bool is_show_base() const ETL_NOEXCEPT
Gets the show base flag.
Definition basic_format_spec.h:370
ETL_CONSTEXPR bool is_upper_case() const ETL_NOEXCEPT
Gets the upper case flag.
Definition basic_format_spec.h:451
ETL_CONSTEXPR14 basic_format_spec & precision(uint32_t p) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT
Definition basic_format_spec.h:406
ETL_CONSTEXPR bool is_left() const ETL_NOEXCEPT
Gets the left justify flag.
Definition basic_format_spec.h:505
ETL_CONSTEXPR TString::value_type get_fill() const ETL_NOEXCEPT
Gets the fill character.
Definition basic_format_spec.h:478
ETL_CONSTEXPR bool is_boolalpha() const ETL_NOEXCEPT
Gets the boolalpha flag.
Definition basic_format_spec.h:559
ETL_CONSTEXPR uint32_t get_width() const ETL_NOEXCEPT
Gets the width.
Definition basic_format_spec.h:397
ETL_CONSTEXPR14 basic_format_spec & decimal() ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT
Definition basic_format_spec.h:310
ETL_CONSTEXPR uint32_t get_precision() const ETL_NOEXCEPT
Gets the precision.
Definition basic_format_spec.h:424
Definition limits.h:1715
bitset_ext
Definition absolute.h:40
ETL_CONSTEXPR14 etl::enable_if< etl::is_specialization< TToDuration, etl::chrono::duration >::value, TToDuration >::type floor(const etl::chrono::duration< TRep, TPeriod > &d) ETL_NOEXCEPT
Rounds down a duration to the nearest lower precision.
Definition duration.h:630
etl::enable_if<!etl::is_same< T, etl::istring >::value &&!etl::is_same< T, etl::string_view >::value, constetl::istring & >::type to_string(const T value, etl::istring &str, bool append=false)
Definition to_string.h:50
ETL_CONSTEXPR14 etl::enable_if< etl::is_specialization< TToDuration, etl::chrono::duration >::value, TToDuration >::type round(const etl::chrono::duration< TRep, TPeriod > &d) ETL_NOEXCEPT
Definition duration.h:665
iterator
Definition iterator.h:424
void add_alignment(TIString &str, typename TIString::iterator position, const etl::basic_format_spec< TIString > &format)
Helper function for left/right alignment.
Definition to_string_helper.h:69
void add_floating_point(const T value, TIString &str, const etl::basic_format_spec< TIString > &format, const bool append)
Helper function for floating point.
Definition to_string_helper.h:282
void add_string(const TIString &value, TIString &str, const etl::basic_format_spec< TIString > &format, const bool append)
Helper function for strings.
Definition to_string_helper.h:434
void add_integral_denominated(const T value, const uint32_t denominator_exponent, TIString &str, const etl::basic_format_spec< TIString > &format, const bool append=false)
Helper function for denominated integers.
Definition to_string_helper.h:347
void add_nan_inf(const bool not_a_number, const bool infinity, TIString &str)
Helper function for floating point nan and inf.
Definition to_string_helper.h:221
void add_integral_and_fractional(const uint32_t integral, const uint32_t fractional, TIString &str, const etl::basic_format_spec< TIString > &integral_format, const etl::basic_format_spec< TIString > &fractional_format, const bool negative)
Helper function for floating point integral and fractional.
Definition to_string_helper.h:242
const TIString & to_string(const bool value, TIString &str, const etl::basic_format_spec< TIString > &format, const bool append=false)
For booleans.
Definition to_string_helper.h:472
void add_integral(T value, TIString &str, const etl::basic_format_spec< TIString > &format, bool append, const bool negative)
Helper function for integrals.
Definition to_string_helper.h:139
void add_string_view(const TSringView &value, TIString &str, const etl::basic_format_spec< TIString > &format, const bool append)
Helper function for string views.
Definition to_string_helper.h:452
void add_pointer(const volatile void *value, TIString &str, const etl::basic_format_spec< TIString > &format, const bool append)
Helper function for pointers.
Definition to_string_helper.h:423
void add_boolean(const bool value, TIString &str, const etl::basic_format_spec< TIString > &format, const bool append)
Helper function for booleans.
Definition to_string_helper.h:94