VTK  9.7.1
vtkStringFormatter.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
2 // SPDX-License-Identifier: BSD-3-Clause
36 #ifndef vtkStringFormatter_h
37 #define vtkStringFormatter_h
38 
39 #include "vtkCharConvCompatibility.h" // For std::chars_format, std::to_chars_result
40 #include "vtkCommonCoreModule.h" // For export macro
41 #include "vtkLogger.h" // For vtkLogF
42 
43 #include "vtk_fmt.h" // For fmt
44 // clang-format off
45 #include VTK_FMT(fmt/args.h) // For fmt's args
46 #include VTK_FMT(fmt/chrono.h) // For fmt's chrono
47 #include VTK_FMT(fmt/compile.h) // For fmt's compile
48 #include VTK_FMT(fmt/format.h) // For fmt's format
49 #include VTK_FMT(fmt/ranges.h) // For fmt's ranges
50 // clang-format on
51 
52 #include <string> // For std::string
53 #include <string_view> // For std::string_view
54 
55 namespace vtk
56 {
57 VTK_ABI_NAMESPACE_BEGIN
59 
66 template <typename T,
67  typename = std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<T, bool>>>
68 VTK_ALWAYS_INLINE auto to_chars(
69  char* first, char* last, const T& value, int base = 10) -> std::to_chars_result
70 {
71  const std::size_t buffer_size = std::distance(first, last);
72  if (buffer_size == 0)
73  {
74  return { first, std::errc::value_too_large };
75  }
76  const std::size_t buffer_size_1 = buffer_size - 1;
77  fmt::format_to_n_result<char*> result;
78  switch (base)
79  {
80  case 2:
81  result = fmt::format_to_n(first, buffer_size_1, FMT_COMPILE("{:b}"), value);
82  break;
83  case 8:
84  result = fmt::format_to_n(first, buffer_size_1, FMT_COMPILE("{:o}"), value);
85  break;
86  case 16:
87  result = fmt::format_to_n(first, buffer_size_1, FMT_COMPILE("{:x}"), value);
88  break;
89  case 10:
90  default:
91  result = fmt::format_to_n(first, buffer_size_1, FMT_COMPILE("{:d}"), value);
92  }
93  if (result.size >= buffer_size_1)
94  {
95  return { first + buffer_size_1, std::errc::value_too_large };
96  }
97  *result.out = '\0'; // Null-terminate
98  return { result.out, std::errc{} }; // Success
99 }
100 template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
101 VTK_ALWAYS_INLINE auto to_chars(
102  char* first, char* last, const T& value, std::chars_format format) -> std::to_chars_result
103 {
104  const std::size_t buffer_size = std::distance(first, last);
105  if (buffer_size == 0)
106  {
107  return { first, std::errc::value_too_large };
108  }
109  const std::size_t buffer_size_1 = buffer_size - 1;
110  fmt::format_to_n_result<char*> result;
111  switch (format)
112  {
113  case std::chars_format::scientific:
114  result = fmt::format_to_n(first, buffer_size_1, FMT_COMPILE("{:e}"), value);
115  break;
116  case std::chars_format::fixed:
117  result = fmt::format_to_n(first, buffer_size_1, FMT_COMPILE("{:f}"), value);
118  break;
119  case std::chars_format::hex:
120  result = fmt::format_to_n(first, buffer_size_1, FMT_COMPILE("{:a}"), value);
121  break;
122  case std::chars_format::general:
123  default:
124  result = fmt::format_to_n(first, buffer_size_1, FMT_COMPILE("{:g}"), value);
125  }
126  if (result.size >= buffer_size_1)
127  {
128  return { first + buffer_size_1, std::errc::value_too_large };
129  }
130  *result.out = '\0'; // Null-terminate
131  return { result.out, std::errc{} }; // Success
132 }
133 template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
134 VTK_ALWAYS_INLINE auto to_chars(char* first, char* last, const T& value, std::chars_format format,
135  int precision) -> std::to_chars_result
136 {
137  const std::size_t buffer_size = std::distance(first, last);
138  if (buffer_size == 0)
139  {
140  return { first, std::errc::value_too_large };
141  }
142  const std::size_t buffer_size_1 = buffer_size - 1;
143  fmt::format_to_n_result<char*> result;
144  switch (format)
145  {
146  case std::chars_format::scientific:
147  result = fmt::format_to_n(first, buffer_size_1, FMT_COMPILE("{:.{}e}"), value, precision);
148  break;
149  case std::chars_format::fixed:
150  result = fmt::format_to_n(first, buffer_size_1, FMT_COMPILE("{:.{}f}"), value, precision);
151  break;
152  case std::chars_format::hex:
153  result = fmt::format_to_n(first, buffer_size_1, FMT_COMPILE("{:.{}a}"), value, precision);
154  break;
155  case std::chars_format::general:
156  default:
157  result = fmt::format_to_n(first, buffer_size_1, FMT_COMPILE("{:.{}g}"), value, precision);
158  }
159  if (result.size >= buffer_size_1)
160  {
161  return { first + buffer_size_1, std::errc::value_too_large };
162  }
163  *result.out = '\0'; // Null-terminate
164  return { result.out, std::errc{} }; // Success
165 }
167 
168 // Create a macro that evaluates the result of to_chars, checks for errors, and executes a command
169 #define VTK_TO_CHARS_RESULT_IF_ERROR_COMMAND(to_chars_result, value, command) \
170  switch (to_chars_result.ec) \
171  { \
172  case std::errc::invalid_argument: \
173  { \
174  vtkLogF(ERROR, "The given argument was invalid, failed to get the converted " #value "."); \
175  command; \
176  } \
177  case std::errc::value_too_large: \
178  { \
179  vtkLogF(ERROR, "The given buffer was too small, failed to get the converted " #value "."); \
180  command; \
181  } \
182  default: \
183  { \
184  } \
185  }
186 // Create a macro that evaluates the result of to_chars, checks for errors, and breaks
187 #define VTK_TO_CHARS_RESULT_IF_ERROR_BREAK(to_chars_result, value) \
188  VTK_TO_CHARS_RESULT_IF_ERROR_COMMAND(to_chars_result, value, break)
189 // Create a macro that evaluates the result of to_chars, checks for errors, and returns a value
190 #define VTK_TO_CHARS_RESULT_IF_ERROR_RETURN(to_chars_result, value, returnValue) \
191  VTK_TO_CHARS_RESULT_IF_ERROR_COMMAND(to_chars_result, value, return returnValue)
192 
198 using fmt::to_string;
199 
205 using fmt::formatted_size;
206 
215 using fmt::runtime;
216 
222 using fmt::format;
223 
224 #define VTK_FORMAT_IF_ERROR_COMMAND(formatCommand, command) \
225  try \
226  { \
227  formatCommand; \
228  } \
229  catch (const std::exception& e) \
230  { \
231  vtkLog(ERROR, "Formatting error: " << e.what()); \
232  command; \
233  } \
234  static_assert(true)
235 #define VTK_FORMAT_IF_ERROR_RETURN(formatCommand, returnValue) \
236  VTK_FORMAT_IF_ERROR_COMMAND(formatCommand, return returnValue)
237 #define VTK_FORMAT_IF_ERROR_BREAK(formatCommand) VTK_FORMAT_IF_ERROR_COMMAND(formatCommand, break)
238 
242 using fmt::format_to_result;
243 
250 using fmt::format_to;
251 
255 using fmt::format_to_n_result;
256 
264 using fmt::format_to_n;
265 
271 using fmt::print;
272 
278 using fmt::println;
279 
285 VTKCOMMONCORE_EXPORT bool is_printf_format(const std::string& format);
286 
292 VTKCOMMONCORE_EXPORT std::string printf_to_std_format(const std::string& printf_format);
293 
298 VTKCOMMONCORE_EXPORT std::string to_std_format(const std::string& format);
299 
300 VTK_ABI_NAMESPACE_END
301 }
302 
303 #endif // vtkStringFormatter_h
304 // VTK-HeaderTest-Exclude: vtkStringFormatter.h
VTKCOMMONCORE_EXPORT std::string to_std_format(const std::string &format)
Convert printf and std::format style format strings.
VTKCOMMONCORE_EXPORT std::string printf_to_std_format(const std::string &printf_format)
Convert a printf style format to a std::format style format.
Specialization of tuple ranges and iterators for vtkAOSDataArrayTemplate.
std::string VTKCOMMONCORE_EXPORT to_string(vtkArrayComponents enumerant)
Given an enumerant, return a human-presentable string with its value.
VTK_ALWAYS_INLINE auto to_chars(char *first, char *last, const T &value, int base=10) -> std::to_chars_result
Given a number, convert it to a string within char* first and char* last, and return a to_chars_resul...
VTKCOMMONCORE_EXPORT bool is_printf_format(const std::string &format)
Check if the given string is a printf style format.