fixed potential ODR issues relating to exception mode handling (fixes #6)

also:
- fixed truncation of floating-point values when using ostreams
- fixed some minor documentation issues (fixes #8)
- fixed missing value deduction guides for dates and times
- added serialization round-trip tests (closes #9)
- added node::is_number()
- added node_view::is_number()
- added node_view::value_or() (closes #7)
- added hexfloat parsing support for all implementations, not just <charconv> ones
This commit is contained in:
Mark Gillard 2020-02-22 16:10:32 +02:00
parent 2219fd22bb
commit 3d653de7c9
24 changed files with 453 additions and 188 deletions

View File

@ -5,6 +5,13 @@
[![GitHub](https://img.shields.io/github/license/marzer/tomlplusplus)](https://github.com/marzer/tomlplusplus/blob/master/LICENSE)
`toml++` is a header-only toml parser and serializer for C++17, C++20 and whatever comes after.
- Fully [TOML v0.5.0]-compliant
- Modern C++17 (with some C++20 features where supported)
- Proper UTF-8 handling (incl. BOM)
- Works with or without exceptions
- Doesn't require RTTI
- First-class support for serializing to JSON
- Supports a number of 'unreleased' TOML features (optional)
<br>
@ -25,10 +32,10 @@ Reading it in C++ is easy with `toml++`:
auto config = toml::parse_file( "configuration.toml" );
// get key-value pairs
std::string_view library_name = config["library"]["name"].as_string()->get();
std::string_view library_version = config["library"]["version"].as_string()->get();
std::string_view library_author = config["library"]["authors"][0].as_string()->get();
int64_t depends_on_cpp_version = config["dependencies"]["cpp"].as_integer()->get();
std::string_view library_name = config["library"]["name"].value_or(""sv);
std::string_view library_version = config["library"]["version"].value_or(""sv);
std::string_view library_author = config["library"]["authors"][0].value_or(""sv);
int64_t depends_on_cpp_version = config["dependencies"]["cpp"].value_or(0);
// modify the data
config.insert_or_assign("alternatives", toml::array{
@ -80,7 +87,7 @@ won't need to mess with these at all, butif you do, set them before including to
| Option | Type | Default | Description |
|----------------------------|:--------------:|-----------------------------------|----------------------------------------------------------------------------------------------------------|
| `TOML_ASSERT(expr)` | function macro | `assert(expr)`<br>(or undefined) | Sets the assert function used by the library. |
| `TOML_CHAR_8_STRINGS` | boolean | `0` | Uses C++20 [char8_t]-based strings as the toml string data type. |
| `TOML_CHAR_8_STRINGS` | boolean | `0` | Uses C++20 [char8_t]-based strings as the toml string data type. **_Experimental!_** |
| `TOML_CONFIG_HEADER` | string literal | undefined | Includes the given header file before the rest of the library. |
| `TOML_LARGE_FILES` | boolean | `0` | Uses 32-bit integers for line and column indices (instead of 16-bit). |
| `TOML_SMALL_FLOAT_TYPE` | type name | undefined | If your codebase has an additional 'small' float type (e.g. half-precision), this tells toml++ about it. |

View File

@ -339,6 +339,9 @@ PREDEFINED = TOML_DOXYGEN=1 \
TOML_ALWAYS_INLINE=inline \
TOML_MAY_THROW= \
TOML_NODISCARD_CTOR= \
TOML_ASYMMETRICAL_EQUALITY_OPS= \
TOML_START="namespace toml" \
TOML_END= \
__cpp_lib_char8_t=201811L
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = NO

View File

@ -1,6 +1,6 @@
#include <toml++/toml.h>
#include <iostream>
#include <fstream>
#include <toml++/toml.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
@ -22,9 +22,8 @@ int main(int argc, char** argv)
}
try
{
const auto table = toml::parse(file, std::move(path));
std::cout << table << std::endl;
const auto tbl = toml::parse(file, std::move(path));
std::cout << tbl << std::endl;
}
catch (const toml::parse_error& err)
{

View File

@ -1,6 +1,6 @@
#include <toml++/toml.h>
#include <iostream>
#include <fstream>
#include <toml++/toml.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

View File

@ -20,7 +20,6 @@
// macro hygiene
#if TOML_UNDEF_MACROS
#undef TOML_EXCEPTIONS
#undef TOML_USE_STREAMS_FOR_FLOATS
#undef TOML_GCC_ATTR
#undef TOML_PUSH_WARNINGS
@ -54,6 +53,10 @@
#undef TOML_DOXYGEN
#undef TOML_RELOPS_REORDERING
#undef TOML_ASYMMETRICAL_EQUALITY_OPS
#undef TOML_START
#undef TOML_END
#undef TOML_IMPL_START
#undef TOML_IMPL_END
#endif
/// \mainpage toml++
@ -126,7 +129,7 @@
///
/// \ecpp
///
/// When exceptions are disabled parsing methods return a toml::parse_error and it is up to the caller
/// When exceptions are disabled parsing methods return a toml::parse_result and it is up to the caller
/// to check if parsing has been successful by examining the return value:
/// \cpp
/// #include <iostream>
@ -151,7 +154,11 @@
/// return 0;
/// }
/// \ecpp
/// \see toml::parse_file()
///
/// \see
/// - toml::parse_file()
/// - toml::parse_result
/// - toml::parse_error
///
///////////////////////////////////
///
@ -189,7 +196,7 @@
/// name = "toml++"
/// version = "0.1.0"
/// \eout
/// \see toml::parse()
/// \see toml::parse()
///
///////////////////////////////////
///
@ -252,7 +259,11 @@
/// 'dinosaurs':
/// \eout
///
/// \see toml::node, toml::node_view, toml::array, toml::table
/// \see
/// - toml::node
/// - toml::node_view
/// - toml::array
/// - toml::table
///
///////////////////////////////////
///
@ -317,7 +328,9 @@
/// ]
/// }
/// \eout
/// \see toml::default_formatter, toml::json_formatter
/// \see
/// - toml::default_formatter
/// - toml::json_formatter
///
///////////////////////////////////////////////////////////////////////
///

View File

@ -1,7 +1,7 @@
#pragma once
#include "toml_value.h"
namespace toml::impl
TOML_IMPL_START
{
template <bool is_const>
class array_iterator final
@ -174,8 +174,9 @@ namespace toml::impl
}
}
}
TOML_IMPL_END
namespace toml
TOML_START
{
[[nodiscard]] bool operator == (const table& lhs, const table& rhs) noexcept;
@ -945,3 +946,4 @@ namespace toml
friend inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>&, const array&) TOML_MAY_THROW;
};
}
TOML_END

View File

@ -229,6 +229,17 @@
__VA_ARGS__ [[nodiscard]] friend bool operator != (RHS rhs, LHS lhs) noexcept { return !(lhs == rhs); }
#endif
#if !TOML_DOXYGEN
#if TOML_EXCEPTIONS
#define TOML_START namespace toml { inline namespace wex
#else
#define TOML_START namespace toml { inline namespace woex
#endif
#define TOML_END }
#endif
#define TOML_IMPL_START TOML_START { namespace impl
#define TOML_IMPL_END } TOML_END
#include "toml_version.h"
#define TOML_MAKE_VERSION(maj, min, rev) \
@ -292,7 +303,9 @@ TOML_POP_WARNINGS
// clang-format on
/// \brief The root namespace for all toml++ functions and types.
namespace toml
namespace toml { }
TOML_START
{
using namespace std::string_literals;
using namespace std::string_view_literals;
@ -621,9 +634,9 @@ namespace toml
TOML_POP_WARNINGS
}
TOML_END
/// \brief Internal implementation details. No user-serviceable parts within.
namespace toml::impl
TOML_IMPL_START
{
template <typename T>
using string_map = std::map<string, T, std::less<>>; //heterogeneous lookup
@ -840,8 +853,9 @@ namespace toml::impl
#undef TOML_P2S_DECL
}
TOML_IMPL_END
namespace toml
TOML_START
{
/// \brief Metafunction for determining if a type is a toml::table.
template <typename T>
@ -905,3 +919,4 @@ namespace toml
}
}
}
TOML_END

View File

@ -1,7 +1,7 @@
#pragma once
#include "toml_common.h"
namespace toml
TOML_START
{
/// \brief A local date.
struct date final
@ -301,3 +301,4 @@ namespace toml
}
};
}
TOML_END

