VTK  9.5.20250903
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
55namespace vtk
56{
57VTK_ABI_NAMESPACE_BEGIN
59
66template <typename T,
67 typename = std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<T, bool>>>
68VTK_ALWAYS_INLINE auto to_chars(char* first, char* last, const T& value, int base = 10)
69 -> 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}
100template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
101VTK_ALWAYS_INLINE auto to_chars(char* first, char* last, const T& value, std::chars_format format)
102 -> 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}
133template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
134VTK_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
198using fmt::to_string;
199
205using fmt::formatted_size;
206
212using fmt::format;
213
217using fmt::format_to_result;
218
225using fmt::format_to;
226
230using fmt::format_to_n_result;
231
239using fmt::format_to_n;
240
248using fmt::localtime;
249
257using fmt::gmtime;
258
264using fmt::print;
265
271using fmt::println;
272
278VTKCOMMONCORE_EXPORT bool is_printf_format(const std::string& format);
279
285VTKCOMMONCORE_EXPORT std::string printf_to_std_format(const std::string& printf_format);
286
287VTK_ABI_NAMESPACE_END
288}
289
290#endif // vtkStringFormatter_h
291// VTK-HeaderTest-Exclude: vtkStringFormatter.h
Specialization of tuple ranges and iterators for vtkAOSDataArrayTemplate.
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 std::string printf_to_std_format(const std::string &printf_format)
Convert a printf style format to a std::format style format.
VTKCOMMONCORE_EXPORT bool is_printf_format(const std::string &format)
Check if the given string is a printf style format.