string value serialization now emits literals where possible (closes #43)

also added support for wide strings on Windows (closes #42):
- added wide-string path arg overloads of `parse()` and `parse_file()`
- added wide-string support to all relevant `table` and `array` ops
- added `std::wstring` support to `node::value()` and `node::value_or()`
- added `std::wstring` support to `node_view::value()` and `node_view::value_or()`
- added wide-string overloads of `table::operator[]`
- added wide-string overloads of `node_view::operator[]`
- added `source_region::wide_path()`
- added `TOML_WINDOWS_COMPAT` switch for explicitly enabling/disabling this stuff

also:
- fixed internal macro `assert_or_assume` leaking out of `toml_parser.hpp`
- deprecated `node_view::get()` in favour of `node_view::node()`
- minor documentation fixes
- minor cleanup
This commit is contained in:
Mark Gillard 2020-07-13 21:18:04 +03:00
parent 8d958fcc54
commit de07ba7187
52 changed files with 1980 additions and 612 deletions

View File

@ -10,10 +10,13 @@ end_of_line = lf
[*.{gitattributes, yml, props, vcxproj}]
indent_style = space
[{Doxyfile, Doxyfile-mcss}]
indent_style = space
[*.{natvis, props, vcxproj, sln, runsettings}]
end_of_line = crlf
[*.{c, cpp, cxx, h, hpp, hxx, inl, toml, xml, py, natvis, props, build, vcxproj, runsettings, yml, ini, json}]
[*.{c, cpp, cxx, dox, h, hpp, hxx, inl, toml, xml, py, natvis, props, build, vcxproj, runsettings, yml, ini, json}]
charset = utf-8
trim_trailing_whitespace = true

1
.gitattributes vendored
View File

@ -2,6 +2,7 @@
*.c text encoding=UTF-8 eol=lf
*.cpp text encoding=UTF-8 eol=lf
*.cxx text encoding=UTF-8 eol=lf
*.dox text encoding=UTF-8 eol=lf
*.h text encoding=UTF-8 eol=lf
*.hpp text encoding=UTF-8 eol=lf
*.hxx text encoding=UTF-8 eol=lf

View File

@ -113,21 +113,22 @@ single-header flavour, however specifying the option `"multiple_headers": True`
A number of configurable options are exposed in the form of preprocessor `#defines`. Most likely you
won't need to mess with these at all, but if you do, set them before including toml++.
| Option | Type | Default | Description |
|----------------------------|:--------------:|-----------------------------------|------------------------------------------------------------------------------------------------------------|
| `TOML_ALL_INLINE` | boolean | `1` | Disable this to explicitly control where toml++'s implementation is compiled (e.g. as part of a library). |
| `TOML_API` | define | undefined | API annotation to add to public symbols (e.g. `__declspec(dllexport)` on Windows). |
| `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. **_Experimental!_** |
| `TOML_CONFIG_HEADER` | string literal | undefined | Includes the given header file before the rest of the library. |
| `TOML_EXCEPTIONS` | boolean | per your compiler's settings | Sets whether the library uses exceptions. |
| `TOML_IMPLEMENTATION` | define | undefined | Define this to enable compilation of the library's implementation. Meaningless if `TOML_ALL_INLINE` is `1`.|
| `TOML_LARGE_FILES` | boolean | `0` | Uses 32-bit integers for line and column indices (instead of 16-bit). |
| `TOML_OPTIONAL_TYPE` | type name | undefined | Overrides the `optional<T>` type used by the library if you need [something better than std::optional]. |
| `TOML_PARSER` | boolean | `1` | Disable this to prevent inclusion of the parser-related parts of the library if you don't need them. |
| `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. |
| `TOML_SMALL_INT_TYPE` | type name | undefined | If your codebase has an additional 'small' integer type (e.g. 24-bits), this tells toml++ about it. |
| `TOML_UNRELEASED_FEATURES` | boolean | `0` | Enables support for [unreleased TOML language features] not yet part of a [numbered version]. |
| Option | Type | Default | Description |
|----------------------------|:--------------:|-----------------------------------|----------------------------------------------------------------------------------------------------------------------|
| `TOML_ALL_INLINE` | boolean | `1` | Disable this to explicitly control where toml++'s implementation is compiled (e.g. as part of a library). |
| `TOML_API` | define | undefined | API annotation to add to public symbols (e.g. `__declspec(dllexport)` on Windows). |
| `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. **_Experimental!_** |
| `TOML_CONFIG_HEADER` | string literal | undefined | Includes the given header file before the rest of the library. |
| `TOML_EXCEPTIONS` | boolean | per your compiler's settings | Sets whether the library uses exceptions. |
| `TOML_IMPLEMENTATION` | define | undefined | Define this to enable compilation of the library's implementation. Meaningless if `TOML_ALL_INLINE` is `1`. |
| `TOML_LARGE_FILES` | boolean | `0` | Uses 32-bit integers for line and column indices (instead of 16-bit). |
| `TOML_OPTIONAL_TYPE` | type name | undefined | Overrides the `optional<T>` type used by the library if you need [something better than std::optional]. |
| `TOML_PARSER` | boolean | `1` | Disable this to prevent inclusion of the parser-related parts of the library if you don't need them. |
| `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. |
| `TOML_SMALL_INT_TYPE` | type name | undefined | If your codebase has an additional 'small' integer type (e.g. 24-bits), this tells toml++ about it. |
| `TOML_UNRELEASED_FEATURES` | boolean | `0` | Enables support for [unreleased TOML language features] not yet part of a [numbered version]. |
| `TOML_WINDOWS_COMPAT` | boolean | `1` on Windows | Enables support for transparent conversion between wide and narrow strings in some places when building for Windows. |
> _A number of these have ABI implications; the library uses inline namespaces to prevent you from accidentally
linking incompatible combinations together._
@ -180,6 +181,7 @@ UTF-8 decoding is performed using a state machine based on Bjoern Hoehrmann's '[
- **[@bjadamson](https://github.com/bjadamson)** - Reported some bugs and helped design a new feature
- **[@bobfang1992](https://github.com/bobfang1992)** - Reported a bug and created a [wrapper in python](https://github.com/bobfang1992/pytomlpp)
- **[@GiulioRomualdi](https://github.com/GiulioRomualdi)** - Added cmake+meson support
- **[@levicki](https://github.com/levicki)** - Helped design some new features
- **[@mosra](https://github.com/mosra)** - Created the awesome [m.css] used to generate the API docs
- **[@ned14](https://github.com/ned14)** - Reported a bunch of bugs and helped design some new features
- **[@okureta](https://github.com/okureta)** - Reported a bug

View File

@ -40,26 +40,26 @@ INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
ALIASES = \
"cpp=@code{.cpp}" \
"ecpp=@endcode" \
"out=@code{.shell-session}" \
"eout=@endcode" \
"bash=@code{.sh}" \
"ebash=@endcode" \
"detail=@details" \
"gh{1}=<a href=\"https://github.com/\1\" target=\"_blank\">\1</a>" \
"gh2{2}=<a href=\"https://github.com/\1\" target=\"_blank\">\2</a>" \
"godbolt{1}=<a href=\"https://godbolt.org/z/\1\" target=\"_blank\">Try this code on Compiler Explorer</a>" \
"m_div{1}=@xmlonly<mcss:div xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:class=\"\1\">@endxmlonly" \
"m_enddiv=@xmlonly</mcss:div>@endxmlonly" \
"m_span{1}=@xmlonly<mcss:span xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:class=\"\1\">@endxmlonly" \
"m_endspan=@xmlonly</mcss:span>@endxmlonly" \
"m_class{1}=@xmlonly<mcss:class xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:class=\"\1\" />@endxmlonly" \
"m_footernavigation=@xmlonly<mcss:footernavigation xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" />@endxmlonly" \
"m_examplenavigation{2}=@xmlonly<mcss:examplenavigation xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:page=\"\1\" mcss:prefix=\"\2\" />@endxmlonly" \
"m_keywords{1}=@xmlonly<mcss:search xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:keywords=\"\1\" />@endxmlonly" \
"m_keyword{3}=@xmlonly<mcss:search xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:keyword=\"\1\" mcss:title=\"\2\" mcss:suffix-length=\"\3\" />@endxmlonly" \
"m_enum_values_as_keywords=@xmlonly<mcss:search xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:enum-values-as-keywords=\"true\" />@endxmlonly"
"cpp=@code{.cpp}" \
"ecpp=@endcode" \
"out=@code{.shell-session}" \
"eout=@endcode" \
"bash=@code{.sh}" \
"ebash=@endcode" \
"detail=@details" \
"gh{1}=<a href=\"https://github.com/\1\" target=\"_blank\">\1</a>" \
"gh2{2}=<a href=\"https://github.com/\1\" target=\"_blank\">\2</a>" \
"godbolt{1}=<a href=\"https://godbolt.org/z/\1\" target=\"_blank\">Try this code on Compiler Explorer</a>" \
"m_div{1}=@xmlonly<mcss:div xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:class=\"\1\">@endxmlonly" \
"m_enddiv=@xmlonly</mcss:div>@endxmlonly" \
"m_span{1}=@xmlonly<mcss:span xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:class=\"\1\">@endxmlonly" \
"m_endspan=@xmlonly</mcss:span>@endxmlonly" \
"m_class{1}=@xmlonly<mcss:class xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:class=\"\1\" />@endxmlonly" \
"m_footernavigation=@xmlonly<mcss:footernavigation xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" />@endxmlonly" \
"m_examplenavigation{2}=@xmlonly<mcss:examplenavigation xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:page=\"\1\" mcss:prefix=\"\2\" />@endxmlonly" \
"m_keywords{1}=@xmlonly<mcss:search xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:keywords=\"\1\" />@endxmlonly" \
"m_keyword{3}=@xmlonly<mcss:search xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:keyword=\"\1\" mcss:title=\"\2\" mcss:suffix-length=\"\3\" />@endxmlonly" \
"m_enum_values_as_keywords=@xmlonly<mcss:search xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:enum-values-as-keywords=\"true\" />@endxmlonly"
TCL_SUBST =
OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_JAVA = NO
@ -309,30 +309,32 @@ EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = NO
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED = TOML_DOXYGEN=1 \
TOML_ALWAYS_INLINE=inline \
TOML_MAY_THROW= \
TOML_NODISCARD_CTOR= \
TOML_EXTERNAL_LINKAGE= \
TOML_API= \
TOML_ABI_NAMESPACE_START(x)= \
TOML_ABI_NAMESPACE_END= \
TOML_ATTR(...)= \
TOML_PUSH_WARNINGS= \
TOML_DISABLE_SWITCH_WARNINGS= \
TOML_DISABLE_INIT_WARNINGS= \
TOML_DISABLE_VTABLE_WARNINGS= \
TOML_DISABLE_PADDING_WARNINGS= \
TOML_DISABLE_FLOAT_WARNINGS= \
TOML_DISABLE_SHADOW_WARNINGS= \
TOML_DISABLE_SUGGEST_WARNINGS= \
TOML_DISABLE_ALL_WARNINGS= \
TOML_POP_WARNINGS= \
TOML_ASYMMETRICAL_EQUALITY_OPS(...)= \
__cplusplus=201703L \
__has_include(x)=0 \
__has_attribute(x)=0 \
__cpp_lib_char8_t=201811L
PREDEFINED = DOXYGEN=1 \
NDEBUG=1 \
__cplusplus=201703L \
__has_include(x)=0 \
__has_attribute(x)=0 \
__cpp_lib_char8_t=201811L \
TOML_ALWAYS_INLINE=inline \
TOML_MAY_THROW= \
TOML_NODISCARD_CTOR= \
TOML_EXTERNAL_LINKAGE= \
TOML_API= \
TOML_ABI_NAMESPACE_START(...)= \
TOML_ABI_NAMESPACE_BOOL(...)= \
TOML_ABI_NAMESPACE_END= \
TOML_ATTR(...)= \
TOML_PUSH_WARNINGS= \
TOML_DISABLE_SWITCH_WARNINGS= \
TOML_DISABLE_INIT_WARNINGS= \
TOML_DISABLE_VTABLE_WARNINGS= \
TOML_DISABLE_PADDING_WARNINGS= \
TOML_DISABLE_FLOAT_WARNINGS= \
TOML_DISABLE_SHADOW_WARNINGS= \
TOML_DISABLE_SUGGEST_WARNINGS= \
TOML_DISABLE_ALL_WARNINGS= \
TOML_POP_WARNINGS= \
TOML_ASYMMETRICAL_EQUALITY_OPS(...)=
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = NO
#---------------------------------------------------------------------------

View File

@ -227,10 +227,10 @@
///
/// // different ways of directly querying data
/// std::optional<std::string_view> str1 = tbl["str"].value<std::string_view>();
/// std::optional<std::string> str2 = tbl["str"].value<std::string>();
/// std::string_view str3 = tbl["str"].value_or("");
/// std::string str4 = tbl["str"].value_or(std::string{});
/// std::string& str5 = tbl["str"].ref<std::string>(); // ~~dangerous~~, but fast
/// std::optional<std::string> str2 = tbl["str"].value<std::string>();
/// std::string_view str3 = tbl["str"].value_or("");
/// std::string str4 = tbl["str"].value_or(std::string{});
/// std::string& str5 = tbl["str"].ref<std::string>(); // ~~dangerous~~, but fast
///
/// std::cout << *str1 << "\n";
/// std::cout << *str2 << "\n";
@ -443,7 +443,7 @@
///
/// \subsection mainpage-adding-lib-conan Conan
/// Add `tomlplusplus/1.3.3` to your conanfile. This adds the single-header version by default, but you can specify the
/// regular version using `multiple_headers": True`.
/// regular version using `"multiple_headers": True`.
///
//////////////////////////////////
///

View File

@ -34,8 +34,15 @@ odt1 = 1979-05-27T07:32:00Z
odt2 = 1979-05-27T00:32:00-07:00
odt3 = 1979-05-27T00:32:00.999999-07:00
# unicode
kosme = "κόσμε"
# strings
str1 = """
This is a
multi-line
string.
"""
str2 = "This is also\na multi-line\nstring."
str3 = 'C:\highway\to\the\danger\zone'
kosme = "κόσμε" # unicode!
arr = [ 'this', 'is', 'a', 'long', 'array', 'with', 16, 'elements.', 'it', 'should', 'be', 'printed', 'as', 'a', 'multiline', 'array.']

View File

@ -29,7 +29,7 @@
#define NOMETAFILE // - typedef METAFILEPICT
#define NOMINMAX // - Macros min(a,b) and max(a,b)
#define NOMSG // - typedef MSG and associated routines
#define NONLS // - All NLS defines and routines
//#define NONLS // - All NLS defines and routines
#define NOOPENFILE // - OpenFile(), OemToAnsi, AnsiToOem, and OF_*
#define NOPROFILER // - Profiler interface.
#define NORASTEROPS // - Binary and Tertiary raster ops

View File

@ -69,7 +69,6 @@
#undef TOML_UNREACHABLE
#undef TOML_INTERFACE
#undef TOML_EMPTY_BASES
#undef TOML_CPP_VERSION
#undef TOML_CPP
#undef TOML_MAY_THROW
#undef TOML_NO_DEFAULT_CASE
@ -82,7 +81,6 @@
#undef TOML_LANG_HIGHER_THAN
#undef TOML_LANG_AT_LEAST
#undef TOML_LANG_UNRELEASED
#undef TOML_STRING_PREFIX_1
#undef TOML_STRING_PREFIX
#undef TOML_UNDEF_MACROS
#undef TOML_RELOPS_REORDERING
@ -96,9 +94,15 @@
#undef TOML_TRIVIAL_ABI
#undef TOML_ABI_NAMESPACES
#undef TOML_ABI_NAMESPACE_START
#undef TOML_ABI_NAMESPACE_BOOL
#undef TOML_ABI_NAMESPACE_END
#undef TOML_PARSER_TYPENAME
#undef TOML_LAUNDER
#undef TOML_CONCAT_1
#undef TOML_CONCAT
#undef TOML_EVAL_BOOL_1
#undef TOML_EVAL_BOOL_0
#undef TOML_HAS_CUSTOM_OPTIONAL_TYPE
#endif
//# {{

View File

@ -185,11 +185,20 @@ namespace toml::impl
}
else
{
static_assert(
!is_wide_string<T> || TOML_WINDOWS_COMPAT,
"Instantiating values from wide-character strings is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
);
static_assert(
is_value_or_promotable<type>,
"Value initializers must be (or be promotable to) one of the TOML value types"
);
return new value{ std::forward<T>(val) };
#if TOML_WINDOWS_COMPAT
if constexpr (is_wide_string<T>)
return new value{ narrow(std::forward<T>(val)) };
else
#endif
return new value{ std::forward<T>(val) };
}
}
@ -656,7 +665,6 @@ namespace toml
/// \returns Iterator to the first node immediately following the last removed node.
iterator erase(const_iterator first, const_iterator last) noexcept;
/// \brief Resizes the array.
///
/// \detail \cpp
@ -943,6 +951,7 @@ namespace toml
return static_cast<toml::array&&>(static_cast<toml::array&>(*this).flatten());
}
/// \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&);
};

View File

@ -22,7 +22,7 @@ TOML_DISABLE_ALL_WARNINGS
#include <vector>
#include <map>
#include <iosfwd>
#ifndef TOML_OPTIONAL_TYPE
#if !TOML_HAS_CUSTOM_OPTIONAL_TYPE
#include <optional>
#endif
@ -40,6 +40,10 @@ TOML_POP_WARNINGS
////////// FORWARD DECLARATIONS & TYPEDEFS
TOML_PUSH_WARNINGS
TOML_DISABLE_PADDING_WARNINGS
TOML_DISABLE_SHADOW_WARNINGS
/// \brief The root namespace for all toml++ functions and types.
namespace toml
{
@ -78,9 +82,30 @@ namespace toml
#endif
TOML_PUSH_WARNINGS
TOML_DISABLE_PADDING_WARNINGS
TOML_DISABLE_SHADOW_WARNINGS // false positive on gcc
#if TOML_WINDOWS_COMPAT
namespace impl
{
[[nodiscard]] TOML_API std::string narrow_char(std::wstring_view) noexcept;
#ifdef __cpp_lib_char8_t
[[nodiscard]] TOML_API std::u8string narrow_char8(std::wstring_view) noexcept;
#endif
template <typename Char = string_char>
[[nodiscard]] auto narrow(std::wstring_view str) noexcept
{
#ifdef __cpp_lib_char8_t
if constexpr (std::is_same_v<Char, char8_t>)
return narrow_char8(str);
else
#endif
return narrow_char(str);
}
[[nodiscard]] TOML_API std::wstring widen(std::string_view) noexcept;
#ifdef __cpp_lib_char8_t
[[nodiscard]] TOML_API std::wstring widen(std::u8string_view) noexcept;
#endif
}
#endif
#if !TOML_DOXYGEN
@ -97,15 +122,11 @@ namespace toml
template <typename> class default_formatter;
template <typename> class json_formatter;
#ifdef TOML_OPTIONAL_TYPE
TOML_ABI_NAMESPACE_START(custopt)
#else
TOML_ABI_NAMESPACE_START(stdopt)
#endif
TOML_ABI_NAMESPACE_BOOL(TOML_HAS_CUSTOM_OPTIONAL_TYPE, custopt, stdopt)
struct date_time;
TOML_ABI_NAMESPACE_END // TOML_OPTIONAL_TYPE
TOML_ABI_NAMESPACE_END // TOML_HAS_CUSTOM_OPTIONAL_TYPE
#endif // !TOML_DOXYGEN
@ -124,9 +145,7 @@ namespace toml
date_time ///< The node is a toml::value<date_time>.
};
TOML_POP_WARNINGS // TOML_DISABLE_PADDING_WARNINGS, TOML_DISABLE_SHADOW_WARNINGS
#ifdef TOML_OPTIONAL_TYPE
#if TOML_HAS_CUSTOM_OPTIONAL_TYPE
template <typename T>
using optional = TOML_OPTIONAL_TYPE<T>;
@ -157,11 +176,7 @@ namespace toml
/// \brief A pointer to a shared string resource containing a source path.
using source_path_ptr = std::shared_ptr<const std::string>;
#if TOML_LARGE_FILES
TOML_ABI_NAMESPACE_START(lf)
#else
TOML_ABI_NAMESPACE_START(sf)
#endif
TOML_ABI_NAMESPACE_BOOL(TOML_LARGE_FILES, lf, sf)
/// \brief A source document line-and-column pair.
///
@ -276,6 +291,23 @@ namespace toml
///
/// \remarks This will be `nullptr` if no path was provided to toml::parse().
source_path_ptr path;
#if TOML_WINDOWS_COMPAT
/// \brief The path to the corresponding source document as a wide-string.
///
/// \remarks This will return an empty optional if no path was provided to toml::parse().
///
/// \attention This function is only available when #TOML_WINDOWS_COMPAT is enabled.
[[nodiscard]]
optional<std::wstring> wide_path() const noexcept
{
if (!path || path->empty())
return {};
return { impl::widen(*path) };
}
#endif
};
TOML_ABI_NAMESPACE_END // TOML_LARGE_FILES
@ -346,6 +378,15 @@ namespace toml::impl
|| std::is_same_v<T, time>
|| std::is_same_v<T, date_time>;
template <typename T>
inline constexpr bool is_wide_string = is_one_of<
std::decay_t<T>,
const wchar_t*,
wchar_t*,
std::wstring_view,
std::wstring
>;
template <typename T>
inline constexpr bool is_value_or_promotable =
is_value<T>
@ -358,6 +399,9 @@ namespace toml::impl
|| std::is_same_v<T, uint16_t>
|| std::is_same_v<T, uint8_t>
|| std::is_same_v<T, float>
#if TOML_WINDOWS_COMPAT
|| is_wide_string<T>
#endif
#ifdef TOML_SMALL_FLOAT_TYPE
|| std::is_same_v<T, TOML_SMALL_FLOAT_TYPE>
#endif
@ -399,6 +443,18 @@ namespace toml::impl
template <size_t N> struct value_promoter<string_char(&&)[N]> { using type = string; };
template <> struct value_promoter<string_char*> { using type = string; };
template <> struct value_promoter<string_view> { using type = string; };
#if TOML_WINDOWS_COMPAT
template <size_t N> struct value_promoter<const wchar_t[N]> { using type = string; };
template <size_t N> struct value_promoter<const wchar_t(&)[N]> { using type = string; };
template <size_t N> struct value_promoter<const wchar_t(&&)[N]> { using type = string; };
template <> struct value_promoter<const wchar_t*> { using type = string; };
template <size_t N> struct value_promoter<wchar_t[N]> { using type = string; };
template <size_t N> struct value_promoter<wchar_t(&)[N]> { using type = string; };
template <size_t N> struct value_promoter<wchar_t(&&)[N]> { using type = string; };
template <> struct value_promoter<wchar_t*> { using type = string; };
template <> struct value_promoter<std::wstring_view> { using type = string; };
template <> struct value_promoter<std::wstring> { using type = string; };
#endif
template <> struct value_promoter<int32_t> { using type = int64_t; };
template <> struct value_promoter<int16_t> { using type = int64_t; };
template <> struct value_promoter<int8_t> { using type = int64_t; };
@ -592,3 +648,5 @@ namespace toml
};
template <typename T> inserter(T&&) -> inserter<T>;
}
TOML_POP_WARNINGS // TOML_DISABLE_PADDING_WARNINGS, TOML_DISABLE_SHADOW_WARNINGS

View File

@ -300,11 +300,7 @@ namespace toml
extern template TOML_API std::ostream& operator << (std::ostream&, const time_offset&);
#endif
#ifdef TOML_OPTIONAL_TYPE
TOML_ABI_NAMESPACE_START(custopt)
#else
TOML_ABI_NAMESPACE_START(stdopt)
#endif
TOML_ABI_NAMESPACE_BOOL(TOML_HAS_CUSTOM_OPTIONAL_TYPE, custopt, stdopt)
/// \brief A date-time.
struct date_time
@ -407,7 +403,7 @@ namespace toml
}
};
TOML_ABI_NAMESPACE_END // TOML_OPTIONAL_TYPE
TOML_ABI_NAMESPACE_END // TOML_HAS_CUSTOM_OPTIONAL_TYPE
/// \brief Prints a date_time out to a stream in RFC 3339 format.
/// \detail \cpp

View File

@ -88,7 +88,11 @@ namespace toml
}
if (requiresQuotes)
base::print_quoted_string(str);
{
impl::print_to_stream('"', base::stream());
impl::print_to_stream_with_escapes(str, base::stream());
impl::print_to_stream('"', base::stream());
}
else
impl::print_to_stream(str, base::stream());
}
@ -320,12 +324,16 @@ namespace toml
public:
/// \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;
/// \brief Constructs a default formatter and binds it to a TOML object.
///
/// \param source The source TOML object.
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit default_formatter(const toml::node& source, format_flags flags = {}) noexcept
explicit default_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
: base{ source, flags }
{}
@ -377,12 +385,27 @@ namespace toml
return lhs << default_formatter<Char>{ rhs };
}
template <typename Char, typename T>
TOML_EXTERNAL_LINKAGE
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const value<T>& rhs)
{
return lhs << default_formatter<Char>{ rhs };
}
#if !TOML_ALL_INLINE
extern template TOML_API std::ostream& operator << (std::ostream&, default_formatter<char>&);
extern template TOML_API std::ostream& operator << (std::ostream&, default_formatter<char>&&);
extern template TOML_API std::ostream& operator << (std::ostream&, const table&);
extern template TOML_API std::ostream& operator << (std::ostream&, const array&);
extern template TOML_API std::ostream& operator << (std::ostream&, const value<toml::string>&);
extern template TOML_API std::ostream& operator << (std::ostream&, const value<int64_t>&);
extern template TOML_API std::ostream& operator << (std::ostream&, const value<double>&);
extern template TOML_API std::ostream& operator << (std::ostream&, const value<bool>&);
extern template TOML_API std::ostream& operator << (std::ostream&, const value<toml::date>&);
extern template TOML_API std::ostream& operator << (std::ostream&, const value<toml::time>&);
extern template TOML_API std::ostream& operator << (std::ostream&, const value<toml::date_time>&);
#endif
}
TOML_POP_WARNINGS // TOML_DISABLE_SWITCH_WARNINGS, TOML_DISABLE_PADDING_WARNINGS