View File

@ -4,7 +4,7 @@
#include "toml_array.h"
#include "toml_utf8.h"
namespace toml::impl
TOML_IMPL_START
{
TOML_PUSH_WARNINGS
TOML_DISABLE_ALL_WARNINGS
@ -131,8 +131,9 @@ namespace toml::impl
return (default_formatter_inline_columns(node) + starting_column_bias) > 120_sz;
}
}
TOML_IMPL_END
namespace toml
TOML_START
{
/// \brief A wrapper for printing TOML objects out to a stream as formatted TOML.
///
@ -494,3 +495,4 @@ namespace toml
return lhs << default_formatter<CHAR>{ rhs };
}
}
TOML_END

View File

@ -1,7 +1,7 @@
#pragma once
#include "toml_print_to_stream.h"
namespace toml
TOML_START
{
/// \brief Format flags for modifying how TOML data is printed to streams.
enum class format_flags : uint8_t
@ -18,8 +18,9 @@ namespace toml
return static_cast<format_flags>( impl::unbox_enum(lhs) | impl::unbox_enum(rhs) );
}
}
TOML_END
namespace toml::impl
TOML_IMPL_START
{
template <typename CHAR = char>
class formatter
@ -142,3 +143,4 @@ namespace toml::impl
{}
};
}
TOML_IMPL_END

View File

@ -1,7 +1,7 @@
#pragma once
#include "toml_formatter.h"
namespace toml
TOML_START
{
/// \brief A wrapper for printing TOML objects out to a stream as formatted JSON.
///
@ -160,4 +160,4 @@ namespace toml
base::clear_naked_newline();
}
}
TOML_END

View File

@ -1,7 +1,7 @@
#pragma once
#include "toml_common.h"
namespace toml
TOML_START
{
/// \brief A TOML node.
///
@ -69,6 +69,8 @@ namespace toml
[[nodiscard]] virtual bool is_integer() const noexcept { return false; }
/// \brief Returns true if this node is an floating-point value.
[[nodiscard]] virtual bool is_floating_point() const noexcept { return false; }
/// \brief Returns true if this node is an integer or floating-point value.
[[nodiscard]] virtual bool is_number() const noexcept { return false; }
/// \brief Returns true if this node is a boolean value.
[[nodiscard]] virtual bool is_boolean() const noexcept { return false; }
/// \brief Returns true if this node is a local date value.
@ -400,3 +402,4 @@ namespace toml
}
};
}
TOML_END

View File

