Embedded Template Library 1.0
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 "../limits.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,
95 TIString& str,
97 const bool append)
98 {
99 typedef typename TIString::value_type type;
100 typedef typename TIString::iterator iterator;
101
102 static const type t[] = { 't', 'r', 'u', 'e' };
103 static const type f[] = { 'f', 'a', 'l', 's', 'e' };
104
105 if (!append)
106 {
107 str.clear();
108 }
109
110 iterator start = str.end();
111
112 if (format.is_boolalpha())
113 {
114 if (value)
115 {
116 str.insert(str.end(), ETL_OR_STD11::begin(t), ETL_OR_STD11::end(t));
117 }
118 else
119 {
120 str.insert(str.end(), ETL_OR_STD11::begin(f), ETL_OR_STD11::end(f));
121 }
122 }
123 else
124 {
125 if (value)
126 {
127 str.push_back(type('1'));
128 }
129 else
130 {
131 str.push_back(type('0'));
132 }
133 }
134
135 etl::private_to_string::add_alignment(str, start, format);
136 }
137
138 //***************************************************************************
140 //***************************************************************************
141 template <typename T, typename TIString>
142 void add_integral(T value,
143 TIString& str,
145 bool append,
146 const bool negative)
147 {
148 typedef typename TIString::value_type type;
149 typedef typename TIString::iterator iterator;
150
151 if (!append)
152 {
153 str.clear();
154 }
155
156 iterator start = str.end();
157
158 if (value == 0)
159 {
160 // If number is negative, append '-' (a negative zero might occur for fractional numbers > -1.0)
161 if ((format.get_base() == 10U) && negative)
162 {
163 str.push_back(type('-'));
164 }
165
166 str.push_back(type('0'));
167 }
168 else
169 {
170 // Extract the digits, in reverse order.
171 while (value != 0)
172 {
173 T remainder = etl::absolute(value % T(format.get_base()));
174 str.push_back((remainder > 9) ? (format.is_upper_case() ? type('A' + (remainder - 10)) : type('a' + (remainder - 10))) : type('0' + remainder));
175 value = value / T(format.get_base());
176 }
177
178 // If number is negative, append '-'
179 if ((format.get_base() == 10U) && negative)
180 {
181 str.push_back(type('-'));
182 }
183
184 if (format.is_show_base())
185 {
186 switch (format.get_base())
187 {
188 case 2U:
189 {
190 str.push_back(format.is_upper_case() ? type('B') : type('b'));
191 str.push_back(type('0'));
192 break;
193 }
194
195 case 8U:
196 {
197 str.push_back(type('0'));
198 break;
199 }
200
201 case 16U:
202 {
203 str.push_back(format.is_upper_case() ? type('X') : type('x'));
204 str.push_back(type('0'));
205 break;
206 }
207
208 default:
209 {
210 break;
211 }
212 }
213 }
214
215 // Reverse the string we appended.
216 etl::reverse(start, str.end());
217 }
218
219 etl::private_to_string::add_alignment(str, start, format);
220 }
221
222 //***************************************************************************
224 //***************************************************************************
225 template <typename TIString>
226 void add_nan_inf(const bool not_a_number,
227 const bool infinity,
228 TIString& str)
229 {
230 typedef typename TIString::value_type type;
231
232 static const type n[] = { 'n', 'a', 'n' };
233 static const type i[] = { 'i', 'n', 'f' };
234
235 if (not_a_number)
236 {
237 str.insert(str.end(), ETL_OR_STD11::begin(n), ETL_OR_STD11::end(n));
238 }
239 else if (infinity)
240 {
241 str.insert(str.end(), ETL_OR_STD11::begin(i), ETL_OR_STD11::end(i));
242 }
243 }
244
245 //***************************************************************************
247 //***************************************************************************
248 template <typename TIString>
249 void add_integral_and_fractional(const uint32_t integral,
250 const uint32_t fractional,
251 TIString& str,
252 const etl::basic_format_spec<TIString>& integral_format,
253 const etl::basic_format_spec<TIString>& fractional_format,
254 const bool negative)
255 {
256 typedef typename TIString::value_type type;
257
258 etl::private_to_string::add_integral(integral, str, integral_format, true, negative);
259
260 if (fractional_format.get_precision() > 0)
261 {
262 str.push_back(type('.'));
263 etl::private_to_string::add_integral(fractional, str, fractional_format, true, false);
264 }
265 }
266
267#if ETL_USING_64BIT_TYPES
268 //***************************************************************************
270 //***************************************************************************
271 template <typename TIString>
272 void add_integral_and_fractional(const uint64_t integral,
273 const uint64_t fractional,
274 TIString& str,
275 const etl::basic_format_spec<TIString>& integral_format,
276 const etl::basic_format_spec<TIString>& fractional_format,
277 const bool negative)
278 {
279 typedef typename TIString::value_type type;
280
281 etl::private_to_string::add_integral(integral, str, integral_format, true, negative);
282
283 if (fractional_format.get_precision() > 0)
284 {
285 str.push_back(type('.'));
286 etl::private_to_string::add_integral(fractional, str, fractional_format, true, false);
287 }
288 }
289#endif
290
291 //***************************************************************************
293 //***************************************************************************
294 template <typename T, typename TIString>
295 void add_floating_point(const T value,
296 TIString& str,
298 const bool append)
299 {
300 typedef typename TIString::iterator iterator;
301 typedef typename TIString::value_type type;
302
303 if (!append)
304 {
305 str.clear();
306 }
307
308 iterator start = str.end();
309
310 if (isnan(value) || isinf(value))
311 {
312 etl::private_to_string::add_nan_inf(isnan(value), isinf(value), str);
313 }
314 else
315 {
316 // Make sure we format the two halves correctly.
317 uint32_t max_precision = etl::numeric_limits<T>::digits10;
318
319#if ETL_NOT_USING_64BIT_TYPES
320 if (max_precision > 9)
321 {
322 max_precision = 9;
323 }
324#endif
325
326 etl::basic_format_spec<TIString> integral_format = format;
327 integral_format.decimal().width(0).precision(format.get_precision() > max_precision ? max_precision : format.get_precision());
328
329 etl::basic_format_spec<TIString> fractional_format = integral_format;
330 fractional_format.width(integral_format.get_precision()).fill(type('0')).right();
331
332 uworkspace_t multiplier = 1U;
333
334 for (uint32_t i = 0U; i < fractional_format.get_precision(); ++i)
335 {
336 multiplier *= 10U;
337 }
338
339 // Find the integral part of the floating point
340 T f_integral = floor(etl::absolute(value));
341 uworkspace_t integral = static_cast<uworkspace_t>(f_integral);
342
343 // Find the fractional part of the floating point.
344 uworkspace_t fractional = static_cast<uworkspace_t>(round((etl::absolute(value) - f_integral) * multiplier));
345
346 // Check for a rounding carry to the integral.
347 if (fractional == multiplier)
348 {
349 ++integral;
350 fractional = 0U;
351 }
352
353 etl::private_to_string::add_integral_and_fractional(integral, fractional, str, integral_format, fractional_format, etl::is_negative(value));
354 }
355
356 etl::private_to_string::add_alignment(str, start, format);
357 }
358
359 //***************************************************************************
361 //***************************************************************************
362 template <typename T, typename TIString>
363 void add_integral_denominated(const T value,
364 const uint32_t denominator_exponent,
365 TIString& str,
367 const bool append = false)
368 {
369 typedef typename TIString::iterator iterator;
370 typedef typename TIString::value_type type;
371 typedef typename etl::make_unsigned<T>::type working_t;
372
373 if (!append)
374 {
375 str.clear();
376 }
377
378 iterator start = str.end();
379
380 // Calculate the denominator.
381 working_t denominator = 1U;
382
383 for (uint32_t i = 0U; i < denominator_exponent; ++i)
384 {
385 denominator *= 10U;
386 }
387
388 // Get the absolute value, taking care of minimum negative values.
389 working_t abs_value = etl::absolute_unsigned(value);
390
391 // Figure out how many decimal digits we have in the value.
392 const uint32_t& original_decimal_digits = denominator_exponent;
393
394 // How many decimal digits are we displaying.
395 const uint32_t displayed_decimal_digits = (format.get_precision() > original_decimal_digits) ? original_decimal_digits : format.get_precision();
396
397 // Format for the integral part.
398 etl::basic_format_spec<TIString> integral_format = format;
399 integral_format.decimal().width(0U);
400
401 // Format for the fractional part.
402 etl::basic_format_spec<TIString> fractional_format = integral_format;
403 fractional_format.precision(displayed_decimal_digits).width(displayed_decimal_digits).fill(type('0')).right();
404
405 // Do we need to check for rounding?
406 if (original_decimal_digits > displayed_decimal_digits)
407 {
408 // Which digit to adjust?
409 uint32_t count = original_decimal_digits - fractional_format.get_width();
410
411 // The 'round-away-from-zero' value.
412 uint32_t rounding = 5U;
413
414 while (count-- > 1U)
415 {
416 rounding *= 10U;
417 }
418
419 abs_value += rounding;
420 }
421
422 // Split the value into integral and fractional.
423 working_t integral = abs_value / denominator;
424 working_t fractional = abs_value % denominator;
425
426 // Move the fractional part to the right place.
427 uint32_t count = original_decimal_digits - fractional_format.get_width();
428 while (count-- > 0U)
429 {
430 fractional /= 10U;
431 }
432
433 // Create the string.
434 etl::private_to_string::add_integral_and_fractional(integral, fractional, str, integral_format, fractional_format, etl::is_negative(value));
435 etl::private_to_string::add_alignment(str, start, format);
436 }
437
438 //***************************************************************************
440 //***************************************************************************
441 template <typename TIString>
442 void add_pointer(const volatile void* value,
443 TIString& str,
445 const bool append)
446 {
447 uintptr_t p = reinterpret_cast<uintptr_t>(value);
448
449 return etl::private_to_string::add_integral(p, str, format, append, false);
450 }
451
452 //***************************************************************************
454 //***************************************************************************
455 template <typename TIString>
456 void add_string(const TIString& value,
457 TIString& str,
459 const bool append)
460 {
461 if (!append)
462 {
463 str.clear();
464 }
465
466 typename TIString::iterator start = str.end();
467
468 str.insert(str.end(), value.begin(), value.end());
469
470 etl::private_to_string::add_alignment(str, start, format);
471 }
472
473 //***************************************************************************
475 //***************************************************************************
476 template <typename TSringView, typename TIString>
477 void add_string_view(const TSringView& value,
478 TIString& str,
480 const bool append)
481 {
482 if (!append)
483 {
484 str.clear();
485 }
486
487 typename TIString::iterator start = str.end();
488
489 str.insert(str.end(), value.begin(), value.end());
490
491 etl::private_to_string::add_alignment(str, start, format);
492 }
493
494 //*********************************************************************************************************
495
496 //***************************************************************************
498 //***************************************************************************
499 template <typename TIString>
500 const TIString& to_string(const bool value,
501 TIString& str,
503 const bool append = false)
504 {
505 etl::private_to_string::add_boolean(value, str, format, append);
506
507 return str;
508 }
509
510 //***************************************************************************
512 //***************************************************************************
513 template <typename TIString>
514 const TIString& to_string(const volatile void* value,
515 TIString& str,
517 const bool append = false)
518 {
519 etl::private_to_string::add_pointer(value, str, format, append);
520
521 return str;
522 }
523
524#if ETL_USING_64BIT_TYPES
525 //***************************************************************************
527 //***************************************************************************
528 template <typename T, typename TIString>
531 !etl::is_one_of<T, int64_t, uint64_t>::value, const TIString&>::type
532 to_string(const T value, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append = false)
533 {
534 typedef typename etl::conditional<etl::is_signed<T>::value, int32_t, uint32_t>::type type;
535
536 etl::private_to_string::add_integral(type(value), str, format, append, etl::is_negative(value));
537
538 return str;
539 }
540
541 //***************************************************************************
543 //***************************************************************************
544 template <typename T, typename TIString>
547 etl::is_one_of<T, int64_t, uint64_t>::value, const TIString&>::type
548 to_string(const T value, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append = false)
549 {
550 etl::private_to_string::add_integral(value, str, format, append, etl::is_negative(value));
551
552 return str;
553 }
554
555 //***************************************************************************
557 //***************************************************************************
558 template <typename T, typename TIString>
561 !etl::is_one_of<T, int64_t, uint64_t>::value, const TIString&>::type
562 to_string(const T value, uint32_t denominator_exponent, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append = false)
563 {
564 typedef typename etl::conditional<etl::is_signed<T>::value, int32_t, uint32_t>::type type;
565
566 etl::private_to_string::add_integral_denominated(type(value), denominator_exponent, str, format, append);
567
568 return str;
569 }
570
571 //***************************************************************************
573 //***************************************************************************
574 template <typename T, typename TIString>
577 etl::is_one_of<T, int64_t, uint64_t>::value, const TIString&>::type
578 to_string(const T value, uint32_t denominator_exponent, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append = false)
579 {
580 etl::private_to_string::add_integral_denominated(value, denominator_exponent, str, format, append);
581
582 return str;
583 }
584#else
585 //***************************************************************************
587 //***************************************************************************
588 template <typename T, typename TIString>
590 !etl::is_same<T, bool>::value>::value, const TIString& > ::type
591 to_string(const T value, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append = false)
592 {
593 typedef typename etl::conditional<etl::is_signed<T>::value, int32_t, uint32_t>::type type;
594
595 etl::private_to_string::add_integral(type(value), str, format, append, false);
596
597 return str;
598 }
599
600 //***************************************************************************
602 //***************************************************************************
603 template <typename T, typename TIString>
605 !etl::is_same<T, bool>::value>::value, const TIString& > ::type
606 to_string(const T value, uint32_t denominator_exponent, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append = false)
607 {
608 etl::private_to_string::add_integral_denominated(type(value), denominator_exponent, str, format, append, false);
609
610 return str;
611 }
612#endif
613
614 //***************************************************************************
616 //***************************************************************************
617 template <typename T, typename TIString>
618 typename etl::enable_if<etl::is_floating_point<T>::value, const TIString&>::type
619 to_string(const T value, TIString& str, const etl::basic_format_spec<TIString>& format, const bool append = false)
620 {
621 etl::private_to_string::add_floating_point(value, str, format, append);
622
623 return str;
624 }
625 }
626}
627
628#endif
basic_format_spec
Definition: basic_format_spec.h:203
ETL_CONSTEXPR bool is_boolalpha() const
Gets the boolalpha flag.
Definition: basic_format_spec.h:455
ETL_CONSTEXPR uint32_t get_width() const
Gets the width.
Definition: basic_format_spec.h:347
ETL_CONSTEXPR14 basic_format_spec & fill(typename TString::value_type c)
Definition: basic_format_spec.h:392
ETL_CONSTEXPR uint32_t get_base() const
Gets the base.
Definition: basic_format_spec.h:311
ETL_CONSTEXPR14 basic_format_spec & precision(uint32_t p)
Definition: basic_format_spec.h:356
ETL_CONSTEXPR TString::value_type get_fill() const
Gets the fill character.
Definition: basic_format_spec.h:401
ETL_CONSTEXPR bool is_show_base() const
Gets the show base flag.
Definition: basic_format_spec.h:329
ETL_CONSTEXPR14 basic_format_spec & decimal()
Definition: basic_format_spec.h:292
ETL_CONSTEXPR uint32_t get_precision() const
Gets the precision.
Definition: basic_format_spec.h:365
ETL_CONSTEXPR14 basic_format_spec & right()
Definition: basic_format_spec.h:428
ETL_CONSTEXPR14 basic_format_spec & width(uint32_t w)
Definition: basic_format_spec.h:338
ETL_CONSTEXPR bool is_left() const
Gets the left justify flag.
Definition: basic_format_spec.h:419
ETL_CONSTEXPR bool is_upper_case() const
Gets the upper case flag.
Definition: basic_format_spec.h:383
Definition: limits.h:1164
add_pointer
Definition: type_traits_generator.h:898
conditional
Definition: type_traits_generator.h:1160
enable_if
Definition: type_traits_generator.h:1191
is_same
Definition: type_traits_generator.h:1041
bitset_ext
Definition: absolute.h:38
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_CONSTEXPR TContainer::iterator begin(TContainer &container)
Definition: iterator.h:931
ETL_CONSTEXPR TContainer::iterator end(TContainer &container)
Definition: iterator.h:961
Definition: type_traits.h:1376
iterator
Definition: iterator.h:399
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:295
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:456
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:363
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:226
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:249
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:142
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:477
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:442
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