diff options
Diffstat (limited to 'vendor/toml++/impl/toml_formatter.inl')
| -rw-r--r-- | vendor/toml++/impl/toml_formatter.inl | 405 |
1 files changed, 405 insertions, 0 deletions
diff --git a/vendor/toml++/impl/toml_formatter.inl b/vendor/toml++/impl/toml_formatter.inl new file mode 100644 index 0000000..e764448 --- /dev/null +++ b/vendor/toml++/impl/toml_formatter.inl @@ -0,0 +1,405 @@ +//# This file is a part of toml++ and is subject to the the terms of the MIT license. +//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au> +//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT +#pragma once + +#include "preprocessor.hpp" +//# {{ +#if !TOML_IMPLEMENTATION +#error This is an implementation-only header. +#endif +//# }} +#if TOML_ENABLE_FORMATTERS + +#include "toml_formatter.hpp" +#include "print_to_stream.hpp" +#include "value.hpp" +#include "table.hpp" +#include "array.hpp" +#include "unicode.hpp" +#include "header_start.hpp" +TOML_DISABLE_ARITHMETIC_WARNINGS; + +TOML_ANON_NAMESPACE_START +{ + TOML_INTERNAL_LINKAGE + size_t toml_formatter_count_inline_columns(const node& node, size_t line_wrap_cols) noexcept + { + switch (node.type()) + { + case node_type::table: + { + auto& tbl = *reinterpret_cast<const table*>(&node); + if (tbl.empty()) + return 2u; // "{}" + size_t weight = 3u; // "{ }" + for (auto&& [k, v] : tbl) + { + weight += k.length() + toml_formatter_count_inline_columns(v, line_wrap_cols) + 2u; // + ", " + if (weight >= line_wrap_cols) + break; + } + return weight; + } + + case node_type::array: + { + auto& arr = *reinterpret_cast<const array*>(&node); + if (arr.empty()) + return 2u; // "[]" + size_t weight = 3u; // "[ ]" + for (auto& elem : arr) + { + weight += toml_formatter_count_inline_columns(elem, line_wrap_cols) + 2u; // + ", " + if (weight >= line_wrap_cols) + break; + } + return weight; + } + + case node_type::string: + { + // todo: proper utf8 decoding? + // todo: tab awareness? + auto& str = (*reinterpret_cast<const value<std::string>*>(&node)).get(); + return str.length() + 2u; // + "" + } + + case node_type::integer: + { + auto val = (*reinterpret_cast<const value<int64_t>*>(&node)).get(); + if (!val) + return 1u; + size_t weight = {}; + if (val < 0) + { + weight += 1u; + val *= -1; + } + return weight + static_cast<size_t>(log10(static_cast<double>(val))) + 1u; + } + + case node_type::floating_point: + { + auto val = (*reinterpret_cast<const value<double>*>(&node)).get(); + if (val == 0.0) + return 3u; // "0.0" + size_t weight = 2u; // ".0" + if (val < 0.0) + { + weight += 1u; + val *= -1.0; + } + return weight + static_cast<size_t>(log10(val)) + 1u; + break; + } + + case node_type::boolean: return 5u; + case node_type::date: [[fallthrough]]; + case node_type::time: return 10u; + case node_type::date_time: return 30u; + case node_type::none: TOML_UNREACHABLE; + default: TOML_UNREACHABLE; + } + + TOML_UNREACHABLE; + } + + TOML_INTERNAL_LINKAGE + bool toml_formatter_forces_multiline(const node& node, size_t line_wrap_cols, size_t starting_column_bias) noexcept + { + return (toml_formatter_count_inline_columns(node, line_wrap_cols) + starting_column_bias) >= line_wrap_cols; + } +} +TOML_ANON_NAMESPACE_END; + +TOML_NAMESPACE_START +{ + TOML_EXTERNAL_LINKAGE + void toml_formatter::print_pending_table_separator() + { + if (pending_table_separator_) + { + print_newline(true); + print_newline(true); + pending_table_separator_ = false; + } + } + + TOML_EXTERNAL_LINKAGE + void toml_formatter::print(const key& k) + { + print_string(k.str(), false, true, false); + } + + TOML_EXTERNAL_LINKAGE + void toml_formatter::print_inline(const table& tbl) + { + if (tbl.empty()) + { + print_unformatted("{}"sv); + return; + } + + print_unformatted("{ "sv); + + bool first = false; + for (auto&& [k, v] : tbl) + { + if (first) + print_unformatted(", "sv); + first = true; + + print(k); + if (terse_kvps()) + print_unformatted("="sv); + else + print_unformatted(" = "sv); + + const auto type = v.type(); + TOML_ASSUME(type != node_type::none); + switch (type) + { + case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break; + case node_type::array: print(*reinterpret_cast<const array*>(&v)); break; + default: print_value(v, type); + } + } + + print_unformatted(" }"sv); + } + + TOML_EXTERNAL_LINKAGE + void toml_formatter::print(const array& arr) + { + if (arr.empty()) + { + print_unformatted("[]"sv); + return; + } + + const auto original_indent = indent(); + const auto multiline = TOML_ANON_NAMESPACE::toml_formatter_forces_multiline( + arr, + 120u, + indent_columns() * static_cast<size_t>(original_indent < 0 ? 0 : original_indent)); + + print_unformatted("["sv); + + if (multiline) + { + if (original_indent < 0) + indent(0); + if (indent_array_elements()) + increase_indent(); + } + else + print_unformatted(' '); + + for (size_t i = 0; i < arr.size(); i++) + { + if (i > 0u) + { + print_unformatted(','); + if (!multiline) + print_unformatted(' '); + } + + if (multiline) + { + print_newline(true); + print_indent(); + } + + auto& v = arr[i]; + const auto type = v.type(); + TOML_ASSUME(type != node_type::none); + switch (type) + { + case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break; + case node_type::array: print(*reinterpret_cast<const array*>(&v)); break; + default: print_value(v, type); + } + } + if (multiline) + { + indent(original_indent); + print_newline(true); + print_indent(); + } + else + print_unformatted(' '); + + print_unformatted("]"sv); + } + + TOML_EXTERNAL_LINKAGE + void toml_formatter::print(const table& tbl) + { + static constexpr auto is_non_inline_array_of_tables = [](const node& n) noexcept + { + const auto arr = n.as_array(); + if (!arr || !arr->is_array_of_tables()) + return false; + + return !reinterpret_cast<const table*>(&(*arr)[0])->is_inline(); + }; + + // values, arrays, and inline tables/table arrays + for (auto&& [k, v] : tbl) + { + const auto type = v.type(); + if ((type == node_type::table && !reinterpret_cast<const table*>(&v)->is_inline()) + || (type == node_type::array && is_non_inline_array_of_tables(v))) + continue; + + pending_table_separator_ = true; + print_newline(); + print_indent(); + print(k); + if (terse_kvps()) + print_unformatted("="sv); + else + print_unformatted(" = "sv); + TOML_ASSUME(type != node_type::none); + switch (type) + { + case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break; + case node_type::array: print(*reinterpret_cast<const array*>(&v)); break; + default: print_value(v, type); + } + } + + const auto print_key_path = [&]() + { + size_t i{}; + for (const auto k : key_path_) + { + if (i++) + print_unformatted('.'); + print(*k); + } + }; + + // non-inline tables + for (auto&& [k, v] : tbl) + { + const auto type = v.type(); + if (type != node_type::table || reinterpret_cast<const table*>(&v)->is_inline()) + continue; + auto& child_tbl = *reinterpret_cast<const table*>(&v); + + // we can skip indenting and emitting the headers for tables that only contain other tables + // (so we don't over-nest) + size_t child_value_count{}; // includes inline tables and non-table arrays + size_t child_table_count{}; + size_t child_table_array_count{}; + for (auto&& [child_k, child_v] : child_tbl) + { + TOML_UNUSED(child_k); + const auto child_type = child_v.type(); + TOML_ASSUME(child_type != node_type::none); + switch (child_type) + { + case node_type::table: + if (reinterpret_cast<const table*>(&child_v)->is_inline()) + child_value_count++; + else + child_table_count++; + break; + + case node_type::array: + if (is_non_inline_array_of_tables(child_v)) + child_table_array_count++; + else + child_value_count++; + break; + + default: child_value_count++; + } + } + bool skip_self = false; + if (child_value_count == 0u && (child_table_count > 0u || child_table_array_count > 0u)) + skip_self = true; + + key_path_.push_back(&k); + + if (!skip_self) + { + print_pending_table_separator(); + if (indent_sub_tables()) + increase_indent(); + print_indent(); + print_unformatted("["sv); + print_key_path(); + print_unformatted("]"sv); + pending_table_separator_ = true; + } + + print(child_tbl); + + key_path_.pop_back(); + if (!skip_self && indent_sub_tables()) + decrease_indent(); + } + + // table arrays + for (auto&& [k, v] : tbl) + { + if (!is_non_inline_array_of_tables(v)) + continue; + auto& arr = *reinterpret_cast<const array*>(&v); + + if (indent_sub_tables()) + increase_indent(); + key_path_.push_back(&k); + + for (size_t i = 0; i < arr.size(); i++) + { + print_pending_table_separator(); + print_indent(); + print_unformatted("[["sv); + print_key_path(); + print_unformatted("]]"sv); + pending_table_separator_ = true; + print(*reinterpret_cast<const table*>(&arr[i])); + } + + key_path_.pop_back(); + if (indent_sub_tables()) + decrease_indent(); + } + } + + TOML_EXTERNAL_LINKAGE + void toml_formatter::print() + { + if (dump_failed_parse_result()) + return; + + switch (auto source_type = source().type()) + { + case node_type::table: + { + auto& tbl = *reinterpret_cast<const table*>(&source()); + if (tbl.is_inline()) + print_inline(tbl); + else + { + decrease_indent(); // so root kvps and tables have the same indent + print(tbl); + } + break; + } + + case node_type::array: print(*reinterpret_cast<const array*>(&source())); break; + + default: print_value(source(), source_type); + } + } +} +TOML_NAMESPACE_END; + +#include "header_end.hpp" +#endif // TOML_ENABLE_FORMATTERS |