@ -3,7 +3,7 @@
#include "toml_array.h"
#include "toml_value.h"
namespace toml
TOML_START
{
/// \brief A view of a node.
///
@ -77,31 +77,29 @@ namespace toml
[[nodiscard]] node_type type() const noexcept { return node_ ? node_->type() : node_type::none; }
/// \brief Returns true if the viewed node is a toml::table.
[[nodiscard]] bool is_table() const noexcept { return type() == node_type::table; }
[[nodiscard]] bool is_table() const noexcept { return node_ && node_->is_table(); }
/// \brief Returns true if the viewed node is a toml::array.
[[nodiscard]] bool is_array() const noexcept { return type() == node_type::array; }
[[nodiscard]] bool is_array() const noexcept { return node_ && node_->is_array(); }
/// \brief Returns true if the viewed node is a toml::value<>.
[[nodiscard]] bool is_value() const noexcept { return type() > node_type::array; }
[[nodiscard]] bool is_value() const noexcept { return node_ && node_->is_value(); }
/// \brief Returns true if the viewed node is a toml::value<string>.
[[nodiscard]] bool is_string() const noexcept { return type() == node_type::string; }
[[nodiscard]] bool is_string() const noexcept { return node_ && node_->is_string(); }
/// \brief Returns true if the viewed node is a toml::value<int64_t>.
[[nodiscard]] bool is_integer() const noexcept { return type() == node_type::integer; }
[[nodiscard]] bool is_integer() const noexcept { return node_ && node_->is_integer(); }
/// \brief Returns true if the viewed node is a toml::value<double>.
[[nodiscard]] bool is_floating_point() const noexcept { return type() == node_type::floating_point; }
[[nodiscard]] bool is_floating_point() const noexcept { return node_ && node_->is_floating_point(); }
/// \brief Returns true if the viewed node is a toml::value<int64_t> or toml::value<double>.
[[nodiscard]] bool is_number() const noexcept { return node_ && node_->is_number(); }
/// \brief Returns true if the viewed node is a toml::value<bool>.
[[nodiscard]] bool is_boolean() const noexcept { return type() == node_type::boolean; }
[[nodiscard]] bool is_boolean() const noexcept { return node_ && node_->is_boolean(); }
/// \brief Returns true if the viewed node is a toml::value<date>.
[[nodiscard]] bool is_date() const noexcept { return type() == node_type::date; }
[[nodiscard]] bool is_date() const noexcept { return node_ && node_->is_date(); }
/// \brief Returns true if the viewed node is a toml::value<time>.
[[nodiscard]] bool is_time() const noexcept { return type() == node_type::time; }
[[nodiscard]] bool is_time() const noexcept { return node_ && node_->is_time(); }
/// \brief Returns true if the viewed node is a toml::value<date_time>.
[[nodiscard]] bool is_date_time() const noexcept { return type() == node_type::date_time; }
[[nodiscard]] bool is_date_time() const noexcept { return node_ && node_->is_date_time(); }
/// \brief Returns true if the viewed node is a toml::array that contains only tables.
[[nodiscard]] bool is_array_of_tables() const noexcept
{
return node_ ? node_->is_array_of_tables() : false;
}
[[nodiscard]] bool is_array_of_tables() const noexcept { return node_ && node_->is_array_of_tables(); }
/// \brief Checks if this view references a node of a specific type.
///
@ -178,6 +176,51 @@ namespace toml
[[nodiscard]] const value<time>* as_time() const noexcept { return as<time>(); }
[[nodiscard]] const value<date_time>* as_date_time() const noexcept { return as<date_time>(); }
/// \brief Gets the raw value represented by the viewed value node, or a default.
///
/// \detail The underlying node is retrieved as if it were a value of the input default value's
/// type. For example, if you specify an integral default value, you'll only get
/// a non-default return value if the underlying node existed _and_ was an integer:\cpp
/// auto tbl = toml::parse(R"(
/// int = 42
/// flt = 420.0
/// bln = false
/// )"sv);
///
/// std::cout << "accessing 'int' as an integer: "sv << tbl["int"].value_or(-1) << std::endl;
/// std::cout << "accessing 'int' as a float: "sv << tbl["int"].value_or(-1.0) << std::endl;
/// std::cout << "accessing 'flt' as a float: "sv << tbl["flt"].value_or(-1.0f) << std::endl;
/// \ecpp
///
/// \out
/// accessing 'int' as an integer: 42
/// accessing 'int' as a float: -1.0
/// accessing 'flt' as a float: 420.0
/// \eout
///
/// \tparam U Default value type. Must be (or be promotable to) one of the TOML value types.
/// \param default_value The default value to return if no matching node was found.
///
/// \returns The selected value, or the default if no match was found.
template <typename U>
[[nodiscard]] auto value_or(U&& default_value) const noexcept
{
static_assert(
impl::is_value_or_promotable<impl::remove_cvref_t<U>>,
"Default value type must be (or be promotable to) one of the TOML value types"
);
using value_type = impl::promoted<impl::remove_cvref_t<U>>;
using return_type = std::conditional_t<
std::is_same_v<value_type, string>,
std::conditional_t<std::is_same_v<impl::remove_cvref_t<U>, string>, string, string_view>,
value_type
>;
if (auto val = node_ ? node_->template as<value_type>() : nullptr)
return return_type{ **val };
return return_type{ std::forward<U>(default_value) };
}
private:
template <typename N, typename FUNC>
@ -348,3 +391,4 @@ namespace toml
return { this->get(key) };
}
}
TOML_END

View File

@ -4,7 +4,7 @@
#include "toml_array.h"
#include "toml_value.h"
namespace toml
TOML_START
{
#if TOML_DOXYGEN || !TOML_EXCEPTIONS
@ -181,8 +181,9 @@ namespace toml
#endif
}
TOML_END
namespace toml::impl
TOML_IMPL_START
{
#if TOML_EXCEPTIONS
#define TOML_ERROR_CHECK(...) (void)0
@ -315,6 +316,7 @@ namespace toml::impl
#if TOML_USE_STREAMS_FOR_FLOATS
{
std::ostringstream oss;
oss.precision(std::numeric_limits<arg_t>::digits10 + 1);
oss << arg;
const auto str = oss.str();
std::memcpy(ptr, str.c_str(), str.length());
@ -1200,7 +1202,7 @@ namespace toml::impl
TOML_UNREACHABLE;
}
#if !TOML_USE_STREAMS_FOR_FLOATS && TOML_LANG_HIGHER_THAN(0, 5, 0) // toml/issues/562
#if TOML_LANG_HIGHER_THAN(0, 5, 0) // toml/issues/562
[[nodiscard]]
double parse_hex_float() TOML_MAY_THROW
@ -1342,38 +1344,62 @@ namespace toml::impl
// convert to double
TOML_GCC_ATTR(uninitialized) double result;
auto fc_result = std::from_chars(chars, chars + length, result, std::chars_format::hex);
switch (fc_result.ec)
#if TOML_USE_STREAMS_FOR_FLOATS
{
case std::errc{}: //ok
return result;
std::string str;
{
std::stringstream ss;
ss.write("0x", 2_sz);
ss.write(chars, static_cast<std::streamsize>(length));
str = ss.str();
}
case std::errc::invalid_argument:
char* end = {};
result = std::strtod(str.c_str(), &end);
if (result == 0.0 && end == str.c_str())
abort_with_error(
"Error parsing hexadecimal "sv, node_type::floating_point,
"; '"sv, std::string_view{ chars, length }, "' could not be interpreted as a value"sv
);
break;
case std::errc::result_out_of_range:
abort_with_error(
"Error parsing hexadecimal "sv, node_type::floating_point,
"; '"sv, std::string_view{ chars, length }, "' is not representable in 64 bits"sv
);
break;
default: //??
abort_with_error(
"Error parsing hexadecimal "sv, node_type::floating_point,
"; an unspecified error occurred while trying to interpret '",
std::string_view{ chars, length }, "' as a value"sv
);
else
return result;
}
#else
{
auto fc_result = std::from_chars(chars, chars + length, result, std::chars_format::hex);
switch (fc_result.ec)
{
case std::errc{}: //ok
return result;
case std::errc::invalid_argument:
abort_with_error(
"Error parsing hexadecimal "sv, node_type::floating_point,
"; '"sv, std::string_view{ chars, length }, "' could not be interpreted as a value"sv
);
break;
case std::errc::result_out_of_range:
abort_with_error(
"Error parsing hexadecimal "sv, node_type::floating_point,
"; '"sv, std::string_view{ chars, length }, "' is not representable in 64 bits"sv
);
break;
default: //??
abort_with_error(
"Error parsing hexadecimal "sv, node_type::floating_point,
"; an unspecified error occurred while trying to interpret '",
std::string_view{ chars, length }, "' as a value"sv
);
}
}
#endif
TOML_ERROR_CHECK({});
TOML_UNREACHABLE;
}
#endif //!TOML_USE_STREAMS_FOR_FLOATS && TOML_LANG_HIGHER_THAN(0, 5, 0)
#endif //TOML_LANG_HIGHER_THAN(0, 5, 0)
template <int base>
[[nodiscard]]
@ -2181,14 +2207,6 @@ namespace toml::impl
begin_pos,
reader.source_path()
);
#elif TOML_USE_STREAMS_FOR_FLOATS
TOML_ERROR(
"Hexadecimal floating-point values are not "
"supported when streams are used to interpret floats "
"(TOML_USE_STREAMS_FOR_FLOATS = 1).",
begin_pos,
reader.source_path()
);
#else
val = std::make_unique<value<double>>(parse_hex_float());
break;
@ -3061,8 +3079,9 @@ namespace toml::impl
#undef TOML_ERROR
#undef TOML_NORETURN
}
TOML_IMPL_END
namespace toml
TOML_START
{
/// \brief Parses a TOML document from a string view.
///
@ -3277,8 +3296,22 @@ namespace toml
/// \brief Convenience literal operators for working with TOML++.
///
/// \remark This namespace exists so you can safely hoist the UDL operators into another scope
/// without dragging in everything in the toml namespace.
/// \detail This namespace exists so you can safely hoist the UDL operators into another scope
/// without dragging in everything in the toml namespace: \cpp
///
/// #include <toml++/toml.h>
/// using namespace toml_literals;
///
/// int main()
/// {
/// auto tbl = "vals = [1, 2, 3]"_toml;
/// /*
/// ... do stuff with the table generated by the "_toml" UDL
/// */
/// return 0;
/// }
/// \ecpp
///
inline namespace literals
{
/// \brief Parses TOML data from a string.
@ -3339,3 +3372,4 @@ namespace toml
}
}
TOML_END

