9#if !TOML_IMPLEMENTATION
10#error This is an implementation-only header.
13#if TOML_ENABLE_FORMATTERS
27 line_breaks = 1u << 0,
29 control_chars = 1u << 2,
30 single_quotes = 1u << 3,
34 all = (non_ascii << 1u) - 1u
39 formatter::formatter(
const node* source_node,
const parse_result* source_pr,
40 const formatter_constants& constants,
41 const formatter_config& config)
noexcept
42#if TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
43 : source_{source_pr && *source_pr ? &source_pr->table() : source_node},
46 : source_{source_pr ? source_pr : source_node},
48 constants_{&constants},
52 config_.flags = (config_.flags | constants_->mandatory_flags) & ~constants_->ignored_flags;
55 for (
auto c : config_.indent) indent_columns_ += c ==
'\t' ? 4u : 1u;
58 config_.flags & (format_flags::allow_binary_integers | format_flags::allow_octal_integers |
59 format_flags::allow_hexadecimal_integers);
63 void formatter::attach(std::ostream & stream)
noexcept {
65 naked_newline_ =
true;
70 void formatter::detach() noexcept {
75 void formatter::print_newline(
bool force) {
76 if (!naked_newline_ || force) {
78 naked_newline_ =
true;
83 void formatter::print_indent() {
84 for (
int i = 0; i < indent_; i++) {
86 naked_newline_ =
false;
91 void formatter::print_unformatted(
char c) {
93 naked_newline_ =
false;
97 void formatter::print_unformatted(std::string_view str) {
99 naked_newline_ =
false;
103 void formatter::print_string(std::string_view str,
bool allow_multi_line,
bool allow_bare,
104 bool allow_literal_whitespace) {
106 print_unformatted(literal_strings_allowed() ?
"''"sv :
"\"\""sv);
111 formatted_string_traits traits = {};
113 if (!allow_bare) traits |= formatted_string_traits::non_bare;
114 bool unicode_allowed = unicode_strings_allowed();
117 if (is_ascii(str.data(), str.length())) {
121 traits |= formatted_string_traits::line_breaks;
124 traits |= formatted_string_traits::tabs;
127 traits |= formatted_string_traits::single_quotes;
131 traits |= formatted_string_traits::control_chars;
133 if (!is_ascii_bare_key_character(
static_cast<char32_t>(c)))
134 traits |= formatted_string_traits::non_bare;
139 static constexpr auto all_ascii_traits =
140 formatted_string_traits::all & ~formatted_string_traits::non_ascii;
141 if (traits == all_ascii_traits)
break;
147 traits |= formatted_string_traits::non_ascii;
148 utf8_decoder decoder;
152 const auto bad_unicode = [&]()
noexcept {
153 traits &= ~formatted_string_traits::line_breaks;
154 traits |= formatted_string_traits::control_chars | formatted_string_traits::non_bare;
155 unicode_allowed =
false;
166 if (!decoder.has_code_point())
continue;
168 switch (decoder.codepoint) {
170 traits |= formatted_string_traits::line_breaks;
173 traits |= formatted_string_traits::tabs;
176 traits |= formatted_string_traits::single_quotes;
180 is_non_ascii_vertical_whitespace(decoder.codepoint))
181 traits |= formatted_string_traits::control_chars;
183 if (!is_bare_key_character(decoder.codepoint))
184 traits |= formatted_string_traits::non_bare;
190 if (decoder.needs_more_input()) bad_unicode();
194 if (!!(traits & (formatted_string_traits::line_breaks | formatted_string_traits::tabs |
195 formatted_string_traits::single_quotes)))
196 traits |= formatted_string_traits::non_bare;
200 if (!(traits & formatted_string_traits::non_bare) &&
201 (!(traits & formatted_string_traits::non_ascii) || unicode_allowed)) {
202 print_unformatted(str);
205 const auto real_tabs_allowed = allow_literal_whitespace && real_tabs_in_strings_allowed();
208 const auto multi_line = allow_literal_whitespace
210 && multi_line_strings_allowed()
211 && !!(traits & formatted_string_traits::line_breaks);
214 const auto literal = literal_strings_allowed()
215 && !(traits & formatted_string_traits::control_chars)
216 && (!(traits & formatted_string_traits::single_quotes) || multi_line)
217 && (!(traits & formatted_string_traits::tabs) || real_tabs_allowed)
218 && (!(traits & formatted_string_traits::line_breaks) || multi_line)
219 && (!(traits & formatted_string_traits::non_ascii) || unicode_allowed);
223 const auto quot = multi_line ? R
"(''')"sv : R"(')"sv;
224 print_unformatted(quot);
225 print_unformatted(str);
226 print_unformatted(quot);
231 print_unformatted(multi_line ? R
"(""")"sv : R"(")"sv);
234 if (!(traits & formatted_string_traits::non_ascii)) {
267 utf8_decoder decoder;
268 const char* cp_start = str.data();
269 const char* cp_end = cp_start;
275 if (decoder.error()) {
276 while (cp_start != cp_end) {
279 value_flags::format_as_hexadecimal, 2);
286 if (!decoder.has_code_point())
continue;
288 switch (decoder.codepoint) {
308 control_char_escapes[
static_cast<uint_least32_t
>(decoder.codepoint)]);
311 else if (decoder.codepoint > U
'\x7F' &&
312 (!unicode_allowed || is_non_ascii_vertical_whitespace(decoder.codepoint))) {
313 if (
static_cast<uint_least32_t
>(decoder.codepoint) > 0xFFFFu) {
315 print_to_stream(*stream_, static_cast<uint_least32_t
>(decoder.codepoint),
316 value_flags::format_as_hexadecimal, 8);
319 print_to_stream(*stream_, static_cast<uint_least32_t
>(decoder.codepoint),
320 value_flags::format_as_hexadecimal, 4);
326 print_to_stream(*stream_, cp_start,
static_cast<size_t>(cp_end - cp_start));
334 print_unformatted(multi_line ? R
"(""")"sv : R"(")"sv);
338 void formatter::print(
const value<std::string>& val) {
339 print_string(val.get());
343 void formatter::print(
const value<int64_t>& val) {
344 naked_newline_ =
false;
346 if (*val >= 0 && !!int_format_mask_) {
347 static constexpr auto value_flags_mask = value_flags::format_as_binary |
348 value_flags::format_as_octal |
349 value_flags::format_as_hexadecimal;
351 const auto fmt = val.flags() & value_flags_mask;
353 case value_flags::format_as_binary:
354 if (!!(int_format_mask_ & format_flags::allow_binary_integers)) {
361 case value_flags::format_as_octal:
362 if (!!(int_format_mask_ & format_flags::allow_octal_integers)) {
369 case value_flags::format_as_hexadecimal:
370 if (!!(int_format_mask_ & format_flags::allow_hexadecimal_integers)) {
387 void formatter::print(
const value<double>& val) {
388 const std::string_view* inf_nan =
nullptr;
389 switch (fpclassify(*val)) {
390 case fp_class::neg_inf:
391 inf_nan = &constants_->float_neg_inf;
393 case fp_class::pos_inf:
394 inf_nan = &constants_->float_pos_inf;
397 inf_nan = &constants_->float_nan;
401 !!(config_.flags & format_flags::relaxed_float_precision));
408 if (!!(config_.flags & format_flags::quote_infinities_and_nans))
414 naked_newline_ =
false;
418 void formatter::print(
const value<bool>& val) {
419 print_unformatted(*val ? constants_->bool_true : constants_->bool_false);
423 void formatter::print(
const value<date>& val) {
424 if (!!(config_.flags & format_flags::quote_dates_and_times))
428 naked_newline_ =
false;
432 void formatter::print(
const value<time>& val) {
433 if (!!(config_.flags & format_flags::quote_dates_and_times))
437 naked_newline_ =
false;
441 void formatter::print(
const value<date_time>& val) {
442 if (!!(config_.flags & format_flags::quote_dates_and_times))
446 naked_newline_ =
false;
450 void formatter::print_value(
const node& val_node, node_type type) {
453 case node_type::string:
454 print(*
reinterpret_cast<const value<std::string>*
>(&val_node));
456 case node_type::integer:
457 print(*
reinterpret_cast<const value<int64_t>*
>(&val_node));
459 case node_type::floating_point:
460 print(*
reinterpret_cast<const value<double>*
>(&val_node));
462 case node_type::boolean:
463 print(*
reinterpret_cast<const value<bool>*
>(&val_node));
465 case node_type::date:
466 print(*
reinterpret_cast<const value<date>*
>(&val_node));
468 case node_type::time:
469 print(*
reinterpret_cast<const value<time>*
>(&val_node));
471 case node_type::date_time:
472 print(*
reinterpret_cast<const value<date_time>*
>(&val_node));
479#if TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
482 bool formatter::dump_failed_parse_result() {
483 if (result_ && !(*result_)) {
484 stream() << result_->error();
494 bool formatter::dump_failed_parse_result() {
The result of a parsing operation.
Definition parse_result.hpp:53
#define TOML_ASSERT_ASSUME(expr)
Definition preprocessor.hpp:1190
#define TOML_UNLIKELY(...)
Definition preprocessor.hpp:538
#define TOML_EXTERNAL_LINKAGE
Definition preprocessor.hpp:1339
#define TOML_UNREACHABLE
Definition preprocessor.hpp:515
#define TOML_CLOSED_FLAGS_ENUM
Definition preprocessor.hpp:562
#define TOML_ATTR(...)
Definition preprocessor.hpp:316
#define TOML_MAKE_FLAGS(T)
Definition preprocessor.hpp:601
#define TOML_ASSUME(expr)
Definition preprocessor.hpp:506
TOML_EXPORTED_FREE_FUNCTION void TOML_CALLCONV print_to_stream(std::ostream &, std::string_view)
void print_to_stream_bookended(std::ostream &stream, const T &val, const U &bookend)
Definition print_to_stream.hpp:120