View File

@ -206,3 +206,91 @@ namespace toml
}
TOML_POP_WARNINGS // TOML_DISABLE_SWITCH_WARNINGS, TOML_DISABLE_FLOAT_WARNINGS
// implementations of windows wide string nonsense
#if TOML_WINDOWS_COMPAT
TOML_PUSH_WARNINGS
TOML_DISABLE_ALL_WARNINGS
#include <Windows.h> // fuckkkk :(
TOML_POP_WARNINGS
namespace toml::impl
{
TOML_API
TOML_EXTERNAL_LINKAGE
std::string narrow_char(std::wstring_view str) noexcept
{
if (str.empty())
return {};
std::string s;
const auto len = WideCharToMultiByte(
65001, 0, str.data(), static_cast<int>(str.length()), nullptr, 0, nullptr, nullptr
);
if (len)
{
s.resize(static_cast<size_t>(len));
WideCharToMultiByte(65001, 0, str.data(), static_cast<int>(str.length()), s.data(), len, nullptr, nullptr);
}
return s;
}
#ifdef __cpp_lib_char8_t
TOML_API
TOML_EXTERNAL_LINKAGE
std::u8string narrow_char8(std::wstring_view str) noexcept
{
if (str.empty())
return {};
std::u8string s;
const auto len = WideCharToMultiByte(
65001, 0, str.data(), static_cast<int>(str.length()), nullptr, 0, nullptr, nullptr
);
if (len)
{
s.resize(static_cast<size_t>(len));
WideCharToMultiByte(
65001, 0, str.data(), static_cast<int>(str.length()), reinterpret_cast<char*>(s.data()), len, nullptr, nullptr
);
}
return s;
}
#endif // __cpp_lib_char8_t
TOML_API
TOML_EXTERNAL_LINKAGE
std::wstring widen(std::string_view str) noexcept
{
if (str.empty())
return {};
std::wstring s;
const auto len = MultiByteToWideChar(65001, 0, str.data(), static_cast<int>(str.length()), nullptr, 0);
if (len)
{
s.resize(static_cast<size_t>(len));
MultiByteToWideChar(65001, 0, str.data(), static_cast<int>(str.length()), s.data(), len);
}
return s;
}
#ifdef __cpp_lib_char8_t
TOML_API
TOML_EXTERNAL_LINKAGE
std::wstring widen(std::u8string_view str) noexcept
{
if (str.empty())
return {};
return widen(std::string_view{ reinterpret_cast<const char*>(str.data()), str.length() });
}
#endif // __cpp_lib_char8_t
}
#endif // TOML_WINDOWS_COMPAT