View File

@ -1,7 +1,7 @@
#pragma once
#include "toml_date_time.h"
namespace toml::impl
TOML_IMPL_START
{
// Q: "why does print_to_stream() exist? why not just use ostream::write(), ostream::put() etc?"
// A: - I'm supporting C++20's char8_t as well; wrapping streams allows switching string modes transparently.
@ -115,7 +115,7 @@ namespace toml::impl
#undef TOML_P2S_OVERLOAD
template <typename T, typename CHAR>
inline void print_floating_point_to_stream(T val, std::basic_ostream<CHAR>& stream) TOML_MAY_THROW
inline void print_floating_point_to_stream(T val, std::basic_ostream<CHAR>& stream, bool hexfloat = false) TOML_MAY_THROW
{
static_assert(
sizeof(CHAR) == 1,
@ -133,6 +133,9 @@ namespace toml::impl
#if TOML_USE_STREAMS_FOR_FLOATS
{
std::ostringstream oss;
oss.precision(std::numeric_limits<T>::digits10 + 1);
if (hexfloat)
oss << std::hexfloat;
oss << val;
const auto str = oss.str();
print_to_stream(str, stream);
@ -142,7 +145,9 @@ namespace toml::impl
#else
{
TOML_GCC_ATTR(uninitialized) char buf[charconv_buffer_length<T>];
const auto res = std::to_chars(buf, buf + sizeof(buf), val);
const auto res = hexfloat
? std::to_chars(buf, buf + sizeof(buf), val, std::chars_format::hex)
: std::to_chars(buf, buf + sizeof(buf), val);
const auto str = std::string_view{ buf, static_cast<size_t>(res.ptr - buf) };
print_to_stream(str, stream);
if (needs_decimal_point(str))
@ -283,8 +288,9 @@ namespace toml::impl
TOML_POP_WARNINGS
}
TOML_IMPL_END
namespace toml
TOML_START
{
template <typename CHAR>
std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const source_position& rhs)
@ -319,3 +325,4 @@ namespace toml
return lhs;
}
}
TOML_END

View File

@ -1,7 +1,7 @@
#pragma once
#include "toml_array.h"
namespace toml::impl
TOML_IMPL_START
{
template <bool is_const>
struct table_proxy_pair final
@ -109,8 +109,9 @@ namespace toml::impl
{}
};
}
TOML_IMPL_END
namespace toml
TOML_START
{
/// \brief A TOML table.
///
@ -778,3 +779,4 @@ namespace toml
friend inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>&, const table&) TOML_MAY_THROW;
};
}
TOML_END

View File

@ -4,7 +4,7 @@
#include "toml_utf8_generated.h"
#endif // TOML_LANG_HIGHER_THAN(0, 5, 0)
namespace toml::impl
TOML_IMPL_START
{
[[nodiscard]] TOML_ALWAYS_INLINE
constexpr bool is_ascii_whitespace(char32_t codepoint) noexcept
@ -603,4 +603,4 @@ namespace toml::impl
#undef TOML_ERROR_CHECK
#undef TOML_ERROR
}
TOML_IMPL_END

View File

@ -6,7 +6,7 @@
TOML_ASSUME(codepoint >= first); \
TOML_ASSUME(codepoint <= last)
namespace toml::impl
TOML_IMPL_START
{
//# Returns true if a codepoint belongs to any of these categories: Ll, Lm, Lo, Lt, Lu
[[nodiscard]]
@ -981,5 +981,6 @@ namespace toml::impl
// chunk summary: 2255 codepoints from 282 ranges (spanning a search area of 917232)
}
}
TOML_IMPL_END
#undef TOML_ASSUME_CODEPOINT_BETWEEN

View File

@ -2,7 +2,7 @@
#include "toml_node.h"
#include "toml_print_to_stream.h"
namespace toml
TOML_START
{
/// \brief A TOML value.
///
@ -92,6 +92,7 @@ namespace toml
[[nodiscard]] bool is_string() const noexcept override { return std::is_same_v<T, string>; }
[[nodiscard]] bool is_integer() const noexcept override { return std::is_same_v<T, int64_t>; }
[[nodiscard]] bool is_floating_point() const noexcept override { return std::is_same_v<T, double>; }
[[nodiscard]] bool is_number() const noexcept override { return impl::is_one_of<T, int64_t, double>; }
[[nodiscard]] bool is_boolean() const noexcept override { return std::is_same_v<T, bool>; }
[[nodiscard]] bool is_date() const noexcept override { return std::is_same_v<T, date>; }
[[nodiscard]] bool is_time() const noexcept override { return std::is_same_v<T, time>; }
@ -326,6 +327,9 @@ namespace toml
value(uint8_t) -> value<int64_t>;
value(uint16_t) -> value<int64_t>;
value(uint32_t) -> value<int64_t>;
value(date) -> value<date>;
value(time) -> value<time>;
value(date_time) -> value<date_time>;
#ifdef TOML_SMALL_FLOAT_TYPE
value(TOML_SMALL_FLOAT_TYPE) -> value<double>;
#endif
@ -333,3 +337,4 @@ namespace toml
value(TOML_SMALL_INT_TYPE) -> value<int64_t>;
#endif
}
TOML_END

View File

@ -1,7 +1,7 @@
#pragma once
#define TOML_LIB_MAJOR 0
#define TOML_LIB_MINOR 1
#define TOML_LIB_MINOR 2
#define TOML_LIB_PATCH 0
#define TOML_LANG_MAJOR 0

View File

