Embedded Template Library  1.0
to_string_helper.h
Go to the documentation of this file.
1 
3 /******************************************************************************
4 The MIT License(MIT)
5 
6 Embedded Template Library.
7 https://github.com/ETLCPP/etl
8 https://www.etlcpp.com
9 
10 Copyright(c) 2019 jwellbelove
11 
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files(the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions :
18 
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21 
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29 ******************************************************************************/
30 
31 #ifndef ETL_TO_STRING_HELPER_INCLUDED
32 #define ETL_TO_STRING_HELPER_INCLUDED
33 
35 
36 #include <math.h>
37 
38 #include "../platform.h"
39 #include "../absolute.h"
40 #include "../negative.h"
41 #include "../basic_format_spec.h"
42 #include "../type_traits.h"
43 #include "../container.h"
44 #include "../absolute.h"
45 #include "../algorithm.h"
46 #include "../iterator.h"
47 #include "../limits.h"
48 
49 namespace etl
50 {
51  namespace private_to_string
52  {
53 #if ETL_NOT_USING_64BIT_TYPES
54  typedef int32_t workspace_t;
55 #else
56  typedef int64_t workspace_t;
57 #endif
58 
59  //***************************************************************************
61  //***************************************************************************
62  template <typename TIString>
63  void add_alignment(TIString& str, typename TIString::iterator position, const etl::basic_format_spec<TIString>& format)
64  {
65  uint32_t length = static_cast<uint32_t>(etl::distance(position, str.end()));
66 
67  if (length < format.get_width())
68  {
69  uint32_t fill_length = format.get_width() - length;
70 
71  if (format.is_left())
72  {
73  // Insert fill characters on the right.
74  str.insert(str.end(), fill_length, format.get_fill());
75  }
76  else
77  {
78  // Insert fill characters on the left.
79  str.insert(position, fill_length, format.get_fill());
80  }
81  }
82  }
83 
84  //***************************************************************************
86  //***************************************************************************
87  template <typename TIString>
88  void add_boolean(const bool value,
89  TIString& str,
91  bool append)
92  {
93  typedef typename TIString::value_type type;
94  typedef typename TIString::iterator iterator;
95 
96  static const type t[] = { 't', 'r', 'u', 'e' };
97  static const type f[] = { 'f', 'a', 'l', 's', 'e' };
98 
99  if (!append)
100  {
101  str.clear();
102  }
103 
104  iterator start = str.end();
105 
106  if (format.is_boolalpha())
107  {
108  if (value)
109  {
110  str.insert(str.end(), etl::begin(t), etl::end(t));
111  }
112  else
113  {
114  str.insert(str.end(), etl::begin(f), etl::end(f));
115  }
116  }
117  else
118  {
119  if (value)
120  {
121  str.push_back(type('1'));
122  }
123  else
124  {
125  str.push_back(type('0'));
126  }
127  }
128 
129  etl::private_to_string::add_alignment(str, start, format);
130  }
131 
132  //***************************************************************************
134  //***************************************************************************
135  template <typename T, typename TIString>
136  void add_integral(T value,
137  TIString& str,
138  const etl::basic_format_spec<TIString>& format,
139  bool append,
140  const bool negative)
141  {
142  typedef typename TIString::value_type type;
143  typedef typename TIString::iterator iterator;
144 
145  if (!append)
146  {
147  str.clear();
148  }
149 
150  iterator start = str.end();
151 
152  if (value == 0)
153  {
154  // If number is negative, append '-' (a negative zero might occure for 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))) : type('0' + remainder));
169  value = value / T(format.get_base());
170  }
171 
172  // If number is negative, append '-'
173  if ((format.get_base() == 10U) && negative)
174  {
175  str.push_back(type('-'));
176  }
177 
178  if (format.is_show_base())
179  {
180  switch (format.get_base())
181  {
182  case 2U:
183  {
184  str.push_back(format.is_upper_case() ? type('B') : type('b'));
185  str.push_back(type('0'));
186  break;
187  }
188 
189  case 8U:
190  {
191  str.push_back(type('0'));
192  break;
193  }
194 
195  case 16U:
196  {
197  str.push_back(format.is_upper_case() ? type('X') : type('x'));
198  str.push_back(type('0'));
199  break;
200  }
201 
202  default:
203  {
204  break;
205  }
206  }
207  }
208 
209  // Reverse the string we appended.
210  etl::reverse(start, str.end());
211  }
212 
213  etl::private_to_string::add_alignment(str, start, format);
214  }
215 
216  //***************************************************************************
218  //***************************************************************************
219  template <typename TIString>
220  void add_nan_inf(const bool not_a_number,
221  const bool infinity,
222  TIString& str)
223  {
224  typedef typename TIString::value_type type;
225 
226  static const type n[] = { 'n', 'a', 'n' };
227  static const type i[] = { 'i', 'n', 'f' };
228 
229  if (not_a_number)
230  {
231  str.insert(str.end(), etl::begin(n), etl::end(n));
232  }
233  else if (infinity)
234  {
235  str.insert(str.end(), etl::begin(i), etl::end(i));
236  }
237  }
238 
239  //***************************************************************************
241  //***************************************************************************
242  template <typename TIString>
243  void add_integral_fractional(const workspace_t integral,
244  const workspace_t fractional,
245  TIString& str,
246  const etl::basic_format_spec<TIString>& integral_format,
247  const etl::basic_format_spec<TIString>& fractional_format,
248  const bool negative)
249  {
250  typedef typename TIString::value_type type;
251 
252  etl::private_to_string::add_integral(integral, str, integral_format, true, negative);
253 
254  if (fractional_format.get_precision() > 0)
255  {
256  str.push_back(type('.'));
257  etl::private_to_string::add_integral(fractional, str, fractional_format, true, false);
258  }
259  }
260 
261  //***************************************************************************
263  //***************************************************************************
264  template <typename T, typename TIString>
265  void add_floating_point(T value,
266  TIString& str,
267  const etl::basic_format_spec<TIString>& format,
268  bool append)
269  {
270  typedef typename TIString::iterator iterator;
271  typedef typename TIString::value_type type;
272 
273  if (!append)
274  {
275  str.clear();
276  }
277 
278  iterator start = str.end();
279 
280  if (isnan(value) || isinf(value))
281  {
282  etl::private_to_string::add_nan_inf(isnan(value), isinf(value), str);
283  }
284  else
285  {
286  // Make sure we format the two halves correctly.
287  uint32_t max_precision = etl::numeric_limits<T>::digits10;
288 
289  etl::basic_format_spec<TIString> integral_format = format;
290  integral_format.decimal().width(0).precision(format.get_precision() > max_precision ? max_precision : format.get_precision());
291 
292  etl::basic_format_spec<TIString> fractional_format = integral_format;
293  fractional_format.width(integral_format.get_precision()).fill(type('0')).right();
294 
295  workspace_t multiplier = 1;
296 
297  for (uint32_t i = 0; i < fractional_format.get_precision(); ++i)
298  {
299  multiplier *= 10U;
300  }
301 
302  // Find the integral part of the floating point
303  T f_integral = (value < T(0.0) ? ceil(value) : floor(value));
304  workspace_t integral = static_cast<workspace_t>(f_integral);
305 
306  // Find the fractional part of the floating point.
307  workspace_t fractional = etl::absolute(static_cast<workspace_t>(round((value - f_integral) * multiplier)));
308 
309  // Check for a rounding carry to the integral.
310  if (fractional == multiplier)
311  {
312  ++integral;
313  fractional = 0;
314  }
315 
316  etl::private_to_string::add_integral_fractional(integral, fractional, str, integral_format, fractional_format, etl::is_negative(value));
317  }
318 
319  etl::private_to_string::add_alignment(str, start, format);
320  }
321 
322  //***************************************************************************
324  //***************************************************************************
325  template <typename TIString>
326  void add_pointer(const volatile void* value,
327  TIString& str,
328  const etl::basic_format_spec<TIString>& format,
329  bool append)
330  {
331  uintptr_t p = reinterpret_cast<uintptr_t>(value);
332 
333  return etl::private_to_string::add_integral(p, str, format, append, false);
334  }
335 
336  //***************************************************************************
338  //***************************************************************************
339  template <typename TIString>
340  void add_string(const TIString& value,
341  TIString& str,
342  const etl::basic_format_spec<TIString>& format,
343  bool append)
344  {
345  if (!append)
346  {
347  str.clear();
348  }
349 
350  typename TIString::iterator start = str.end();
351 
352  str.insert(str.end(), value.begin(), value.end());
353 
354  etl::private_to_string::add_alignment(str, start, format);
355  }
356 
357  //***************************************************************************
359  //***************************************************************************
360  template <typename TSringView, typename TIString>
361  void add_string_view(const TSringView& value,
362  TIString& str,
363  const etl::basic_format_spec<TIString>& format,
364  bool append)
365  {
366  if (!append)
367  {
368  str.clear();
369  }
370 
371  typename TIString::iterator start = str.end();
372 
373  str.insert(str.end(), value.begin(), value.end());
374 
375  etl::private_to_string::add_alignment(str, start, format);
376  }
377 
378  //*********************************************************************************************************
379 
380  //***************************************************************************
382  //***************************************************************************
383  template <typename TIString>
384  const TIString& to_string(const bool value,
385  TIString& str,
386  bool append = false)
387  {
389 
390  etl::private_to_string::add_boolean(value, str, format, append);
391 
392  return str;
393  }
394 
395  //***************************************************************************
397  //***************************************************************************
398  template <typename TIString>
399  const TIString& to_string(const bool value,
400  TIString& str,
401  const etl::basic_format_spec<TIString>& format,
402  bool append = false)
403  {
404  etl::private_to_string::add_boolean(value, str, format, append);
405 
406  return str;
407  }
408 
409  //***************************************************************************
411  //***************************************************************************
412  template <typename TIString>
413  const TIString& to_string(const volatile void* value,
414  TIString& str,
415  bool append = false)
416  {
418 
419  etl::private_to_string::add_pointer(value, str, format, append);
420 
421  return str;
422  }
423 
424  //***************************************************************************
426  //***************************************************************************
427  template <typename TIString>
428  const TIString& to_string(const volatile void* value,
429  TIString& str,
430  const etl::basic_format_spec<TIString>& format,
431  bool append = false)
432  {
433  etl::private_to_string::add_pointer(value, str, format, append);
434 
435  return str;
436  }
437 
438 #if ETL_NOT_USING_64BIT_TYPES
439  //***************************************************************************
441  //***************************************************************************
442  template <typename T, typename TIString>
445  !etl::is_same<T, bool>::value>::value, const TIString& > ::type
446  to_string(const T value, TIString& str, bool append = false)
447  {
449 
450  etl::private_to_string::add_integral(int32_t(value), str, format, append, etl::is_negative(value));
451 
452  return str;
453  }
454 
455  //***************************************************************************
457  //***************************************************************************
458  template <typename T, typename TIString>
461  !etl::is_same<T, bool>::value>::value, const TIString& > ::type
462  to_string(const T value, TIString& str, const etl::basic_format_spec<TIString>& format, bool append = false)
463  {
464  etl::private_to_string::add_integral(int32_t(value), str, format, append, etl::is_negative(value));
465 
466  return str;
467  }
468 
469  //***************************************************************************
471  //***************************************************************************
472  template <typename T, typename TIString>
475  !etl::is_same<T, bool>::value>::value, const TIString& > ::type
476  to_string(const T value, TIString& str, bool append = false)
477  {
479 
480  etl::private_to_string::add_integral(uint32_t(value), str, format, append, false);
481 
482  return str;
483  }
484 
485  //***************************************************************************
487  //***************************************************************************
488  template <typename T, typename TIString>
491  !etl::is_same<T, bool>::value>::value, const TIString& > ::type
492  to_string(const T value, TIString& str, const etl::basic_format_spec<TIString>& format, bool append = false)
493  {
494  etl::private_to_string::add_integral(uint32_t(value), str, format, append, false);
495 
496  return str;
497  }
498 #else
499  //***************************************************************************
501  //***************************************************************************
502  template <typename T, typename TIString>
506  !etl::is_same<T, int64_t>::value, const TIString&>::type
507  to_string(const T value, TIString& str, bool append = false)
508  {
510 
511  etl::private_to_string::add_integral(int32_t(value), str, format, append, etl::is_negative(value));
512 
513  return str;
514  }
515 
516  //***************************************************************************
518  //***************************************************************************
519  template <typename T, typename TIString>
523  !etl::is_same<T, int64_t>::value, const TIString&>::type
524  to_string(const T value, TIString& str, const etl::basic_format_spec<TIString>& format, bool append = false)
525  {
526  etl::private_to_string::add_integral(int32_t(value), str, format, append, etl::is_negative(value));
527 
528  return str;
529  }
530 
531  //***************************************************************************
533  //***************************************************************************
534  template <typename T, typename TIString>
538  !etl::is_same<T, uint64_t>::value, const TIString&>::type
539  to_string(const T value, TIString& str, bool append = false)
540  {
542 
543  etl::private_to_string::add_integral(uint32_t(value), str, format, append, false);
544 
545  return str;
546  }
547 
548  //***************************************************************************
550  //***************************************************************************
551  template <typename T, typename TIString>
555  !etl::is_same<T, uint64_t>::value, const TIString&>::type
556  to_string(const T value, TIString& str, const etl::basic_format_spec<TIString>& format, bool append = false)
557  {
558  etl::private_to_string::add_integral(uint32_t(value), str, format, append, false);
559 
560  return str;
561  }
562 
563  //***************************************************************************
565  //***************************************************************************
566  template <typename T, typename TIString>
570  etl::is_same<T, int64_t>::value, const TIString&>::type
571  to_string(const T value, TIString& str, bool append = false)
572  {
574 
575  etl::private_to_string::add_integral(int64_t(value), str, format, append, etl::is_negative(value));
576 
577  return str;
578  }
579 
580  //***************************************************************************
582  //***************************************************************************
583  template <typename T, typename TIString>
587  etl::is_same<T, int64_t>::value, const TIString&>::type
588  to_string(const T value, TIString& str, const etl::basic_format_spec<TIString>& format, bool append = false)
589  {
590  etl::private_to_string::add_integral(int64_t(value), str, format, append, etl::is_negative(value));
591 
592  return str;
593  }
594 
595  //***************************************************************************
597  //***************************************************************************
598  template <typename T, typename TIString>
602  etl::is_same<T, uint64_t>::value, const TIString&>::type
603  to_string(const T value, TIString& str, bool append = false)
604  {
606 
607  etl::private_to_string::add_integral(uint64_t(value), str, format, append, false);
608 
609  return str;
610  }
611 
612  //***************************************************************************
614  //***************************************************************************
615  template <typename T, typename TIString>
619  etl::is_same<T, uint64_t>::value, const TIString&>::type
620  to_string(const T value, TIString& str, const etl::basic_format_spec<TIString>& format, bool append = false)
621  {
622  etl::private_to_string::add_integral(uint64_t(value), str, format, append, false);
623 
624  return str;
625  }
626 #endif
627 
628  //***************************************************************************
630  //***************************************************************************
631  template <typename T, typename TIString>
632  typename etl::enable_if<etl::is_floating_point<T>::value, const TIString&>::type
633  to_string(const T value, TIString& str, bool append = false)
634  {
636 
637  etl::private_to_string::add_floating_point(value, str, format, append);
638 
639  return str;
640  }
641 
642  //***************************************************************************
644  //***************************************************************************
645  template <typename T, typename TIString>
646  typename etl::enable_if<etl::is_floating_point<T>::value, const TIString&>::type
647  to_string(const T value, TIString& str, const etl::basic_format_spec<TIString>& format, bool append = false)
648  {
649  etl::private_to_string::add_floating_point(value, str, format, append);
650 
651  return str;
652  }
653  }
654 }
655 
656 #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_CONSTEXPR14 basic_format_spec & fill(typename TString::value_type c)
Definition: basic_format_spec.h:392
ETL_CONSTEXPR uint32_t get_width() const
Gets the width.
Definition: basic_format_spec.h:347
ETL_CONSTEXPR14 basic_format_spec & right()
Definition: basic_format_spec.h:428
ETL_CONSTEXPR uint32_t get_base() const
Gets the base.
Definition: basic_format_spec.h:311
ETL_CONSTEXPR14 basic_format_spec & decimal()
Definition: basic_format_spec.h:292
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 & width(uint32_t w)
Definition: basic_format_spec.h:338
ETL_CONSTEXPR uint32_t get_precision() const
Gets the precision.
Definition: basic_format_spec.h:365
ETL_CONSTEXPR14 basic_format_spec & precision(uint32_t p)
Definition: basic_format_spec.h:356
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:639
ETL_CONSTEXPR TContainer::iterator begin(TContainer &container)
Definition: container.h:49
ETL_CONSTEXPR TContainer::iterator end(TContainer &container)
Definition: container.h:99
add_pointer
Definition: type_traits_generator.h:851
enable_if
Definition: type_traits_generator.h:1228
is_same
Definition: type_traits_generator.h:981
is_signed
Definition: type_traits_generator.h:951
is_unsigned
Definition: type_traits_generator.h:961
Definition: absolute.h:37
etl::enable_if<!etl::is_same< T, etl::istring >::value &&!etl::is_same< T, etl::string_view >::value, const etl::istring & >::type to_string(const T value, etl::istring &str, bool append=false)
Definition: to_string.h:50
iterator
Definition: iterator.h:422
void add_floating_point(T value, TIString &str, const etl::basic_format_spec< TIString > &format, bool append)
Helper function for floating point.
Definition: to_string_helper.h:265
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:63
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:220
void add_integral_fractional(const workspace_t integral, const workspace_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:243
void add_string(const TIString &value, TIString &str, const etl::basic_format_spec< TIString > &format, bool append)
Helper function for strings.
Definition: to_string_helper.h:340
void add_string_view(const TSringView &value, TIString &str, const etl::basic_format_spec< TIString > &format, bool append)
Helper function for string views.
Definition: to_string_helper.h:361
void add_boolean(const bool value, TIString &str, const etl::basic_format_spec< TIString > &format, bool append)
Helper function for booleans.
Definition: to_string_helper.h:88
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:136
void add_pointer(const volatile void *value, TIString &str, const etl::basic_format_spec< TIString > &format, bool append)
Helper function for pointers.
Definition: to_string_helper.h:326