View File

@ -15,8 +15,17 @@ namespace toml
/// \brief Format flags for modifying how TOML data is printed to streams.
enum class format_flags : uint8_t
{
/// \brief None.
none,
quote_dates_and_times = 1
/// \brief Sates 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]]
@ -51,7 +60,6 @@ namespace toml::impl
protected:
[[nodiscard]] const toml::node& source() const noexcept { return *source_; }
[[nodiscard]] format_flags flags() const noexcept { return flags_; }
[[nodiscard]] std::basic_ostream<Char>& stream() const noexcept { return *stream_; }
static constexpr size_t indent_columns = 4;
@ -61,8 +69,28 @@ namespace toml::impl
void increase_indent() noexcept { indent_++; }
void decrease_indent() noexcept { indent_--; }
TOML_ALWAYS_INLINE
void clear_naked_newline() noexcept { naked_newline_ = false; }
[[nodiscard]]
bool quote_dates_and_times() const noexcept
{
return (flags_ & format_flags::quote_dates_and_times) != format_flags::none;
}
[[nodiscard]]
bool literal_strings_allowed() const noexcept
{
return (flags_ & format_flags::allow_literal_strings) != format_flags::none;
}
[[nodiscard]]
bool multi_line_strings_allowed() const noexcept
{
return (flags_ & format_flags::allow_multi_line_strings) != format_flags::none;
}
void clear_naked_newline() noexcept
{
naked_newline_ = false;
}
void attach(std::basic_ostream<Char>& stream) noexcept
{
@ -94,17 +122,62 @@ namespace toml::impl
}
}
void print_quoted_string(toml::string_view str)
void print_quoted_string(toml::string_view str, bool allow_multi_line = true)
{
auto literals = literal_strings_allowed();
if (str.empty())
print_to_stream("\"\""sv, *stream_);
{
print_to_stream(literals ? "''"sv : "\"\""sv, *stream_);
clear_naked_newline();
return;
}
auto multi_line = allow_multi_line && multi_line_strings_allowed();
if (multi_line || literals)
{
utf8_decoder decoder;
bool has_line_breaks = false;
bool has_control_chars = false;
bool has_single_quotes = false;
for (size_t i = 0; i < str.length() && !(has_line_breaks && has_control_chars && has_single_quotes); i++)
{
decoder(static_cast<uint8_t>(str[i]));
if (decoder.error())
{
has_line_breaks = false;
has_control_chars = true; //force ""
has_single_quotes = true;
break;
}
else if (decoder.has_code_point())
{
if (is_line_break(decoder.codepoint))
has_line_breaks = true;
else if (is_nontab_control_character(decoder.codepoint))
has_control_chars = true;
else if (decoder.codepoint == U'\'')
has_single_quotes = true;
}
}
multi_line = multi_line && has_line_breaks;
literals = literals && !has_control_chars && !(!multi_line && has_single_quotes);
}
if (literals)
{
const auto quot = multi_line ? "'''"sv : "'"sv;
print_to_stream(quot, *stream_);
print_to_stream(str, *stream_);
print_to_stream(quot, *stream_);
}
else
{
print_to_stream('"', *stream_);
const auto quot = multi_line ? R"(""")"sv : R"(")"sv;
print_to_stream(quot, *stream_);
print_to_stream_with_escapes(str, *stream_);
print_to_stream('"', *stream_);
print_to_stream(quot, *stream_);
}
naked_newline_ = false;
clear_naked_newline();
}
template <typename T>
@ -123,17 +196,18 @@ namespace toml::impl
if constexpr (is_dt)
{
if ((flags_ & format_flags::quote_dates_and_times) != format_flags::none)
print_to_stream('"', *stream_);
}
*stream_ << val;
if constexpr (is_dt)
{
if ((flags_ & format_flags::quote_dates_and_times) != format_flags::none)
print_to_stream('"', *stream_);
if (quote_dates_and_times())
{
const auto quot = literal_strings_allowed() ? '\'' : '"';
print_to_stream(quot, *stream_);
print_to_stream(*val, *stream_);
print_to_stream(quot, *stream_);
}
else
print_to_stream(*val, *stream_);
}
else
print_to_stream(*val, *stream_);
naked_newline_ = false;
}

View File

@ -24,6 +24,7 @@ TOML_POP_WARNINGS
#include "toml_default_formatter.h"
#include "toml_json_formatter.h"
// template instantiations
namespace toml
{
// value<>
@ -77,26 +78,32 @@ namespace toml
template TOML_API void print_floating_point_to_stream(float, std::ostream&, bool);
template TOML_API void print_floating_point_to_stream(double, std::ostream&, bool);
}
// parser machinery
#if TOML_PARSER
// parse error ostream
template TOML_API std::ostream& operator << (std::ostream&, const parse_error&);
// parse() and parse_file()
#if TOML_EXCEPTIONS
TOML_ABI_NAMESPACE_START(parse_ex)
#else
TOML_ABI_NAMESPACE_START(parse_noex)
#endif
template TOML_API parse_result parse(std::istream&, std::string_view) TOML_MAY_THROW;
template TOML_API parse_result parse(std::istream&, std::string&&) TOML_MAY_THROW;
template TOML_API parse_result parse_file(std::string_view) TOML_MAY_THROW;
#ifdef __cpp_lib_char8_t
template TOML_API parse_result parse_file(std::u8string_view) TOML_MAY_THROW;
#endif
TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
#endif // TOML_PARSER
}
// parser instantiations
#if TOML_PARSER
#include "toml_parser.h"
namespace toml
{
// parse error ostream
template TOML_API std::ostream& operator << (std::ostream&, const parse_error&);
// parse() and parse_file()
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, parse_ex, parse_noex)
template TOML_API parse_result parse(std::istream&, std::string_view) TOML_MAY_THROW;
template TOML_API parse_result parse(std::istream&, std::string&&) TOML_MAY_THROW;
template TOML_API parse_result parse_file(std::string_view) TOML_MAY_THROW;
#ifdef __cpp_lib_char8_t
template TOML_API parse_result parse_file(std::u8string_view) TOML_MAY_THROW;
#endif
#if TOML_WINDOWS_COMPAT
template TOML_API parse_result parse_file(std::wstring_view) TOML_MAY_THROW;
#endif
TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
}
#endif // TOML_PARSER

