Zserio C++17 runtime library  0.5.0
Built for Zserio 2.17.0
StringConvertUtil.h
Go to the documentation of this file.
1 #ifndef ZSERIO_STRING_CONVERT_UTIL_H_INC
2 #define ZSERIO_STRING_CONVERT_UTIL_H_INC
3 
4 #include <array>
5 #include <limits>
6 #include <sstream>
7 #include <string_view>
8 
9 #include "zserio/RebindAlloc.h"
10 #include "zserio/String.h"
11 
12 namespace zserio
13 {
14 
15 namespace detail
16 {
17 
25 template <typename T, std::enable_if_t<std::is_unsigned_v<T> && !std::is_same_v<T, bool>, int> = 0>
26 const char* convertIntToString(std::array<char, 24>& buffer, T value, bool isNegative)
27 {
28  static const std::array<char, 201> DIGITS_100_10 = {
29  "0001020304050607080910111213141516171819"
30  "2021222324252627282930313233343536373839"
31  "4041424344454647484950515253545556575859"
32  "6061626364656667686970717273747576777879"
33  "8081828384858687888990919293949596979899"};
34  static const std::array<char, 11> DIGITS_1 = {"0123456789"};
35 
36  auto bufferEnd = buffer.end();
37  *(--bufferEnd) = '\0'; // always terminate with '\0'
38 
39  while (value >= 100)
40  {
41  const unsigned int index = static_cast<unsigned int>((value % 100) * 2);
42  value /= 100;
43  *(--bufferEnd) = DIGITS_100_10[index + 1];
44  *(--bufferEnd) = DIGITS_100_10[index];
45  }
46 
47  if (value < 10)
48  {
49  *(--bufferEnd) = DIGITS_1[static_cast<unsigned int>(value)];
50  }
51  else
52  {
53  const unsigned int index = static_cast<unsigned int>(value * 2);
54  *(--bufferEnd) = DIGITS_100_10[index + 1];
55  *(--bufferEnd) = DIGITS_100_10[index];
56  }
57 
58  if (isNegative)
59  {
60  *(--bufferEnd) = '-';
61  }
62 
63  return &(*bufferEnd);
64 }
65 
66 } // namespace detail
67 
78 template <typename T, std::enable_if_t<std::is_unsigned_v<T>, int> = 0>
79 const char* convertIntToString(std::array<char, 24>& buffer, T value)
80 {
81  return detail::convertIntToString(buffer, value, false);
82 }
83 
94 template <typename T, std::enable_if_t<std::is_signed_v<T>, int> = 0>
95 const char* convertIntToString(std::array<char, 24>& buffer, T value)
96 {
97  using UnsignedType = typename std::make_unsigned_t<T>;
98  UnsignedType absValue = static_cast<UnsignedType>(value);
99  const bool isNegative = value < 0;
100  if (isNegative)
101  {
102  absValue = static_cast<UnsignedType>(0 - absValue);
103  }
104 
105  return detail::convertIntToString(buffer, absValue, isNegative);
106 }
107 
119 inline void convertFloatToString(std::array<char, 24>& integerPartBuffer,
120  std::array<char, 24>& floatingPartBuffer, float value, const char*& integerPartString,
121  const char*& floatingPartString)
122 {
123  if (value >= static_cast<float>(std::numeric_limits<int64_t>::max()))
124  {
125  integerPartString = "+Inf";
126  floatingPartString = nullptr;
127  }
128  else if (value <= static_cast<float>(std::numeric_limits<int64_t>::min()))
129  {
130  integerPartString = "-Inf";
131  floatingPartString = nullptr;
132  }
133  else
134  {
135  const int64_t integerPart = static_cast<int64_t>(value);
136  const int64_t floatingPart =
137  static_cast<int64_t>((value - static_cast<float>(integerPart)) * 1e3F); // 3 digits
138  const int64_t floatingPartAbs = (floatingPart < 0) ? 0 - floatingPart : floatingPart;
139  integerPartString = convertIntToString(integerPartBuffer, integerPart);
140  floatingPartString = convertIntToString(floatingPartBuffer, floatingPartAbs);
141  }
142 }
143 
151 inline const char* convertBoolToString(bool value)
152 {
153  return value ? "true" : "false";
154 }
155 
164 template <typename ALLOC, typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
165 BasicString<RebindAlloc<ALLOC, char>> toString(T value, const ALLOC& allocator = ALLOC())
166 {
167  std::array<char, 24> buffer = {};
168  return BasicString<RebindAlloc<ALLOC, char>>(convertIntToString(buffer, value), allocator);
169 }
170 
179 template <typename ALLOC, typename T, std::enable_if_t<std::is_integral_v<typename T::ValueType>, int> = 0>
180 BasicString<RebindAlloc<ALLOC, char>> toString(T value, const ALLOC& allocator = ALLOC())
181 {
182  if constexpr (std::is_same_v<bool, typename T::ValueType>)
183  {
184  return BasicString<RebindAlloc<ALLOC, char>>(convertBoolToString(value), allocator);
185  }
186  else
187  {
188  std::array<char, 24> buffer = {};
189  return BasicString<RebindAlloc<ALLOC, char>>(
190  convertIntToString(buffer, static_cast<typename T::ValueType>(value)), allocator);
191  }
192 }
193 
203 template <typename ALLOC>
204 BasicString<RebindAlloc<ALLOC, char>> toString(bool value, const ALLOC& allocator = ALLOC())
205 {
207 }
208 
215 template <typename ALLOC>
216 BasicString<RebindAlloc<ALLOC, char>> toString(std::string_view value, const ALLOC& allocator = ALLOC())
217 {
218  return BasicString<RebindAlloc<ALLOC, char>>(value, allocator);
219 }
220 
228 template <typename T>
230 {
231  return toString<std::allocator<char>>(value);
232 }
233 
234 } // namespace zserio
235 
236 #endif // ifndef ZSERIO_STRING_CONVERT_UTIL_H_INC
const char * convertIntToString(std::array< char, 24 > &buffer, T value)
std::basic_string< char, std::char_traits< char >, ALLOC > BasicString
Definition: String.h:17
BasicString< RebindAlloc< ALLOC, char > > toString(T value, const ALLOC &allocator=ALLOC())
const char * convertBoolToString(bool value)
void convertFloatToString(std::array< char, 24 > &integerPartBuffer, std::array< char, 24 > &floatingPartBuffer, float value, const char *&integerPartString, const char *&floatingPartString)