NeBuild dev
Loading...
Searching...
No Matches
print_to_stream.inl
Go to the documentation of this file.
1// # This file is a part of toml++ and is subject to the the terms of the MIT license.
2// # Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
3// # See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
4// SPDX-License-Identifier: MIT
5#pragma once
6
7// # {{
8#include "preprocessor.hpp"
9#if !TOML_IMPLEMENTATION
10#error This is an implementation-only header.
11#endif
12// # }}
13
14#include "array.hpp"
15#include "date_time.hpp"
16#include "print_to_stream.hpp"
17#include "source_region.hpp"
18#include "table.hpp"
19#include "toml_formatter.hpp"
20#include "value.hpp"
22#include <ostream>
23#if TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV
24#include <charconv>
25#endif
26#if !TOML_INT_CHARCONV || !TOML_FLOAT_CHARCONV
27#include <sstream>
28#endif
29#if !TOML_INT_CHARCONV
30#include <iomanip>
31#endif
33#include "header_start.hpp"
34
36 template <typename T>
37 inline constexpr size_t charconv_buffer_length = 0;
38
39 template <>
40 inline constexpr size_t charconv_buffer_length<int8_t> = 4; // strlen("-128")
41
42 template <>
43 inline constexpr size_t charconv_buffer_length<int16_t> = 6; // strlen("-32768")
44
45 template <>
46 inline constexpr size_t charconv_buffer_length<int32_t> = 11; // strlen("-2147483648")
47
48 template <>
49 inline constexpr size_t charconv_buffer_length<int64_t> = 20; // strlen("-9223372036854775808")
50
51 template <>
52 inline constexpr size_t charconv_buffer_length<uint8_t> = 3; // strlen("255")
53
54 template <>
55 inline constexpr size_t charconv_buffer_length<uint16_t> = 5; // strlen("65535")
56
57 template <>
58 inline constexpr size_t charconv_buffer_length<uint32_t> = 10; // strlen("4294967295")
59
60 template <>
61 inline constexpr size_t charconv_buffer_length<uint64_t> = 20; // strlen("18446744073709551615")
62
63 template <>
64 inline constexpr size_t charconv_buffer_length<float> = 64;
65
66 template <>
67 inline constexpr size_t charconv_buffer_length<double> = 64;
68
69 template <typename T>
71 std::ostream & stream, T val, value_flags format = {}, size_t min_digits = 0) {
72 if (!val) {
73 if (!min_digits) min_digits = 1;
74
75 for (size_t i = 0; i < min_digits; i++) stream.put('0');
76
77 return;
78 }
79
80 static constexpr auto value_flags_mask = value_flags::format_as_binary |
81 value_flags::format_as_octal |
82 value_flags::format_as_hexadecimal;
83 format &= value_flags_mask;
84
85 int base = 10;
86 if (format != value_flags::none && val > T{}) {
87 switch (format) {
88 case value_flags::format_as_binary:
89 base = 2;
90 break;
91 case value_flags::format_as_octal:
92 base = 8;
93 break;
94 case value_flags::format_as_hexadecimal:
95 base = 16;
96 break;
97 default:
98 break;
99 }
100 }
101
102#if TOML_INT_CHARCONV
103
104 char buf[(sizeof(T) * CHAR_BIT)];
105 const auto res = std::to_chars(buf, buf + sizeof(buf), val, base);
106 const auto len = static_cast<size_t>(res.ptr - buf);
107 for (size_t i = len; i < min_digits; i++) stream.put('0');
108 if (base == 16) {
109 for (size_t i = 0; i < len; i++)
110 if (buf[i] >= 'a') buf[i] -= 32;
111 }
112 impl::print_to_stream(stream, buf, len);
113
114#else
115
116 using unsigned_type =
117 std::conditional_t<(sizeof(T) > sizeof(unsigned)), std::make_unsigned_t<T>, unsigned>;
118 using cast_type =
119 std::conditional_t<std::is_signed_v<T>, std::make_signed_t<unsigned_type>, unsigned_type>;
120
121 if (base == 2) {
122 const auto len = sizeof(T) * CHAR_BIT;
123 for (size_t i = len; i < min_digits; i++) stream.put('0');
124
125 bool found_one = false;
126 const auto v = static_cast<unsigned_type>(val);
127 unsigned_type mask = unsigned_type{1} << (len - 1u);
128 for (size_t i = 0; i < len; i++) {
129 if ((v & mask)) {
130 stream.put('1');
131 found_one = true;
132 } else if (found_one)
133 stream.put('0');
134 mask >>= 1;
135 }
136 } else {
137 std::ostringstream ss;
138 ss.imbue(std::locale::classic());
139 ss << std::uppercase << std::setbase(base);
140 if (min_digits) ss << std::setfill('0') << std::setw(static_cast<int>(min_digits));
141 ss << static_cast<cast_type>(val);
142 const auto str = std::move(ss).str();
143 impl::print_to_stream(stream, str);
144 }
145
146#endif
147 }
148
149 template <typename T>
151 std::ostream & stream, T val, value_flags format, [[maybe_unused]] bool relaxed_precision) {
152 switch (impl::fpclassify(val)) {
153 case impl::fp_class::neg_inf:
154 impl::print_to_stream(stream, "-inf"sv);
155 break;
156
157 case impl::fp_class::pos_inf:
158 impl::print_to_stream(stream, "inf"sv);
159 break;
160
161 case impl::fp_class::nan:
162 impl::print_to_stream(stream, "nan"sv);
163 break;
164
165 case impl::fp_class::ok: {
166 static constexpr auto needs_decimal_point = [](auto&& s) noexcept {
167 for (auto c : s)
168 if (c == '.' || c == 'E' || c == 'e') return false;
169 return true;
170 };
171
172#if TOML_FLOAT_CHARCONV
173
174 const auto hex = !!(format & value_flags::format_as_hexadecimal);
175 char buf[charconv_buffer_length<T>];
176 auto res = hex ? std::to_chars(buf, buf + sizeof(buf), val, std::chars_format::hex)
177 : std::to_chars(buf, buf + sizeof(buf), val);
178 auto str = std::string_view{buf, static_cast<size_t>(res.ptr - buf)};
179
180 char buf2[charconv_buffer_length<T>];
181 if (!hex && relaxed_precision) {
182 res = std::to_chars(buf2, buf2 + sizeof(buf2), val, std::chars_format::general, 6);
183 const auto str2 = std::string_view{buf2, static_cast<size_t>(res.ptr - buf2)};
184 if (str2.length() < str.length()) str = str2;
185 }
186
187 impl::print_to_stream(stream, str);
188 if (!hex && needs_decimal_point(str)) toml::impl::print_to_stream(stream, ".0"sv);
189
190#else
191
192 std::ostringstream ss;
193 ss.imbue(std::locale::classic());
194 if (!relaxed_precision) ss.precision(std::numeric_limits<T>::max_digits10);
195 if (!!(format & value_flags::format_as_hexadecimal)) ss << std::hexfloat;
196 ss << val;
197 const auto str = std::move(ss).str();
198 impl::print_to_stream(stream, str);
199 if (!(format & value_flags::format_as_hexadecimal) && needs_decimal_point(str))
200 impl::print_to_stream(stream, ".0"sv);
201
202#endif
203 } break;
204
205 default:
207 }
208 }
209}
211
214 TOML_ATTR(nonnull)
215 void TOML_CALLCONV print_to_stream(std::ostream & stream, const char* val, size_t len) {
216 stream.write(val, static_cast<std::streamsize>(len));
217 }
218
220 void TOML_CALLCONV print_to_stream(std::ostream & stream, std::string_view val) {
221 stream.write(val.data(), static_cast<std::streamsize>(val.length()));
222 }
223
225 void TOML_CALLCONV print_to_stream(std::ostream & stream, const std::string& val) {
226 stream.write(val.data(), static_cast<std::streamsize>(val.length()));
227 }
228
230 void TOML_CALLCONV print_to_stream(std::ostream & stream, char val) {
231 stream.put(val);
232 }
233
235 void TOML_CALLCONV print_to_stream(std::ostream & stream, signed char val, value_flags format,
236 size_t min_digits) {
237 TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
238 }
239
241 void TOML_CALLCONV print_to_stream(std::ostream & stream, signed short val, value_flags format,
242 size_t min_digits) {
243 TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
244 }
245
247 void TOML_CALLCONV print_to_stream(std::ostream & stream, signed int val, value_flags format,
248 size_t min_digits) {
249 TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
250 }
251
253 void TOML_CALLCONV print_to_stream(std::ostream & stream, signed long val, value_flags format,
254 size_t min_digits) {
255 TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
256 }
257
259 void TOML_CALLCONV print_to_stream(std::ostream & stream, signed long long val,
260 value_flags format, size_t min_digits) {
261 TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
262 }
263
265 void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned char val, value_flags format,
266 size_t min_digits) {
267 TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
268 }
269
271 void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned short val, value_flags format,
272 size_t min_digits) {
273 TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
274 }
275
277 void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned int val, value_flags format,
278 size_t min_digits) {
279 TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
280 }
281
283 void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned long val, value_flags format,
284 size_t min_digits) {
285 TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
286 }
287
289 void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned long long val,
290 value_flags format, size_t min_digits) {
291 TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
292 }
293
295 void TOML_CALLCONV print_to_stream(std::ostream & stream, float val, value_flags format,
296 bool relaxed_precision) {
297 TOML_ANON_NAMESPACE::print_floating_point_to_stream(stream, val, format, relaxed_precision);
298 }
299
301 void TOML_CALLCONV print_to_stream(std::ostream & stream, double val, value_flags format,
302 bool relaxed_precision) {
303 TOML_ANON_NAMESPACE::print_floating_point_to_stream(stream, val, format, relaxed_precision);
304 }
305
307 void TOML_CALLCONV print_to_stream(std::ostream & stream, bool val) {
308 print_to_stream(stream, val ? "true"sv : "false"sv);
309 }
310
312 void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::date& val) {
313 print_to_stream(stream, val.year, {}, 4);
314 stream.put('-');
315 print_to_stream(stream, val.month, {}, 2);
316 stream.put('-');
317 print_to_stream(stream, val.day, {}, 2);
318 }
319
321 void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::time& val) {
322 print_to_stream(stream, val.hour, {}, 2);
323 stream.put(':');
324 print_to_stream(stream, val.minute, {}, 2);
325 stream.put(':');
326 print_to_stream(stream, val.second, {}, 2);
327 if (val.nanosecond && val.nanosecond <= 999999999u) {
328 stream.put('.');
329 auto ns = val.nanosecond;
330 size_t digits = 9u;
331 while (ns % 10u == 0u) {
332 ns /= 10u;
333 digits--;
334 }
335 print_to_stream(stream, ns, {}, digits);
336 }
337 }
338
340 void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::time_offset& val) {
341 if (!val.minutes) {
342 stream.put('Z');
343 return;
344 }
345
346 auto mins = static_cast<int>(val.minutes);
347 if (mins < 0) {
348 stream.put('-');
349 mins = -mins;
350 } else
351 stream.put('+');
352 const auto hours = mins / 60;
353 if (hours) {
354 print_to_stream(stream, static_cast<unsigned int>(hours), {}, 2);
355 mins -= hours * 60;
356 } else
357 print_to_stream(stream, "00"sv);
358 stream.put(':');
359 print_to_stream(stream, static_cast<unsigned int>(mins), {}, 2);
360 }
361
363 void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::date_time& val) {
364 print_to_stream(stream, val.date);
365 stream.put('T');
366 print_to_stream(stream, val.time);
367 if (val.offset) print_to_stream(stream, *val.offset);
368 }
369
371 void TOML_CALLCONV print_to_stream(std::ostream & stream, const source_position& val) {
372 print_to_stream(stream, "line "sv);
373 print_to_stream(stream, val.line);
374 print_to_stream(stream, ", column "sv);
375 print_to_stream(stream, val.column);
376 }
377
379 void TOML_CALLCONV print_to_stream(std::ostream & stream, const source_region& val) {
380 print_to_stream(stream, val.begin);
381 if (val.path) {
382 print_to_stream(stream, " of '"sv);
383 print_to_stream(stream, *val.path);
384 stream.put('\'');
385 }
386 }
387
388#if TOML_ENABLE_FORMATTERS
389
391 void TOML_CALLCONV print_to_stream(std::ostream & stream, const array& arr) {
392 stream << toml_formatter{arr};
393 }
394
396 void TOML_CALLCONV print_to_stream(std::ostream & stream, const table& tbl) {
397 stream << toml_formatter{tbl};
398 }
399
401 void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<std::string>& val) {
402 stream << toml_formatter{val};
403 }
404
406 void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<int64_t>& val) {
407 stream << toml_formatter{val};
408 }
409
411 void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<double>& val) {
412 stream << toml_formatter{val};
413 }
414
416 void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<bool>& val) {
417 stream << toml_formatter{val};
418 }
419
421 void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<date>& val) {
422 stream << toml_formatter{val};
423 }
424
426 void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<time>& val) {
427 stream << toml_formatter{val};
428 }
429
431 void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<date_time>& val) {
432 stream << toml_formatter{val};
433 }
434
435#endif
436}
438
439#include "header_end.hpp"
A TOML array.
Definition array.hpp:285
A TOML table.
Definition table.hpp:220
enum TOML_OPEN_FLAGS_ENUM value_flags
Metadata associated with TOML values.
Definition forward_declarations.hpp:272
#define TOML_CALLCONV
Calling convention to apply to exported free/static functions. \detail Not defined by default (let th...
Definition preprocessor.hpp:1134
#define TOML_INTERNAL_LINKAGE
Definition preprocessor.hpp:1340
#define TOML_EXTERNAL_LINKAGE
Definition preprocessor.hpp:1339
#define TOML_UNREACHABLE
Definition preprocessor.hpp:515
#define TOML_ATTR(...)
Definition preprocessor.hpp:316
#define TOML_IMPL_NAMESPACE_END
Definition preprocessor.hpp:1334
TOML_EXPORTED_FREE_FUNCTION void TOML_CALLCONV print_to_stream(std::ostream &, std::string_view)
constexpr size_t charconv_buffer_length< int16_t >
Definition print_to_stream.inl:43
constexpr size_t charconv_buffer_length< uint8_t >
Definition print_to_stream.inl:52
constexpr size_t charconv_buffer_length< int64_t >
Definition print_to_stream.inl:49
TOML_ANON_NAMESPACE_START
Definition print_to_stream.inl:35
TOML_ENABLE_WARNINGS
Definition print_to_stream.inl:32
TOML_DISABLE_WARNINGS
Definition print_to_stream.inl:21
TOML_INTERNAL_LINKAGE void print_floating_point_to_stream(std::ostream &stream, T val, value_flags format, bool relaxed_precision)
Definition print_to_stream.inl:150
constexpr size_t charconv_buffer_length< uint16_t >
Definition print_to_stream.inl:55
constexpr size_t charconv_buffer_length< int8_t >
Definition print_to_stream.inl:40
constexpr size_t charconv_buffer_length< uint32_t >
Definition print_to_stream.inl:58
constexpr size_t charconv_buffer_length< int32_t >
Definition print_to_stream.inl:46
constexpr size_t charconv_buffer_length< uint64_t >
Definition print_to_stream.inl:61
constexpr size_t charconv_buffer_length< double >
Definition print_to_stream.inl:67
TOML_ANON_NAMESPACE_END
Definition print_to_stream.inl:210
constexpr size_t charconv_buffer_length< float >
Definition print_to_stream.inl:64
TOML_INTERNAL_LINKAGE void print_integer_to_stream(std::ostream &stream, T val, value_flags format={}, size_t min_digits=0)
Definition print_to_stream.inl:70
TOML_IMPL_NAMESPACE_START
Definition print_to_stream.inl:212
A source document line-and-column pair.
Definition source_region.hpp:43
source_index line
The line number.
Definition source_region.hpp:46
source_index column
The column number.
Definition source_region.hpp:50
A source document region.
Definition source_region.hpp:167
source_path_ptr path
The path to the corresponding source document.
Definition source_region.hpp:177
source_position begin
The beginning of the region (inclusive).
Definition source_region.hpp:169