View File

@ -104,13 +104,16 @@ namespace toml
public:
/// \brief The default flags for a json_formatter.
static constexpr format_flags default_flags = format_flags::quote_dates_and_times;
/// \brief Constructs a JSON formatter and binds it to a TOML object.
///
/// \param source The source TOML object.
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit json_formatter(const toml::node& source, format_flags flags = {}) noexcept
: base{ source, flags | format_flags::quote_dates_and_times }
explicit json_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
: base{ source, flags }
{}
template <typename T, typename U>

View File

@ -37,7 +37,7 @@ namespace toml
base::print_newline(true);
base::print_indent();
base::print_quoted_string(k);
base::print_quoted_string(k, false);
impl::print_to_stream(" : "sv, base::stream());
const auto type = v.type();

View File

@ -48,7 +48,7 @@ namespace toml
/// std::cout << tbl["products"][0]["keywords"] << std::endl;
/// std::cout << "has product[2]: "sv << !!tbl["products"][2] << std::endl;
/// std::cout << "product[2]: "sv << tbl["products"][2] << std::endl;
/// \ecpp
/// \ecpp
///
/// \out
/// "my hardware store"
@ -89,7 +89,10 @@ namespace toml
/// \brief Returns true if the view references a node.
[[nodiscard]] explicit operator bool() const noexcept { return node_ != nullptr; }
/// \brief Returns the node that's being referenced by the view.
[[nodiscard]] viewed_type* get() const noexcept { return node_; }
[[nodiscard]] viewed_type* node() const noexcept { return node_; }
[[nodiscard, deprecated("use node_view::node() instead (the name is better)")]]
viewed_type* get() const noexcept { return node_; }
/// \brief Returns the type identifier for the viewed node.
[[nodiscard]] node_type type() const noexcept { return node_ ? node_->type() : node_type::none; }
@ -296,13 +299,25 @@ namespace toml
template <typename U, typename = std::enable_if_t<impl::is_value_or_promotable<U>>>
[[nodiscard]] friend bool operator == (const node_view& lhs, const U& rhs) noexcept
{
const auto val = lhs.as<impl::promoted<U>>();
return val && *val == rhs;
static_assert(
!impl::is_wide_string<U> || TOML_WINDOWS_COMPAT,
"Comparison with wide-character strings is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
);
#if TOML_WINDOWS_COMPAT
if constexpr (impl::is_wide_string<U>)
return lhs == impl::narrow(rhs);
else
#endif
{
const auto val = lhs.as<impl::promoted<U>>();
return val && *val == rhs;
}
}
TOML_ASYMMETRICAL_EQUALITY_OPS(
const node_view&,
const U&,
template <typename U, typename = std::enable_if_t<impl::is_value_or_promotable<U>>>
const node_view&,
const U&,
template <typename U, typename = std::enable_if_t<impl::is_value_or_promotable<U>>>
)
/// \brief Returns true if the viewed node is an array with the same contents as the RHS initializer list.
@ -336,6 +351,25 @@ namespace toml
return { nullptr };
}
#if TOML_WINDOWS_COMPAT
/// \brief Returns a view of the selected subnode.
///
/// \param key The key of the node to retrieve
///
/// \returns A view of the selected node if this node represented a table and it contained a
/// value at the given key, or an empty view.
///
/// \attention This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
[[nodiscard]] node_view operator[] (std::wstring_view key) const noexcept
{
if (auto tbl = this->as_table())
return { tbl->get(key) };
return { nullptr };
}
#endif // TOML_WINDOWS_COMPAT
/// \brief Returns a view of the selected subnode.
///
/// \param index The index of the node to retrieve

View File

@ -23,11 +23,7 @@ TOML_DISABLE_VTABLE_WARNINGS
namespace toml
{
#if TOML_LARGE_FILES
TOML_ABI_NAMESPACE_START(lf)
#else
TOML_ABI_NAMESPACE_START(sf)
#endif
TOML_ABI_NAMESPACE_BOOL(TOML_LARGE_FILES, lf, sf)
#if TOML_DOXYGEN || !TOML_EXCEPTIONS

View File

@ -86,7 +86,7 @@ namespace toml
[[nodiscard]] bool succeeded() const noexcept { return !is_err; }
/// \brief Returns true if parsing failed.
[[nodiscard]] bool failed() const noexcept { return is_err; }
/// \brief Returns true if parsing succeeeded.
/// \brief Returns true if parsing succeeded.
[[nodiscard]] explicit operator bool() const noexcept { return !is_err; }
/// \brief Returns the internal toml::table.
@ -208,11 +208,52 @@ namespace toml
}
/// \brief Gets a node_view for the selected key-value pair in the wrapped table (const overload).
///
/// \param key The key used for the lookup.
///
/// \returns A view of the value at the given key if parsing was successful and a matching key existed,
/// or an empty node view.
///
/// \see toml::node_view
[[nodiscard]] node_view<const node> operator[] (string_view key) const noexcept
{
return is_err ? node_view<const node>{} : get()[key];
}
#if TOML_WINDOWS_COMPAT
/// \brief Gets a node_view for the selected key-value pair in the wrapped table.
///
/// \param key The key used for the lookup.
///
/// \returns A view of the value at the given key if parsing was successful and a matching key existed,
/// or an empty node view.
///
/// \see toml::node_view
///
/// \attention This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
[[nodiscard]] node_view<node> operator[] (std::wstring_view key) noexcept
{
return is_err ? node_view<node>{} : get()[key];
}
/// \brief Gets a node_view for the selected key-value pair in the wrapped table (const overload).
///
/// \param key The key used for the lookup.
///
/// \returns A view of the value at the given key if parsing was successful and a matching key existed,
/// or an empty node view.
///
/// \see toml::node_view
///
/// \attention This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
[[nodiscard]] node_view<const node> operator[] (std::wstring_view key) const noexcept
{
return is_err ? node_view<const node>{} : get()[key];
}
#endif // TOML_WINDOWS_COMPAT
/// \brief Returns an iterator to the first key-value pair in the wrapped table.
/// \remarks Returns a default-constructed 'nothing' iterator if the parsing failed.
[[nodiscard]] table_iterator begin() noexcept
@ -265,14 +306,9 @@ namespace toml
#endif
}
namespace toml::impl
{
#if TOML_EXCEPTIONS
TOML_ABI_NAMESPACE_START(impl_ex)
#else
TOML_ABI_NAMESPACE_START(impl_noex)
#endif
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, impl_ex, impl_noex)
[[nodiscard]] TOML_API
parse_result do_parse(utf8_reader_interface&&) TOML_MAY_THROW;
@ -280,14 +316,21 @@ namespace toml::impl
TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
}
#if TOML_EXCEPTIONS
#define TOML_THROW_PARSE_ERROR(msg, path) \
throw parse_error{ \
msg, source_position{}, std::make_shared<const std::string>(std::move(path)) \
}
#else
#define TOML_THROW_PARSE_ERROR(msg, path) \
return parse_result{ parse_error{ \
msg, source_position{}, std::make_shared<const std::string>(std::move(path)) \
}}
#endif
namespace toml
{
#if TOML_EXCEPTIONS
TOML_ABI_NAMESPACE_START(parse_ex)
#else
TOML_ABI_NAMESPACE_START(parse_noex)
#endif
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, parse_ex, parse_noex)
/// \brief Parses a TOML document from a string view.
///
@ -326,6 +369,8 @@ namespace toml
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns <strong><em>With exceptions:</em></strong> A toml::table. <br>
/// <strong><em>Without exceptions:</em></strong> A toml::parse_result detailing the parsing outcome.
@ -333,6 +378,35 @@ namespace toml
TOML_API
parse_result parse(std::string_view doc, std::string&& source_path) TOML_MAY_THROW;
#if TOML_WINDOWS_COMPAT
/// \brief Parses a TOML document from a string view.
///
/// \detail \cpp
/// auto tbl = toml::parse("a = 3"sv, L"foo.toml");
/// std::cout << tbl["a"] << std::endl;
///
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns <strong><em>With exceptions:</em></strong> A toml::table. <br>
/// <strong><em>Without exceptions:</em></strong> A toml::parse_result detailing the parsing outcome.
///
/// \attention This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
[[nodiscard]]
TOML_API
parse_result parse(std::string_view doc, std::wstring_view source_path) TOML_MAY_THROW;
#endif // TOML_WINDOWS_COMPAT
#ifdef __cpp_lib_char8_t
/// \brief Parses a TOML document from a char8_t string view.
@ -374,6 +448,8 @@ namespace toml
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns <strong><em>With exceptions:</em></strong> A toml::table. <br>
/// <strong><em>Without exceptions:</em></strong> A toml::parse_result detailing the parsing outcome.
@ -383,6 +459,36 @@ namespace toml
TOML_API
parse_result parse(std::u8string_view doc, std::string&& source_path) TOML_MAY_THROW;
#if TOML_WINDOWS_COMPAT
/// \brief Parses a TOML document from a char8_t string view.
///
/// \detail \cpp
/// auto tbl = toml::parse(u8"a = 3"sv, L"foo.toml");
/// std::cout << tbl["a"] << std::endl;
///
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns <strong><em>With exceptions:</em></strong> A toml::table. <br>
/// <strong><em>Without exceptions:</em></strong> A toml::parse_result detailing the parsing outcome.
///
/// \attention This overload is only available when #TOML_WINDOWS_COMPAT is enabled and your compiler
/// supports char8_t-based strings.
[[nodiscard]]
TOML_API
parse_result parse(std::u8string_view doc, std::wstring_view source_path) TOML_MAY_THROW;
#endif // TOML_WINDOWS_COMPAT
#endif // __cpp_lib_char8_t
/// \brief Parses a TOML document from a stream.
@ -439,6 +545,8 @@ namespace toml
/// \tparam Char The stream's underlying character type. Must be 1 byte in size.
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns <strong><em>With exceptions:</em></strong> A toml::table. <br>
/// <strong><em>Without exceptions:</em></strong> A toml::parse_result detailing the parsing outcome.
@ -455,6 +563,43 @@ namespace toml
return impl::do_parse(impl::utf8_reader{ doc, std::move(source_path) });
}
#if TOML_WINDOWS_COMPAT
/// \brief Parses a TOML document from a stream.
///
/// \detail \cpp
/// std::stringstream ss;
/// ss << "a = 3"sv;
///
/// auto tbl = toml::parse(ss);
/// std::cout << tbl["a"] << std::endl;
///
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \tparam Char The stream's underlying character type. Must be 1 byte in size.
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns <strong><em>With exceptions:</em></strong> A toml::table. <br>
/// <strong><em>Without exceptions:</em></strong> A toml::parse_result detailing the parsing outcome.
///
/// \attention This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
template <typename Char>
[[nodiscard]]
TOML_EXTERNAL_LINKAGE
parse_result parse(std::basic_istream<Char>& doc, std::wstring_view source_path) TOML_MAY_THROW
{
return parse(doc, impl::narrow<char>(source_path));
}
#endif // TOML_WINDOWS_COMPAT
// Q: "why are the parse_file functions templated??"
// A: I don't want to force users to drag in <fstream> if they're not going to do
@ -474,7 +619,7 @@ namespace toml
/// }
/// \ecpp
///
/// \tparam Char The path's character type. Must be 1 byte in size.
/// \tparam Char The path's character type.
/// \param file_path The TOML document to parse. Must be valid UTF-8.
///
/// \returns <strong><em>With exceptions:</em></strong> A toml::table. <br>
@ -487,25 +632,32 @@ namespace toml
parse_result parse_file(std::basic_string_view<Char> file_path) TOML_MAY_THROW
{
static_assert(
sizeof(Char) == 1,
"The path's character type must be 1 byte in size."
!std::is_same_v<Char, wchar_t> || TOML_WINDOWS_COMPAT,
"Wide-character file paths are only supported on Windows with TOML_WINDOWS_COMPAT enabled."
);
static_assert(
sizeof(StreamChar) == 1,
"The stream's character type must be 1 byte in size."
);
#if TOML_EXCEPTIONS
#define TOML_PARSE_FILE_ERROR(msg, pos) \
throw parse_error{ msg, pos, std::make_shared<const std::string>(std::move(file_path_str)) }
#if TOML_WINDOWS_COMPAT
static_assert(
sizeof(Char) == 1 || std::is_same_v<Char, wchar_t>,
"The file path's underlying character type must be wchar_t or be 1 byte in size."
);
#else
#define TOML_PARSE_FILE_ERROR(msg, pos) \
return parse_result{ \
parse_error{ msg, pos, std::make_shared<const std::string>(std::move(file_path_str)) } \
}
static_assert(
sizeof(Char) == 1,
"The file path's underlying character type must be 1 byte in size."
);
#endif
static_assert(
std::is_same_v<StreamChar, char>,
"StreamChar must be 'char' (it is as an instantiation-delaying hack and is not user-configurable)."
);
auto file_path_str = std::string(reinterpret_cast<const char*>(file_path.data()), file_path.length());
std::string file_path_str;
#if TOML_WINDOWS_COMPAT
if constexpr (std::is_same_v<Char, wchar_t>)
file_path_str = impl::narrow<char>(file_path);
else
#endif
file_path_str = std::string_view{ reinterpret_cast<const char*>(file_path.data()), file_path.length() };
// open file with a custom-sized stack buffer
using ifstream = std::basic_ifstream<StreamChar>;
@ -514,12 +666,12 @@ namespace toml
file.rdbuf()->pubsetbuf(file_buffer, sizeof(file_buffer));
file.open(file_path_str, ifstream::in | ifstream::binary | ifstream::ate);
if (!file.is_open())
TOML_PARSE_FILE_ERROR("File could not be opened for reading", source_position{});
TOML_THROW_PARSE_ERROR("File could not be opened for reading", file_path_str);
// get size
const auto file_size = file.tellg();
if (file_size == -1)
TOML_PARSE_FILE_ERROR("Could not determine file size", source_position{});
TOML_THROW_PARSE_ERROR("Could not determine file size", file_path_str);
file.seekg(0, std::ios::beg);
// read the whole file into memory first if the file isn't too large
@ -535,8 +687,6 @@ namespace toml
// otherwise parse it using the streams
else
return parse(file, std::move(file_path_str));
#undef TOML_PARSE_FILE_ERROR
}
#if !TOML_ALL_INLINE
@ -546,6 +696,9 @@ namespace toml
#ifdef __cpp_lib_char8_t
extern template TOML_API parse_result parse_file(std::u8string_view) TOML_MAY_THROW;
#endif
#if TOML_WINDOWS_COMPAT
extern template TOML_API parse_result parse_file(std::wstring_view) TOML_MAY_THROW;
#endif
#endif
template <typename Char>
@ -584,13 +737,9 @@ namespace toml
///
inline namespace literals
{
#if TOML_EXCEPTIONS
TOML_ABI_NAMESPACE_START(lit_ex)
#else
TOML_ABI_NAMESPACE_START(lit_noex)
#endif
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, lit_ex, lit_noex)
/// \brief Parses TOML data from a string.
/// \brief Parses TOML data from a string literal.
///
/// \detail \cpp
/// using namespace toml::literals;
@ -604,7 +753,7 @@ namespace toml
/// 3
/// \eout
///
/// \param str The string data.
/// \param str The string data. Must be valid UTF-8.
/// \param len The string length.
///
/// \returns <strong><em>With exceptions:</em></strong> A toml::table. <br>
@ -615,7 +764,7 @@ namespace toml
#ifdef __cpp_lib_char8_t
/// \brief Parses TOML data from a string.
/// \brief Parses TOML data from a utf8 string literal.
///
/// \detail \cpp
/// using namespace toml::literals;
@ -629,7 +778,7 @@ namespace toml
/// 3
/// \eout
///
/// \param str The string data.
/// \param str The string data. Must be valid UTF-8.
/// \param len The string length.
///
/// \returns <strong><em>With exceptions:</em></strong> A toml::table. <br>
@ -644,6 +793,9 @@ namespace toml
TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
}
}
#undef TOML_THROW_PARSE_ERROR
TOML_POP_WARNINGS // TOML_DISABLE_PADDING_WARNINGS