@ -504,11 +504,11 @@ def main():
print('#pragma once', file=output_file)
print('#include "toml_common.h"', file=output_file)
print('\n#define TOML_ASSUME_CODEPOINT_BETWEEN(first, last)\t\\\n\tTOML_ASSUME(codepoint >= first);\t\t\t\t\\\n\tTOML_ASSUME(codepoint <= last)', file=output_file)
print('\nnamespace toml::impl\n{', file=output_file, end='')
print('\nTOML_IMPL_START\n{', file=output_file, end='')
emit_function('is_unicode_letter', ('Ll', 'Lm', 'Lo', 'Lt', 'Lu'), output_file, codepoints)
emit_function('is_unicode_number', ('Nd', 'Nl'), output_file, codepoints)
emit_function('is_unicode_combining_mark', ('Mn', 'Mc'), output_file, codepoints)
print('}\n\n#undef TOML_ASSUME_CODEPOINT_BETWEEN', file=output_file)
print('}\nTOML_IMPL_END\n\n#undef TOML_ASSUME_CODEPOINT_BETWEEN', file=output_file)
if __name__ == '__main__':
try:

View File

@ -103,14 +103,14 @@ flt8 = 224_617.445_991_228
parse_expected_value( "1.112_650_06e-17"sv, 1.11265006e-17 );
//toml/issues/562 - hexfloat literals
#if TOML_LANG_HIGHER_THAN(0, 5, 0) && !TOML_USE_STREAMS_FOR_FLOATS
#if TOML_LANG_HIGHER_THAN(0, 5, 0)
parse_expected_value(" 0x10.1p0"sv, 0x10.1p0 );
parse_expected_value(" 0x0.3p10"sv, 0x0.3p10 );
parse_expected_value(" 0x12.2P2"sv, 0x12.2P2 );
#else
parsing_should_fail(S("flt = 0x10.1p0"sv));
parsing_should_fail(S("flt = 0x0.3p10"sv));
parsing_should_fail(S("flt = 0x12.2P2"sv));
parsing_should_fail(S("val = 0x10.1p0"sv));
parsing_should_fail(S("val = 0x0.3p10"sv));
parsing_should_fail(S("val = 0x12.2P2"sv));
#endif
}

View File

