added value_flags

Allows controlling the output format of integers, and round-trips their format when serializing after parsing.
This commit is contained in:
Mark Gillard 2020-09-06 13:01:14 +03:00
parent 1381240e10
commit dc29f80a4d
11 changed files with 445 additions and 174 deletions

View File

@ -109,6 +109,7 @@ TOML_POP_WARNINGS // TOML_DISABLE_SPAM_WARNINGS
#undef TOML_LANG_UNRELEASED
#undef TOML_LAUNDER
#undef TOML_LIKELY
#undef TOML_MAKE_BITOPS
#undef TOML_MAKE_VERSION
#undef TOML_MAY_THROW
#undef TOML_MSVC

View File

@ -1029,6 +1029,7 @@ TOML_NAMESPACE_START
/// \brief Prints the array out to a stream as formatted TOML.
template <typename Char>
friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const array&);
// implemented in toml_default_formatter.h
};
}
TOML_NAMESPACE_END

View File

@ -161,24 +161,6 @@ TOML_NAMESPACE_START // abi namespace
template <typename T>
inline constexpr bool dependent_false = false;
#define TOML_P2S_DECL(Type) \
template <typename Char> \
inline void print_to_stream(Type, std::basic_ostream<Char>&)
TOML_P2S_DECL(int8_t);
TOML_P2S_DECL(int16_t);
TOML_P2S_DECL(int32_t);
TOML_P2S_DECL(int64_t);
TOML_P2S_DECL(uint8_t);
TOML_P2S_DECL(uint16_t);
TOML_P2S_DECL(uint32_t);
TOML_P2S_DECL(uint64_t);
TOML_P2S_DECL(float);
TOML_P2S_DECL(const date&);
TOML_P2S_DECL(const time&);
TOML_P2S_DECL(time_offset);
TOML_P2S_DECL(const date_time&);
#undef TOML_P2S_DECL
#if TOML_WINDOWS_COMPAT
[[nodiscard]] TOML_API std::string narrow(std::wstring_view) noexcept;
[[nodiscard]] TOML_API std::wstring widen(std::string_view) noexcept;
@ -314,7 +296,6 @@ TOML_IMPL_NAMESPACE_START
template <typename T> struct value_traits<T* volatile> : value_traits<T*> {};
template <typename T> struct value_traits<T* const volatile> : value_traits<T*> {};
// integer value traits
template <typename T>
struct integer_value_limits
@ -866,6 +847,43 @@ TOML_NAMESPACE_END
TOML_NAMESPACE_START
{
/// \brief Metadata associated with TOML values.
enum class value_flags : uint8_t
{
/// \brief None.
none,
/// \brief Format integer values as binary.
format_as_binary = 1,
/// \brief Format integer values as octal.
format_as_octal = 2,
/// \brief Format integer values as hexadecimal.
format_as_hexadecimal = 3,
};
TOML_MAKE_BITOPS(value_flags)
/// \brief Format flags for modifying how TOML data is printed to streams.
enum class format_flags : uint8_t
{
/// \brief None.
none,
/// \brief Dates and times will be emitted as quoted strings.
quote_dates_and_times = 1,
/// \brief Strings will be emitted as single-quoted literal strings where possible.
allow_literal_strings = 2,
/// \brief Strings containing newlines will be emitted as triple-quoted 'multi-line' strings where possible.
allow_multi_line_strings = 4,
/// \brief Values with special format flags will be formatted accordingly.
allow_value_format_flags = 8,
};
TOML_MAKE_BITOPS(format_flags)
/// \brief Pretty-prints the value of a node_type to a stream.
///
/// \detail \cpp
@ -897,9 +915,39 @@ TOML_NAMESPACE_START
}
}
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
#ifndef DOXYGEN
namespace impl
{
#define TOML_P2S_DECL(Type) \
template <typename Char> \
inline void print_to_stream(Type, std::basic_ostream<Char>&, value_flags = {})
TOML_P2S_DECL(int8_t);
TOML_P2S_DECL(int16_t);
TOML_P2S_DECL(int32_t);
TOML_P2S_DECL(int64_t);
TOML_P2S_DECL(uint8_t);
TOML_P2S_DECL(uint16_t);
TOML_P2S_DECL(uint32_t);
TOML_P2S_DECL(uint64_t);
#undef TOML_P2S_DECL
#define TOML_P2S_DECL(Type) \
template <typename Char> \
inline void print_to_stream(Type, std::basic_ostream<Char>&)
TOML_P2S_DECL(double);
TOML_P2S_DECL(const date&);
TOML_P2S_DECL(const time&);
TOML_P2S_DECL(time_offset);
TOML_P2S_DECL(const date_time&);
#undef TOML_P2S_DECL
}
#if !TOML_HEADER_ONLY
extern template TOML_API std::ostream& operator << (std::ostream&, node_type);
#endif
#endif // !TOML_HEADER_ONLY
#endif // !DOXYGEN
}
TOML_NAMESPACE_END