View File

@ -257,12 +257,6 @@ namespace TOML_INTERNAL_NAMESPACE
namespace toml::impl
{
#if defined(NDEBUG) || !defined(_DEBUG)
#define assert_or_assume(cond) TOML_ASSUME(cond)
#else
#define assert_or_assume(cond) TOML_ASSERT(cond)
#endif
// Q: "what the fuck is this? MACROS????"
// A: The parser needs to work in exceptionless mode (returning error objects directly)
// and exception mode (reporting parse failures by throwing). Two totally different control flows.
@ -271,6 +265,12 @@ namespace toml::impl
// They're all #undef'd at the bottom of the parser's implementation so they should be harmless outside
// of toml++.
#if defined(NDEBUG) || !defined(_DEBUG)
#define assert_or_assume(cond) TOML_ASSUME(cond)
#else
#define assert_or_assume(cond) TOML_ASSERT(cond)
#endif
#define is_eof() !cp
#define assert_not_eof() assert_or_assume(cp)
#define return_if_eof(...) do { if (is_eof()) return __VA_ARGS__; } while(false)
@ -302,11 +302,7 @@ namespace toml::impl
set_error_and_return_if_eof(__VA_ARGS__); \
} while (false)
#if TOML_EXCEPTIONS
TOML_ABI_NAMESPACE_START(impl_ex)
#else
TOML_ABI_NAMESPACE_START(impl_noex)
#endif
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, impl_ex, impl_noex)
class parser final
{
@ -2909,33 +2905,30 @@ namespace toml::impl
TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
#undef push_parse_scope_2
#undef push_parse_scope_1
#undef push_parse_scope
#undef TOML_RETURNS_BY_THROWING
#undef is_eof
#undef assert_not_eof
#undef return_if_eof
#undef is_error
#undef return_after_error
#undef assert_not_error
#undef return_if_error
#undef return_if_error_or_eof
#undef set_error_and_return
#undef set_error_and_return_default
#undef set_error_and_return_if_eof
#undef advance_and_return_if_error
#undef advance_and_return_if_error_or_eof
#undef assert_or_assume
}
#undef push_parse_scope_2
#undef push_parse_scope_1
#undef push_parse_scope
#undef TOML_RETURNS_BY_THROWING
#undef is_eof
#undef assert_not_eof
#undef return_if_eof
#undef is_error
#undef return_after_error
#undef assert_not_error
#undef return_if_error
#undef return_if_error_or_eof
#undef set_error_and_return
#undef set_error_and_return_default
#undef set_error_and_return_if_eof
#undef advance_and_return_if_error
#undef advance_and_return_if_error_or_eof
namespace toml
{
#if TOML_EXCEPTIONS
TOML_ABI_NAMESPACE_START(parse_ex)
#else
TOML_ABI_NAMESPACE_START(parse_noex)
#endif
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, parse_ex, parse_noex)
TOML_API
TOML_EXTERNAL_LINKAGE
@ -2951,6 +2944,17 @@ namespace toml
return impl::do_parse(impl::utf8_reader{ doc, std::move(source_path) });
}
#if TOML_WINDOWS_COMPAT
TOML_API
TOML_EXTERNAL_LINKAGE
parse_result parse(std::string_view doc, std::wstring_view source_path) TOML_MAY_THROW
{
return impl::do_parse(impl::utf8_reader{ doc, impl::narrow<char>(source_path) });
}
#endif // TOML_WINDOWS_COMPAT
#ifdef __cpp_lib_char8_t
TOML_API
@ -2967,17 +2971,24 @@ namespace toml
return impl::do_parse(impl::utf8_reader{ doc, std::move(source_path) });
}
#if TOML_WINDOWS_COMPAT
TOML_API
TOML_EXTERNAL_LINKAGE
parse_result parse(std::u8string_view doc, std::wstring_view source_path) TOML_MAY_THROW
{
return impl::do_parse(impl::utf8_reader{ doc, impl::narrow<char>(source_path) });
}
#endif // TOML_WINDOWS_COMPAT
#endif // __cpp_lib_char8_t
TOML_ABI_NAMESPACE_END // TOML_EXCEPTIONS
inline namespace literals
{
#if TOML_EXCEPTIONS
TOML_ABI_NAMESPACE_START(lit_ex)
#else
TOML_ABI_NAMESPACE_START(lit_noex)
#endif
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, lit_ex, lit_noex)
TOML_API
TOML_EXTERNAL_LINKAGE

View File