@ -152,11 +152,11 @@ void parsing_should_fail(std::basic_string_view<CHAR> toml_str) noexcept
template <typename T>
void parse_expected_value(std::string_view value_str, const T& expected) noexcept
{
std::string value;
static constexpr auto value_key = "val = "sv;
value.reserve(value_key.length() + value_str.length());
value.append(value_key);
value.append(value_str);
std::string val;
static constexpr auto key = "val = "sv;
val.reserve(key.length() + value_str.length());
val.append(key);
val.append(value_str);
static constexpr auto is_val = [](char32_t codepoint) noexcept
{
@ -166,7 +166,7 @@ void parse_expected_value(std::string_view value_str, const T& expected) noexcep
return !impl::is_whitespace(codepoint);
};
source_position pos{ 1, static_cast<source_index>(value_key.length()) };
source_position pos{ 1, static_cast<source_index>(key.length()) };
source_position begin{}, end{};
impl::utf8_decoder decoder;
for (auto c : value_str)
@ -198,31 +198,73 @@ void parse_expected_value(std::string_view value_str, const T& expected) noexcep
end = begin;
end.column++;
parsing_should_succeed(std::string_view{ value }, [&](table&& tbl) noexcept
using value_type = impl::promoted<impl::remove_cvref_t<T>>;
value<value_type> val_parsed;
parsing_should_succeed(std::string_view{ val }, [&](table&& tbl) noexcept
{
INFO("String being parsed: '"sv << val << "'"sv);
CHECK(tbl.size() == 1);
const auto nv = tbl[S("val"sv)];
auto nv = tbl[S("val"sv)];
REQUIRE(nv);
REQUIRE(nv.as<impl::promoted<T>>());
REQUIRE(nv.as<value_type>());
REQUIRE(nv.get()->type() == impl::node_type_of<T>);
//check the raw value
CHECK(nv.as<impl::promoted<T>>()->get() == expected);
// check the raw value
CHECK(nv.as<value_type>()->get() == expected);
CHECK(nv.value_or(T{}) == expected);
//check the value relops
CHECK(*nv.as<impl::promoted<T>>() == expected);
CHECK(expected == *nv.as<impl::promoted<T>>());
CHECK(!(*nv.as<impl::promoted<T>>() != expected));
CHECK(!(expected != *nv.as<impl::promoted<T>>()));
// check the table relops
CHECK(tbl == table{ { { S("val"sv), expected } } });
CHECK(!(tbl != table{ { { S("val"sv), expected } } }));
//check the node_view relops
// check the value relops
CHECK(*nv.as<value_type>() == expected);
CHECK(expected == *nv.as<value_type>());
CHECK(!(*nv.as<value_type>() != expected));
CHECK(!(expected != *nv.as<value_type>()));
// check the node_view relops
CHECK(nv == expected);
CHECK(expected == nv);
CHECK(!(nv != expected));
CHECK(!(expected != nv));
//make sure source info is correct
// make sure source info is correct
CHECK(nv.get()->source().begin == begin);
CHECK(nv.get()->source().end == end);
// steal the val for round-trip tests
val_parsed = std::move(*nv.as<value_type>());
});
// check round-tripping
value<value_type> val_reparsed;
{
std::string str;
{
auto tbl = table{ { { S("val"sv), *val_parsed } } };
std::stringstream ss;
ss << tbl;
str = ss.str();
}
parsing_should_succeed(std::string_view{ str }, [&](table&& tbl) noexcept
{
CHECK(tbl.size() == 1);
auto nv = tbl[S("val"sv)];
REQUIRE(nv);
REQUIRE(nv.as<value_type>());
REQUIRE(nv.get()->type() == impl::node_type_of<T>);
CHECK(nv.as<value_type>()->get() == expected);
CHECK(nv.value_or(T{}) == expected);
val_reparsed = std::move(*nv.as<value_type>());
});
}
CHECK(val_reparsed == val_parsed);
CHECK(val_reparsed == expected);
}

227
toml.hpp
View File

@ -1,6 +1,6 @@
//----------------------------------------------------------------------------------------------------------------------
//
// toml++ v0.1.0
// toml++ v0.2.0
// https://github.com/marzer/tomlplusplus
// SPDX-License-Identifier: MIT
//
@ -293,8 +293,19 @@
__VA_ARGS__ [[nodiscard]] friend bool operator != (RHS rhs, LHS lhs) noexcept { return !(lhs == rhs); }
#endif
#if !TOML_DOXYGEN
#if TOML_EXCEPTIONS
#define TOML_START namespace toml { inline namespace wex
#else
#define TOML_START namespace toml { inline namespace woex
#endif
#define TOML_END }
#endif
#define TOML_IMPL_START TOML_START { namespace impl
#define TOML_IMPL_END } TOML_END
#define TOML_LIB_MAJOR 0
#define TOML_LIB_MINOR 1
#define TOML_LIB_MINOR 2
#define TOML_LIB_PATCH 0
#define TOML_LANG_MAJOR 0
@ -355,7 +366,9 @@ TOML_POP_WARNINGS
#define TOML_STRING_PREFIX(S) S
#endif
namespace toml
namespace toml { }
TOML_START
{
using namespace std::string_literals;
using namespace std::string_view_literals;
@ -558,8 +571,9 @@ namespace toml
TOML_POP_WARNINGS
}
TOML_END
namespace toml::impl
TOML_IMPL_START
{
template <typename T>
using string_map = std::map<string, T, std::less<>>; //heterogeneous lookup
@ -775,8 +789,9 @@ namespace toml::impl
#undef TOML_P2S_DECL
}
TOML_IMPL_END
namespace toml
TOML_START
{
template <typename T>
inline constexpr bool is_table = std::is_same_v<impl::remove_cvref_t<T>, table>;
@ -815,6 +830,7 @@ namespace toml
}
}
}
TOML_END
#pragma endregion
//----------------- ↑ toml_common.h ----------------------------------------------------------------------------------
@ -822,7 +838,7 @@ namespace toml
//---------------------------------------- ↓ toml_date_time.h --------------------------------------------------------
#pragma region
namespace toml
TOML_START
{
struct date final
{
@ -977,6 +993,7 @@ namespace toml
}
};
}
TOML_END
#pragma endregion
//---------------------------------------- ↑ toml_date_time.h --------------------------------------------------------
@ -984,7 +1001,7 @@ namespace toml
//-------------------------------------------------------------- ↓ toml_print_to_stream.h ----------------------------
#pragma region
namespace toml::impl
TOML_IMPL_START
{
// Q: "why does print_to_stream() exist? why not just use ostream::write(), ostream::put() etc?"
// A: - I'm supporting C++20's char8_t as well; wrapping streams allows switching string modes transparently.
@ -1098,7 +1115,7 @@ namespace toml::impl
#undef TOML_P2S_OVERLOAD
template <typename T, typename CHAR>
inline void print_floating_point_to_stream(T val, std::basic_ostream<CHAR>& stream) TOML_MAY_THROW
inline void print_floating_point_to_stream(T val, std::basic_ostream<CHAR>& stream, bool hexfloat = false) TOML_MAY_THROW
{
static_assert(
sizeof(CHAR) == 1,
@ -1116,6 +1133,9 @@ namespace toml::impl
#if TOML_USE_STREAMS_FOR_FLOATS
{
std::ostringstream oss;
oss.precision(std::numeric_limits<T>::digits10 + 1);
if (hexfloat)
oss << std::hexfloat;
oss << val;
const auto str = oss.str();
print_to_stream(str, stream);
@ -1125,7 +1145,9 @@ namespace toml::impl
#else
{
TOML_GCC_ATTR(uninitialized) char buf[charconv_buffer_length<T>];
const auto res = std::to_chars(buf, buf + sizeof(buf), val);
const auto res = hexfloat
? std::to_chars(buf, buf + sizeof(buf), val, std::chars_format::hex)
: std::to_chars(buf, buf + sizeof(buf), val);
const auto str = std::string_view{ buf, static_cast<size_t>(res.ptr - buf) };
print_to_stream(str, stream);
if (needs_decimal_point(str))
@ -1266,8 +1288,9 @@ namespace toml::impl
TOML_POP_WARNINGS
}
TOML_IMPL_END
namespace toml
TOML_START
{
template <typename CHAR>
std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const source_position& rhs)
@ -1302,6 +1325,7 @@ namespace toml
return lhs;
}
}
TOML_END
#pragma endregion
//-------------------------------------------------------------- ↑ toml_print_to_stream.h ----------------------------
@ -1309,7 +1333,7 @@ namespace toml
//--------------------------------------------------------------------------------------------- ↓ toml_node.h --------
#pragma region
namespace toml
TOML_START
{
class TOML_INTERFACE node
{
@ -1364,6 +1388,7 @@ namespace toml
[[nodiscard]] virtual bool is_string() const noexcept { return false; }
[[nodiscard]] virtual bool is_integer() const noexcept { return false; }
[[nodiscard]] virtual bool is_floating_point() const noexcept { return false; }
[[nodiscard]] virtual bool is_number() const noexcept { return false; }
[[nodiscard]] virtual bool is_boolean() const noexcept { return false; }
[[nodiscard]] virtual bool is_date() const noexcept { return false; }
[[nodiscard]] virtual bool is_time() const noexcept { return false; }
@ -1619,6 +1644,7 @@ namespace toml
}
};
}
TOML_END
#pragma endregion
//--------------------------------------------------------------------------------------------- ↑ toml_node.h --------
@ -1626,7 +1652,7 @@ namespace toml
//----------------- ↓ toml_value.h -----------------------------------------------------------------------------------
#pragma region
namespace toml
TOML_START
{
template <typename T>
class value final : public node
@ -1684,6 +1710,7 @@ namespace toml
[[nodiscard]] bool is_string() const noexcept override { return std::is_same_v<T, string>; }
[[nodiscard]] bool is_integer() const noexcept override { return std::is_same_v<T, int64_t>; }
[[nodiscard]] bool is_floating_point() const noexcept override { return std::is_same_v<T, double>; }
[[nodiscard]] bool is_number() const noexcept override { return impl::is_one_of<T, int64_t, double>; }
[[nodiscard]] bool is_boolean() const noexcept override { return std::is_same_v<T, bool>; }
[[nodiscard]] bool is_date() const noexcept override { return std::is_same_v<T, date>; }
[[nodiscard]] bool is_time() const noexcept override { return std::is_same_v<T, time>; }
@ -1833,6 +1860,9 @@ namespace toml
value(uint8_t) -> value<int64_t>;
value(uint16_t) -> value<int64_t>;
value(uint32_t) -> value<int64_t>;
value(date) -> value<date>;
value(time) -> value<time>;
value(date_time) -> value<date_time>;
#ifdef TOML_SMALL_FLOAT_TYPE
value(TOML_SMALL_FLOAT_TYPE) -> value<double>;
#endif
@ -1840,6 +1870,7 @@ namespace toml
value(TOML_SMALL_INT_TYPE) -> value<int64_t>;
#endif
}
TOML_END
#pragma endregion
//----------------- ↑ toml_value.h -----------------------------------------------------------------------------------
@ -1847,7 +1878,7 @@ namespace toml
//------------------------------------------ ↓ toml_array.h ----------------------------------------------------------
#pragma region
namespace toml::impl
TOML_IMPL_START
{
template <bool is_const>
class array_iterator final
@ -2020,8 +2051,9 @@ namespace toml::impl
}
}
}
TOML_IMPL_END
namespace toml
TOML_START
{
[[nodiscard]] bool operator == (const table& lhs, const table& rhs) noexcept;
@ -2429,6 +2461,7 @@ namespace toml
friend inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>&, const array&) TOML_MAY_THROW;
};
}
TOML_END
#pragma endregion
//------------------------------------------ ↑ toml_array.h ----------------------------------------------------------
@ -2436,7 +2469,7 @@ namespace toml
//------------------------------------------------------------------- ↓ toml_table.h ---------------------------------
#pragma region
namespace toml::impl
TOML_IMPL_START
{
template <bool is_const>
struct table_proxy_pair final
@ -2544,8 +2577,9 @@ namespace toml::impl
{}
};
}
TOML_IMPL_END
namespace toml
TOML_START
{
class table final
: public node
@ -2792,6 +2826,7 @@ namespace toml
friend inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>&, const table&) TOML_MAY_THROW;
};
}
TOML_END
#pragma endregion
//------------------------------------------------------------------- ↑ toml_table.h ---------------------------------
@ -2799,7 +2834,7 @@ namespace toml
//------------------------------------------------------------------------------------------ ↓ toml_node_view.h ------
#pragma region
namespace toml
TOML_START
{
template <typename T>
class node_view final
@ -2824,20 +2859,18 @@ namespace toml
[[nodiscard]] const viewed_type* get() const noexcept { return node_; }
[[nodiscard]] node_type type() const noexcept { return node_ ? node_->type() : node_type::none; }
[[nodiscard]] bool is_table() const noexcept { return type() == node_type::table; }
[[nodiscard]] bool is_array() const noexcept { return type() == node_type::array; }
[[nodiscard]] bool is_value() const noexcept { return type() > node_type::array; }
[[nodiscard]] bool is_string() const noexcept { return type() == node_type::string; }
[[nodiscard]] bool is_integer() const noexcept { return type() == node_type::integer; }
[[nodiscard]] bool is_floating_point() const noexcept { return type() == node_type::floating_point; }
[[nodiscard]] bool is_boolean() const noexcept { return type() == node_type::boolean; }
[[nodiscard]] bool is_date() const noexcept { return type() == node_type::date; }
[[nodiscard]] bool is_time() const noexcept { return type() == node_type::time; }
[[nodiscard]] bool is_date_time() const noexcept { return type() == node_type::date_time; }
[[nodiscard]] bool is_array_of_tables() const noexcept
{
return node_ ? node_->is_array_of_tables() : false;
}
[[nodiscard]] bool is_table() const noexcept { return node_ && node_->is_table(); }
[[nodiscard]] bool is_array() const noexcept { return node_ && node_->is_array(); }
[[nodiscard]] bool is_value() const noexcept { return node_ && node_->is_value(); }
[[nodiscard]] bool is_string() const noexcept { return node_ && node_->is_string(); }
[[nodiscard]] bool is_integer() const noexcept { return node_ && node_->is_integer(); }
[[nodiscard]] bool is_floating_point() const noexcept { return node_ && node_->is_floating_point(); }
[[nodiscard]] bool is_number() const noexcept { return node_ && node_->is_number(); }
[[nodiscard]] bool is_boolean() const noexcept { return node_ && node_->is_boolean(); }
[[nodiscard]] bool is_date() const noexcept { return node_ && node_->is_date(); }
[[nodiscard]] bool is_time() const noexcept { return node_ && node_->is_time(); }
[[nodiscard]] bool is_date_time() const noexcept { return node_ && node_->is_date_time(); }
[[nodiscard]] bool is_array_of_tables() const noexcept { return node_ && node_->is_array_of_tables(); }
template <typename U>
[[nodiscard]]
@ -2889,6 +2922,25 @@ namespace toml
[[nodiscard]] const value<time>* as_time() const noexcept { return as<time>(); }
[[nodiscard]] const value<date_time>* as_date_time() const noexcept { return as<date_time>(); }
template <typename U>
[[nodiscard]] auto value_or(U&& default_value) const noexcept
{
static_assert(
impl::is_value_or_promotable<impl::remove_cvref_t<U>>,
"Default value type must be (or be promotable to) one of the TOML value types"
);
using value_type = impl::promoted<impl::remove_cvref_t<U>>;
using return_type = std::conditional_t<
std::is_same_v<value_type, string>,
std::conditional_t<std::is_same_v<impl::remove_cvref_t<U>, string>, string, string_view>,
value_type
>;
if (auto val = node_ ? node_->template as<value_type>() : nullptr)
return return_type{ **val };
return return_type{ std::forward<U>(default_value) };
}
private:
template <typename N, typename FUNC>
@ -3025,6 +3077,7 @@ namespace toml
return { this->get(key) };
}
}
TOML_END
#pragma endregion
//------------------------------------------------------------------------------------------ ↑ toml_node_view.h ------
@ -3038,7 +3091,7 @@ namespace toml
TOML_ASSUME(codepoint >= first); \
TOML_ASSUME(codepoint <= last)
namespace toml::impl
TOML_IMPL_START
{
[[nodiscard]]
constexpr bool is_unicode_letter(char32_t codepoint) noexcept
@ -4010,12 +4063,13 @@ namespace toml::impl
// chunk summary: 2255 codepoints from 282 ranges (spanning a search area of 917232)
}
}
TOML_IMPL_END
#undef TOML_ASSUME_CODEPOINT_BETWEEN
#endif // TOML_LANG_HIGHER_THAN(0, 5, 0)
namespace toml::impl
TOML_IMPL_START
{
[[nodiscard]] TOML_ALWAYS_INLINE
constexpr bool is_ascii_whitespace(char32_t codepoint) noexcept
@ -4611,6 +4665,7 @@ namespace toml::impl
#undef TOML_ERROR_CHECK
#undef TOML_ERROR
}
TOML_IMPL_END
#pragma endregion
//------------------ ↑ toml_utf8.h -----------------------------------------------------------------------------------
@ -4618,7 +4673,7 @@ namespace toml::impl
//------------------------------------------ ↓ toml_parser.h ---------------------------------------------------------
#pragma region
namespace toml
TOML_START
{
#if TOML_DOXYGEN || !TOML_EXCEPTIONS
@ -4740,8 +4795,9 @@ namespace toml
#endif
}
TOML_END
namespace toml::impl
TOML_IMPL_START
{
#if TOML_EXCEPTIONS
#define TOML_ERROR_CHECK(...) (void)0
@ -4874,6 +4930,7 @@ namespace toml::impl
#if TOML_USE_STREAMS_FOR_FLOATS
{
std::ostringstream oss;
oss.precision(std::numeric_limits<arg_t>::digits10 + 1);
oss << arg;
const auto str = oss.str();
std::memcpy(ptr, str.c_str(), str.length());
@ -5759,7 +5816,7 @@ namespace toml::impl
TOML_UNREACHABLE;
}
#if !TOML_USE_STREAMS_FOR_FLOATS && TOML_LANG_HIGHER_THAN(0, 5, 0) // toml/issues/562
#if TOML_LANG_HIGHER_THAN(0, 5, 0) // toml/issues/562
[[nodiscard]]
double parse_hex_float() TOML_MAY_THROW
@ -5901,38 +5958,62 @@ namespace toml::impl
// convert to double
TOML_GCC_ATTR(uninitialized) double result;
auto fc_result = std::from_chars(chars, chars + length, result, std::chars_format::hex);
switch (fc_result.ec)
#if TOML_USE_STREAMS_FOR_FLOATS
{
case std::errc{}: //ok
return result;
std::string str;
{
std::stringstream ss;
ss.write("0x", 2_sz);
ss.write(chars, static_cast<std::streamsize>(length));
str = ss.str();
}
case std::errc::invalid_argument:
char* end = {};
result = std::strtod(str.c_str(), &end);
if (result == 0.0 && end == str.c_str())
abort_with_error(
"Error parsing hexadecimal "sv, node_type::floating_point,
"; '"sv, std::string_view{ chars, length }, "' could not be interpreted as a value"sv
);
break;
case std::errc::result_out_of_range:
abort_with_error(
"Error parsing hexadecimal "sv, node_type::floating_point,
"; '"sv, std::string_view{ chars, length }, "' is not representable in 64 bits"sv
);
break;
default: //??
abort_with_error(
"Error parsing hexadecimal "sv, node_type::floating_point,
"; an unspecified error occurred while trying to interpret '",
std::string_view{ chars, length }, "' as a value"sv
);
else
return result;
}
#else
{
auto fc_result = std::from_chars(chars, chars + length, result, std::chars_format::hex);
switch (fc_result.ec)
{
case std::errc{}: //ok
return result;
case std::errc::invalid_argument:
abort_with_error(
"Error parsing hexadecimal "sv, node_type::floating_point,
"; '"sv, std::string_view{ chars, length }, "' could not be interpreted as a value"sv
);
break;
case std::errc::result_out_of_range:
abort_with_error(
"Error parsing hexadecimal "sv, node_type::floating_point,
"; '"sv, std::string_view{ chars, length }, "' is not representable in 64 bits"sv
);
break;
default: //??
abort_with_error(
"Error parsing hexadecimal "sv, node_type::floating_point,
"; an unspecified error occurred while trying to interpret '",
std::string_view{ chars, length }, "' as a value"sv
);
}
}
#endif
TOML_ERROR_CHECK({});
TOML_UNREACHABLE;
}
#endif //!TOML_USE_STREAMS_FOR_FLOATS && TOML_LANG_HIGHER_THAN(0, 5, 0)
#endif //TOML_LANG_HIGHER_THAN(0, 5, 0)
template <int base>
[[nodiscard]]
@ -6738,14 +6819,6 @@ namespace toml::impl
begin_pos,
reader.source_path()
);
#elif TOML_USE_STREAMS_FOR_FLOATS
TOML_ERROR(
"Hexadecimal floating-point values are not "
"supported when streams are used to interpret floats "
"(TOML_USE_STREAMS_FOR_FLOATS = 1).",
begin_pos,
reader.source_path()
);
#else
val = std::make_unique<value<double>>(parse_hex_float());
break;
@ -7617,8 +7690,9 @@ namespace toml::impl
#undef TOML_ERROR
#undef TOML_NORETURN
}
TOML_IMPL_END
namespace toml
TOML_START
{
[[nodiscard]]
inline parse_result parse(std::string_view doc, std::string_view source_path = {}) TOML_MAY_THROW
@ -7711,6 +7785,7 @@ namespace toml
}
}
TOML_END
#pragma endregion
//------------------------------------------ ↑ toml_parser.h ---------------------------------------------------------
@ -7718,7 +7793,7 @@ namespace toml
//----------------------------------------------------------------- ↓ toml_formatter.h -------------------------------
#pragma region
namespace toml
TOML_START
{
enum class format_flags : uint8_t
{
@ -7734,8 +7809,9 @@ namespace toml
return static_cast<format_flags>( impl::unbox_enum(lhs) | impl::unbox_enum(rhs) );
}
}
TOML_END
namespace toml::impl
TOML_IMPL_START
{
template <typename CHAR = char>
class formatter
@ -7856,6 +7932,7 @@ namespace toml::impl
{}
};
}
TOML_IMPL_END
#pragma endregion
//----------------------------------------------------------------- ↑ toml_formatter.h -------------------------------
@ -7863,7 +7940,7 @@ namespace toml::impl
//-------------------------------------------------------------------------------------- ↓ toml_default_formatter.h --
#pragma region
namespace toml::impl
TOML_IMPL_START
{
TOML_PUSH_WARNINGS
TOML_DISABLE_ALL_WARNINGS
@ -7990,8 +8067,9 @@ namespace toml::impl
return (default_formatter_inline_columns(node) + starting_column_bias) > 120_sz;
}
}
TOML_IMPL_END
namespace toml
TOML_START
{
template <typename CHAR = char>
class default_formatter final : impl::formatter<CHAR>
@ -8317,6 +8395,7 @@ namespace toml
return lhs << default_formatter<CHAR>{ rhs };
}
}
TOML_END
#pragma endregion
//-------------------------------------------------------------------------------------- ↑ toml_default_formatter.h --
@ -8324,7 +8403,7 @@ namespace toml
//------------- ↓ toml_json_formatter.h ------------------------------------------------------------------------------
#pragma region
namespace toml
TOML_START
{
template <typename CHAR = char>
class json_formatter final : impl::formatter<CHAR>
@ -8443,13 +8522,13 @@ namespace toml
base::clear_naked_newline();
}
}
TOML_END
#pragma endregion
//------------- ↑ toml_json_formatter.h ------------------------------------------------------------------------------
// macro hygiene
#if TOML_UNDEF_MACROS
#undef TOML_EXCEPTIONS
#undef TOML_USE_STREAMS_FOR_FLOATS
#undef TOML_GCC_ATTR
#undef TOML_PUSH_WARNINGS
@ -8483,6 +8562,10 @@ namespace toml
#undef TOML_DOXYGEN
#undef TOML_RELOPS_REORDERING
#undef TOML_ASYMMETRICAL_EQUALITY_OPS
#undef TOML_START
#undef TOML_END
#undef TOML_IMPL_START
#undef TOML_IMPL_END
#endif
#ifdef __GNUC__