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 "../negative.h"
39#include "../basic_format_spec.h"
40#include "../type_traits.h"
41#include "../container.h"
42#include "../absolute.h"
43#include "../algorithm.h"
44#include "../iterator.h"
45#include "../math.h"
46#include "../limits.h"
47
48#include <math.h>
49
50#if ETL_USING_STL && ETL_USING_CPP11
51 #include <iterator> // For std::begin, std::end and std::size
52#endif
53
54namespace etl
55{
56 namespace private_to_string
57 {
58#if ETL_NOT_USING_64BIT_TYPES
59 typedef int32_t workspace_t;
60 typedef uint32_t uworkspace_t;
61#else
62 typedef int64_t workspace_t;
63 typedef uint64_t uworkspace_t;
64#endif
65
66 //***************************************************************************
68 //***************************************************************************
69 template <typename TIString>
70 void add_alignment(TIString& str, typename TIString::iterator position, const etl::basic_format_spec<TIString>& format)
71 {
72 uint32_t length = static_cast<uint32_t>(etl::distance(position, str.end()));
73
74 if (length < format.get_width())
75 {
76 uint32_t fill_length = format.get_width() - length;
77
78 if (format.is_left())
79 {
80 // Insert fill characters on the right.
81 str.insert(str.end(), fill_length, format.get_fill());
82 }
83 else
84 {
85 // Insert fill characters on the left.
86 str.insert(position, fill_length, format.get_fill());
87 }
88 }
89 }
90
91 //***************************************************************************
93 //***************************************************************************
94 template <typename TIString>
95 void add_boolean(const bool value,
96 TIString& str,
98 const bool append)
99 {
100 typedef typename TIString::value_type type;
101 typedef typename TIString::iterator iterator;
102
103 static const type t[] = { 't', 'r', 'u', 'e' };
104 static const type f[] = { 'f', 'a', 'l', 's', 'e' };
105
106 if (!append)
107 {
108 str.clear();
109 }
110
111 iterator start = str.end();
112
113 if (format.is_boolalpha())
114 {
115 if (value)
116 {
117 str.insert(str.end(), ETL_OR_STD11::begin(t), ETL_OR_STD11::end(t));
118 }
119 else
120 {
121 str.insert(str.end(), ETL_OR_STD11::begin(f), ETL_OR_STD11::end(f));
122 }
123 }
124 else
125 {
126 if (value)
127 {
128 str.push_back(type('1'));
129 }
130 else
131 {
132 str.push_back(type('0'));
133 }
134 }
135
136 etl::private_to_string::add_alignment(str, start, format);
137 }
138
139 //***************************************************************************
141 //***************************************************************************
142 template <typename T, typename TIString>
143 void add_integral(T value,
144 TIString& str,
146 bool append,
147 const bool negative)
148 {
149 typedef typename TIString::value_type type;
150 typedef typename TIString::iterator iterator;
151
152 if (!append)
153 {
154 str.clear();
155 }
156
157 iterator start = str.end();
158
159 if (value == 0)
160 {
161 // If number is negative, append '-' (a negative zero might occur for fractional numbers > -1.0)
162 if ((format.get_base() == 10U) && negative)
163 {
164 str.push_back(type('-'));
165 }
166
167 str.push_back(type('0'));
168 }
169 else
170 {
171 // Extract the digits, in reverse order.
172 while (value != 0)
173 {
174 T remainder = etl::absolute(value % T(format.get_base()));
175 str.push_back((remainder > 9) ? (format.is_upper_case() ? type('A' + (remainder - 10)) : type('a' + (remainder - 10))) : type('0' + remainder));
176 value = value / T(format.get_base());
177 }
178
179 // If number is negative, append '-'
180 if ((format.get_base() == 10U) && negative)
181 {
182 str.push_back(type('-'));
183 }
184
185 if (format.is_show_base())
186 {
187 switch (format.get_base())
188 {
189 case 2U:
190 {
191 str.push_back(format.is_upper_case() ? type('B') : type('b'));
192 str.push_back(type('0'));
193 break;
194 }
195
196 case 8U:
197 {
198 str.push_back(type('0'));
199 break;
200 }
201
202 case 16U:
203 {
204 str.push_back(format.is_upper_case() ? type('X') : type('x'));
205 str.push_back(type('0'));
206 break;
207 }
208
209 default:
210 {
211 break;
212 }
213 }
214 }
215
216 // Reverse the string we appended.
217 etl::reverse(start, str.end());
218 }
219
220 etl::private_to_string::add_alignment(str, start, format);
221 }
222
223 //***************************************************************************
225 //***************************************************************************
226 template <typename TIString>
227 void add_nan_inf(const bool not_a_number,
228 const bool infinity,
229 TIString& str)
230 {
231 typedef typename TIString::value_type type;
232
233 static const type n[] = { 'n', 'a', 'n' };
234 static const type i[] = { 'i', 'n', 'f' };
235
236 if (not_a_number)
237 {
238 str.insert(str.end(), ETL_OR_STD11::begin(n), ETL_OR_STD11::end(n));
239 }
240 else if (infinity)
241 {
242 str.insert(str.end(), ETL_OR_STD11::begin(i), ETL_OR_STD11::end(i));
243 }
244 }
245
246 //***************************************************************************
248 //***************************************************************************
249 template <typename TIString>
251 const uint32_t fractional,
252 TIString& str,
255 const bool negative)
256 {
257 typedef typename TIString::value_type type;
258
260
261 if (fractional_format.get_precision() > 0)
262 {
263 str.push_back(type('.'));
265 }
266 }
267
268#if ETL_USING_64BIT_TYPES
269 //***************************************************************************
271 //***************************************************************************
272 template <typename TIString>
274 const uint64_t fractional,
275 TIString& str,
278 const bool negative)
279 {
280 typedef typename TIString::value_type type;
281
283
284 if (fractional_format.get_precision() > 0)
285 {
286 str.push_back(type('.'));
288 }
289 }
290#endif
291
292 //***************************************************************************
294 //***************************************************************************
295 template <typename T, typename TIString>
296 void add_floating_point(const T value,
297 TIString& str,
299 const bool append)
300 {
301 typedef typename TIString::iterator iterator;
302 typedef typename TIString::value_type type;
303
304 if (!append)
305 {
306 str.clear();
307 }
308
309 iterator start = str.end();
310
311 if (isnan(value) || isinf(value))
312 {
314 }
315 else
316 {
317 // Make sure we format the two halves correctly.
319
320#if ETL_NOT_USING_64BIT_TYPES
321 if (max_precision > 9)
322 {
323 max_precision = 9;
324 }
325#endif
326
328 integral_format.decimal().width(0).precision(format.get_precision() > max_precision ? max_precision : format.get_precision());
329
331 fractional_format.width(integral_format.get_precision()).fill(type('0')).right();
332
333 uworkspace_t multiplier = 1U;
334
335 for (uint32_t i = 0U; i < fractional_format.get_precision(); ++i)
336 {
337 multiplier *= 10U;
338 }
339
340 // Find the integral part of the floating point
341 T f_integral = floor(etl::absolute(value));
343
344 // Find the fractional part of the floating point.
345 uworkspace_t fractional = static_cast<uworkspace_t>(round((etl::absolute(value) - f_integral) * multiplier));
346
347 // Check for a rounding carry to the integral.
348 if (fractional == multiplier)
349 {
350 ++integral;
351 fractional = 0U;
352 }
353
355 }
356
357 etl::private_to_string::add_alignment(str, start, format);
358 }
359
360 //***************************************************************************
362 //***************************************************************************
363 template <typename T, typename TIString>
364 void add_integral_denominated(const T value,
366 TIString& str,
368 const bool append = false)
369 {
370 typedef typename TIString::iterator iterator;
371 typedef typename TIString::value_type type;
372 typedef typename etl::make_unsigned<T>::type working_t;
373
374 if (!append)
375 {
376 str.clear();
377 }
378
379 iterator start = str.end();
380
381 // Calculate the denominator.
383
384 for (uint32_t i = 0U; i < denominator_exponent; ++i)
385 {
386 denominator *= 10U;
387 }
388
389 // Get the absolute value, taking care of minimum negative values.
390 working_t abs_value = etl::absolute_unsigned(value);
391
392 // Figure out how many decimal digits we have in the value.
394
395 // How many decimal digits are we displaying.
396 const uint32_t displayed_decimal_digits = (format.get_precision() > original_decimal_digits) ? original_decimal_digits : format.get_precision();
397
398 // Format for the integral part.
400 integral_format.decimal().width(0U);
401
402 // Format for the fractional part.
404 fractional_format.precision(displayed_decimal_digits).width(displayed_decimal_digits).fill(type('0')).right();
405
406 // Do we need to check for rounding?
408 {
409 // Which digit to adjust?
411
412 // The 'round-away-from-zero' value.
413 uint32_t rounding = 5U;
414
415 while (count-- > 1U)
416 {
417 rounding *= 10U;
418 }
419
421 }
422
423 // Split the value into integral and fractional.
426
427 // Move the fractional part to the right place.
429 while (count-- > 0U)
430 {
431 fractional /= 10U;
432 }
433
434 // Create the string.
436 etl::private_to_string::add_alignment(str, start, format);
437 }
438
439 //***************************************************************************
441 //***************************************************************************
442 template <typename TIString>
443 void add_pointer(const volatile void* value,
444 TIString& str,
446 const bool append)
447 {
448 uintptr_t p = reinterpret_cast<uintptr_t>(value);
449
450 return etl::private_to_string::add_integral(p, str, format, append, false);
451 }
452
453 //***************************************************************************
455 //***************************************************************************
456 template <typename TIString>
457 void add_string(const TIString& value,
458 TIString& str,
460 const bool append)
461 {
462 if (!append)
463 {
464 str.clear();
465 }
466
467 typename TIString::iterator start = str.end();
468
469 str.insert(str.end(), value.begin(), value.end());
470
471 etl::private_to_string::add_alignment(str, start, format);
472 }
473
474 //***************************************************************************
476 //***************************************************************************
477 template <typename TSringView, typename TIString>
478 void add_string_view(const TSringView& value,
479 TIString& str,
481 const bool append)
482 {
483 if (!append)
484 {
485 str.clear();
486 }
487
488 typename TIString::iterator start = str.end();
489
490 str.insert(str.end(), value.begin(), value.end());
491
492 etl::private_to_string::add_alignment(str, start, format);
493 }
494
495 //*********************************************************************************************************
496
497 //***************************************************************************
499 //***************************************************************************
500 template <typename TIString>
501 const TIString& to_string(const bool value,
502 TIString& str,
504 const bool append = false)
505 {
506 etl::private_to_string::add_boolean(value, str, format, append);
507
508 return str;
509 }
510
511 //***************************************************************************
513 //***************************************************************************
514 template <typename TIString>
515 const TIString& to_string(const volatile void* value,
516 TIString& str,
518 const bool append = false)
519 {
520 etl::private_to_string::add_pointer(value, str, format, append);
521
522 return str;
523 }
524
525#if ETL_USING_64BIT_TYPES
526 //***************************************************************************
528 //***************************************************************************
529 template <typename T, typename TIString>
533 to_string(const T value, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append = false)
534 {
535 typedef typename etl::conditional<etl::is_signed<T>::value, int32_t, uint32_t>::type type;
536
537 etl::private_to_string::add_integral(type(value), str, format, append, etl::is_negative(value));
538
539 return str;
540 }
541
542 //***************************************************************************
544 //***************************************************************************
545 template <typename T, typename TIString>
549 to_string(const T value, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append = false)
550 {
551 etl::private_to_string::add_integral(value, str, format, append, etl::is_negative(value));
552
553 return str;
554 }
555
556 //***************************************************************************
558 //***************************************************************************
559 template <typename T, typename TIString>
563 to_string(const T value, uint32_t denominator_exponent, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append = false)
564 {
565 typedef typename etl::conditional<etl::is_signed<T>::value, int32_t, uint32_t>::type type;
566
568
569 return str;
570 }
571
572 //***************************************************************************
574 //***************************************************************************
575 template <typename T, typename TIString>
579 to_string(const T value, uint32_t denominator_exponent, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append = false)
580 {
582
583 return str;
584 }
585#else
586 //***************************************************************************
588 //***************************************************************************
589 template <typename T, typename TIString>
591 !etl::is_same<T, bool>::value>::value, const TIString& > ::type
592 to_string(const T value, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append = false)
593 {
594 typedef typename etl::conditional<etl::is_signed<T>::value, int32_t, uint32_t>::type type;
595
596 etl::private_to_string::add_integral(type(value), str, format, append, false);
597
598 return str;
599 }
600
601 //***************************************************************************
603 //***************************************************************************
604 template <typename T, typename TIString>
606 !etl::is_same<T, bool>::value>::value, const TIString& > ::type
607 to_string(const T value, uint32_t denominator_exponent, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append = false)
608 {
609 etl::private_to_string::add_integral_denominated(type(value), denominator_exponent, str, format, append, false);
610
611 return str;
612 }
613#endif
614
615 //***************************************************************************
617 //***************************************************************************
618 template <typename T, typename TIString>
619 typename etl::enable_if<etl::is_floating_point<T>::value, const TIString&>::type
620 to_string(const T value, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append = false)
621 {
622 etl::private_to_string::add_floating_point(value, str, format, append);
623
624 return str;
625 }
626 }
627}
628
629#endif
Definition limits.h:1175
add_pointer
Definition type_traits_generator.h:898
is_same
Definition type_traits_generator.h:1041
make_unsigned
Definition type_traits_generator.h:1181
bitset_ext
Definition absolute.h:38
iterator
Definition iterator.h:399
pair holds two objects of arbitrary type
Definition utility.h:164
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:70
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:296
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:457
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:364
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:227
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:250
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:501
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:143
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:478
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:443
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:95