@ -48,11 +48,29 @@
#define TOML_PARSER 1
#endif
#if (defined(_WIN32) || defined(DOXYGEN)) && !defined(TOML_WINDOWS_COMPAT)
#define TOML_WINDOWS_COMPAT 1
#endif
#if !(defined(_WIN32) || defined(DOXYGEN)) || !defined(TOML_WINDOWS_COMPAT)
#undef TOML_WINDOWS_COMPAT
#define TOML_WINDOWS_COMPAT 0
#endif
#ifdef TOML_OPTIONAL_TYPE
#define TOML_HAS_CUSTOM_OPTIONAL_TYPE 1
#else
#define TOML_HAS_CUSTOM_OPTIONAL_TYPE 0
#endif
////////// COMPILER & ENVIRONMENT
#ifndef __cplusplus
#error toml++ is a C++ library.
#endif
#ifdef DOXYGEN
#undef TOML_DOXYGEN
#define TOML_DOXYGEN 1
#endif
#ifndef TOML_DOXYGEN
#define TOML_DOXYGEN 0
#endif
@ -192,7 +210,6 @@
#ifndef TOML_CPP_VERSION
#define TOML_CPP_VERSION __cplusplus
#endif
#if TOML_CPP_VERSION < 201103L
#error toml++ requires C++17 or higher. For a TOML library supporting pre-C++11 see https://github.com/ToruNiina/Boost.toml
#elif TOML_CPP_VERSION < 201703L
@ -206,12 +223,14 @@
#elif TOML_CPP_VERSION >= 201703L
#define TOML_CPP 17
#endif
#undef TOML_CPP_VERSION
#ifndef TOML_COMPILER_EXCEPTIONS
#define TOML_COMPILER_EXCEPTIONS 1
#endif
#if TOML_COMPILER_EXCEPTIONS
#ifndef TOML_EXCEPTIONS
#if !defined(TOML_EXCEPTIONS) || (defined(TOML_EXCEPTIONS) && TOML_EXCEPTIONS)
#undef TOML_EXCEPTIONS
#define TOML_EXCEPTIONS 1
#endif
#else
@ -381,13 +400,21 @@
#define TOML_LANG_UNRELEASED \
TOML_LANG_HIGHER_THAN(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH)
#define TOML_CONCAT_1(x, y) x##y
#define TOML_CONCAT(x, y) TOML_CONCAT_1(x, y)
#define TOML_EVAL_BOOL_1(T, F) T
#define TOML_EVAL_BOOL_0(T, F) F
#if TOML_DOXYGEN || defined(__INTELLISENSE__)
#define TOML_ABI_NAMESPACES 0
#define TOML_ABI_NAMESPACE_BOOL(cond, T, F)
#define TOML_ABI_NAMESPACE_START(name)
#define TOML_ABI_NAMESPACE_END
#else
#define TOML_ABI_NAMESPACES 1
#define TOML_ABI_NAMESPACE_START(name) inline namespace abi_##name {
#define TOML_ABI_NAMESPACE_START(name) inline namespace TOML_CONCAT(abi_, name) {
#define TOML_ABI_NAMESPACE_BOOL(cond, T, F) TOML_ABI_NAMESPACE_START(TOML_CONCAT(TOML_EVAL_BOOL_, cond)(T, F))
#define TOML_ABI_NAMESPACE_END }
#endif
@ -404,8 +431,7 @@ TOML_DISABLE_ALL_WARNINGS
TOML_POP_WARNINGS
#if TOML_CHAR_8_STRINGS
#define TOML_STRING_PREFIX_1(S) u8##S
#define TOML_STRING_PREFIX(S) TOML_STRING_PREFIX_1(S)
#define TOML_STRING_PREFIX(S) TOML_CONCAT(u8, S)
#else
#define TOML_STRING_PREFIX(S) S
#endif
@ -424,7 +450,7 @@ TOML_POP_WARNINGS
/// \def TOML_ALL_INLINE
/// \brief Sets whether the library is entirely inline.
/// \detail Defaults to `1`.
/// \remark Disabling this means that you must define `TOML_IMPLEMENTATION` in
/// \remark Disabling this means that you must define #TOML_IMPLEMENTATION in
/// <strong><em>exactly one</em></strong> translation unit in your project:
/// \cpp
/// // global_header_that_includes_toml++.h
@ -512,6 +538,20 @@ TOML_POP_WARNINGS
/// \see [TOML Language Support](https://github.com/marzer/tomlplusplus/blob/master/README.md#toml-language-support)
/// \def TOML_WINDOWS_COMPAT
/// \brief Enables the use of wide strings (wchar_t, std::wstring) in various places throughout the library
/// when building for Windows.
/// \detail Defaults to `1` when building for Windows, `0` otherwise. Has no effect when building for anything other
/// than Windows.
/// \attention This <strong>does not</strong> change the underlying string type used to represent TOML keys and string values;
/// that will still be std::string or std::u8string according to whatever #TOML_CHAR_8_STRINGS is set to.
/// This setting simply enables some narrow &lt;=&gt; wide string conversions when necessary at
/// various interface boundaries.
/// <br><br>
/// If you're building for Windows and you have no need for Windows' "Pretends-to-be-unicode" wide strings,
/// you can safely set this to `0`.
/// @}
#endif // TOML_DOXYGEN
//# }}

View File

@ -68,7 +68,7 @@ namespace toml::impl
stream.write(reinterpret_cast<const Char*>(str), static_cast<std::streamsize>(len));
}
#if defined(__cpp_lib_char8_t)
#ifdef __cpp_lib_char8_t
template <typename Char>
TOML_ALWAYS_INLINE

View File

@ -145,23 +145,45 @@ namespace toml::impl
string key;
std::unique_ptr<node> value;
template <typename T>
table_init_pair(string&& k, T && v) noexcept
template <typename V>
table_init_pair(string&& k, V&& v) noexcept
: key{ std::move(k) },
value{ make_node(std::forward<T>(v)) }
value{ make_node(std::forward<V>(v)) }
{}
template <typename T>
table_init_pair(string_view k, T&& v) noexcept
template <typename V>
table_init_pair(string_view k, V&& v) noexcept
: key{ k },
value{ make_node(std::forward<T>(v)) }
value{ make_node(std::forward<V>(v)) }
{}
template <typename T>
table_init_pair(const string_char* k, T&& v) noexcept
template <typename V>
table_init_pair(const string_char* k, V&& v) noexcept
: key{ k },
value{ make_node(std::forward<T>(v)) }
value{ make_node(std::forward<V>(v)) }
{}
#if TOML_WINDOWS_COMPAT
template <typename V>
table_init_pair(std::wstring&& k, V&& v) noexcept
: key{ narrow(k) },
value{ make_node(std::forward<V>(v)) }
{}
template <typename V>
table_init_pair(std::wstring_view k, V&& v) noexcept
: key{ narrow(k) },
value{ make_node(std::forward<V>(v)) }
{}
template <typename V>
table_init_pair(const wchar_t* k, V&& v) noexcept
: key{ narrow(std::wstring_view{ k }) },
value{ make_node(std::forward<V>(v)) }
{}
#endif
};
}
@ -319,8 +341,52 @@ namespace toml
[[nodiscard]] node_view<node> operator[] (string_view key) noexcept;
/// \brief Gets a node_view for the selected key-value pair (const overload).
///
/// \param key The key used for the lookup.
///
/// \returns A view of the value at the given key if one existed, or an empty node view.
///
/// \remarks std::map::operator[]'s behaviour of default-constructing a value at a key if it
/// didn't exist is a crazy bug factory so I've deliberately chosen not to emulate it.
/// <strong>This is not an error.</strong>
///
/// \see toml::node_view
[[nodiscard]] node_view<const node> operator[] (string_view key) const noexcept;
#if TOML_WINDOWS_COMPAT
/// \brief Gets a node_view for the selected key-value pair.
///
/// \param key The key used for the lookup.
///
/// \returns A view of the value at the given key if one existed, or an empty node view.
///
/// \remarks std::map::operator[]'s behaviour of default-constructing a value at a key if it
/// didn't exist is a crazy bug factory so I've deliberately chosen not to emulate it.
/// <strong>This is not an error.</strong>
///
/// \see toml::node_view
///
/// \attention This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
[[nodiscard]] node_view<node> operator[] (std::wstring_view key) noexcept;
/// \brief Gets a node_view for the selected key-value pair (const overload).
///
/// \param key The key used for the lookup.
///
/// \returns A view of the value at the given key if one existed, or an empty node view.
///
/// \remarks std::map::operator[]'s behaviour of default-constructing a value at a key if it
/// didn't exist is a crazy bug factory so I've deliberately chosen not to emulate it.
/// <strong>This is not an error.</strong>
///
/// \see toml::node_view
///
/// \attention This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
[[nodiscard]] node_view<const node> operator[] (std::wstring_view key) const noexcept;
#endif // TOML_WINDOWS_COMPAT
/// \brief Returns an iterator to the first key-value pair.
[[nodiscard]] iterator begin() noexcept;
/// \brief Returns an iterator to the first key-value pair.
@ -378,16 +444,29 @@ namespace toml
/// - A boolean indicating if the insertion was successful.
template <typename K, typename V, typename = std::enable_if_t<
std::is_convertible_v<K&&, string_view>
|| impl::is_wide_string<K>
>>
std::pair<iterator, bool> insert(K&& key, V&& val) noexcept
{
auto ipos = values.lower_bound(key);
if (ipos == values.end() || ipos->first != key)
static_assert(
!impl::is_wide_string<K> || TOML_WINDOWS_COMPAT,
"Insertion using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
);
#if TOML_WINDOWS_COMPAT
if constexpr (impl::is_wide_string<K>)
return insert(impl::narrow(std::forward<K>(key)), std::forward<V>(val));
else
#endif
{
ipos = values.emplace_hint(ipos, std::forward<K>(key), impl::make_node(std::forward<V>(val)));
return { ipos, true };
auto ipos = values.lower_bound(key);
if (ipos == values.end() || ipos->first != key)
{
ipos = values.emplace_hint(ipos, std::forward<K>(key), impl::make_node(std::forward<V>(val)));
return { ipos, true };
}
return { ipos, false };
}
return { ipos, false };
}
/// \brief Inserts a series of key-value pairs into the table.
@ -422,7 +501,8 @@ namespace toml
/// key-value pair covered by the iterator range, so any values with keys already found in the
/// table will not be replaced.
template <typename Iter, typename = std::enable_if_t<
!std::is_convertible_v<Iter&&, string_view>
!std::is_convertible_v<Iter, string_view>
&& !impl::is_wide_string<Iter>
>>
void insert(Iter first, Iter last) noexcept
{
@ -475,16 +555,28 @@ namespace toml
template <typename K, typename V>
std::pair<iterator, bool> insert_or_assign(K&& key, V&& val) noexcept
{
auto ipos = values.lower_bound(key);
if (ipos == values.end() || ipos->first != key)
{
ipos = values.emplace_hint(ipos, std::forward<K>(key), impl::make_node(std::forward<V>(val)));
return { ipos, true };
}
static_assert(
!impl::is_wide_string<K> || TOML_WINDOWS_COMPAT,
"Insertion using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
);
#if TOML_WINDOWS_COMPAT
if constexpr (impl::is_wide_string<K>)
return insert_or_assign(impl::narrow(std::forward<K>(key)), std::forward<V>(val));
else
#endif
{
(*ipos).second.reset(impl::make_node(std::forward<V>(val)));
return { ipos, false };
auto ipos = values.lower_bound(key);
if (ipos == values.end() || ipos->first != key)
{
ipos = values.emplace_hint(ipos, std::forward<K>(key), impl::make_node(std::forward<V>(val)));
return { ipos, true };
}
else
{
(*ipos).second.reset(impl::make_node(std::forward<V>(val)));
return { ipos, false };
}
}
}
@ -529,23 +621,36 @@ namespace toml
template <typename U, typename K, typename... V>
std::pair<iterator, bool> emplace(K&& key, V&&... args) noexcept
{
using type = impl::unwrapped<U>;
static_assert(
impl::is_value_or_node<type>,
"Emplacement type parameter must be one of the basic value types, a toml::table, or a toml::array"
!impl::is_wide_string<K> || TOML_WINDOWS_COMPAT,
"Emplacement using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
);
auto ipos = values.lower_bound(key);
if (ipos == values.end() || ipos->first != key)
#if TOML_WINDOWS_COMPAT
if constexpr (impl::is_wide_string<K>)
return emplace<U>(impl::narrow(std::forward<K>(key)), std::forward<V>(args)...);
else
#endif
{
ipos = values.emplace_hint(
ipos,
std::forward<K>(key),
new impl::node_of<type>{ std::forward<V>(args)... }
using type = impl::unwrapped<U>;
static_assert(
impl::is_value_or_node<type>,
"Emplacement type parameter must be one of the basic value types, a toml::table, or a toml::array"
);
return { ipos, true };
auto ipos = values.lower_bound(key);
if (ipos == values.end() || ipos->first != key)
{
ipos = values.emplace_hint(
ipos,
std::forward<K>(key),
new impl::node_of<type>{ std::forward<V>(args)... }
);
return { ipos, true };
}
return { ipos, false };
}
return { ipos, false };
}
/// \brief Removes the specified key-value pair from the table.
@ -653,20 +758,40 @@ namespace toml
/// \returns True if any values with matching keys were found and erased.
bool erase(string_view key) noexcept;
#if TOML_WINDOWS_COMPAT
/// \brief Removes the value with the given key from the table.
///
/// \param key Key to erase.
///
/// \returns True if any values with matching keys were found and erased.
///
/// \attention This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
bool erase(std::wstring_view key) noexcept;
#endif
private:
template <typename Map, typename Key>
[[nodiscard]] static auto do_get(Map& vals, const Key& key) noexcept
-> std::conditional_t<std::is_const_v<Map>, const node*, node*>
{
using return_type = std::conditional_t<
std::is_const_v<Map>,
const node*,
node*
>;
static_assert(
!impl::is_wide_string<Key> || TOML_WINDOWS_COMPAT,
"Retrieval using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
);
if (auto it = vals.find(key); it != vals.end())
return return_type{ it->second.get() };
return return_type{};
#if TOML_WINDOWS_COMPAT
if constexpr (impl::is_wide_string<Key>)
return do_get(vals, impl::narrow(key));
else
#endif
{
if (auto it = vals.find(key); it != vals.end())
return { it->second.get() };
return {};
}
}
template <typename T, typename Map, typename Key>
@ -680,11 +805,7 @@ namespace toml
[[nodiscard]] TOML_ALWAYS_INLINE
static bool do_contains(Map& vals, const Key& key) noexcept
{
#if TOML_CPP >= 20
return vals.contains(key);
#else
return do_get(vals, key) != nullptr;
#endif
return do_get(vals, key) != nullptr;
}
public:
@ -723,9 +844,68 @@ namespace toml
/// \returns A pointer to the node at the specified key, or nullptr.
[[nodiscard]] const node* get(string_view key) const noexcept;
/// \brief Gets an iterator to the node at a specific key.
///
/// \param key The node's key.
///
/// \returns An iterator to the node at the specified key, or end().
[[nodiscard]] iterator find(string_view key) noexcept;
/// \brief Gets an iterator to the node at a specific key (const overload)
///
/// \param key The node's key.
///
/// \returns A const iterator to the node at the specified key, or cend().
[[nodiscard]] const_iterator find(string_view key) const noexcept;
/// \brief Returns true if the table contains a node at the given key.
[[nodiscard]] bool contains(string_view key) const noexcept;
#if TOML_WINDOWS_COMPAT
/// \brief Gets the node at a specific key.
///
/// \param key The node's key.
///
/// \returns A pointer to the node at the specified key, or nullptr.
///
/// \attention This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
[[nodiscard]] node* get(std::wstring_view key) noexcept;
/// \brief Gets the node at a specific key (const overload).
///
/// \param key The node's key.
///
/// \returns A pointer to the node at the specified key, or nullptr.
///
/// \attention This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
[[nodiscard]] const node* get(std::wstring_view key) const noexcept;
/// \brief Gets an iterator to the node at a specific key.
///
/// \param key The node's key.
///
/// \returns An iterator to the node at the specified key, or end().
///
/// \attention This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
[[nodiscard]] iterator find(std::wstring_view key) noexcept;
/// \brief Gets an iterator to the node at a specific key (const overload).
///
/// \param key The node's key.
///
/// \returns A const iterator to the node at the specified key, or cend().
///
/// \attention This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
[[nodiscard]] const_iterator find(std::wstring_view key) const noexcept;
/// \brief Returns true if the table contains a node at the given key.
///
/// \attention This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
[[nodiscard]] bool contains(std::wstring_view key) const noexcept;
#endif // TOML_WINDOWS_COMPAT
/// \brief Gets the node at a specific key if it is a particular type.
///
/// \detail \cpp
@ -764,8 +944,37 @@ namespace toml
return do_get_as<T>(values, key);
}
/// \brief Returns true if the table contains a node at the given key.
[[nodiscard]] bool contains(string_view key) const noexcept;
#if TOML_WINDOWS_COMPAT
/// \brief Gets the node at a specific key if it is a particular type.
///
/// \tparam T The node's type.
/// \param key The node's key.
///
/// \returns A pointer to the node at the specified key if it was of the given type, or nullptr.
///
/// \attention This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
template <typename T>
[[nodiscard]] impl::node_of<T>* get_as(std::wstring_view key) noexcept
{
return get_as<T>(impl::narrow(key));
}
/// \brief Gets the node at a specific key if it is a particular type (const overload).
///
/// \tparam T The node's type.
/// \param key The node's key.
///
/// \returns A pointer to the node at the specified key if it was of the given type, or nullptr.
///
/// \attention This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
template <typename T>
[[nodiscard]] const impl::node_of<T>* get_as(std::wstring_view key) const noexcept
{
return get_as<T>(impl::narrow(key));
}
#endif // TOML_WINDOWS_COMPAT
/// \brief Equality operator.
///
@ -783,6 +992,7 @@ namespace toml
/// \returns True if the tables did not contain the same keys and values.
friend bool operator != (const table& lhs, const table& rhs) noexcept;
/// \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&);
};

