mirror of
https://github.com/marzer/tomlplusplus.git
synced 2024-09-15 15:13:21 +00:00
fixed incorrect unicode scalar sequence transformations (#125)
also: - fixed extended-precision fractional times causing parse error instead of truncating per the spec (closes #127) - fixed some non-spec vertical whitespace being accepted as line breaks (closes #128) - added `format_flags::allow_unicode_strings`
This commit is contained in:
parent
f3bd22bff4
commit
b41e12f736
@ -35,6 +35,9 @@ code changes at callsites or in build systems are indicated with ⚠️.
|
|||||||
- fixed missing `TOML_API` on interfaces
|
- fixed missing `TOML_API` on interfaces
|
||||||
- fixed parser not correctly round-tripping the format of binary and octal integers in some cases
|
- fixed parser not correctly round-tripping the format of binary and octal integers in some cases
|
||||||
- fixed strong exception guarantee edge-cases in `toml::table` and `toml::array`
|
- fixed strong exception guarantee edge-cases in `toml::table` and `toml::array`
|
||||||
|
- fixed some incorrect unicode scalar sequence transformations (#125) (@moorereason)
|
||||||
|
- fixed extended-precision fractional times causing parse error instead of truncating per the spec (#127) (@moorereason)
|
||||||
|
- fixed some non-spec vertical whitespace being accepted as line breaks (#128) (@moorereason)
|
||||||
|
|
||||||
#### Additions:
|
#### Additions:
|
||||||
- added `operator->` to `toml::value` for class types
|
- added `operator->` to `toml::value` for class types
|
||||||
@ -48,6 +51,7 @@ code changes at callsites or in build systems are indicated with ⚠️.
|
|||||||
- added `toml::format_flags::allow_hexadecimal_integers`
|
- added `toml::format_flags::allow_hexadecimal_integers`
|
||||||
- added `toml::format_flags::allow_octal_integers`
|
- added `toml::format_flags::allow_octal_integers`
|
||||||
- added `toml::format_flags::allow_real_tabs_in_strings`
|
- added `toml::format_flags::allow_real_tabs_in_strings`
|
||||||
|
- added `toml::format_flags::allow_unicode_strings`
|
||||||
- added `toml::format_flags::indent_array_elements`
|
- added `toml::format_flags::indent_array_elements`
|
||||||
- added `toml::format_flags::indent_sub_tables`
|
- added `toml::format_flags::indent_sub_tables`
|
||||||
- added `toml::format_flags::quote_infinities_and_nans`
|
- added `toml::format_flags::quote_infinities_and_nans`
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
// This example shows the error messages the library produces by forcing a set of specific parsing
|
// This example shows the error messages the library produces by forcing a set of specific parsing
|
||||||
// failures and printing their results.
|
// failures and printing their results.
|
||||||
|
|
||||||
#include "examples.hpp"
|
#include "examples.h"
|
||||||
|
|
||||||
#define TOML_EXCEPTIONS 0
|
#define TOML_EXCEPTIONS 0
|
||||||
#define TOML_ENABLE_UNRELEASED_FEATURES 0
|
#define TOML_ENABLE_UNRELEASED_FEATURES 0
|
||||||
@ -17,10 +17,11 @@ using namespace std::string_view_literals;
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
inline constexpr auto invalid_parses = std::array{
|
inline constexpr auto invalid_parses = std::array{
|
||||||
"########## comments"sv,
|
"########## comments and whitespace"sv,
|
||||||
"# bar\rkek"sv,
|
"# bar\rkek"sv,
|
||||||
"# bar\bkek"sv,
|
"# bar\bkek"sv,
|
||||||
"# \xf1\x63"sv,
|
"# \xf1\x63"sv,
|
||||||
|
"# val1 = 1\fval2 = 2"sv,
|
||||||
|
|
||||||
"########## inline tables"sv,
|
"########## inline tables"sv,
|
||||||
"val = {,}"sv,
|
"val = {,}"sv,
|
||||||
|
@ -55,7 +55,7 @@
|
|||||||
<Text Include="CMakeLists.txt" />
|
<Text Include="CMakeLists.txt" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="examples.hpp" />
|
<ClInclude Include="examples.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
</Project>
|
</Project>
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
// This example is just a short-n-shiny benchmark.
|
// This example is just a short-n-shiny benchmark.
|
||||||
|
|
||||||
#include "examples.hpp"
|
#include "examples.h"
|
||||||
#include <toml++/toml.h>
|
#include <toml++/toml.h>
|
||||||
|
|
||||||
using namespace std::string_view_literals;
|
using namespace std::string_view_literals;
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
<Text Include="CMakeLists.txt" />
|
<Text Include="CMakeLists.txt" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="examples.hpp" />
|
<ClInclude Include="examples.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
</Project>
|
</Project>
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
// This example demonstrates how to parse TOML from a file or stdin and re-serialize it (print it out) to stdout.
|
// This example demonstrates how to parse TOML from a file or stdin and re-serialize it (print it out) to stdout.
|
||||||
|
|
||||||
#include "examples.hpp"
|
#include "examples.h"
|
||||||
|
|
||||||
#define TOML_ENABLE_UNRELEASED_FEATURES 1
|
#define TOML_ENABLE_UNRELEASED_FEATURES 1
|
||||||
#include <toml++/toml.h>
|
#include <toml++/toml.h>
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
<Text Include="CMakeLists.txt" />
|
<Text Include="CMakeLists.txt" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="examples.hpp" />
|
<ClInclude Include="examples.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
</Project>
|
</Project>
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
// This example demonstrates the use of some more advanced features to generate a tree of random TOML data.
|
// This example demonstrates the use of some more advanced features to generate a tree of random TOML data.
|
||||||
|
|
||||||
#include "examples.hpp"
|
#include "examples.h"
|
||||||
|
|
||||||
#define TOML_ENABLE_PARSER 0
|
#define TOML_ENABLE_PARSER 0
|
||||||
#include <toml++/toml.h>
|
#include <toml++/toml.h>
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
<Text Include="CMakeLists.txt" />
|
<Text Include="CMakeLists.txt" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="examples.hpp" />
|
<ClInclude Include="examples.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
</Project>
|
</Project>
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
// This example demonstrates how to use the toml::json_formatter to re-serialize TOML data as JSON.
|
// This example demonstrates how to use the toml::json_formatter to re-serialize TOML data as JSON.
|
||||||
|
|
||||||
#include "examples.hpp"
|
#include "examples.h"
|
||||||
|
|
||||||
#define TOML_ENABLE_UNRELEASED_FEATURES 1
|
#define TOML_ENABLE_UNRELEASED_FEATURES 1
|
||||||
#include <toml++/toml.h>
|
#include <toml++/toml.h>
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
<Text Include="CMakeLists.txt" />
|
<Text Include="CMakeLists.txt" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="examples.hpp" />
|
<ClInclude Include="examples.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
</Project>
|
</Project>
|
@ -106,6 +106,24 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
return !!(config_.flags & format_flags::allow_literal_strings);
|
return !!(config_.flags & format_flags::allow_literal_strings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TOML_PURE_INLINE_GETTER
|
||||||
|
bool multi_line_strings_allowed() const noexcept
|
||||||
|
{
|
||||||
|
return !!(config_.flags & format_flags::allow_multi_line_strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
TOML_PURE_INLINE_GETTER
|
||||||
|
bool real_tabs_in_strings_allowed() const noexcept
|
||||||
|
{
|
||||||
|
return !!(config_.flags & format_flags::allow_real_tabs_in_strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
TOML_PURE_INLINE_GETTER
|
||||||
|
bool unicode_strings_allowed() const noexcept
|
||||||
|
{
|
||||||
|
return !!(config_.flags & format_flags::allow_unicode_strings);
|
||||||
|
}
|
||||||
|
|
||||||
TOML_API
|
TOML_API
|
||||||
void attach(std::ostream& stream) noexcept;
|
void attach(std::ostream& stream) noexcept;
|
||||||
|
|
||||||
|
@ -14,15 +14,29 @@
|
|||||||
|
|
||||||
#include "formatter.h"
|
#include "formatter.h"
|
||||||
#include "print_to_stream.h"
|
#include "print_to_stream.h"
|
||||||
#include "utf8.h"
|
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
#include "table.h"
|
#include "table.h"
|
||||||
#include "array.h"
|
#include "array.h"
|
||||||
|
#include "unicode.h"
|
||||||
#include "parse_result.h"
|
#include "parse_result.h"
|
||||||
#include "header_start.h"
|
#include "header_start.h"
|
||||||
|
|
||||||
TOML_IMPL_NAMESPACE_START
|
TOML_IMPL_NAMESPACE_START
|
||||||
{
|
{
|
||||||
|
enum class formatted_string_traits : unsigned
|
||||||
|
{
|
||||||
|
none,
|
||||||
|
line_breaks = 1u << 0, // \n
|
||||||
|
tabs = 1u << 1, // \t
|
||||||
|
control_chars = 1u << 2, // also includes non-ascii vertical whitespace
|
||||||
|
single_quotes = 1u << 3,
|
||||||
|
non_bare = 1u << 4, // anything not satisfying "is bare key character"
|
||||||
|
non_ascii = 1u << 5, // any codepoint >= 128
|
||||||
|
|
||||||
|
all = (non_ascii << 1u) - 1u
|
||||||
|
};
|
||||||
|
TOML_MAKE_FLAGS(formatted_string_traits);
|
||||||
|
|
||||||
TOML_EXTERNAL_LINKAGE
|
TOML_EXTERNAL_LINKAGE
|
||||||
formatter::formatter(const node* source_node,
|
formatter::formatter(const node* source_node,
|
||||||
const parse_result* source_pr,
|
const parse_result* source_pr,
|
||||||
@ -101,70 +115,236 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
TOML_EXTERNAL_LINKAGE
|
TOML_EXTERNAL_LINKAGE
|
||||||
void formatter::print_string(std::string_view str, bool allow_multi_line, bool allow_bare)
|
void formatter::print_string(std::string_view str, bool allow_multi_line, bool allow_bare)
|
||||||
{
|
{
|
||||||
auto literal = literal_strings_allowed();
|
|
||||||
if (str.empty())
|
if (str.empty())
|
||||||
{
|
{
|
||||||
print_to_stream(*stream_, literal ? "''"sv : "\"\""sv);
|
print_unformatted(literal_strings_allowed() ? "''"sv : "\"\""sv);
|
||||||
naked_newline_ = false;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool multi_line = allow_multi_line && !!(config_.flags & format_flags::allow_multi_line_strings);
|
// pre-scan the string to determine how we should output it
|
||||||
const bool treat_raw_tab_as_control_char = !(config_.flags & format_flags::allow_real_tabs_in_strings);
|
formatted_string_traits traits = {};
|
||||||
if (multi_line || literal || treat_raw_tab_as_control_char || allow_bare)
|
|
||||||
|
if (!allow_bare)
|
||||||
|
traits |= formatted_string_traits::non_bare;
|
||||||
|
bool unicode_allowed = unicode_strings_allowed();
|
||||||
|
|
||||||
|
// ascii fast path
|
||||||
|
if (is_ascii(str.data(), str.length()))
|
||||||
{
|
{
|
||||||
utf8_decoder decoder;
|
for (auto c : str)
|
||||||
bool has_line_breaks = false;
|
|
||||||
bool has_control_chars = false;
|
|
||||||
bool has_single_quotes = false;
|
|
||||||
for (size_t i = 0; i < str.length(); i++)
|
|
||||||
{
|
{
|
||||||
decoder(static_cast<uint8_t>(str[i]));
|
switch (c)
|
||||||
if (decoder.error())
|
|
||||||
{
|
{
|
||||||
has_line_breaks = false;
|
case '\n': traits |= formatted_string_traits::line_breaks; break;
|
||||||
has_control_chars = true; // force ""
|
case '\t': traits |= formatted_string_traits::tabs; break;
|
||||||
has_single_quotes = true;
|
case '\'': traits |= formatted_string_traits::single_quotes; break;
|
||||||
allow_bare = false;
|
default:
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (decoder.has_code_point())
|
|
||||||
{
|
|
||||||
if (decoder.codepoint == U'\n')
|
|
||||||
{
|
{
|
||||||
has_line_breaks = true;
|
if (is_control_character(c))
|
||||||
if (!multi_line)
|
traits |= formatted_string_traits::control_chars;
|
||||||
has_control_chars = true;
|
|
||||||
|
if (!is_ascii_bare_key_character(static_cast<char32_t>(c)))
|
||||||
|
traits |= formatted_string_traits::non_bare;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if (is_nontab_control_character(decoder.codepoint)
|
|
||||||
|| (treat_raw_tab_as_control_char && decoder.codepoint == U'\t')
|
|
||||||
|| is_vertical_whitespace(decoder.codepoint))
|
|
||||||
has_control_chars = true;
|
|
||||||
else if (decoder.codepoint == U'\'')
|
|
||||||
has_single_quotes = true;
|
|
||||||
if (allow_bare)
|
|
||||||
allow_bare = is_bare_key_character(decoder.codepoint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_line_breaks && has_control_chars && has_single_quotes && !allow_bare)
|
static constexpr auto all_ascii_traits =
|
||||||
|
formatted_string_traits::all & ~formatted_string_traits::non_ascii;
|
||||||
|
if (traits == all_ascii_traits)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
multi_line = multi_line && has_line_breaks;
|
|
||||||
literal = literal && !has_control_chars && !(!multi_line && has_single_quotes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allow_bare)
|
// unicode slow path
|
||||||
print_to_stream(*stream_, str);
|
|
||||||
else if (literal)
|
|
||||||
print_to_stream_bookended(*stream_, str, multi_line ? "'''"sv : "'"sv);
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const auto quot = multi_line ? R"(""")"sv : R"(")"sv;
|
traits |= formatted_string_traits::non_ascii;
|
||||||
print_to_stream(*stream_, quot);
|
utf8_decoder decoder;
|
||||||
print_to_stream_with_escapes(*stream_, str);
|
|
||||||
print_to_stream(*stream_, quot);
|
// if the unicode is malformed just treat the string as a single-line non-literal and
|
||||||
|
// escape all non-ascii characters (to ensure round-tripping and help with diagnostics)
|
||||||
|
const auto bad_unicode = [&]() noexcept
|
||||||
|
{
|
||||||
|
traits &= ~formatted_string_traits::line_breaks;
|
||||||
|
traits |= formatted_string_traits::control_chars | formatted_string_traits::non_bare;
|
||||||
|
unicode_allowed = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto c : str)
|
||||||
|
{
|
||||||
|
decoder(c);
|
||||||
|
|
||||||
|
if TOML_UNLIKELY(decoder.error())
|
||||||
|
{
|
||||||
|
bad_unicode();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!decoder.has_code_point())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (decoder.codepoint)
|
||||||
|
{
|
||||||
|
case U'\n': traits |= formatted_string_traits::line_breaks; break;
|
||||||
|
case U'\t': traits |= formatted_string_traits::tabs; break;
|
||||||
|
case U'\'': traits |= formatted_string_traits::single_quotes; break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
if (is_control_character(decoder.codepoint)
|
||||||
|
|| is_non_ascii_vertical_whitespace(decoder.codepoint))
|
||||||
|
traits |= formatted_string_traits::control_chars;
|
||||||
|
|
||||||
|
if (!is_bare_key_character(decoder.codepoint))
|
||||||
|
traits |= formatted_string_traits::non_bare;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decoder.needs_more_input())
|
||||||
|
bad_unicode();
|
||||||
}
|
}
|
||||||
naked_newline_ = false;
|
|
||||||
|
// if the string meets the requirements of being 'bare' we can emit a bare string
|
||||||
|
// (bare strings are composed of letters and numbers; no whitespace, control chars, quotes, etc)
|
||||||
|
if (!(traits & formatted_string_traits::non_bare)
|
||||||
|
&& (!(traits & formatted_string_traits::non_ascii) || unicode_allowed))
|
||||||
|
{
|
||||||
|
print_unformatted(str);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine if this should be a multi-line string (triple-quotes)
|
||||||
|
const auto multi_line = allow_multi_line //
|
||||||
|
&& multi_line_strings_allowed() //
|
||||||
|
&& !!(traits & formatted_string_traits::line_breaks);
|
||||||
|
|
||||||
|
// determine if this should be a literal string (single-quotes with no escaping)
|
||||||
|
const auto literal = literal_strings_allowed() //
|
||||||
|
&& !(traits & formatted_string_traits::control_chars) //
|
||||||
|
&& (!(traits & formatted_string_traits::single_quotes) || multi_line) //
|
||||||
|
&& (!(traits & formatted_string_traits::tabs) || real_tabs_in_strings_allowed()) //
|
||||||
|
&& (!(traits & formatted_string_traits::non_ascii) || unicode_allowed);
|
||||||
|
|
||||||
|
// literal strings (single quotes, no escape codes)
|
||||||
|
if (literal)
|
||||||
|
{
|
||||||
|
const auto quot = multi_line ? R"(''')"sv : R"(')"sv;
|
||||||
|
print_unformatted(quot);
|
||||||
|
print_unformatted(str);
|
||||||
|
print_unformatted(quot);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// anything from here down is a non-literal string, so requires iteration and escaping.
|
||||||
|
print_unformatted(multi_line ? R"(""")"sv : R"(")"sv);
|
||||||
|
|
||||||
|
const auto real_tabs_allowed = real_tabs_in_strings_allowed();
|
||||||
|
|
||||||
|
// ascii fast path
|
||||||
|
if (!(traits & formatted_string_traits::non_ascii))
|
||||||
|
{
|
||||||
|
for (auto c : str)
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '"': print_to_stream(*stream_, R"(\")"sv); break;
|
||||||
|
case '\\': print_to_stream(*stream_, R"(\\)"sv); break;
|
||||||
|
case '\x7F': print_to_stream(*stream_, R"(\u007F)"sv); break;
|
||||||
|
case '\t': print_to_stream(*stream_, real_tabs_allowed ? "\t"sv : R"(\t)"sv); break;
|
||||||
|
case '\n': print_to_stream(*stream_, multi_line ? "\n"sv : R"(\n)"sv); break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// control characters from lookup table
|
||||||
|
if TOML_UNLIKELY(c >= '\x00' && c <= '\x1F')
|
||||||
|
print_to_stream(*stream_, control_char_escapes[c]);
|
||||||
|
|
||||||
|
// regular characters
|
||||||
|
else
|
||||||
|
print_to_stream(*stream_, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unicode slow path
|
||||||
|
else
|
||||||
|
{
|
||||||
|
utf8_decoder decoder;
|
||||||
|
const char* cp_start = str.data();
|
||||||
|
const char* cp_end = cp_start;
|
||||||
|
for (auto c : str)
|
||||||
|
{
|
||||||
|
decoder(c);
|
||||||
|
cp_end++;
|
||||||
|
|
||||||
|
// if the decoder encounters malformed unicode just emit raw bytes and
|
||||||
|
if (decoder.error())
|
||||||
|
{
|
||||||
|
while (cp_start != cp_end)
|
||||||
|
{
|
||||||
|
print_to_stream(*stream_, R"(\u00)"sv);
|
||||||
|
print_to_stream(*stream_,
|
||||||
|
static_cast<uint8_t>(*cp_start),
|
||||||
|
value_flags::format_as_hexadecimal,
|
||||||
|
2);
|
||||||
|
cp_start++;
|
||||||
|
}
|
||||||
|
decoder.reset();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!decoder.has_code_point())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (decoder.codepoint)
|
||||||
|
{
|
||||||
|
case U'"': print_to_stream(*stream_, R"(\")"sv); break;
|
||||||
|
case U'\\': print_to_stream(*stream_, R"(\\)"sv); break;
|
||||||
|
case U'\x7F': print_to_stream(*stream_, R"(\u007F)"sv); break;
|
||||||
|
case U'\t': print_to_stream(*stream_, real_tabs_allowed ? "\t"sv : R"(\t)"sv); break;
|
||||||
|
case U'\n': print_to_stream(*stream_, multi_line ? "\n"sv : R"(\n)"sv); break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// control characters from lookup table
|
||||||
|
if TOML_UNLIKELY(decoder.codepoint <= U'\x1F')
|
||||||
|
print_to_stream(*stream_,
|
||||||
|
control_char_escapes[static_cast<uint_least32_t>(decoder.codepoint)]);
|
||||||
|
|
||||||
|
// escaped unicode characters
|
||||||
|
else if (decoder.codepoint > U'\x7F'
|
||||||
|
&& (!unicode_allowed || is_non_ascii_vertical_whitespace(decoder.codepoint)))
|
||||||
|
{
|
||||||
|
if (static_cast<uint_least32_t>(decoder.codepoint) > 0xFFFFu)
|
||||||
|
{
|
||||||
|
print_to_stream(*stream_, R"(\U)"sv);
|
||||||
|
print_to_stream(*stream_,
|
||||||
|
static_cast<uint_least32_t>(decoder.codepoint),
|
||||||
|
value_flags::format_as_hexadecimal,
|
||||||
|
8);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
print_to_stream(*stream_, R"(\u)"sv);
|
||||||
|
print_to_stream(*stream_,
|
||||||
|
static_cast<uint_least32_t>(decoder.codepoint),
|
||||||
|
value_flags::format_as_hexadecimal,
|
||||||
|
4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// regular characters
|
||||||
|
else
|
||||||
|
print_to_stream(*stream_, cp_start, static_cast<size_t>(cp_end - cp_start));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cp_start = cp_end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print_unformatted(multi_line ? R"(""")"sv : R"(")"sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
TOML_EXTERNAL_LINKAGE
|
TOML_EXTERNAL_LINKAGE
|
||||||
|
@ -119,7 +119,7 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
||||||
inline constexpr std::string_view low_character_escape_table[] =
|
inline constexpr std::string_view control_char_escapes[] =
|
||||||
{
|
{
|
||||||
"\\u0000"sv,
|
"\\u0000"sv,
|
||||||
"\\u0001"sv,
|
"\\u0001"sv,
|
||||||
@ -309,20 +309,23 @@ TOML_NAMESPACE_START // abi namespace
|
|||||||
/// \brief Allow real tab characters in string literals (as opposed to the escaped form `\t`).
|
/// \brief Allow real tab characters in string literals (as opposed to the escaped form `\t`).
|
||||||
allow_real_tabs_in_strings = (1ull << 4),
|
allow_real_tabs_in_strings = (1ull << 4),
|
||||||
|
|
||||||
|
/// \brief Allow non-ASCII characters in strings (as opposed to their escaped form, e.g. `\u00DA`).
|
||||||
|
allow_unicode_strings = (1ull << 5),
|
||||||
|
|
||||||
/// \brief Allow integers with #value_flags::format_as_binary to be emitted as binary.
|
/// \brief Allow integers with #value_flags::format_as_binary to be emitted as binary.
|
||||||
allow_binary_integers = (1ull << 5),
|
allow_binary_integers = (1ull << 6),
|
||||||
|
|
||||||
/// \brief Allow integers with #value_flags::format_as_octal to be emitted as octal.
|
/// \brief Allow integers with #value_flags::format_as_octal to be emitted as octal.
|
||||||
allow_octal_integers = (1ull << 6),
|
allow_octal_integers = (1ull << 7),
|
||||||
|
|
||||||
/// \brief Allow integers with #value_flags::format_as_hexadecimal to be emitted as hexadecimal.
|
/// \brief Allow integers with #value_flags::format_as_hexadecimal to be emitted as hexadecimal.
|
||||||
allow_hexadecimal_integers = (1ull << 7),
|
allow_hexadecimal_integers = (1ull << 8),
|
||||||
|
|
||||||
/// \brief Apply indentation to tables nested within other tables/arrays.
|
/// \brief Apply indentation to tables nested within other tables/arrays.
|
||||||
indent_sub_tables = (1ull << 8),
|
indent_sub_tables = (1ull << 9),
|
||||||
|
|
||||||
/// \brief Apply indentation to array elements when the array is forced to wrap over multiple lines.
|
/// \brief Apply indentation to array elements when the array is forced to wrap over multiple lines.
|
||||||
indent_array_elements = (1ull << 9),
|
indent_array_elements = (1ull << 10),
|
||||||
|
|
||||||
/// \brief Combination mask of all indentation-enabling flags.
|
/// \brief Combination mask of all indentation-enabling flags.
|
||||||
indentation = indent_sub_tables | indent_array_elements,
|
indentation = indent_sub_tables | indent_array_elements,
|
||||||
|
@ -75,6 +75,7 @@ TOML_NAMESPACE_START
|
|||||||
/// \brief The default flags for a json_formatter.
|
/// \brief The default flags for a json_formatter.
|
||||||
static constexpr format_flags default_flags = constants.mandatory_flags //
|
static constexpr format_flags default_flags = constants.mandatory_flags //
|
||||||
| format_flags::quote_infinities_and_nans //
|
| format_flags::quote_infinities_and_nans //
|
||||||
|
| format_flags::allow_unicode_strings //
|
||||||
| format_flags::indentation;
|
| format_flags::indentation;
|
||||||
|
|
||||||
/// \brief Constructs a JSON formatter and binds it to a TOML object.
|
/// \brief Constructs a JSON formatter and binds it to a TOML object.
|
||||||
|
@ -35,6 +35,12 @@ TOML_NAMESPACE_START
|
|||||||
source_region source_;
|
source_region source_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/// A const iterator for iterating over the characters in the key.
|
||||||
|
using const_iterator = const char*;
|
||||||
|
|
||||||
|
/// A const iterator for iterating over the characters in the key.
|
||||||
|
using iterator = const_iterator;
|
||||||
|
|
||||||
/// \brief Default constructor.
|
/// \brief Default constructor.
|
||||||
TOML_NODISCARD_CTOR
|
TOML_NODISCARD_CTOR
|
||||||
key() noexcept = default;
|
key() noexcept = default;
|
||||||
@ -287,6 +293,40 @@ TOML_NAMESPACE_START
|
|||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
/// \name Iterators
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
TOML_PURE_INLINE_GETTER
|
||||||
|
const_iterator begin() const noexcept
|
||||||
|
{
|
||||||
|
return key_.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
TOML_PURE_INLINE_GETTER
|
||||||
|
const_iterator end() const noexcept
|
||||||
|
{
|
||||||
|
return key_.data() + key_.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
/// \name Iterators (ADL)
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
TOML_PURE_INLINE_GETTER
|
||||||
|
friend const_iterator begin(const key& k) noexcept
|
||||||
|
{
|
||||||
|
return k.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
TOML_PURE_INLINE_GETTER
|
||||||
|
friend const_iterator end(const key& k) noexcept
|
||||||
|
{
|
||||||
|
return k.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
/// \brief Prints the key's underlying string out to the stream.
|
/// \brief Prints the key's underlying string out to the stream.
|
||||||
friend std::ostream& operator<<(std::ostream& lhs, const key& rhs)
|
friend std::ostream& operator<<(std::ostream& lhs, const key& rhs)
|
||||||
{
|
{
|
||||||
|
@ -12,15 +12,15 @@
|
|||||||
//# }}
|
//# }}
|
||||||
#if TOML_ENABLE_PARSER
|
#if TOML_ENABLE_PARSER
|
||||||
|
|
||||||
#include "std_optional.h"
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "std_optional.h"
|
||||||
#include "source_region.h"
|
#include "source_region.h"
|
||||||
#include "parse_error.h"
|
#include "parse_error.h"
|
||||||
#include "utf8.h"
|
|
||||||
#include "date_time.h"
|
#include "date_time.h"
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
#include "array.h"
|
#include "array.h"
|
||||||
#include "table.h"
|
#include "table.h"
|
||||||
|
#include "unicode.h"
|
||||||
TOML_DISABLE_WARNINGS;
|
TOML_DISABLE_WARNINGS;
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@ -34,7 +34,6 @@ TOML_DISABLE_WARNINGS;
|
|||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#endif
|
#endif
|
||||||
TOML_ENABLE_WARNINGS;
|
TOML_ENABLE_WARNINGS;
|
||||||
#include "simd.h"
|
|
||||||
#include "header_start.h"
|
#include "header_start.h"
|
||||||
|
|
||||||
//#---------------------------------------------------------------------------------------------------------------------
|
//#---------------------------------------------------------------------------------------------------------------------
|
||||||
@ -43,48 +42,6 @@ TOML_ENABLE_WARNINGS;
|
|||||||
|
|
||||||
TOML_ANON_NAMESPACE_START
|
TOML_ANON_NAMESPACE_START
|
||||||
{
|
{
|
||||||
template <typename T>
|
|
||||||
TOML_PURE_GETTER
|
|
||||||
TOML_ATTR(nonnull)
|
|
||||||
TOML_INTERNAL_LINKAGE
|
|
||||||
bool is_ascii(const T* str, size_t size) noexcept
|
|
||||||
{
|
|
||||||
static_assert(sizeof(T) == 1);
|
|
||||||
|
|
||||||
const T* const end = str + size;
|
|
||||||
|
|
||||||
#if TOML_HAS_SSE2 && (128 % CHAR_BIT) == 0
|
|
||||||
{
|
|
||||||
constexpr size_t chars_per_vector = 128 / CHAR_BIT;
|
|
||||||
|
|
||||||
if (const size_t simdable = size - (size % chars_per_vector))
|
|
||||||
{
|
|
||||||
__m128i mask = _mm_setzero_si128();
|
|
||||||
for (const T* const e = str + simdable; str < e; str += chars_per_vector)
|
|
||||||
{
|
|
||||||
const __m128i current_bytes = _mm_loadu_si128(reinterpret_cast<const __m128i*>(str));
|
|
||||||
mask = _mm_or_si128(mask, current_bytes);
|
|
||||||
}
|
|
||||||
const __m128i has_error = _mm_cmpgt_epi8(_mm_setzero_si128(), mask);
|
|
||||||
|
|
||||||
#if TOML_HAS_SSE4_1
|
|
||||||
if (!_mm_testz_si128(has_error, has_error))
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
if (_mm_movemask_epi8(_mm_cmpeq_epi8(has_error, _mm_setzero_si128())) != 0xFFFF)
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (; str < end; str++)
|
|
||||||
if (static_cast<unsigned char>(*str) > 127u)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class utf8_byte_stream;
|
class utf8_byte_stream;
|
||||||
|
|
||||||
@ -363,7 +320,7 @@ TOML_ANON_NAMESPACE_START
|
|||||||
auto& cp = codepoints_.buffer[i];
|
auto& cp = codepoints_.buffer[i];
|
||||||
cp.position = next_pos_;
|
cp.position = next_pos_;
|
||||||
|
|
||||||
if (impl::is_vertical_whitespace_excl_cr(cp))
|
if (cp == U'\n')
|
||||||
{
|
{
|
||||||
next_pos_.line++;
|
next_pos_.line++;
|
||||||
next_pos_.column = source_index{ 1 };
|
next_pos_.column = source_index{ 1 };
|
||||||
@ -374,7 +331,7 @@ TOML_ANON_NAMESPACE_START
|
|||||||
};
|
};
|
||||||
|
|
||||||
// decide whether we need to use the UTF-8 decoder or if we can treat this block as plain ASCII
|
// decide whether we need to use the UTF-8 decoder or if we can treat this block as plain ASCII
|
||||||
const auto ascii_fast_path = !decoder_.needs_more_input() && is_ascii(raw_bytes, raw_bytes_read);
|
const auto ascii_fast_path = !decoder_.needs_more_input() && impl::is_ascii(raw_bytes, raw_bytes_read);
|
||||||
|
|
||||||
// ASCII fast-path
|
// ASCII fast-path
|
||||||
if (ascii_fast_path)
|
if (ascii_fast_path)
|
||||||
@ -726,7 +683,7 @@ TOML_ANON_NAMESPACE_START
|
|||||||
std::string_view to_sv(const utf8_codepoint& cp) noexcept
|
std::string_view to_sv(const utf8_codepoint& cp) noexcept
|
||||||
{
|
{
|
||||||
if TOML_UNLIKELY(cp.value <= U'\x1F')
|
if TOML_UNLIKELY(cp.value <= U'\x1F')
|
||||||
return impl::low_character_escape_table[cp.value];
|
return impl::control_char_escapes[cp.value];
|
||||||
else if TOML_UNLIKELY(cp.value == U'\x7F')
|
else if TOML_UNLIKELY(cp.value == U'\x7F')
|
||||||
return "\\u007F"sv;
|
return "\\u007F"sv;
|
||||||
else
|
else
|
||||||
@ -1183,8 +1140,9 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
{
|
{
|
||||||
return_if_error_or_eof({});
|
return_if_error_or_eof({});
|
||||||
|
|
||||||
if (!is_vertical_whitespace(*cp))
|
if TOML_UNLIKELY(is_match(*cp, U'\v', U'\f'))
|
||||||
return false;
|
set_error_and_return_default(
|
||||||
|
R"(vertical tabs '\v' and form-feeds '\f' are not legal whitespace in TOML.)"sv);
|
||||||
|
|
||||||
if (*cp == U'\r')
|
if (*cp == U'\r')
|
||||||
{
|
{
|
||||||
@ -1192,10 +1150,14 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
|
|
||||||
if (is_eof())
|
if (is_eof())
|
||||||
return true; // eof after \r is 'fine'
|
return true; // eof after \r is 'fine'
|
||||||
else if (*cp != U'\n')
|
|
||||||
|
if (*cp != U'\n')
|
||||||
set_error_and_return_default("expected \\n, saw '"sv, to_sv(*cp), "'"sv);
|
set_error_and_return_default("expected \\n, saw '"sv, to_sv(*cp), "'"sv);
|
||||||
}
|
}
|
||||||
advance_and_return_if_error({}); // skip \n (or other single-character line ending)
|
else if (*cp != U'\n')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
advance_and_return_if_error({}); // skip \n
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1205,7 +1167,7 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (is_vertical_whitespace(*cp))
|
if (is_ascii_vertical_whitespace(*cp))
|
||||||
return consume_line_break();
|
return consume_line_break();
|
||||||
else
|
else
|
||||||
advance();
|
advance();
|
||||||
@ -1349,7 +1311,7 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool skipped_escaped_codepoint = false;
|
bool skip_escaped_codepoint = true;
|
||||||
assert_not_eof();
|
assert_not_eof();
|
||||||
switch (const auto escaped_codepoint = *cp)
|
switch (const auto escaped_codepoint = *cp)
|
||||||
{
|
{
|
||||||
@ -1373,9 +1335,9 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
case U'u': [[fallthrough]];
|
case U'u': [[fallthrough]];
|
||||||
case U'U':
|
case U'U':
|
||||||
{
|
{
|
||||||
push_parse_scope("unicode scalar escape sequence"sv);
|
push_parse_scope("unicode scalar sequence"sv);
|
||||||
advance_and_return_if_error_or_eof({});
|
advance_and_return_if_error_or_eof({});
|
||||||
skipped_escaped_codepoint = true;
|
skip_escaped_codepoint = false;
|
||||||
|
|
||||||
uint32_t place_value =
|
uint32_t place_value =
|
||||||
escaped_codepoint == U'U' ? 0x10000000u : (escaped_codepoint == U'u' ? 0x1000u : 0x10u);
|
escaped_codepoint == U'U' ? 0x10000000u : (escaped_codepoint == U'u' ? 0x1000u : 0x10u);
|
||||||
@ -1395,25 +1357,28 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
"unicode surrogates (U+D800 - U+DFFF) are explicitly prohibited"sv);
|
"unicode surrogates (U+D800 - U+DFFF) are explicitly prohibited"sv);
|
||||||
else if (sequence_value > 0x10FFFFu)
|
else if (sequence_value > 0x10FFFFu)
|
||||||
set_error_and_return_default("values greater than U+10FFFF are invalid"sv);
|
set_error_and_return_default("values greater than U+10FFFF are invalid"sv);
|
||||||
else if (sequence_value <= 0x7Fu) // ascii
|
|
||||||
str += static_cast<char>(sequence_value & 0x7Fu);
|
if (sequence_value < 0x80)
|
||||||
else if (sequence_value <= 0x7FFu)
|
|
||||||
{
|
{
|
||||||
str += static_cast<char>(0xC0u | ((sequence_value >> 6) & 0x1Fu));
|
str += static_cast<char>(sequence_value);
|
||||||
str += static_cast<char>(0x80u | (sequence_value & 0x3Fu));
|
|
||||||
}
|
}
|
||||||
else if (sequence_value <= 0xFFFFu)
|
else if (sequence_value < 0x800u)
|
||||||
{
|
{
|
||||||
str += static_cast<char>(0xE0u | ((sequence_value >> 12) & 0x0Fu));
|
str += static_cast<char>((sequence_value >> 6) | 0xC0u);
|
||||||
str += static_cast<char>(0x80u | ((sequence_value >> 6) & 0x1Fu));
|
str += static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
|
||||||
str += static_cast<char>(0x80u | (sequence_value & 0x3Fu));
|
|
||||||
}
|
}
|
||||||
else
|
else if (sequence_value < 0x10000u)
|
||||||
{
|
{
|
||||||
str += static_cast<char>(0xF0u | ((sequence_value >> 18) & 0x07u));
|
str += static_cast<char>((sequence_value >> 12) | 0xE0u);
|
||||||
str += static_cast<char>(0x80u | ((sequence_value >> 12) & 0x3Fu));
|
str += static_cast<char>(((sequence_value >> 6) & 0x3Fu) | 0x80u);
|
||||||
str += static_cast<char>(0x80u | ((sequence_value >> 6) & 0x3Fu));
|
str += static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
|
||||||
str += static_cast<char>(0x80u | (sequence_value & 0x3Fu));
|
}
|
||||||
|
else if (sequence_value < 0x110000u)
|
||||||
|
{
|
||||||
|
str += static_cast<char>((sequence_value >> 18) | 0xF0u);
|
||||||
|
str += static_cast<char>(((sequence_value >> 12) & 0x3Fu) | 0x80u);
|
||||||
|
str += static_cast<char>(((sequence_value >> 6) & 0x3Fu) | 0x80u);
|
||||||
|
str += static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1422,8 +1387,7 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
default: set_error_and_return_default("unknown escape sequence '\\"sv, to_sv(*cp), "'"sv);
|
default: set_error_and_return_default("unknown escape sequence '\\"sv, to_sv(*cp), "'"sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip the escaped character
|
if (skip_escaped_codepoint)
|
||||||
if (!skipped_escaped_codepoint)
|
|
||||||
advance_and_return_if_error_or_eof({});
|
advance_and_return_if_error_or_eof({});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1492,7 +1456,7 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handle line endings in multi-line mode
|
// handle line endings in multi-line mode
|
||||||
if (multi_line && is_vertical_whitespace(*cp))
|
if (multi_line && is_ascii_vertical_whitespace(*cp))
|
||||||
{
|
{
|
||||||
consume_line_break();
|
consume_line_break();
|
||||||
return_if_error({});
|
return_if_error({});
|
||||||
@ -1608,7 +1572,7 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handle line endings in multi-line mode
|
// handle line endings in multi-line mode
|
||||||
if (multi_line && is_vertical_whitespace(*cp))
|
if (multi_line && is_ascii_vertical_whitespace(*cp))
|
||||||
{
|
{
|
||||||
consume_line_break();
|
consume_line_break();
|
||||||
return_if_error({});
|
return_if_error({});
|
||||||
@ -2275,7 +2239,8 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
|
TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
|
||||||
push_parse_scope("time"sv);
|
push_parse_scope("time"sv);
|
||||||
|
|
||||||
static constexpr size_t max_digits = 9;
|
static constexpr size_t max_digits = 64; // far more than necessary but needed to allow fractional
|
||||||
|
// millisecond truncation per the spec
|
||||||
uint32_t digits[max_digits];
|
uint32_t digits[max_digits];
|
||||||
|
|
||||||
// "HH"
|
// "HH"
|
||||||
@ -2344,15 +2309,14 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
else if (!part_of_datetime && !is_value_terminator(*cp))
|
else if (!part_of_datetime && !is_value_terminator(*cp))
|
||||||
set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
|
set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t value = 0u;
|
uint32_t value = 0u;
|
||||||
uint32_t place = 1u;
|
uint32_t place = 1u;
|
||||||
for (auto i = digit_count; i-- > 0u;)
|
for (auto i = impl::min<size_t>(digit_count, 9u); i-- > 0u;)
|
||||||
{
|
{
|
||||||
value += digits[i] * place;
|
value += digits[i] * place;
|
||||||
place *= 10u;
|
place *= 10u;
|
||||||
}
|
}
|
||||||
for (auto i = digit_count; i < max_digits; i++) // implicit zeros
|
for (auto i = digit_count; i < 9u; i++) // implicit zeros
|
||||||
value *= 10u;
|
value *= 10u;
|
||||||
time.nanosecond = value;
|
time.nanosecond = value;
|
||||||
return time;
|
return time;
|
||||||
|
@ -30,28 +30,28 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
void print_to_stream(std::ostream&, char);
|
void print_to_stream(std::ostream&, char);
|
||||||
|
|
||||||
TOML_API
|
TOML_API
|
||||||
void print_to_stream(std::ostream&, int8_t, value_flags = {});
|
void print_to_stream(std::ostream&, int8_t, value_flags = {}, size_t min_digits = 0);
|
||||||
|
|
||||||
TOML_API
|
TOML_API
|
||||||
void print_to_stream(std::ostream&, int16_t, value_flags = {});
|
void print_to_stream(std::ostream&, int16_t, value_flags = {}, size_t min_digits = 0);
|
||||||
|
|
||||||
TOML_API
|
TOML_API
|
||||||
void print_to_stream(std::ostream&, int32_t, value_flags = {});
|
void print_to_stream(std::ostream&, int32_t, value_flags = {}, size_t min_digits = 0);
|
||||||
|
|
||||||
TOML_API
|
TOML_API
|
||||||
void print_to_stream(std::ostream&, int64_t, value_flags = {});
|
void print_to_stream(std::ostream&, int64_t, value_flags = {}, size_t min_digits = 0);
|
||||||
|
|
||||||
TOML_API
|
TOML_API
|
||||||
void print_to_stream(std::ostream&, uint8_t, value_flags = {});
|
void print_to_stream(std::ostream&, uint8_t, value_flags = {}, size_t min_digits = 0);
|
||||||
|
|
||||||
TOML_API
|
TOML_API
|
||||||
void print_to_stream(std::ostream&, uint16_t, value_flags = {});
|
void print_to_stream(std::ostream&, uint16_t, value_flags = {}, size_t min_digits = 0);
|
||||||
|
|
||||||
TOML_API
|
TOML_API
|
||||||
void print_to_stream(std::ostream&, uint32_t, value_flags = {});
|
void print_to_stream(std::ostream&, uint32_t, value_flags = {}, size_t min_digits = 0);
|
||||||
|
|
||||||
TOML_API
|
TOML_API
|
||||||
void print_to_stream(std::ostream&, uint64_t, value_flags = {});
|
void print_to_stream(std::ostream&, uint64_t, value_flags = {}, size_t min_digits = 0);
|
||||||
|
|
||||||
TOML_API
|
TOML_API
|
||||||
void print_to_stream(std::ostream&, float, value_flags = {});
|
void print_to_stream(std::ostream&, float, value_flags = {});
|
||||||
@ -111,24 +111,6 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline void print_to_stream_with_escapes(std::ostream & stream, const T& str)
|
|
||||||
{
|
|
||||||
for (auto c : str)
|
|
||||||
{
|
|
||||||
if TOML_UNLIKELY(c >= '\x00' && c <= '\x1F')
|
|
||||||
print_to_stream(stream, low_character_escape_table[c]);
|
|
||||||
else if TOML_UNLIKELY(c == '\x7F')
|
|
||||||
print_to_stream(stream, "\\u007F"sv);
|
|
||||||
else if TOML_UNLIKELY(c == '"')
|
|
||||||
print_to_stream(stream, "\\\""sv);
|
|
||||||
else if TOML_UNLIKELY(c == '\\')
|
|
||||||
print_to_stream(stream, "\\\\"sv);
|
|
||||||
else
|
|
||||||
print_to_stream(stream, c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
inline void print_to_stream_bookended(std::ostream & stream, const T& val, const U& bookend)
|
inline void print_to_stream_bookended(std::ostream & stream, const T& val, const U& bookend)
|
||||||
{
|
{
|
||||||
|
@ -69,11 +69,16 @@ TOML_ANON_NAMESPACE_START
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
TOML_INTERNAL_LINKAGE
|
TOML_INTERNAL_LINKAGE
|
||||||
void print_integer_to_stream(std::ostream & stream, T val, value_flags format = {})
|
void print_integer_to_stream(std::ostream & stream, T val, value_flags format = {}, size_t min_digits = 0)
|
||||||
{
|
{
|
||||||
if (!val)
|
if (!val)
|
||||||
{
|
{
|
||||||
stream.put('0');
|
if (!min_digits)
|
||||||
|
min_digits = 1;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < min_digits; i++)
|
||||||
|
stream.put('0');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +87,7 @@ TOML_ANON_NAMESPACE_START
|
|||||||
format &= value_flags_mask;
|
format &= value_flags_mask;
|
||||||
|
|
||||||
int base = 10;
|
int base = 10;
|
||||||
if (format != value_flags::none && val >= T{})
|
if (format != value_flags::none && val > T{})
|
||||||
{
|
{
|
||||||
switch (format)
|
switch (format)
|
||||||
{
|
{
|
||||||
@ -98,6 +103,8 @@ TOML_ANON_NAMESPACE_START
|
|||||||
char buf[(sizeof(T) * CHAR_BIT)];
|
char buf[(sizeof(T) * CHAR_BIT)];
|
||||||
const auto res = std::to_chars(buf, buf + sizeof(buf), val, base);
|
const auto res = std::to_chars(buf, buf + sizeof(buf), val, base);
|
||||||
const auto len = static_cast<size_t>(res.ptr - buf);
|
const auto len = static_cast<size_t>(res.ptr - buf);
|
||||||
|
for (size_t i = len; i < min_digits; i++)
|
||||||
|
stream.put('0');
|
||||||
if (base == 16)
|
if (base == 16)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < len; i++)
|
for (size_t i = 0; i < len; i++)
|
||||||
@ -111,12 +118,16 @@ TOML_ANON_NAMESPACE_START
|
|||||||
using unsigned_type = std::conditional_t<(sizeof(T) > sizeof(unsigned)), std::make_unsigned_t<T>, unsigned>;
|
using unsigned_type = std::conditional_t<(sizeof(T) > sizeof(unsigned)), std::make_unsigned_t<T>, unsigned>;
|
||||||
using cast_type = std::conditional_t<std::is_signed_v<T>, std::make_signed_t<unsigned_type>, unsigned_type>;
|
using cast_type = std::conditional_t<std::is_signed_v<T>, std::make_signed_t<unsigned_type>, unsigned_type>;
|
||||||
|
|
||||||
if TOML_UNLIKELY(format == value_flags::format_as_binary)
|
if (base == 2)
|
||||||
{
|
{
|
||||||
|
const auto len = sizeof(T) * CHAR_BIT;
|
||||||
|
for (size_t i = len; i < min_digits; i++)
|
||||||
|
stream.put('0');
|
||||||
|
|
||||||
bool found_one = false;
|
bool found_one = false;
|
||||||
const auto v = static_cast<unsigned_type>(val);
|
const auto v = static_cast<unsigned_type>(val);
|
||||||
unsigned_type mask = unsigned_type{ 1 } << (sizeof(unsigned_type) * CHAR_BIT - 1u);
|
unsigned_type mask = unsigned_type{ 1 } << (len - 1u);
|
||||||
for (unsigned i = 0; i < sizeof(unsigned_type) * CHAR_BIT; i++)
|
for (size_t i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
if ((v & mask))
|
if ((v & mask))
|
||||||
{
|
{
|
||||||
@ -133,6 +144,8 @@ TOML_ANON_NAMESPACE_START
|
|||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss.imbue(std::locale::classic());
|
ss.imbue(std::locale::classic());
|
||||||
ss << std::uppercase << std::setbase(base);
|
ss << std::uppercase << std::setbase(base);
|
||||||
|
if (min_digits)
|
||||||
|
ss << std::setfill('0') << std::setw(static_cast<int>(min_digits));
|
||||||
ss << static_cast<cast_type>(val);
|
ss << static_cast<cast_type>(val);
|
||||||
const auto str = std::move(ss).str();
|
const auto str = std::move(ss).str();
|
||||||
impl::print_to_stream(stream, str);
|
impl::print_to_stream(stream, str);
|
||||||
@ -194,31 +207,6 @@ TOML_ANON_NAMESPACE_START
|
|||||||
default: TOML_UNREACHABLE;
|
default: TOML_UNREACHABLE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
TOML_INTERNAL_LINKAGE
|
|
||||||
void print_integer_leftpad_zeros(std::ostream & stream, T val, size_t min_digits)
|
|
||||||
{
|
|
||||||
#if TOML_INT_CHARCONV
|
|
||||||
|
|
||||||
char buf[charconv_buffer_length<T>];
|
|
||||||
const auto res = std::to_chars(buf, buf + sizeof(buf), val);
|
|
||||||
const auto len = static_cast<size_t>(res.ptr - buf);
|
|
||||||
for (size_t i = len; i < min_digits; i++)
|
|
||||||
stream.put('0');
|
|
||||||
impl::print_to_stream(stream, buf, static_cast<size_t>(res.ptr - buf));
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss.imbue(std::locale::classic());
|
|
||||||
using cast_type = std::conditional_t<std::is_signed_v<T>, int64_t, uint64_t>;
|
|
||||||
ss << std::setfill('0') << std::setw(static_cast<int>(min_digits)) << static_cast<cast_type>(val);
|
|
||||||
const auto str = std::move(ss).str();
|
|
||||||
impl::print_to_stream(stream, str);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
TOML_ANON_NAMESPACE_END;
|
TOML_ANON_NAMESPACE_END;
|
||||||
|
|
||||||
@ -250,51 +238,51 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
}
|
}
|
||||||
|
|
||||||
TOML_EXTERNAL_LINKAGE
|
TOML_EXTERNAL_LINKAGE
|
||||||
void print_to_stream(std::ostream & stream, int8_t val, value_flags format)
|
void print_to_stream(std::ostream & stream, int8_t val, value_flags format, size_t min_digits)
|
||||||
{
|
{
|
||||||
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format);
|
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
|
||||||
}
|
}
|
||||||
|
|
||||||
TOML_EXTERNAL_LINKAGE
|
TOML_EXTERNAL_LINKAGE
|
||||||
void print_to_stream(std::ostream & stream, int16_t val, value_flags format)
|
void print_to_stream(std::ostream & stream, int16_t val, value_flags format, size_t min_digits)
|
||||||
{
|
{
|
||||||
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format);
|
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
|
||||||
}
|
}
|
||||||
|
|
||||||
TOML_EXTERNAL_LINKAGE
|
TOML_EXTERNAL_LINKAGE
|
||||||
void print_to_stream(std::ostream & stream, int32_t val, value_flags format)
|
void print_to_stream(std::ostream & stream, int32_t val, value_flags format, size_t min_digits)
|
||||||
{
|
{
|
||||||
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format);
|
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
|
||||||
}
|
}
|
||||||
|
|
||||||
TOML_EXTERNAL_LINKAGE
|
TOML_EXTERNAL_LINKAGE
|
||||||
void print_to_stream(std::ostream & stream, int64_t val, value_flags format)
|
void print_to_stream(std::ostream & stream, int64_t val, value_flags format, size_t min_digits)
|
||||||
{
|
{
|
||||||
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format);
|
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
|
||||||
}
|
}
|
||||||
|
|
||||||
TOML_EXTERNAL_LINKAGE
|
TOML_EXTERNAL_LINKAGE
|
||||||
void print_to_stream(std::ostream & stream, uint8_t val, value_flags format)
|
void print_to_stream(std::ostream & stream, uint8_t val, value_flags format, size_t min_digits)
|
||||||
{
|
{
|
||||||
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format);
|
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
|
||||||
}
|
}
|
||||||
|
|
||||||
TOML_EXTERNAL_LINKAGE
|
TOML_EXTERNAL_LINKAGE
|
||||||
void print_to_stream(std::ostream & stream, uint16_t val, value_flags format)
|
void print_to_stream(std::ostream & stream, uint16_t val, value_flags format, size_t min_digits)
|
||||||
{
|
{
|
||||||
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format);
|
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
|
||||||
}
|
}
|
||||||
|
|
||||||
TOML_EXTERNAL_LINKAGE
|
TOML_EXTERNAL_LINKAGE
|
||||||
void print_to_stream(std::ostream & stream, uint32_t val, value_flags format)
|
void print_to_stream(std::ostream & stream, uint32_t val, value_flags format, size_t min_digits)
|
||||||
{
|
{
|
||||||
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format);
|
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
|
||||||
}
|
}
|
||||||
|
|
||||||
TOML_EXTERNAL_LINKAGE
|
TOML_EXTERNAL_LINKAGE
|
||||||
void print_to_stream(std::ostream & stream, uint64_t val, value_flags format)
|
void print_to_stream(std::ostream & stream, uint64_t val, value_flags format, size_t min_digits)
|
||||||
{
|
{
|
||||||
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format);
|
TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
|
||||||
}
|
}
|
||||||
|
|
||||||
TOML_EXTERNAL_LINKAGE
|
TOML_EXTERNAL_LINKAGE
|
||||||
@ -318,21 +306,21 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
TOML_EXTERNAL_LINKAGE
|
TOML_EXTERNAL_LINKAGE
|
||||||
void print_to_stream(std::ostream & stream, const toml::date& val)
|
void print_to_stream(std::ostream & stream, const toml::date& val)
|
||||||
{
|
{
|
||||||
print_integer_leftpad_zeros(stream, val.year, 4u);
|
print_to_stream(stream, val.year, {}, 4);
|
||||||
stream.put('-');
|
stream.put('-');
|
||||||
print_integer_leftpad_zeros(stream, val.month, 2u);
|
print_to_stream(stream, val.month, {}, 2);
|
||||||
stream.put('-');
|
stream.put('-');
|
||||||
print_integer_leftpad_zeros(stream, val.day, 2u);
|
print_to_stream(stream, val.day, {}, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
TOML_EXTERNAL_LINKAGE
|
TOML_EXTERNAL_LINKAGE
|
||||||
void print_to_stream(std::ostream & stream, const toml::time& val)
|
void print_to_stream(std::ostream & stream, const toml::time& val)
|
||||||
{
|
{
|
||||||
print_integer_leftpad_zeros(stream, val.hour, 2u);
|
print_to_stream(stream, val.hour, {}, 2);
|
||||||
stream.put(':');
|
stream.put(':');
|
||||||
print_integer_leftpad_zeros(stream, val.minute, 2u);
|
print_to_stream(stream, val.minute, {}, 2);
|
||||||
stream.put(':');
|
stream.put(':');
|
||||||
print_integer_leftpad_zeros(stream, val.second, 2u);
|
print_to_stream(stream, val.second, {}, 2);
|
||||||
if (val.nanosecond && val.nanosecond <= 999999999u)
|
if (val.nanosecond && val.nanosecond <= 999999999u)
|
||||||
{
|
{
|
||||||
stream.put('.');
|
stream.put('.');
|
||||||
@ -343,7 +331,7 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
ns /= 10u;
|
ns /= 10u;
|
||||||
digits--;
|
digits--;
|
||||||
}
|
}
|
||||||
print_integer_leftpad_zeros(stream, ns, digits);
|
print_to_stream(stream, ns, {}, digits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,13 +355,13 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
const auto hours = mins / 60;
|
const auto hours = mins / 60;
|
||||||
if (hours)
|
if (hours)
|
||||||
{
|
{
|
||||||
print_integer_leftpad_zeros(stream, static_cast<unsigned int>(hours), 2u);
|
print_to_stream(stream, static_cast<unsigned int>(hours), {}, 2);
|
||||||
mins -= hours * 60;
|
mins -= hours * 60;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
print_to_stream(stream, "00"sv);
|
print_to_stream(stream, "00"sv);
|
||||||
stream.put(':');
|
stream.put(':');
|
||||||
print_integer_leftpad_zeros(stream, static_cast<unsigned int>(mins), 2u);
|
print_to_stream(stream, static_cast<unsigned int>(mins), {}, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
TOML_EXTERNAL_LINKAGE
|
TOML_EXTERNAL_LINKAGE
|
||||||
|
@ -68,8 +68,8 @@ TOML_NAMESPACE_START
|
|||||||
TOML_API
|
TOML_API
|
||||||
void print();
|
void print();
|
||||||
|
|
||||||
static constexpr impl::formatter_constants constants = { format_flags::none, // mandatory flags
|
static constexpr impl::formatter_constants constants = { format_flags::none, // mandatory
|
||||||
format_flags::none, // ignored flags
|
format_flags::none, // ignored
|
||||||
"inf"sv,
|
"inf"sv,
|
||||||
"-inf"sv,
|
"-inf"sv,
|
||||||
"nan"sv,
|
"nan"sv,
|
||||||
@ -83,6 +83,7 @@ TOML_NAMESPACE_START
|
|||||||
static constexpr format_flags default_flags = constants.mandatory_flags //
|
static constexpr format_flags default_flags = constants.mandatory_flags //
|
||||||
| format_flags::allow_literal_strings //
|
| format_flags::allow_literal_strings //
|
||||||
| format_flags::allow_multi_line_strings //
|
| format_flags::allow_multi_line_strings //
|
||||||
|
| format_flags::allow_unicode_strings //
|
||||||
| format_flags::allow_real_tabs_in_strings //
|
| format_flags::allow_real_tabs_in_strings //
|
||||||
| format_flags::allow_binary_integers //
|
| format_flags::allow_binary_integers //
|
||||||
| format_flags::allow_octal_integers //
|
| format_flags::allow_octal_integers //
|
||||||
|
@ -14,10 +14,10 @@
|
|||||||
|
|
||||||
#include "toml_formatter.h"
|
#include "toml_formatter.h"
|
||||||
#include "print_to_stream.h"
|
#include "print_to_stream.h"
|
||||||
#include "utf8.h"
|
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
#include "table.h"
|
#include "table.h"
|
||||||
#include "array.h"
|
#include "array.h"
|
||||||
|
#include "unicode.h"
|
||||||
#include "header_start.h"
|
#include "header_start.h"
|
||||||
TOML_DISABLE_ARITHMETIC_WARNINGS;
|
TOML_DISABLE_ARITHMETIC_WARNINGS;
|
||||||
|
|
||||||
|
@ -102,15 +102,21 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
}
|
}
|
||||||
|
|
||||||
TOML_CONST_GETTER
|
TOML_CONST_GETTER
|
||||||
constexpr bool is_vertical_whitespace(char32_t c) noexcept
|
constexpr bool is_ascii_vertical_whitespace(char32_t c) noexcept
|
||||||
{
|
{
|
||||||
return (U'\n' <= c && c <= U'\r') || (U'\u2028' <= c && c <= U'\u2029') || c == U'\x85';
|
return U'\n' <= c && c <= U'\r';
|
||||||
}
|
}
|
||||||
|
|
||||||
TOML_CONST_GETTER
|
TOML_CONST_GETTER
|
||||||
constexpr bool is_vertical_whitespace_excl_cr(char32_t c) noexcept
|
constexpr bool is_non_ascii_vertical_whitespace(char32_t c) noexcept
|
||||||
{
|
{
|
||||||
return (U'\n' <= c && c <= U'\f') || (U'\u2028' <= c && c <= U'\u2029') || c == U'\x85';
|
return (U'\u2028' <= c && c <= U'\u2029') || c == U'\x85';
|
||||||
|
}
|
||||||
|
|
||||||
|
TOML_CONST_GETTER
|
||||||
|
constexpr bool is_vertical_whitespace(char32_t c) noexcept
|
||||||
|
{
|
||||||
|
return is_ascii_vertical_whitespace(c) || is_non_ascii_vertical_whitespace(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
TOML_CONST_GETTER
|
TOML_CONST_GETTER
|
||||||
@ -122,6 +128,11 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
TOML_CONST_GETTER
|
TOML_CONST_GETTER
|
||||||
constexpr bool is_ascii_bare_key_character(char32_t c) noexcept
|
constexpr bool is_ascii_bare_key_character(char32_t c) noexcept
|
||||||
{
|
{
|
||||||
|
#if TOML_LANG_UNRELEASED // toml/issues/644 ('+' in bare keys)
|
||||||
|
if (c == U'+')
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (c < U'-' || c > U'z')
|
if (c < U'-' || c > U'z')
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -861,8 +872,7 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
constexpr bool is_bare_key_character(char32_t c) noexcept
|
constexpr bool is_bare_key_character(char32_t c) noexcept
|
||||||
{
|
{
|
||||||
return is_ascii_bare_key_character(c)
|
return is_ascii_bare_key_character(c)
|
||||||
#if TOML_LANG_UNRELEASED // toml/issues/644 ('+' in bare keys) & toml/issues/687 (unicode bare keys)
|
#if TOML_LANG_UNRELEASED // toml/issues/687 (unicode bare keys)
|
||||||
|| c == U'+' //
|
|
||||||
|| is_non_ascii_bare_key_character(c)
|
|| is_non_ascii_bare_key_character(c)
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
@ -874,6 +884,12 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
return is_whitespace(c) || c == U']' || c == U'}' || c == U',' || c == U'#';
|
return is_whitespace(c) || c == U']' || c == U'}' || c == U',' || c == U'#';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TOML_CONST_GETTER
|
||||||
|
constexpr bool is_control_character(char c) noexcept
|
||||||
|
{
|
||||||
|
return c <= '\u001F' || c == '\u007F';
|
||||||
|
}
|
||||||
|
|
||||||
TOML_CONST_GETTER
|
TOML_CONST_GETTER
|
||||||
constexpr bool is_control_character(char32_t c) noexcept
|
constexpr bool is_control_character(char32_t c) noexcept
|
||||||
{
|
{
|
||||||
@ -949,12 +965,22 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
state = state_table[state + uint_least32_t{ 256u } + type];
|
state = state_table[state + uint_least32_t{ 256u } + type];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TOML_ALWAYS_INLINE
|
||||||
|
constexpr void operator()(char c) noexcept
|
||||||
|
{
|
||||||
|
operator()(static_cast<uint8_t>(c));
|
||||||
|
}
|
||||||
|
|
||||||
TOML_ALWAYS_INLINE
|
TOML_ALWAYS_INLINE
|
||||||
constexpr void reset() noexcept
|
constexpr void reset() noexcept
|
||||||
{
|
{
|
||||||
state = {};
|
state = {};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TOML_PURE_GETTER
|
||||||
|
TOML_ATTR(nonnull)
|
||||||
|
bool is_ascii(const char* str, size_t len) noexcept;
|
||||||
}
|
}
|
||||||
TOML_IMPL_NAMESPACE_END;
|
TOML_IMPL_NAMESPACE_END;
|
||||||
|
|
59
include/toml++/impl/unicode.inl
Normal file
59
include/toml++/impl/unicode.inl
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
//# 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.h"
|
||||||
|
#if !TOML_IMPLEMENTATION
|
||||||
|
#error This is an implementation-only header.
|
||||||
|
#endif
|
||||||
|
//# }}
|
||||||
|
|
||||||
|
#include "unicode.h"
|
||||||
|
#include "simd.h"
|
||||||
|
#include "header_start.h"
|
||||||
|
|
||||||
|
TOML_IMPL_NAMESPACE_START
|
||||||
|
{
|
||||||
|
TOML_EXTERNAL_LINKAGE
|
||||||
|
bool is_ascii(const char* str, size_t len) noexcept
|
||||||
|
{
|
||||||
|
const char* const end = str + len;
|
||||||
|
|
||||||
|
#if TOML_HAS_SSE2 && (128 % CHAR_BIT) == 0
|
||||||
|
{
|
||||||
|
constexpr size_t chars_per_vector = 128u / CHAR_BIT;
|
||||||
|
|
||||||
|
if (const size_t simdable = len - (len % chars_per_vector))
|
||||||
|
{
|
||||||
|
__m128i mask = _mm_setzero_si128();
|
||||||
|
for (const char* const e = str + simdable; str < e; str += chars_per_vector)
|
||||||
|
{
|
||||||
|
const __m128i current_bytes = _mm_loadu_si128(reinterpret_cast<const __m128i*>(str));
|
||||||
|
mask = _mm_or_si128(mask, current_bytes);
|
||||||
|
}
|
||||||
|
const __m128i has_error = _mm_cmpgt_epi8(_mm_setzero_si128(), mask);
|
||||||
|
|
||||||
|
#if TOML_HAS_SSE4_1
|
||||||
|
if (!_mm_testz_si128(has_error, has_error))
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
if (_mm_movemask_epi8(_mm_cmpeq_epi8(has_error, _mm_setzero_si128())) != 0xFFFF)
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (; str < end; str++)
|
||||||
|
if (static_cast<unsigned char>(*str) > 127u)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TOML_IMPL_NAMESPACE_END;
|
||||||
|
|
||||||
|
#include "header_end.h"
|
@ -73,6 +73,7 @@ TOML_NAMESPACE_START
|
|||||||
/// \brief The default flags for a yaml_formatter.
|
/// \brief The default flags for a yaml_formatter.
|
||||||
static constexpr format_flags default_flags = constants.mandatory_flags //
|
static constexpr format_flags default_flags = constants.mandatory_flags //
|
||||||
| format_flags::allow_literal_strings //
|
| format_flags::allow_literal_strings //
|
||||||
|
| format_flags::allow_unicode_strings //
|
||||||
| format_flags::allow_octal_integers //
|
| format_flags::allow_octal_integers //
|
||||||
| format_flags::allow_hexadecimal_integers;
|
| format_flags::allow_hexadecimal_integers;
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ TOML_DISABLE_SUGGEST_ATTR_WARNINGS;
|
|||||||
#include "impl/array.h"
|
#include "impl/array.h"
|
||||||
#include "impl/key.h"
|
#include "impl/key.h"
|
||||||
#include "impl/table.h"
|
#include "impl/table.h"
|
||||||
#include "impl/utf8.h"
|
#include "impl/unicode.h"
|
||||||
#include "impl/parse_error.h"
|
#include "impl/parse_error.h"
|
||||||
#include "impl/parse_result.h"
|
#include "impl/parse_result.h"
|
||||||
#include "impl/parser.h"
|
#include "impl/parser.h"
|
||||||
@ -57,6 +57,7 @@ TOML_DISABLE_SUGGEST_ATTR_WARNINGS;
|
|||||||
#include "impl/value.inl"
|
#include "impl/value.inl"
|
||||||
#include "impl/array.inl"
|
#include "impl/array.inl"
|
||||||
#include "impl/table.inl"
|
#include "impl/table.inl"
|
||||||
|
#include "impl/unicode.inl"
|
||||||
#include "impl/parser.inl"
|
#include "impl/parser.inl"
|
||||||
#include "impl/formatter.inl"
|
#include "impl/formatter.inl"
|
||||||
#include "impl/toml_formatter.inl"
|
#include "impl/toml_formatter.inl"
|
||||||
|
@ -24,7 +24,7 @@ namespace
|
|||||||
friend std::ostream& operator<<(std::ostream& os, const char32_printer& p)
|
friend std::ostream& operator<<(std::ostream& os, const char32_printer& p)
|
||||||
{
|
{
|
||||||
if (p.value <= U'\x1F')
|
if (p.value <= U'\x1F')
|
||||||
return os << '\'' << impl::low_character_escape_table[static_cast<size_t>(p.value)] << '\'';
|
return os << '\'' << impl::control_char_escapes[static_cast<size_t>(p.value)] << '\'';
|
||||||
else if (p.value == U'\x7F')
|
else if (p.value == U'\x7F')
|
||||||
return os << "'\\u007F'"sv;
|
return os << "'\\u007F'"sv;
|
||||||
else if (p.value < 127u)
|
else if (p.value < 127u)
|
||||||
@ -52,6 +52,7 @@ namespace
|
|||||||
{
|
{
|
||||||
string_difference diff{ { 1u, 1u } };
|
string_difference diff{ { 1u, 1u } };
|
||||||
impl::utf8_decoder a, b;
|
impl::utf8_decoder a, b;
|
||||||
|
|
||||||
for (size_t i = 0, e = std::min(str_a.length(), str_b.length()); i < e; i++, diff.index++)
|
for (size_t i = 0, e = std::min(str_a.length(), str_b.length()); i < e; i++, diff.index++)
|
||||||
{
|
{
|
||||||
a(static_cast<uint8_t>(str_a[i]));
|
a(static_cast<uint8_t>(str_a[i]));
|
||||||
@ -76,7 +77,7 @@ namespace
|
|||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (impl::is_vertical_whitespace_excl_cr(a.codepoint))
|
if (a.codepoint == U'\n')
|
||||||
{
|
{
|
||||||
diff.position.line++;
|
diff.position.line++;
|
||||||
diff.position.column = 1u;
|
diff.position.column = 1u;
|
||||||
|
@ -198,9 +198,9 @@ inline bool parse_expected_value(std::string_view test_file,
|
|||||||
if (!decoder.has_code_point())
|
if (!decoder.has_code_point())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (impl::is_vertical_whitespace_excl_cr(decoder.codepoint))
|
if (impl::is_ascii_vertical_whitespace(decoder.codepoint))
|
||||||
{
|
{
|
||||||
if (decoder.codepoint != U'\r')
|
if (decoder.codepoint == U'\n')
|
||||||
{
|
{
|
||||||
pos.line++;
|
pos.line++;
|
||||||
pos.column = source_index{ 1 };
|
pos.column = source_index{ 1 };
|
||||||
|
@ -192,4 +192,42 @@ b = []
|
|||||||
)",
|
)",
|
||||||
4);
|
4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("github/issues/125") // https://github.com/marzer/tomlplusplus/issues/125
|
||||||
|
{
|
||||||
|
parse_expected_value(FILE_LINE_ARGS, R"("\u0800")"sv, "\xE0\xA0\x80"sv);
|
||||||
|
parse_expected_value(FILE_LINE_ARGS, R"("\u7840")"sv, "\xE7\xA1\x80"sv);
|
||||||
|
parse_expected_value(FILE_LINE_ARGS, R"("\uAA23")"sv, "\xEA\xA8\xA3"sv);
|
||||||
|
parse_expected_value(FILE_LINE_ARGS, R"("\uA928")"sv, "\xEA\xA4\xA8"sv);
|
||||||
|
parse_expected_value(FILE_LINE_ARGS, R"("\u9CBF")"sv, "\xE9\xB2\xBF"sv);
|
||||||
|
parse_expected_value(FILE_LINE_ARGS, R"("\u2247")"sv, "\xE2\x89\x87"sv);
|
||||||
|
parse_expected_value(FILE_LINE_ARGS, R"("\u13D9")"sv, "\xE1\x8F\x99"sv);
|
||||||
|
parse_expected_value(FILE_LINE_ARGS, R"("\u69FC")"sv, "\xE6\xA7\xBC"sv);
|
||||||
|
parse_expected_value(FILE_LINE_ARGS, R"("\u8DE5")"sv, "\xE8\xB7\xA5"sv);
|
||||||
|
parse_expected_value(FILE_LINE_ARGS, R"("\u699C")"sv, "\xE6\xA6\x9C"sv);
|
||||||
|
parse_expected_value(FILE_LINE_ARGS, R"("\u8CD4")"sv, "\xE8\xB3\x94"sv);
|
||||||
|
parse_expected_value(FILE_LINE_ARGS, R"("\u4ED4")"sv, "\xE4\xBB\x94"sv);
|
||||||
|
parse_expected_value(FILE_LINE_ARGS, R"("\u2597")"sv, "\xE2\x96\x97"sv);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("github/issues/127") // https://github.com/marzer/tomlplusplus/issues/127
|
||||||
|
{
|
||||||
|
parse_expected_value(FILE_LINE_ARGS,
|
||||||
|
"12:34:56.11122233345678"sv,
|
||||||
|
toml::time{
|
||||||
|
12,
|
||||||
|
34,
|
||||||
|
56,
|
||||||
|
111222333u // should truncate the .45678 part
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("github/issues/128") // https://github.com/marzer/tomlplusplus/issues/128
|
||||||
|
{
|
||||||
|
parsing_should_fail(FILE_LINE_ARGS, "\f"sv);
|
||||||
|
parsing_should_fail(FILE_LINE_ARGS, "\v"sv);
|
||||||
|
parsing_should_succeed(FILE_LINE_ARGS, " "sv);
|
||||||
|
parsing_should_succeed(FILE_LINE_ARGS, "\t"sv);
|
||||||
|
parsing_should_succeed(FILE_LINE_ARGS, "\n"sv);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@
|
|||||||
<ClInclude Include="include\toml++\impl\std_vector.h" />
|
<ClInclude Include="include\toml++\impl\std_vector.h" />
|
||||||
<ClInclude Include="include\toml++\impl\table.h" />
|
<ClInclude Include="include\toml++\impl\table.h" />
|
||||||
<ClInclude Include="include\toml++\impl\table.inl" />
|
<ClInclude Include="include\toml++\impl\table.inl" />
|
||||||
<ClInclude Include="include\toml++\impl\utf8.h" />
|
<ClInclude Include="include\toml++\impl\unicode.h" />
|
||||||
<ClInclude Include="include\toml++\impl\value.h" />
|
<ClInclude Include="include\toml++\impl\value.h" />
|
||||||
<ClInclude Include="include\toml++\impl\value.inl" />
|
<ClInclude Include="include\toml++\impl\value.inl" />
|
||||||
<ClInclude Include="include\toml++\impl\value_extern.inl" />
|
<ClInclude Include="include\toml++\impl\value_extern.inl" />
|
||||||
@ -95,6 +95,7 @@
|
|||||||
<None Include="CHANGELOG.md" />
|
<None Include="CHANGELOG.md" />
|
||||||
<None Include="CODE_OF_CONDUCT.md" />
|
<None Include="CODE_OF_CONDUCT.md" />
|
||||||
<None Include="CONTRIBUTING.md" />
|
<None Include="CONTRIBUTING.md" />
|
||||||
|
<None Include="include\toml++\impl\unicode.inl" />
|
||||||
<None Include="include\toml++\impl\node_view_extern.inl" />
|
<None Include="include\toml++\impl\node_view_extern.inl" />
|
||||||
<None Include="include\toml++\impl\yaml_formatter.inl" />
|
<None Include="include\toml++\impl\yaml_formatter.inl" />
|
||||||
<None Include="LICENSE" />
|
<None Include="LICENSE" />
|
||||||
|
@ -61,7 +61,7 @@
|
|||||||
<ClInclude Include="include\toml++\impl\table.inl">
|
<ClInclude Include="include\toml++\impl\table.inl">
|
||||||
<Filter>include\impl</Filter>
|
<Filter>include\impl</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="include\toml++\impl\utf8.h">
|
<ClInclude Include="include\toml++\impl\unicode.h">
|
||||||
<Filter>include\impl</Filter>
|
<Filter>include\impl</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="include\toml++\impl\value.h">
|
<ClInclude Include="include\toml++\impl\value.h">
|
||||||
@ -214,6 +214,9 @@
|
|||||||
<None Include="tools\generate_single_header.bat">
|
<None Include="tools\generate_single_header.bat">
|
||||||
<Filter>tools</Filter>
|
<Filter>tools</Filter>
|
||||||
</None>
|
</None>
|
||||||
|
<None Include="include\toml++\impl\unicode.inl">
|
||||||
|
<Filter>include\impl</Filter>
|
||||||
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include=".circleci">
|
<Filter Include=".circleci">
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
#include "tt.hpp"
|
#include "tt.h"
|
||||||
|
|
||||||
using nlohmann::json;
|
using nlohmann::json;
|
||||||
using namespace std::string_view_literals;
|
using namespace std::string_view_literals;
|
||||||
@ -85,30 +85,29 @@ TOML_NAMESPACE_END;
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
json j;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
const std::string str(std::istreambuf_iterator<char>{ std::cin }, std::istreambuf_iterator<char>{});
|
const std::string str(std::istreambuf_iterator<char>{ std::cin }, std::istreambuf_iterator<char>{});
|
||||||
|
|
||||||
j = toml::parse(str, "stdin"sv);
|
json j = toml::parse(str, "stdin"sv);
|
||||||
|
|
||||||
|
std::cout << j << "\n";
|
||||||
}
|
}
|
||||||
catch (const toml::parse_error& err)
|
catch (const toml::parse_error& err)
|
||||||
{
|
{
|
||||||
std::cerr << err << "\n";
|
std::cerr << "\n\n" << err << "\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
catch (const std::exception& exc)
|
catch (const std::exception& exc)
|
||||||
{
|
{
|
||||||
std::cerr << exc.what() << "\n";
|
std::cerr << "\n\n" << exc.what() << "\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
std::cerr << "An unspecified error occurred.\n";
|
std::cerr << "\n\nAn unspecified error occurred.\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << j << "\n";
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
<None Include="README.md" />
|
<None Include="README.md" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="tt.hpp" />
|
<ClInclude Include="tt.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
</Project>
|
</Project>
|
@ -3,7 +3,7 @@
|
|||||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
#include "tt.hpp"
|
#include "tt.h"
|
||||||
|
|
||||||
using nlohmann::json;
|
using nlohmann::json;
|
||||||
using namespace std::string_view_literals;
|
using namespace std::string_view_literals;
|
||||||
@ -191,12 +191,13 @@ TOML_NAMESPACE_END;
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
toml::table tbl;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
const std::string str(std::istreambuf_iterator<char>{ std::cin }, std::istreambuf_iterator<char>{});
|
const std::string str(std::istreambuf_iterator<char>{ std::cin }, std::istreambuf_iterator<char>{});
|
||||||
|
|
||||||
tbl = json::parse(str);
|
toml::table tbl = json::parse(str);
|
||||||
|
|
||||||
|
std::cout << tbl << "\n";
|
||||||
}
|
}
|
||||||
catch (const std::exception& exc)
|
catch (const std::exception& exc)
|
||||||
{
|
{
|
||||||
@ -209,7 +210,5 @@ int main()
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << tbl << "\n";
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
<None Include="README.md" />
|
<None Include="README.md" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="tt.hpp" />
|
<ClInclude Include="tt.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
</Project>
|
</Project>
|
Loading…
Reference in New Issue
Block a user