View File

@ -319,7 +319,9 @@ TOML_NAMESPACE_START
/// \brief The default flags for a default_formatter.
static constexpr format_flags default_flags
= format_flags::allow_literal_strings | format_flags::allow_multi_line_strings;
= format_flags::allow_literal_strings
| format_flags::allow_multi_line_strings
| format_flags::allow_value_format_flags;
/// \brief Constructs a default formatter and binds it to a TOML object.
///

View File

@ -9,44 +9,6 @@
TOML_PUSH_WARNINGS
TOML_DISABLE_SWITCH_WARNINGS
TOML_NAMESPACE_START
{
/// \brief Format flags for modifying how TOML data is printed to streams.
enum class format_flags : uint8_t
{
/// \brief None.
none,
/// \brief Dates and times will be emitted as quoted strings.
quote_dates_and_times = 1,
/// \brief Strings will be emitted as single-quoted literal strings where possible.
allow_literal_strings = 2,
/// \brief Strings containing newlines will be emitted as triple-quoted 'multi-line' strings where possible.
allow_multi_line_strings = 4,
};
[[nodiscard]]
TOML_ALWAYS_INLINE
TOML_ATTR(const)
TOML_ATTR(flatten)
constexpr format_flags operator & (format_flags lhs, format_flags rhs) noexcept
{
return static_cast<format_flags>(impl::unwrap_enum(lhs) & impl::unwrap_enum(rhs));
}
[[nodiscard]]
TOML_ALWAYS_INLINE
TOML_ATTR(const)
TOML_ATTR(flatten)
constexpr format_flags operator | (format_flags lhs, format_flags rhs) noexcept
{
return static_cast<format_flags>( impl::unwrap_enum(lhs) | impl::unwrap_enum(rhs) );
}
}
TOML_NAMESPACE_END
TOML_IMPL_NAMESPACE_START
{
template <typename Char = char>
@ -56,7 +18,7 @@ TOML_IMPL_NAMESPACE_START
const toml::node* source_;
std::basic_ostream<Char>* stream_ = nullptr;
format_flags flags_;
int8_t indent_;
int indent_;
bool naked_newline_;
protected:
@ -66,8 +28,8 @@ TOML_IMPL_NAMESPACE_START
static constexpr size_t indent_columns = 4;
static constexpr std::string_view indent_string = " "sv;
[[nodiscard]] int8_t indent() const noexcept { return indent_; }
void indent(int8_t level) noexcept { indent_ = level; }
[[nodiscard]] int indent() const noexcept { return indent_; }
void indent(int level) noexcept { indent_ = level; }
void increase_indent() noexcept { indent_++; }
void decrease_indent() noexcept { indent_--; }
@ -89,6 +51,12 @@ TOML_IMPL_NAMESPACE_START
return (flags_ & format_flags::allow_multi_line_strings) != format_flags::none;
}
[[nodiscard]]
bool value_format_flags_allowed() const noexcept
{
return (flags_ & format_flags::allow_value_format_flags) != format_flags::none;
}
[[nodiscard]]
bool naked_newline() const noexcept
{
@ -123,7 +91,7 @@ TOML_IMPL_NAMESPACE_START
void print_indent()
{
for (int8_t i = 0; i < indent_; i++)
for (int i = 0; i < indent_; i++)
{
print_to_stream(indent_string, *stream_);
naked_newline_ = false;
@ -197,12 +165,7 @@ TOML_IMPL_NAMESPACE_START
}
else
{
static constexpr auto is_dt =
std::is_same_v<T, date>
|| std::is_same_v<T, time>
|| std::is_same_v<T, date_time>;
if constexpr (is_dt)
if constexpr (is_one_of<T, date, time, date_time>)
{
if (quote_dates_and_times())
{
@ -214,6 +177,27 @@ TOML_IMPL_NAMESPACE_START
else
print_to_stream(*val, *stream_);
}
else if constexpr (is_one_of<T, int64_t/*, double*/>)
{
if (value_format_flags_allowed() && *val >= 0)
{
const auto fmt = val.flags() & value_flags::format_as_hexadecimal;
if (fmt != value_flags::none)
{
switch (fmt)
{
case value_flags::format_as_binary: print_to_stream("0b"sv, *stream_); break;
case value_flags::format_as_octal: print_to_stream("0o"sv, *stream_); break;
case value_flags::format_as_hexadecimal: print_to_stream("0x"sv, *stream_); break;
}
print_to_stream(*val, *stream_, fmt);
}
else
print_to_stream(*val, *stream_);
}
else
print_to_stream(*val, *stream_);
}
else
print_to_stream(*val, *stream_);

View File

@ -2022,11 +2022,20 @@ TOML_IMPL_NAMESPACE_START
if (has_any(has_p))
val = new value{ parse_hex_float() };
else if (has_any(has_x))
{
val = new value{ parse_integer<16>() };
reinterpret_cast<value<int64_t>*>(val)->flags(value_flags::format_as_hexadecimal);
}
else if (has_any(has_o))
{
val = new value{ parse_integer<8>() };
reinterpret_cast<value<int64_t>*>(val)->flags(value_flags::format_as_octal);
}
else if (has_any(has_b))
{
val = new value{ parse_integer<2>() };
reinterpret_cast<value<int64_t>*>(val)->flags(value_flags::format_as_binary);
}
else if (has_any(has_e) || (has_any(begins_zero | begins_digit) && chars[1] == U'.'))
val = new value{ parse_float() };
else if (has_any(begins_sign))
@ -2066,12 +2075,14 @@ TOML_IMPL_NAMESPACE_START
// 0b10
case bzero_msk | has_b:
val = new value{ parse_integer<2>() };
reinterpret_cast<value<int64_t>*>(val)->flags(value_flags::format_as_binary);
break;
//=================== octal integers
// 0o10
case bzero_msk | has_o:
val = new value{ parse_integer<8>() };
reinterpret_cast<value<int64_t>*>(val)->flags(value_flags::format_as_octal);
break;
//=================== decimal integers
@ -2090,6 +2101,7 @@ TOML_IMPL_NAMESPACE_START
// 0x10
case bzero_msk | has_x:
val = new value{ parse_integer<16>() };
reinterpret_cast<value<int64_t>*>(val)->flags(value_flags::format_as_hexadecimal);
break;
//=================== decimal floats

View File

@ -467,6 +467,24 @@ is no longer necessary.
#else
#define TOML_ARM 0
#endif
#define TOML_MAKE_BITOPS(type) \
[[nodiscard]] \
TOML_ALWAYS_INLINE \
TOML_ATTR(const) \
TOML_ATTR(flatten) \
constexpr type operator & (type lhs, type rhs) noexcept \
{ \
return static_cast<type>(::toml::impl::unwrap_enum(lhs) & ::toml::impl::unwrap_enum(rhs)); \
} \
[[nodiscard]] \
TOML_ALWAYS_INLINE \
TOML_ATTR(const) \
TOML_ATTR(flatten) \
constexpr type operator | (type lhs, type rhs) noexcept \
{ \
return static_cast<type>(::toml::impl::unwrap_enum(lhs) | ::toml::impl::unwrap_enum(rhs)); \
}
//#====================================================================================================================
//# EXTENDED INT AND FLOAT TYPES

View File

@ -18,6 +18,9 @@ TOML_DISABLE_WARNINGS
#endif
TOML_ENABLE_WARNINGS
TOML_PUSH_WARNINGS
TOML_DISABLE_SWITCH_WARNINGS
TOML_IMPL_NAMESPACE_START
{
// Q: "why does print_to_stream() exist? why not just use ostream::write(), ostream::put() etc?"
@ -95,38 +98,85 @@ TOML_IMPL_NAMESPACE_START
template <> inline constexpr size_t charconv_buffer_length<uint8_t> = 3; // strlen("255")
template <typename T, typename Char>
inline void print_integer_to_stream(T val, std::basic_ostream<Char>& stream)
inline void print_integer_to_stream(T val, std::basic_ostream<Char>& stream, value_flags format = {})
{
static_assert(
sizeof(Char) == 1,
"The stream's underlying character type must be 1 byte in size."
);
if (!val)
{
print_to_stream('0', stream);
return;
}
int base = 10;
if (format != value_flags::none && val >= T{})
{
switch (format)
{
case value_flags::format_as_binary: base = 2; break;
case value_flags::format_as_octal: base = 8; break;
case value_flags::format_as_hexadecimal: base = 16; break;
default: break;
}
}
#if TOML_INT_CHARCONV
char buf[charconv_buffer_length<T>];
const auto res = std::to_chars(buf, buf + sizeof(buf), val);
{
char buf[(sizeof(T) * CHAR_BIT)];
const auto res = std::to_chars(buf, buf + sizeof(buf), val, base);
const auto len = static_cast<size_t>(res.ptr - buf);
if (base == 16)
{
for (size_t i = 0; i < len; i++)
if (buf[i] >= 'a')
buf[i] -= 32;
}
print_to_stream(buf, len, stream);
}
#else
{
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>;
std::ostringstream ss;
ss.imbue(std::locale::classic());
using cast_type = std::conditional_t<std::is_signed_v<T>, int64_t, uint64_t>;
ss << static_cast<cast_type>(val);
const auto str = std::move(ss).str();
print_to_stream(str, stream);
if TOML_UNLIKELY(format == value_flags::format_as_binary)
{
bool found_one = false;
const auto v = static_cast<unsigned_type>(val);
unsigned_type mask = unsigned_type{ 1 } << (sizeof(unsigned_type) * CHAR_BIT - 1u);
for (unsigned i = 0; i < sizeof(unsigned_type) * CHAR_BIT; i++)
{
if ((v & mask))
{
print_to_stream('1', stream);
found_one = true;
}
else if (found_one)
print_to_stream('0', stream);
mask >>= 1;
}
}
else
{
std::ostringstream ss;
ss.imbue(std::locale::classic());
ss << std::uppercase << std::setbase(base);
ss << static_cast<cast_type>(val);
const auto str = std::move(ss).str();
print_to_stream(str, stream);
}
}
#endif
}
#define TOML_P2S_OVERLOAD(Type) \
template <typename Char> \
inline void print_to_stream(Type val, std::basic_ostream<Char>& stream) \
{ \
static_assert(sizeof(Char) == 1); \
print_integer_to_stream(val, stream); \
#define TOML_P2S_OVERLOAD(Type) \
template <typename Char> \
inline void print_to_stream(Type val, std::basic_ostream<Char>& stream, value_flags format) \
{ \
static_assert(sizeof(Char) == 1); \
print_integer_to_stream(val, stream, format); \
}
TOML_P2S_OVERLOAD(int8_t)
@ -432,3 +482,5 @@ TOML_NAMESPACE_START
#endif
}
TOML_NAMESPACE_END
TOML_POP_WARNINGS // TOML_DISABLE_SWITCH_WARNINGS

View File

@ -1089,6 +1089,7 @@ TOML_NAMESPACE_START
/// \brief Prints the table out to a stream as formatted TOML.
template <typename Char>
friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const table&);
// implemented in toml_default_formatter.h
};
#ifndef DOXYGEN

View File

@ -200,6 +200,7 @@ TOML_NAMESPACE_START
}
ValueType val_;
value_flags flags_ = value_flags::none;
public:
@ -234,14 +235,16 @@ TOML_NAMESPACE_START
TOML_NODISCARD_CTOR
value(const value& other) noexcept
: node{ other },
val_{ other.val_ }
val_{ other.val_ },
flags_{ other.flags_ }
{}
/// \brief Move constructor.
TOML_NODISCARD_CTOR
value(value&& other) noexcept
: node{ std::move(other) },
val_{ std::move(other.val_) }
val_{ std::move(other.val_) },
flags_{ other.flags_ }
{}
/// \brief Copy-assignment operator.
@ -249,6 +252,7 @@ TOML_NAMESPACE_START
{
node::operator=(rhs);
val_ = rhs.val_;
flags_ = rhs.flags_;
return *this;
}
@ -259,6 +263,7 @@ TOML_NAMESPACE_START
{
node::operator=(std::move(rhs));
val_ = std::move(rhs.val_);
flags_ = rhs.flags_;
}
return *this;
}
@ -369,9 +374,24 @@ TOML_NAMESPACE_START
/// \brief Returns a reference to the underlying value (const overload).
[[nodiscard]] explicit operator const value_type& () const& noexcept { return val_; }
/// \brief Returns the metadata flags associated with this value.
[[nodiscard]] value_flags flags() const noexcept
{
return flags_;
}
/// \brief Sets the metadata flags associated with this value.
/// \returns A reference to the value object.
value& flags(value_flags new_flags) noexcept
{
flags_ = new_flags;
return *this;
}
/// \brief Prints the value out to a stream as formatted TOML.
template <typename Char, typename T>
friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const value<T>& rhs);
// implemented in toml_default_formatter.h
/// \brief Value-assignment operator.
value& operator= (value_arg rhs) noexcept