View File

@ -145,6 +145,57 @@ namespace toml
return do_contains(values, key);
}
#if TOML_WINDOWS_COMPAT
TOML_EXTERNAL_LINKAGE
node_view<node> table::operator[] (std::wstring_view key) noexcept
{
return { this->get(key) };
}
TOML_EXTERNAL_LINKAGE
node_view<const node> table::operator[] (std::wstring_view key) const noexcept
{
return { this->get(key) };
}
TOML_EXTERNAL_LINKAGE
bool table::erase(std::wstring_view key) noexcept
{
return erase(impl::narrow(key));
}
TOML_EXTERNAL_LINKAGE
node* table::get(std::wstring_view key) noexcept
{
return get(impl::narrow(key));
}
TOML_EXTERNAL_LINKAGE
const node* table::get(std::wstring_view key) const noexcept
{
return get(impl::narrow(key));
}
TOML_EXTERNAL_LINKAGE
table::iterator table::find(std::wstring_view key) noexcept
{
return find(impl::narrow(key));
}
TOML_EXTERNAL_LINKAGE
table::const_iterator table::find(std::wstring_view key) const noexcept
{
return find(impl::narrow(key));
}
TOML_EXTERNAL_LINKAGE
bool table::contains(std::wstring_view key) const noexcept
{
return contains(impl::narrow(key));
}
#endif // TOML_WINDOWS_COMPAT
TOML_API
TOML_EXTERNAL_LINKAGE
bool operator == (const table& lhs, const table& rhs) noexcept

View File

@ -135,11 +135,7 @@ namespace toml::impl
}
};
#if TOML_LARGE_FILES
TOML_ABI_NAMESPACE_START(impl_lf)
#else
TOML_ABI_NAMESPACE_START(impl_sf)
#endif
TOML_ABI_NAMESPACE_BOOL(TOML_LARGE_FILES, impl_lf, impl_sf)
struct utf8_codepoint final
{
@ -369,13 +365,10 @@ namespace toml::impl
template <typename Char>
utf8_reader(std::basic_string_view<Char>, std::string_view) -> utf8_reader<std::basic_string_view<Char>>;
template <typename Char>
utf8_reader(std::basic_istream<Char>&, std::string_view) -> utf8_reader<std::basic_istream<Char>>;
template <typename Char>
utf8_reader(std::basic_string_view<Char>, std::string&&) -> utf8_reader<std::basic_string_view<Char>>;
template <typename Char>
utf8_reader(std::basic_istream<Char>&, std::string_view) -> utf8_reader<std::basic_istream<Char>>;
template <typename Char>
utf8_reader(std::basic_istream<Char>&, std::string&&) -> utf8_reader<std::basic_istream<Char>>;

View File

@ -172,6 +172,7 @@ namespace toml
/// \brief Returns a reference to the underlying value (const overload).
[[nodiscard]] explicit operator const T& () const& noexcept { return val_; }
/// \brief Prints the value out to a stream as formatted TOML.
template <typename Char, typename U>
friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const value<U>& rhs);
@ -366,36 +367,6 @@ namespace toml
value(TOML_SMALL_INT_TYPE) -> value<int64_t>;
#endif
/// \brief Prints the value out to a stream.
template <typename Char, typename T>
TOML_EXTERNAL_LINKAGE
std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const value<T>& rhs)
{
// this is the same behaviour as default_formatter, but it's so simple that there's
// no need to spin up a new instance of it just for individual values.
if constexpr (std::is_same_v<T, string>)
{
impl::print_to_stream('"', lhs);
impl::print_to_stream_with_escapes(rhs.val_, lhs);
impl::print_to_stream('"', lhs);
}
else
impl::print_to_stream(rhs.val_, lhs);
return lhs;
}
#if !TOML_ALL_INLINE
extern template TOML_API std::ostream& operator << (std::ostream&, const value<toml::string>&);
extern template TOML_API std::ostream& operator << (std::ostream&, const value<int64_t>&);
extern template TOML_API std::ostream& operator << (std::ostream&, const value<double>&);
extern template TOML_API std::ostream& operator << (std::ostream&, const value<bool>&);
extern template TOML_API std::ostream& operator << (std::ostream&, const value<toml::date>&);
extern template TOML_API std::ostream& operator << (std::ostream&, const value<toml::time>&);
extern template TOML_API std::ostream& operator << (std::ostream&, const value<toml::date_time>&);
#endif
TOML_PUSH_WARNINGS
TOML_DISABLE_INIT_WARNINGS
@ -403,7 +374,13 @@ namespace toml
inline optional<T> node::value() const noexcept
{
static_assert(
impl::is_value<T> || std::is_same_v<T, string_view>,
!impl::is_wide_string<T> || TOML_WINDOWS_COMPAT,
"Retrieving values as wide-character strings is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
);
static_assert(
impl::is_value<T>
|| std::is_same_v<T, string_view>
|| (TOML_WINDOWS_COMPAT && std::is_same_v<T, std::wstring>),
"Value type must be one of the TOML value types (or string_view)"
);
@ -418,6 +395,12 @@ namespace toml
{
if constexpr (std::is_same_v<T, string> || std::is_same_v<T, string_view>)
return { T{ ref_cast<string>().get() } };
#if TOML_WINDOWS_COMPAT
else if constexpr (std::is_same_v<T, std::wstring>)
return { impl::widen(ref_cast<string>().get()) };
#endif
else
return {};
}
@ -485,21 +468,36 @@ namespace toml
template <typename T>
inline auto node::value_or(T&& default_value) const noexcept
{
static_assert(
!impl::is_wide_string<T> || TOML_WINDOWS_COMPAT,
"Retrieving values as wide-character strings is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
);
static_assert(
impl::is_value_or_promotable<impl::remove_cvref_t<T>>,
"Default value type must be (or be promotable to) one of the TOML value types"
);
using value_type = impl::promoted<impl::remove_cvref_t<T>>;
using return_type = std::conditional_t<
std::is_same_v<value_type, string>,
std::conditional_t<std::is_same_v<impl::remove_cvref_t<T>, string>, string, string_view>,
value_type
>;
#if TOML_WINDOWS_COMPAT
if constexpr (impl::is_wide_string<T>)
{
if (this->type() == node_type::string)
return impl::widen(ref_cast<string>().get());
return std::wstring{ std::forward<T>(default_value) };
}
else
#endif
{
using value_type = impl::promoted<impl::remove_cvref_t<T>>;
using return_type = std::conditional_t<
std::is_same_v<value_type, string>,
std::conditional_t<std::is_same_v<impl::remove_cvref_t<T>, string>, string, string_view>,
value_type
>;
if (auto val = this->value<return_type>())
return *val;
return return_type{ std::forward<T>(default_value) };
if (auto val = this->value<return_type>())
return *val;
return return_type{ std::forward<T>(default_value) };
}
}
}

