2020-01-04 14:21:38 +00:00
|
|
|
#pragma once
|
|
|
|
#include "toml_value.h"
|
|
|
|
|
|
|
|
namespace toml::impl
|
|
|
|
{
|
2020-01-07 15:52:50 +00:00
|
|
|
TOML_PUSH_WARNINGS
|
|
|
|
TOML_DISABLE_ALL_WARNINGS // some compilers will complain about a tautological unsigned >= 0.
|
|
|
|
// TINAE - char can have signed _or_ unsigned semantics and I can't
|
|
|
|
// be arsed handling this differently
|
2020-01-04 14:21:38 +00:00
|
|
|
|
2020-01-07 15:52:50 +00:00
|
|
|
inline toml::string_view escape_string_character(const toml::string_char& c) noexcept
|
2020-01-04 14:21:38 +00:00
|
|
|
{
|
2020-01-07 15:52:50 +00:00
|
|
|
if (c >= TOML_STRING_PREFIX('\x00') && c <= TOML_STRING_PREFIX('\x1F')) TOML_UNLIKELY
|
|
|
|
return low_character_escape_table[c];
|
|
|
|
else if (c == TOML_STRING_PREFIX('\x7F')) TOML_UNLIKELY
|
|
|
|
return TOML_STRING_PREFIX("\\u007F"sv);
|
|
|
|
else if (c == TOML_STRING_PREFIX('"')) TOML_UNLIKELY
|
|
|
|
return TOML_STRING_PREFIX("\\\""sv);
|
|
|
|
else
|
|
|
|
return toml::string_view{ &c, 1_sz };
|
|
|
|
}
|
|
|
|
|
|
|
|
TOML_POP_WARNINGS
|
2020-01-04 14:21:38 +00:00
|
|
|
|
2020-01-06 18:21:16 +00:00
|
|
|
struct formatter_options final
|
|
|
|
{
|
|
|
|
toml::string_view indent_string;
|
|
|
|
bool quote_dates_and_times;
|
|
|
|
};
|
|
|
|
|
2020-01-07 15:52:50 +00:00
|
|
|
template <typename CHAR = char>
|
2020-01-06 18:21:16 +00:00
|
|
|
class formatter
|
2020-01-04 14:21:38 +00:00
|
|
|
{
|
|
|
|
private:
|
2020-01-07 15:52:50 +00:00
|
|
|
const toml::table& source_;
|
|
|
|
std::basic_ostream<CHAR>* stream_ = nullptr;
|
|
|
|
formatter_options options_;
|
|
|
|
int indent_;
|
|
|
|
bool naked_newline_;
|
|
|
|
size_t indent_columns_;
|
2020-01-04 14:21:38 +00:00
|
|
|
|
2020-01-06 18:21:16 +00:00
|
|
|
protected:
|
2020-01-04 14:21:38 +00:00
|
|
|
|
2020-01-07 15:52:50 +00:00
|
|
|
|
|
|
|
[[nodiscard]] const toml::table& source() const noexcept { return source_; }
|
|
|
|
[[nodiscard]] const formatter_options& options() const noexcept { return options_; }
|
|
|
|
[[nodiscard]] std::basic_ostream<CHAR>& stream() const noexcept { return *stream_; }
|
2020-01-04 14:21:38 +00:00
|
|
|
|
2020-01-07 15:52:50 +00:00
|
|
|
[[nodiscard]] int indent() const noexcept { return indent_; }
|
|
|
|
void indent(int level) noexcept { indent_ = level; }
|
|
|
|
void increase_indent() noexcept { indent_++; }
|
|
|
|
void decrease_indent() noexcept { indent_--; }
|
|
|
|
size_t indent_columns() const noexcept { return indent_columns_; }
|
2020-01-04 14:21:38 +00:00
|
|
|
|
2020-01-07 15:52:50 +00:00
|
|
|
void clear_naked_newline() noexcept { naked_newline_ = false; }
|
2020-01-04 14:21:38 +00:00
|
|
|
|
2020-01-07 15:52:50 +00:00
|
|
|
void attach(std::basic_ostream<CHAR>& stream) noexcept
|
2020-01-04 14:21:38 +00:00
|
|
|
{
|
2020-01-07 15:52:50 +00:00
|
|
|
indent_ = 0;
|
|
|
|
naked_newline_ = true;
|
|
|
|
stream_ = &stream;
|
2020-01-04 14:21:38 +00:00
|
|
|
}
|
|
|
|
|
2020-01-07 15:52:50 +00:00
|
|
|
void detach() noexcept
|
2020-01-04 14:21:38 +00:00
|
|
|
{
|
2020-01-07 15:52:50 +00:00
|
|
|
stream_ = nullptr;
|
2020-01-06 18:21:16 +00:00
|
|
|
}
|
|
|
|
|
2020-01-07 15:52:50 +00:00
|
|
|
void print_newline(bool force = false) TOML_MAY_THROW
|
2020-01-06 18:21:16 +00:00
|
|
|
{
|
2020-01-07 15:52:50 +00:00
|
|
|
if (!naked_newline_ || force)
|
2020-01-04 14:21:38 +00:00
|
|
|
{
|
2020-01-07 15:52:50 +00:00
|
|
|
print_to_stream('\n', *stream_);
|
|
|
|
naked_newline_ = true;
|
2020-01-04 14:21:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-07 15:52:50 +00:00
|
|
|
void print_indent() TOML_MAY_THROW
|
2020-01-04 14:21:38 +00:00
|
|
|
{
|
2020-01-07 15:52:50 +00:00
|
|
|
for (int i = 0; i < indent_; i++)
|
2020-01-04 14:21:38 +00:00
|
|
|
{
|
2020-01-07 15:52:50 +00:00
|
|
|
print_to_stream(options_.indent_string, *stream_);
|
|
|
|
naked_newline_ = false;
|
2020-01-04 14:21:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-07 15:52:50 +00:00
|
|
|
void print_quoted_string(toml::string_view str) TOML_MAY_THROW
|
2020-01-06 18:21:16 +00:00
|
|
|
{
|
|
|
|
if (str.empty())
|
2020-01-07 15:52:50 +00:00
|
|
|
print_to_stream("\"\""sv, *stream_);
|
2020-01-06 18:21:16 +00:00
|
|
|
else
|
|
|
|
{
|
2020-01-07 15:52:50 +00:00
|
|
|
print_to_stream('"', *stream_);
|
2020-01-06 18:21:16 +00:00
|
|
|
for (auto c : str)
|
2020-01-07 15:52:50 +00:00
|
|
|
print_to_stream(escape_string_character(c), *stream_);
|
|
|
|
print_to_stream('"', *stream_);
|
2020-01-06 18:21:16 +00:00
|
|
|
}
|
2020-01-07 15:52:50 +00:00
|
|
|
naked_newline_ = false;
|
2020-01-06 18:21:16 +00:00
|
|
|
}
|
|
|
|
|
2020-01-04 14:21:38 +00:00
|
|
|
template <typename T>
|
2020-01-07 15:52:50 +00:00
|
|
|
void print(const value<T>& val) TOML_MAY_THROW
|
2020-01-04 14:21:38 +00:00
|
|
|
{
|
2020-01-07 15:52:50 +00:00
|
|
|
if constexpr (std::is_same_v<T, string>)
|
2020-01-04 14:21:38 +00:00
|
|
|
{
|
2020-01-07 15:52:50 +00:00
|
|
|
print_quoted_string(val.get());
|
2020-01-04 14:21:38 +00:00
|
|
|
}
|
2020-01-07 15:52:50 +00:00
|
|
|
else
|
2020-01-04 14:21:38 +00:00
|
|
|
{
|
2020-01-07 15:52:50 +00:00
|
|
|
static constexpr auto is_date_time =
|
|
|
|
std::is_same_v<T, date>
|
|
|
|
|| std::is_same_v<T, time>
|
|
|
|
|| std::is_same_v<T, date_time>;
|
|
|
|
|
|
|
|
if constexpr (is_date_time)
|
2020-01-04 14:21:38 +00:00
|
|
|
{
|
2020-01-07 15:52:50 +00:00
|
|
|
if (options_.quote_dates_and_times)
|
|
|
|
print_to_stream('"', *stream_);
|
2020-01-04 14:21:38 +00:00
|
|
|
}
|
|
|
|
|
2020-01-07 15:52:50 +00:00
|
|
|
*stream_ << val;
|
2020-01-04 14:21:38 +00:00
|
|
|
|
2020-01-07 15:52:50 +00:00
|
|
|
if constexpr (is_date_time)
|
|
|
|
{
|
|
|
|
if (options_.quote_dates_and_times)
|
|
|
|
print_to_stream('"', *stream_);
|
|
|
|
}
|
2020-01-04 14:21:38 +00:00
|
|
|
|
2020-01-07 15:52:50 +00:00
|
|
|
naked_newline_ = false;
|
|
|
|
}
|
2020-01-04 14:21:38 +00:00
|
|
|
}
|
|
|
|
|
2020-01-07 15:52:50 +00:00
|
|
|
void print(const node& val_node, node_type type) TOML_MAY_THROW
|
2020-01-04 14:21:38 +00:00
|
|
|
{
|
2020-01-06 18:21:16 +00:00
|
|
|
switch (type)
|
2020-01-04 14:21:38 +00:00
|
|
|
{
|
2020-01-07 15:52:50 +00:00
|
|
|
case node_type::string: print(*reinterpret_cast<const value<string>*>(&val_node)); break;
|
|
|
|
case node_type::integer: print(*reinterpret_cast<const value<int64_t>*>(&val_node)); break;
|
|
|
|
case node_type::floating_point: print(*reinterpret_cast<const value<double>*>(&val_node)); break;
|
|
|
|
case node_type::boolean: print(*reinterpret_cast<const value<bool>*>(&val_node)); break;
|
|
|
|
case node_type::date: print(*reinterpret_cast<const value<date>*>(&val_node)); break;
|
|
|
|
case node_type::time: print(*reinterpret_cast<const value<time>*>(&val_node)); break;
|
|
|
|
case node_type::date_time: print(*reinterpret_cast<const value<date_time>*>(&val_node)); break;
|
2020-01-04 14:21:38 +00:00
|
|
|
TOML_NO_DEFAULT_CASE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-07 15:52:50 +00:00
|
|
|
formatter(const toml::table& source, formatter_options&& options) noexcept
|
|
|
|
: source_{ source },
|
|
|
|
options_{ std::move(options) }
|
|
|
|
|
2020-01-04 14:21:38 +00:00
|
|
|
{
|
2020-01-07 15:52:50 +00:00
|
|
|
if (options_.indent_string.empty())
|
2020-01-04 14:21:38 +00:00
|
|
|
{
|
2020-01-07 15:52:50 +00:00
|
|
|
options_.indent_string = TOML_STRING_PREFIX(" "sv);
|
|
|
|
indent_columns_ = 4_sz;
|
2020-01-04 14:21:38 +00:00
|
|
|
}
|
2020-01-06 18:21:16 +00:00
|
|
|
else
|
2020-01-04 14:21:38 +00:00
|
|
|
{
|
2020-01-07 15:52:50 +00:00
|
|
|
indent_columns_ = {};
|
|
|
|
for (auto c : options_.indent_string)
|
|
|
|
indent_columns_ += c == '\t' ? 4_sz : 1_sz;
|
2020-01-04 14:21:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|