300
toml.hpp
View File

@ -481,6 +481,24 @@ is no longer necessary.
#define TOML_ARM 0
#endif
#define TOML_MAKE_BITOPS(type) \
[[nodiscard]] \
TOML_ALWAYS_INLINE \
TOML_ATTR(const) \
TOML_ATTR(flatten) \
constexpr type operator & (type lhs, type rhs) noexcept \
{ \
return static_cast<type>(::toml::impl::unwrap_enum(lhs) & ::toml::impl::unwrap_enum(rhs)); \
} \
[[nodiscard]] \
TOML_ALWAYS_INLINE \
TOML_ATTR(const) \
TOML_ATTR(flatten) \
constexpr type operator | (type lhs, type rhs) noexcept \
{ \
return static_cast<type>(::toml::impl::unwrap_enum(lhs) | ::toml::impl::unwrap_enum(rhs)); \
}
#ifdef __FLT16_MANT_DIG__
#if __FLT_RADIX__ == 2 \
&& __FLT16_MANT_DIG__ == 11 \
@ -743,24 +761,6 @@ TOML_NAMESPACE_START // abi namespace
template <typename T>
inline constexpr bool dependent_false = false;
#define TOML_P2S_DECL(Type) \
template <typename Char> \
inline void print_to_stream(Type, std::basic_ostream<Char>&)
TOML_P2S_DECL(int8_t);
TOML_P2S_DECL(int16_t);
TOML_P2S_DECL(int32_t);
TOML_P2S_DECL(int64_t);
TOML_P2S_DECL(uint8_t);
TOML_P2S_DECL(uint16_t);
TOML_P2S_DECL(uint32_t);
TOML_P2S_DECL(uint64_t);
TOML_P2S_DECL(float);
TOML_P2S_DECL(const date&);
TOML_P2S_DECL(const time&);
TOML_P2S_DECL(time_offset);
TOML_P2S_DECL(const date_time&);
#undef TOML_P2S_DECL
#if TOML_WINDOWS_COMPAT
[[nodiscard]] TOML_API std::string narrow(std::wstring_view) noexcept;
[[nodiscard]] TOML_API std::wstring widen(std::string_view) noexcept;
@ -1293,6 +1293,32 @@ TOML_NAMESPACE_START
TOML_ABI_NAMESPACE_END // TOML_LARGE_FILES
enum class value_flags : uint8_t
{
none,
format_as_binary = 1,
format_as_octal = 2,
format_as_hexadecimal = 3,
};
TOML_MAKE_BITOPS(value_flags)
enum class format_flags : uint8_t
{
none,
quote_dates_and_times = 1,
allow_literal_strings = 2,
allow_multi_line_strings = 4,
allow_value_format_flags = 8,
};
TOML_MAKE_BITOPS(format_flags)
template <typename Char>
inline std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, node_type rhs)
{
@ -1309,9 +1335,39 @@ TOML_NAMESPACE_START
}
}
#if !defined(DOXYGEN) && !TOML_HEADER_ONLY
#ifndef DOXYGEN
namespace impl
{
#define TOML_P2S_DECL(Type) \
template <typename Char> \
inline void print_to_stream(Type, std::basic_ostream<Char>&, value_flags = {})
TOML_P2S_DECL(int8_t);
TOML_P2S_DECL(int16_t);
TOML_P2S_DECL(int32_t);
TOML_P2S_DECL(int64_t);
TOML_P2S_DECL(uint8_t);
TOML_P2S_DECL(uint16_t);
TOML_P2S_DECL(uint32_t);
TOML_P2S_DECL(uint64_t);
#undef TOML_P2S_DECL
#define TOML_P2S_DECL(Type) \
template <typename Char> \
inline void print_to_stream(Type, std::basic_ostream<Char>&)
TOML_P2S_DECL(double);
TOML_P2S_DECL(const date&);
TOML_P2S_DECL(const time&);
TOML_P2S_DECL(time_offset);
TOML_P2S_DECL(const date_time&);
#undef TOML_P2S_DECL
}
#if !TOML_HEADER_ONLY
extern template TOML_API std::ostream& operator << (std::ostream&, node_type);
#endif
#endif // !TOML_HEADER_ONLY
#endif // !DOXYGEN
}
TOML_NAMESPACE_END
@ -1637,6 +1693,9 @@ TOML_DISABLE_WARNINGS
#endif
TOML_ENABLE_WARNINGS
TOML_PUSH_WARNINGS
TOML_DISABLE_SWITCH_WARNINGS
TOML_IMPL_NAMESPACE_START
{
// Q: "why does print_to_stream() exist? why not just use ostream::write(), ostream::put() etc?"
@ -1714,38 +1773,85 @@ TOML_IMPL_NAMESPACE_START
template <> inline constexpr size_t charconv_buffer_length<uint8_t> = 3; // strlen("255")
template <typename T, typename Char>
inline void print_integer_to_stream(T val, std::basic_ostream<Char>& stream)
inline void print_integer_to_stream(T val, std::basic_ostream<Char>& stream, value_flags format = {})
{
static_assert(
sizeof(Char) == 1,
"The stream's underlying character type must be 1 byte in size."
);
if (!val)
{
print_to_stream('0', stream);
return;
}
int base = 10;
if (format != value_flags::none && val >= T{})
{
switch (format)
{
case value_flags::format_as_binary: base = 2; break;
case value_flags::format_as_octal: base = 8; break;
case value_flags::format_as_hexadecimal: base = 16; break;
default: break;
}
}
#if TOML_INT_CHARCONV
char buf[charconv_buffer_length<T>];
const auto res = std::to_chars(buf, buf + sizeof(buf), val);
{
char buf[(sizeof(T) * CHAR_BIT)];
const auto res = std::to_chars(buf, buf + sizeof(buf), val, base);
const auto len = static_cast<size_t>(res.ptr - buf);
if (base == 16)
{
for (size_t i = 0; i < len; i++)
if (buf[i] >= 'a')
buf[i] -= 32;
}
print_to_stream(buf, len, stream);
}
#else
{
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>;
std::ostringstream ss;
ss.imbue(std::locale::classic());
using cast_type = std::conditional_t<std::is_signed_v<T>, int64_t, uint64_t>;
ss << static_cast<cast_type>(val);
const auto str = std::move(ss).str();
print_to_stream(str, stream);
if TOML_UNLIKELY(format == value_flags::format_as_binary)
{
bool found_one = false;
const auto v = static_cast<unsigned_type>(val);
unsigned_type mask = unsigned_type{ 1 } << (sizeof(unsigned_type) * CHAR_BIT - 1u);
for (unsigned i = 0; i < sizeof(unsigned_type) * CHAR_BIT; i++)
{
if ((v & mask))
{
print_to_stream('1', stream);
found_one = true;
}
else if (found_one)
print_to_stream('0', stream);
mask >>= 1;
}
}
else
{
std::ostringstream ss;
ss.imbue(std::locale::classic());
ss << std::uppercase << std::setbase(base);
ss << static_cast<cast_type>(val);
const auto str = std::move(ss).str();
print_to_stream(str, stream);
}
}
#endif
}
#define TOML_P2S_OVERLOAD(Type) \
template <typename Char> \
inline void print_to_stream(Type val, std::basic_ostream<Char>& stream) \
{ \
static_assert(sizeof(Char) == 1); \
print_integer_to_stream(val, stream); \
#define TOML_P2S_OVERLOAD(Type) \
template <typename Char> \
inline void print_to_stream(Type val, std::basic_ostream<Char>& stream, value_flags format) \
{ \
static_assert(sizeof(Char) == 1); \
print_integer_to_stream(val, stream, format); \
}
TOML_P2S_OVERLOAD(int8_t)
@ -2012,6 +2118,8 @@ TOML_NAMESPACE_START
}
TOML_NAMESPACE_END
TOML_POP_WARNINGS // TOML_DISABLE_SWITCH_WARNINGS
#endif //------------------------------------------------------------------------------- ↑ toml_print_to_stream.h ----
#if 1 //---------- ↓ toml_node.h ------------------------------------------------------------------------------------
@ -2667,6 +2775,7 @@ TOML_NAMESPACE_START
}
ValueType val_;
value_flags flags_ = value_flags::none;
public:
@ -2689,19 +2798,22 @@ TOML_NAMESPACE_START
TOML_NODISCARD_CTOR
value(const value& other) noexcept
: node{ other },
val_{ other.val_ }
val_{ other.val_ },
flags_{ other.flags_ }
{}
TOML_NODISCARD_CTOR
value(value&& other) noexcept
: node{ std::move(other) },
val_{ std::move(other.val_) }
val_{ std::move(other.val_) },
flags_{ other.flags_ }
{}
value& operator= (const value& rhs) noexcept
{
node::operator=(rhs);
val_ = rhs.val_;
flags_ = rhs.flags_;
return *this;
}
@ -2711,6 +2823,7 @@ TOML_NAMESPACE_START
{
node::operator=(std::move(rhs));
val_ = std::move(rhs.val_);
flags_ = rhs.flags_;
}
return *this;
}
@ -2797,8 +2910,21 @@ TOML_NAMESPACE_START
[[nodiscard]] explicit operator value_type && () && noexcept { return std::move(val_); }
[[nodiscard]] explicit operator const value_type& () const& noexcept { return val_; }
[[nodiscard]] value_flags flags() const noexcept
{
return flags_;
}
value& flags(value_flags new_flags) noexcept
{
flags_ = new_flags;
return *this;
}
template <typename Char, typename T>
friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const value<T>& rhs);
// implemented in toml_default_formatter.h
value& operator= (value_arg rhs) noexcept
{
if constexpr (std::is_same_v<value_type, std::string>)
@ -3810,6 +3936,7 @@ TOML_NAMESPACE_START
template <typename Char>
friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const array&);
// implemented in toml_default_formatter.h
};
}
TOML_NAMESPACE_END
@ -4323,6 +4450,7 @@ TOML_NAMESPACE_START
template <typename Char>
friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const table&);
// implemented in toml_default_formatter.h
};
#ifndef DOXYGEN
@ -5741,39 +5869,6 @@ TOML_IMPL_NAMESPACE_END
TOML_PUSH_WARNINGS
TOML_DISABLE_SWITCH_WARNINGS
TOML_NAMESPACE_START
{
enum class format_flags : uint8_t
{
none,
quote_dates_and_times = 1,
allow_literal_strings = 2,
allow_multi_line_strings = 4,
};
[[nodiscard]]
TOML_ALWAYS_INLINE
TOML_ATTR(const)
TOML_ATTR(flatten)
constexpr format_flags operator & (format_flags lhs, format_flags rhs) noexcept
{
return static_cast<format_flags>(impl::unwrap_enum(lhs) & impl::unwrap_enum(rhs));
}
[[nodiscard]]
TOML_ALWAYS_INLINE
TOML_ATTR(const)
TOML_ATTR(flatten)
constexpr format_flags operator | (format_flags lhs, format_flags rhs) noexcept
{
return static_cast<format_flags>( impl::unwrap_enum(lhs) | impl::unwrap_enum(rhs) );
}
}
TOML_NAMESPACE_END
TOML_IMPL_NAMESPACE_START
{
template <typename Char = char>
@ -5783,7 +5878,7 @@ TOML_IMPL_NAMESPACE_START
const toml::node* source_;
std::basic_ostream<Char>* stream_ = nullptr;
format_flags flags_;
int8_t indent_;
int indent_;
bool naked_newline_;
protected:
@ -5793,8 +5888,8 @@ TOML_IMPL_NAMESPACE_START
static constexpr size_t indent_columns = 4;
static constexpr std::string_view indent_string = " "sv;
[[nodiscard]] int8_t indent() const noexcept { return indent_; }
void indent(int8_t level) noexcept { indent_ = level; }
[[nodiscard]] int indent() const noexcept { return indent_; }
void indent(int level) noexcept { indent_ = level; }
void increase_indent() noexcept { indent_++; }
void decrease_indent() noexcept { indent_--; }
[[nodiscard]]
@ -5815,6 +5910,12 @@ TOML_IMPL_NAMESPACE_START
return (flags_ & format_flags::allow_multi_line_strings) != format_flags::none;
}
[[nodiscard]]
bool value_format_flags_allowed() const noexcept
{
return (flags_ & format_flags::allow_value_format_flags) != format_flags::none;
}
[[nodiscard]]
bool naked_newline() const noexcept
{
@ -5849,7 +5950,7 @@ TOML_IMPL_NAMESPACE_START
void print_indent()
{
for (int8_t i = 0; i < indent_; i++)
for (int i = 0; i < indent_; i++)
{
print_to_stream(indent_string, *stream_);
naked_newline_ = false;
@ -5923,12 +6024,7 @@ TOML_IMPL_NAMESPACE_START
}
else
{
static constexpr auto is_dt =
std::is_same_v<T, date>
|| std::is_same_v<T, time>
|| std::is_same_v<T, date_time>;
if constexpr (is_dt)
if constexpr (is_one_of<T, date, time, date_time>)
{
if (quote_dates_and_times())
{
@ -5940,6 +6036,27 @@ TOML_IMPL_NAMESPACE_START
else
print_to_stream(*val, *stream_);
}
else if constexpr (is_one_of<T, int64_t/*, double*/>)
{
if (value_format_flags_allowed() && *val >= 0)
{
const auto fmt = val.flags() & value_flags::format_as_hexadecimal;
if (fmt != value_flags::none)
{
switch (fmt)
{
case value_flags::format_as_binary: print_to_stream("0b"sv, *stream_); break;
case value_flags::format_as_octal: print_to_stream("0o"sv, *stream_); break;
case value_flags::format_as_hexadecimal: print_to_stream("0x"sv, *stream_); break;
}
print_to_stream(*val, *stream_, fmt);
}
else
print_to_stream(*val, *stream_);
}
else
print_to_stream(*val, *stream_);
}
else
print_to_stream(*val, *stream_);
@ -6261,7 +6378,9 @@ TOML_NAMESPACE_START
public:
static constexpr format_flags default_flags
= format_flags::allow_literal_strings | format_flags::allow_multi_line_strings;
= format_flags::allow_literal_strings
| format_flags::allow_multi_line_strings
| format_flags::allow_value_format_flags;
TOML_NODISCARD_CTOR
explicit default_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
@ -10500,11 +10619,20 @@ TOML_IMPL_NAMESPACE_START
if (has_any(has_p))
val = new value{ parse_hex_float() };
else if (has_any(has_x))
{
val = new value{ parse_integer<16>() };
reinterpret_cast<value<int64_t>*>(val)->flags(value_flags::format_as_hexadecimal);
}
else if (has_any(has_o))
{
val = new value{ parse_integer<8>() };
reinterpret_cast<value<int64_t>*>(val)->flags(value_flags::format_as_octal);
}
else if (has_any(has_b))
{
val = new value{ parse_integer<2>() };
reinterpret_cast<value<int64_t>*>(val)->flags(value_flags::format_as_binary);
}
else if (has_any(has_e) || (has_any(begins_zero | begins_digit) && chars[1] == U'.'))
val = new value{ parse_float() };
else if (has_any(begins_sign))
@ -10544,12 +10672,14 @@ TOML_IMPL_NAMESPACE_START
// 0b10
case bzero_msk | has_b:
val = new value{ parse_integer<2>() };
reinterpret_cast<value<int64_t>*>(val)->flags(value_flags::format_as_binary);
break;
//=================== octal integers
// 0o10
case bzero_msk | has_o:
val = new value{ parse_integer<8>() };
reinterpret_cast<value<int64_t>*>(val)->flags(value_flags::format_as_octal);
break;
//=================== decimal integers
@ -10568,6 +10698,7 @@ TOML_IMPL_NAMESPACE_START
// 0x10
case bzero_msk | has_x:
val = new value{ parse_integer<16>() };
reinterpret_cast<value<int64_t>*>(val)->flags(value_flags::format_as_hexadecimal);
break;
//=================== decimal floats
@ -11703,6 +11834,7 @@ TOML_POP_WARNINGS // TOML_DISABLE_SPAM_WARNINGS
#undef TOML_LANG_UNRELEASED
#undef TOML_LAUNDER
#undef TOML_LIKELY
#undef TOML_MAKE_BITOPS
#undef TOML_MAKE_VERSION
#undef TOML_MAY_THROW
#undef TOML_MSVC