View File

@ -7,7 +7,7 @@
#define TOML_LIB_MAJOR 1
#define TOML_LIB_MINOR 3
#define TOML_LIB_PATCH 3
#define TOML_LIB_PATCH 4
#define TOML_LANG_MAJOR 1
#define TOML_LANG_MINOR 0

View File

@ -1,7 +1,7 @@
project(
'tomlplusplus',
'cpp',
version : '1.3.3',
version : '1.3.4',
license : 'MIT',
default_options : [
'cpp_std=c++17',

View File

@ -26,6 +26,10 @@
#error TOML_EXCEPTIONS does not match TOML_COMPILER_EXCEPTIONS (default behaviour should be to match)
#endif
#if (defined(_WIN32) && !TOML_WINDOWS_COMPAT) || (!defined(_WIN32) && TOML_WINDOWS_COMPAT)
#error TOML_WINDOWS_COMPAT does not match _WIN32 (default behaviour should be to match)
#endif
namespace toml
{
using std::declval;

View File

@ -47,6 +47,10 @@ TEST_CASE("values - printing")
// large floats might get output as scientific notation and that's fine
CHECK(print_value(10000000000) == "10000000000");
CHECK(print_value(100000000000000) == "100000000000000");
}
static_assert(std::is_same_v<string, decltype(std::declval<node>().value_or(S(""s)))>);
static_assert(std::is_same_v<string_view, decltype(std::declval<node>().value_or(S(""sv)))>);
static_assert(std::is_same_v<string_view, decltype(std::declval<node>().value_or(S("")))>);

View File

@ -21,6 +21,7 @@ test_sources = [
'manipulating_values.cpp',
'unicode.cpp',
'unicode_generated.cpp',
'windows_compat.cpp'
]
compiler_supports_char8_strings = compiler.compiles('''

View File

@ -65,7 +65,7 @@
#define NOMETAFILE // - typedef METAFILEPICT
#define NOMINMAX // - Macros min(a,b) and max(a,b)
#define NOMSG // - typedef MSG and associated routines
#define NONLS // - All NLS defines and routines
//#define NONLS // - All NLS defines and routines
#define NOOPENFILE // - OpenFile(), OemToAnsi, AnsiToOem, and OF_*
#define NOPROFILER // - Profiler interface.
#define NORASTEROPS // - Binary and Tertiary raster ops

View File

@ -168,16 +168,16 @@ inline bool parse_expected_value(
auto nv = tbl[S("val"sv)];
REQUIRE(nv);
REQUIRE(nv.as<value_type>());
REQUIRE(nv.get()->type() == impl::node_type_of<T>);
REQUIRE(nv.node()->type() == impl::node_type_of<T>);
// check the raw value
REQUIRE(nv.get()->value<value_type>() == expected);
REQUIRE(nv.get()->value_or(T{}) == expected);
REQUIRE(nv.node()->value<value_type>() == expected);
REQUIRE(nv.node()->value_or(T{}) == expected);
REQUIRE(nv.as<value_type>()->get() == expected);
REQUIRE(nv.value<value_type>() == expected);
REQUIRE(nv.value_or(T{}) == expected);
REQUIRE(nv.ref<value_type>() == expected);
REQUIRE(nv.get()->ref<value_type>() == expected);
REQUIRE(nv.node()->ref<value_type>() == expected);
// check the table relops
REQUIRE(tbl == table{ { { S("val"sv), expected } } });
@ -196,8 +196,8 @@ inline bool parse_expected_value(
REQUIRE(!(expected != nv));
// make sure source info is correct
REQUIRE(nv.get()->source().begin == begin);
REQUIRE(nv.get()->source().end == end);
REQUIRE(nv.node()->source().begin == begin);
REQUIRE(nv.node()->source().end == end);
// steal the val for round-trip tests
if (!stolen_value)
@ -235,7 +235,7 @@ inline bool parse_expected_value(
auto nv = tbl[S("val"sv)];
REQUIRE(nv);
REQUIRE(nv.as<value_type>());
REQUIRE(nv.get()->type() == impl::node_type_of<T>);
REQUIRE(nv.node()->type() == impl::node_type_of<T>);
if (value_ok && nv.ref<value_type>() != expected)
{

77
tests/windows_compat.cpp Normal file
View File

@ -0,0 +1,77 @@
// This file is a part of toml++ and is subject to the the terms of the MIT license.
// Copyright (c) 2019-2020 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
#include "tests.h"
#if TOML_WINDOWS_COMPAT
TEST_CASE("windows compat")
{
static constexpr auto toml_text = R"(
[library]
name = "toml++"
authors = ["Mark Gillard <mark.gillard@outlook.com.au>"]
[dependencies]
cpp = 17
)"sv;
auto res = toml::parse(toml_text, L"kek.toml");
#if !TOML_EXCEPTIONS
REQUIRE(res.succeeded());
#endif
toml::table& tbl = res;
// source paths
REQUIRE(tbl.source().path != nullptr);
CHECK(*tbl.source().path == "kek.toml"sv);
CHECK(tbl.source().wide_path().has_value());
CHECK(tbl.source().wide_path().value() == L"kek.toml"sv);
// direct lookups from tables
REQUIRE(tbl.get(S("library")) != nullptr);
CHECK(tbl.get(S("library")) == tbl.get(S("library"sv)));
CHECK(tbl.get(S("library")) == tbl.get(S("library"s)));
CHECK(tbl.get(L"library") != nullptr);
CHECK(tbl.get(L"library") == tbl.get(L"library"sv));
CHECK(tbl.get(L"library") == tbl.get(L"library"s));
CHECK(tbl.get(L"library") == tbl.get(S("library")));
// node-view lookups
CHECK(tbl[L"library"].node() != nullptr);
CHECK(tbl[L"library"].node() == tbl.get(L"library"));
// value queries
REQUIRE(tbl[L"library"][L"name"].as_string() != nullptr);
CHECK(tbl[L"library"][L"name"].value<std::wstring>() == L"toml++"s);
CHECK(tbl[L"library"][L"name"].value_or(L""sv) == L"toml++"s);
CHECK(tbl[L"library"][L"name"].value_or(L""s) == L"toml++"s);
CHECK(tbl[L"library"][L"name"].value_or(L"") == L"toml++"s);
// node-view comparisons
CHECK(tbl[L"library"][L"name"] == S("toml++"sv));
CHECK(tbl[L"library"][L"name"] == S("toml++"s));
CHECK(tbl[L"library"][L"name"] == S("toml++"));
CHECK(tbl[L"library"][L"name"] == L"toml++"sv);
CHECK(tbl[L"library"][L"name"] == L"toml++"s);
CHECK(tbl[L"library"][L"name"] == L"toml++");
// table manipulation
tbl.insert(L"foo", L"bar");
REQUIRE(tbl.contains(S("foo")));
REQUIRE(tbl.contains(L"foo"));
CHECK(tbl[S("foo")] == S("bar"));
tbl.insert_or_assign(L"foo", L"kek");
CHECK(tbl[S("foo")] == S("kek"));
tbl.erase(L"foo");
REQUIRE(!tbl.contains(S("foo")));
REQUIRE(!tbl.contains(L"foo"));
}
static_assert(std::is_same_v<std::wstring, decltype(std::declval<toml::node>().value_or(L""s))>);
static_assert(std::is_same_v<std::wstring, decltype(std::declval<toml::node>().value_or(L""sv))>);
static_assert(std::is_same_v<std::wstring, decltype(std::declval<toml::node>().value_or(L""))>);
#endif // TOML_WINDOWS_COMPAT

1028
toml.hpp

File diff suppressed because it is too large Load Diff

View File

@ -90,6 +90,7 @@
</ClCompile>
<ClCompile Include="..\tests\unicode.cpp" />
<ClCompile Include="..\tests\unicode_generated.cpp" />
<ClCompile Include="..\tests\windows_compat.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />

View File

@ -90,6 +90,7 @@
</ClCompile>
<ClCompile Include="..\tests\unicode.cpp" />
<ClCompile Include="..\tests\unicode_generated.cpp" />
<ClCompile Include="..\tests\windows_compat.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />

View File

@ -92,6 +92,7 @@
</ClCompile>
<ClCompile Include="..\tests\unicode.cpp" />
<ClCompile Include="..\tests\unicode_generated.cpp" />
<ClCompile Include="..\tests\windows_compat.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />

View File

@ -90,6 +90,7 @@
</ClCompile>
<ClCompile Include="..\tests\unicode.cpp" />
<ClCompile Include="..\tests\unicode_generated.cpp" />
<ClCompile Include="..\tests\windows_compat.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />

View File

@ -92,6 +92,7 @@
</ClCompile>
<ClCompile Include="..\tests\unicode.cpp" />
<ClCompile Include="..\tests\unicode_generated.cpp" />
<ClCompile Include="..\tests\windows_compat.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />

View File

@ -92,6 +92,7 @@
</ClCompile>
<ClCompile Include="..\tests\unicode.cpp" />
<ClCompile Include="..\tests\unicode_generated.cpp" />
<ClCompile Include="..\tests\windows_compat.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />

View File

@ -90,6 +90,7 @@
</ClCompile>
<ClCompile Include="..\tests\unicode.cpp" />
<ClCompile Include="..\tests\unicode_generated.cpp" />
<ClCompile Include="..\tests\windows_compat.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />

View File

@ -92,6 +92,7 @@
</ClCompile>
<ClCompile Include="..\tests\unicode.cpp" />
<ClCompile Include="..\tests\unicode_generated.cpp" />
<ClCompile Include="..\tests\windows_compat.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />

View File

@ -90,6 +90,7 @@
</ClCompile>
<ClCompile Include="..\tests\unicode.cpp" />
<ClCompile Include="..\tests\unicode_generated.cpp" />
<ClCompile Include="..\tests\windows_compat.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />

View File

@ -90,6 +90,7 @@
</ClCompile>
<ClCompile Include="..\tests\unicode.cpp" />
<ClCompile Include="..\tests\unicode_generated.cpp" />
<ClCompile Include="..\tests\windows_compat.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />

View File

@ -92,6 +92,7 @@
</ClCompile>
<ClCompile Include="..\tests\unicode.cpp" />
<ClCompile Include="..\tests\unicode_generated.cpp" />
<ClCompile Include="..\tests\windows_compat.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />

View File

@ -90,6 +90,7 @@
</ClCompile>
<ClCompile Include="..\tests\unicode.cpp" />
<ClCompile Include="..\tests\unicode_generated.cpp" />
<ClCompile Include="..\tests\windows_compat.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />

View File

@ -92,6 +92,7 @@
</ClCompile>
<ClCompile Include="..\tests\unicode.cpp" />
<ClCompile Include="..\tests\unicode_generated.cpp" />
<ClCompile Include="..\tests\windows_compat.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />

View File

@ -92,6 +92,7 @@
</ClCompile>
<ClCompile Include="..\tests\unicode.cpp" />
<ClCompile Include="..\tests\unicode_generated.cpp" />
<ClCompile Include="..\tests\windows_compat.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />

View File

@ -90,6 +90,7 @@
</ClCompile>
<ClCompile Include="..\tests\unicode.cpp" />
<ClCompile Include="..\tests\unicode_generated.cpp" />
<ClCompile Include="..\tests\windows_compat.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />

View File

@ -92,6 +92,7 @@
</ClCompile>
<ClCompile Include="..\tests\unicode.cpp" />
<ClCompile Include="..\tests\unicode_generated.cpp" />
<ClCompile Include="..\tests\windows_compat.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="toml++.natvis" />