minor refactoring to better enable explicit instantiations

This commit is contained in:
Mark Gillard 2020-03-03 10:10:07 +02:00
parent d874264432
commit 14249f4e66
17 changed files with 533 additions and 335 deletions

View File

@ -23,7 +23,7 @@ Given a TOML file `configuration.toml` containing the following:
```toml
[library]
name = "toml++"
version = "0.1.0"
version = "0.3.2"
authors = ["Mark Gillard <mark@notarealwebsite.com>"]
[dependencies]
@ -89,7 +89,7 @@ won't need to mess with these at all, but if you do, set them before including t
| 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_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. |

View File

@ -21,8 +21,8 @@
#if TOML_IMPLEMENTATION
#include "toml_instantiations.h"
#include "toml_node_impl.h"
#include "toml_value_impl.h"
#include "toml_array_impl.h"
#include "toml_table_impl.h"
#include "toml_parser_impl.h"

View File

@ -358,10 +358,12 @@ TOML_START
struct date_time;
class node;
template <typename T> class node_view;
template <typename T> class value;
class array;
class table;
template <typename> class node_view;
template <typename> class value;
template <typename> class default_formatter;
template <typename> class json_formatter;
/// \brief TOML node type identifiers.
enum class node_type : uint8_t

View File

@ -70,24 +70,23 @@ TOML_START
{
return pack(lhs) >= pack(rhs);
}
/// \brief Prints a date out to a stream as `YYYY-MM-DD` (per RFC 3339).
/// \detail \cpp
/// std::cout << toml::date{ 1987, 3, 16 } << std::endl;
/// \ecpp
///
/// \out
/// 1987-03-16
/// \eout
template <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const date& rhs)
TOML_MAY_THROW
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
};
/// \brief Prints a date out to a stream as `YYYY-MM-DD` (per RFC 3339).
/// \detail \cpp
/// std::cout << toml::date{ 1987, 3, 16 } << std::endl;
/// \ecpp
///
/// \out
/// 1987-03-16
/// \eout
template <typename CHAR>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const date& rhs) TOML_MAY_THROW
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
/// \brief A local time-of-day.
struct time final
{
@ -157,26 +156,25 @@ TOML_START
{
return pack(lhs) >= pack(rhs);
}
/// \brief Prints a time out to a stream as `HH:MM:SS.FFFFFF` (per RFC 3339).
/// \detail \cpp
/// std::cout << toml::time{ 10, 20, 34 } << std::endl;
/// std::cout << toml::time{ 10, 20, 34, 500000000 } << std::endl;
/// \ecpp
///
/// \out
/// 10:20:34
/// 10:20:34.5
/// \eout
template <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const time& rhs)
TOML_MAY_THROW
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
};
/// \brief Prints a time out to a stream as `HH:MM:SS.FFFFFF` (per RFC 3339).
/// \detail \cpp
/// std::cout << toml::time{ 10, 20, 34 } << std::endl;
/// std::cout << toml::time{ 10, 20, 34, 500000000 } << std::endl;
/// \ecpp
///
/// \out
/// 10:20:34
/// 10:20:34.5
/// \eout
template <typename CHAR>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const time& rhs) TOML_MAY_THROW
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
/// \brief A timezone offset.
struct time_offset final
{
@ -254,32 +252,31 @@ TOML_START
{
return lhs.minutes >= rhs.minutes;
}
/// \brief Prints a time_offset out to a stream as `+-HH:MM or Z` (per RFC 3339).
/// \detail \cpp
/// std::cout << toml::time_offset{ 2, 30 } << std::endl;
/// std::cout << toml::time_offset{ 2, -30 } << std::endl;
/// std::cout << toml::time_offset{} << std::endl;
/// std::cout << toml::time_offset{ -2, 30 } << std::endl;
/// std::cout << toml::time_offset{ -2, -30 } << std::endl;
/// \ecpp
///
/// \out
/// +02:30
/// +01:30
/// Z
/// -01:30
/// -02:30
/// \eout
template <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const time_offset& rhs)
TOML_MAY_THROW
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
};
/// \brief Prints a time_offset out to a stream as `+-HH:MM or Z` (per RFC 3339).
/// \detail \cpp
/// std::cout << toml::time_offset{ 2, 30 } << std::endl;
/// std::cout << toml::time_offset{ 2, -30 } << std::endl;
/// std::cout << toml::time_offset{} << std::endl;
/// std::cout << toml::time_offset{ -2, 30 } << std::endl;
/// std::cout << toml::time_offset{ -2, -30 } << std::endl;
/// \ecpp
///
/// \out
/// +02:30
/// +01:30
/// Z
/// -01:30
/// -02:30
/// \eout
template <typename CHAR>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const time_offset& rhs) TOML_MAY_THROW
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
/// \brief A date-time.
struct date_time final
{
@ -379,26 +376,25 @@ TOML_START
{
return !(lhs < rhs);
}
/// \brief Prints a date_time out to a stream in RFC 3339 format.
/// \detail \cpp
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 } } << std::endl;
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 }, { -2, -30 } } << std::endl;
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 }, {} } << std::endl;
/// \ecpp
///
/// \out
/// 1987-03-16T10:20:34
/// 1987-03-16T10:20:34-02:30
/// 1987-03-16T10:20:34Z
/// \eout
template <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const date_time& rhs)
TOML_MAY_THROW
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
};
/// \brief Prints a date_time out to a stream in RFC 3339 format.
/// \detail \cpp
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 } } << std::endl;
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 }, { -2, -30 } } << std::endl;
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 }, {} } << std::endl;
/// \ecpp
///
/// \out
/// 1987-03-16T10:20:34
/// 1987-03-16T10:20:34-02:30
/// 1987-03-16T10:20:34Z
/// \eout
template <typename CHAR>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const date_time& rhs) TOML_MAY_THROW
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
}
TOML_END

View File

@ -151,6 +151,11 @@ TOML_IMPL_END
TOML_START
{
template <typename T, typename U>
std::basic_ostream<T>& operator << (std::basic_ostream<T>&, default_formatter<U>&) TOML_MAY_THROW;
template <typename T, typename U>
std::basic_ostream<T>& operator << (std::basic_ostream<T>&, default_formatter<U>&&) TOML_MAY_THROW;
/// \brief A wrapper for printing TOML objects out to a stream as formatted TOML.
///
/// \remarks You generally don't need to create an instance of this class explicitly; the stream
@ -444,25 +449,10 @@ TOML_START
: base{ source, flags }
{}
/// \brief Prints the bound TOML object out to the stream as formatted TOML.
template <typename T>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<T>& lhs, default_formatter& rhs)
TOML_MAY_THROW
{
rhs.attach(lhs);
rhs.key_path.clear();
rhs.print();
rhs.detach();
return lhs;
}
/// \brief Prints the bound TOML object out to the stream as formatted TOML (rvalue overload).
template <typename T>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<T>& lhs, default_formatter&& rhs)
TOML_MAY_THROW
{
return lhs << rhs; //as lvalue
}
template <typename T, typename U>
friend std::basic_ostream<T>& operator << (std::basic_ostream<T>&, default_formatter<U>&) TOML_MAY_THROW;
template <typename T, typename U>
friend std::basic_ostream<T>& operator << (std::basic_ostream<T>&, default_formatter<U>&&) TOML_MAY_THROW;
};
template <typename CHAR>
@ -499,6 +489,24 @@ TOML_START
base::clear_naked_newline();
}
/// \brief Prints the bound TOML object out to the stream as formatted TOML.
template <typename T, typename U>
inline std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, default_formatter<U>& rhs) TOML_MAY_THROW
{
rhs.attach(lhs);
rhs.key_path.clear();
rhs.print();
rhs.detach();
return lhs;
}
/// \brief Prints the bound TOML object out to the stream as formatted TOML (rvalue overload).
template <typename T, typename U>
inline std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, default_formatter<U>&& rhs) TOML_MAY_THROW
{
return lhs << rhs; //as lvalue
}
template <typename CHAR>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const table& rhs) TOML_MAY_THROW
{

View File

@ -1,5 +1,6 @@
#pragma once
#include "toml_value.h"
#include "toml_node_view.h"
TOML_START
{
@ -10,5 +11,8 @@ TOML_START
template class TOML_API value<date>;
template class TOML_API value<time>;
template class TOML_API value<date_time>;
template class TOML_API node_view<node>;
template class TOML_API node_view<const node>;
}
TOML_END

View File

@ -3,6 +3,11 @@
TOML_START
{
template <typename T, typename U>
std::basic_ostream<T>& operator << (std::basic_ostream<T>&, json_formatter<U>&) TOML_MAY_THROW;
template <typename T, typename U>
std::basic_ostream<T>& operator << (std::basic_ostream<T>&, json_formatter<U>&&) TOML_MAY_THROW;
/// \brief A wrapper for printing TOML objects out to a stream as formatted JSON.
///
/// \detail \cpp
@ -100,25 +105,10 @@ TOML_START
: base{ source, flags }
{}
/// \brief Prints the bound TOML object out to the stream as JSON.
template <typename T>
friend std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, json_formatter& rhs)
TOML_MAY_THROW
{
rhs.attach(lhs);
rhs.print();
rhs.detach();
return lhs;
}
/// \brief Prints the bound TOML object out to the stream as JSON (rvalue overload).
template <typename T>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<T>& lhs, json_formatter&& rhs)
TOML_MAY_THROW
{
return lhs << rhs; //as lvalue
}
template <typename T, typename U>
friend std::basic_ostream<T>& operator << (std::basic_ostream<T>&, json_formatter<U>&) TOML_MAY_THROW;
template <typename T, typename U>
friend std::basic_ostream<T>& operator << (std::basic_ostream<T>&, json_formatter<U>&&) TOML_MAY_THROW;
};
template <typename CHAR>
@ -159,5 +149,22 @@ TOML_START
}
base::clear_naked_newline();
}
/// \brief Prints the bound TOML object out to the stream as JSON.
template <typename T, typename U>
inline std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, json_formatter<U>& rhs) TOML_MAY_THROW
{
rhs.attach(lhs);
rhs.print();
rhs.detach();
return lhs;
}
/// \brief Prints the bound TOML object out to the stream as JSON (rvalue overload).
template <typename T, typename U>
inline std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, json_formatter<U>&& rhs) TOML_MAY_THROW
{
return lhs << rhs; //as lvalue
}
}
TOML_END

View File

@ -5,6 +5,9 @@
TOML_START
{
template <typename CHAR, typename T>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>&, const node_view<T>&) TOML_MAY_THROW;
/// \brief A view of a node.
///
/// \detail A node_view is like a std::optional<toml::node> with lots of toml-specific stuff built-in.
@ -49,13 +52,14 @@ TOML_START
/// product[2]:
/// \eout
template <typename T>
class node_view final
class TOML_API node_view final
{
public:
using viewed_type = T;
private:
friend class toml::table;
template <typename U> friend class toml::node_view;
viewed_type* node_;
@ -331,7 +335,15 @@ TOML_START
///
/// \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.
[[nodiscard]] node_view<viewed_type> operator[] (string_view key) noexcept
[[nodiscard]] node_view operator[] (string_view key) noexcept
{
if (auto tbl = this->as_table())
return { tbl->get(key) };
return { nullptr };
}
/// \brief Returns a view of the selected subnode (const overload).
[[nodiscard]] node_view<const viewed_type> operator[] (string_view key) const noexcept
{
if (auto tbl = this->as_table())
return { tbl->get(key) };
@ -344,42 +356,42 @@ TOML_START
///
/// \returns A view of the selected node if this node represented an array and it contained a
/// value at the given index, or an empty view.
[[nodiscard]] node_view<viewed_type> operator[] (size_t index) noexcept
[[nodiscard]] node_view operator[] (size_t index) noexcept
{
if (auto tbl = this->as_array())
return { tbl->get(index) };
return { nullptr };
}
/// \brief Returns a view of the selected subnode (const overload).
[[nodiscard]] node_view<const viewed_type> operator[] (string_view key) const noexcept
{
if (auto tbl = this->as_table())
return { tbl->get(key) };
if (auto arr = this->as_array())
return { arr->get(index) };
return { nullptr };
}
/// \brief Returns a view of the selected subnode (const overload).
[[nodiscard]] node_view<const viewed_type> operator[] (size_t index) const noexcept
{
if (auto tbl = this->as_array())
return { tbl->get(index) };
if (auto arr = this->as_array())
return { arr->get(index) };
return { nullptr };
}
/// \brief Prints the viewed node out to a stream.
template <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& os, const node_view& nv) TOML_MAY_THROW
{
if (nv.node_)
{
nv.node_->visit([&os](const auto& n) TOML_MAY_THROW
{
os << n;
});
}
return os;
}
template <typename CHAR, typename U>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>&, const node_view<U>&) TOML_MAY_THROW;
};
#if !TOML_ALL_INLINE
extern template class TOML_API node_view<node>;
extern template class TOML_API node_view<const node>;
#endif
/// \brief Prints the viewed node out to a stream.
template <typename CHAR, typename T>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& os, const node_view<T>& nv) TOML_MAY_THROW
{
if (nv.node_)
{
nv.node_->visit([&os](const auto& n) TOML_MAY_THROW
{
os << n;
});
}
return os;
}
}
TOML_END

View File

@ -4,6 +4,9 @@
TOML_START
{
template <typename CHAR, typename T>
std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>&, const value<T>&) TOML_MAY_THROW;
/// \brief A TOML value.
///
/// \tparam T The value's data type. Can be one of:
@ -160,23 +163,8 @@ TOML_START
/// \brief Returns a reference to the underlying value (const overload).
[[nodiscard]] explicit operator const T& () const& noexcept { return val_; }
template <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const value& rhs) TOML_MAY_THROW
{
// 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;
}
template <typename CHAR, typename U>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const value<U>& rhs) TOML_MAY_THROW;
/// \brief Value-assignment operator.
value& operator= (value_arg rhs) noexcept
@ -309,6 +297,16 @@ TOML_START
}
};
#if !TOML_ALL_INLINE
extern template class TOML_API value<string>;
extern template class TOML_API value<int64_t>;
extern template class TOML_API value<double>;
extern template class TOML_API value<bool>;
extern template class TOML_API value<date>;
extern template class TOML_API value<time>;
extern template class TOML_API value<date_time>;
#endif
template <size_t N> value(const string_char(&)[N]) -> value<string>;
template <size_t N> value(const string_char(&&)[N]) -> value<string>;
value(const string_char*) -> value<string>;
@ -337,15 +335,24 @@ TOML_START
value(TOML_SMALL_INT_TYPE) -> value<int64_t>;
#endif
#if !TOML_ALL_INLINE
extern template class TOML_API value<string>;
extern template class TOML_API value<int64_t>;
extern template class TOML_API value<double>;
extern template class TOML_API value<bool>;
extern template class TOML_API value<date>;
extern template class TOML_API value<time>;
extern template class TOML_API value<date_time>;
#endif
/// \brief Prints the value out to a stream.
template <typename CHAR, typename T>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const value<T>& rhs) TOML_MAY_THROW
{
// 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;
}
template <typename T>
inline std::optional<T> node::value() const noexcept

View File

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

View File

@ -1,7 +1,7 @@
project(
'tomlplusplus',
'cpp',
version : '0.3.0',
version : '0.3.2',
license : 'MIT',
default_options : [
'cpp_std=c++17',
@ -30,6 +30,7 @@ if compiler.get_id() == 'clang'
'-g0',
'-ferror-limit=5',
'-fchar8_t',
# '-Weverything',
'-Wno-c++98-compat',
'-Wno-c++98-compat-pedantic',
'-Wno-float-equal',
@ -38,7 +39,7 @@ if compiler.get_id() == 'clang'
'-Wno-padded',
'-Wno-weak-vtables',
'-Wno-double-promotion'
#, '-Weverything'
#, '-ftime-trace'
],
language : 'cpp'
)

View File

@ -11,7 +11,8 @@ test_sources = [
'parsing_strings.cpp',
'parsing_tables.cpp',
'manipulating_arrays.cpp',
'manipulating_tables.cpp'
'manipulating_tables.cpp',
'tests.cpp'
]
disable_exceptions = 'cpp_eh=none'

View File

@ -1,3 +1,61 @@
#include "tests.h"
// this file is a no-op. it's only here for PCH on MSVC.
#if TESTS_MANUAL_INSTANTIATIONS
template void parse_expected_value(std::string_view, const int&) noexcept;
template void parse_expected_value(std::string_view, const unsigned int&) noexcept;
template void parse_expected_value(std::string_view, const bool&) noexcept;
template void parse_expected_value(std::string_view, const float&) noexcept;
template void parse_expected_value(std::string_view, const double&) noexcept;
template void parse_expected_value(std::string_view, const toml::string_view&) noexcept;
TOML_IMPL_START
{
template class formatter<char>;
}
TOML_IMPL_END
TOML_START
{
template class default_formatter<char>;
template std::ostream& operator<< (std::ostream&, const table&) TOML_MAY_THROW;
template std::ostream& operator<< (std::ostream&, const array&) TOML_MAY_THROW;
template std::ostream& operator<< (std::ostream&, const value<string>&) TOML_MAY_THROW;
template std::ostream& operator<< (std::ostream&, const value<int64_t>&) TOML_MAY_THROW;
template std::ostream& operator<< (std::ostream&, const value<double>&) TOML_MAY_THROW;
template std::ostream& operator<< (std::ostream&, const value<bool>&) TOML_MAY_THROW;
template std::ostream& operator<< (std::ostream&, const value<date>&) TOML_MAY_THROW;
template std::ostream& operator<< (std::ostream&, const value<time>&) TOML_MAY_THROW;
template std::ostream& operator<< (std::ostream&, const value<date_time>&) TOML_MAY_THROW;
template std::ostream& operator<< (std::ostream&, const node_view<node>&) TOML_MAY_THROW;
template std::ostream& operator<< (std::ostream&, const node_view<const node>&) TOML_MAY_THROW;
template std::ostream& operator<< (std::ostream&, node_type) TOML_MAY_THROW;
template std::ostream& operator<< (std::ostream&, const source_region&) TOML_MAY_THROW;
template std::ostream& operator<< (std::ostream&, const source_position&) TOML_MAY_THROW;
template std::ostream& operator<< (std::ostream&, const parse_error&) TOML_MAY_THROW;
template std::ostream& operator<< (std::ostream&, const date&) TOML_MAY_THROW;
template std::ostream& operator<< (std::ostream&, const time&) TOML_MAY_THROW;
template std::ostream& operator<< (std::ostream&, const time_offset&) TOML_MAY_THROW;
template std::ostream& operator<< (std::ostream&, const date_time&) TOML_MAY_THROW;
template std::ostream& operator<< (std::ostream&, default_formatter<char>&) TOML_MAY_THROW;
template std::ostream& operator<< (std::ostream&, default_formatter<char>&&) TOML_MAY_THROW;
}
TOML_END
template class std::unique_ptr<const Catch::IExceptionTranslator>;
namespace Catch
{
template struct StringMaker<node_view<node>>;
template struct StringMaker<node_view<const node>>;
template ReusableStringStream& ReusableStringStream::operator << (toml::node_view<toml::node> const&);
template ReusableStringStream& ReusableStringStream::operator << (toml::node_view<const toml::node> const&);
namespace Detail
{
template std::string stringify(const node_view<node>&);
template std::string stringify(const node_view<const node>&);
}
}
#endif // TESTS_MANUAL_INSTANTIATIONS

View File

@ -13,7 +13,7 @@ TOML_POP_WARNINGS
#define S(str) TOML_STRING_PREFIX(str)
template <typename CHAR, typename FUNC>
void parsing_should_succeed(std::basic_string_view<CHAR> toml_str, FUNC&& func, std::string_view source_path = {}) noexcept
inline void parsing_should_succeed(std::basic_string_view<CHAR> toml_str, FUNC&& func, std::string_view source_path = {}) noexcept
{
INFO("String being parsed: '"sv << std::string_view( reinterpret_cast<const char*>(toml_str.data()), toml_str.length() ) << "'"sv)
@ -29,7 +29,6 @@ void parsing_should_succeed(std::basic_string_view<CHAR> toml_str, FUNC&& func,
REQUIRE(tabl.source().path != nullptr);
CHECK(*tabl.source().path == path);
}
return std::move(tabl);
};
@ -48,7 +47,7 @@ void parsing_should_succeed(std::basic_string_view<CHAR> toml_str, FUNC&& func,
std::forward<FUNC>(func)(validate_table(toml::parse(ss, source_path), source_path));
}
}
catch (const toml::parse_error& err)
catch (const parse_error& err)
{
FAIL(
"Parse error on line "sv << err.source().begin.line
@ -61,7 +60,7 @@ void parsing_should_succeed(std::basic_string_view<CHAR> toml_str, FUNC&& func,
{
INFO("Parsing string directly"sv)
toml::parse_result result = toml::parse(toml_str, source_path);
parse_result result = toml::parse(toml_str, source_path);
if (result)
std::forward<FUNC>(func)(validate_table(std::move(result), source_path));
else
@ -79,7 +78,7 @@ void parsing_should_succeed(std::basic_string_view<CHAR> toml_str, FUNC&& func,
INFO("Parsing from a string stream"sv)
std::basic_stringstream<CHAR, std::char_traits<CHAR>, std::allocator<CHAR>> ss;
ss.write(toml_str.data(), static_cast<std::streamsize>(toml_str.length()));
toml::parse_result result = toml::parse(ss, source_path);
parse_result result = toml::parse(ss, source_path);
if (result)
std::forward<FUNC>(func)(validate_table(std::move(result), source_path));
else
@ -97,7 +96,7 @@ void parsing_should_succeed(std::basic_string_view<CHAR> toml_str, FUNC&& func,
}
template <typename CHAR>
void parsing_should_fail(std::basic_string_view<CHAR> toml_str) noexcept
inline void parsing_should_fail(std::basic_string_view<CHAR> toml_str) noexcept
{
#if TOML_EXCEPTIONS
@ -107,9 +106,9 @@ void parsing_should_fail(std::basic_string_view<CHAR> toml_str) noexcept
{
fn();
}
catch (const toml::parse_error&)
catch (const parse_error&)
{
SUCCEED("toml::parse_error thrown OK"sv);
SUCCEED("parse_error thrown OK"sv);
return true;
}
catch (const std::exception& exc)
@ -135,7 +134,7 @@ void parsing_should_fail(std::basic_string_view<CHAR> toml_str) noexcept
static constexpr auto run_tests = [](auto&& fn) noexcept
{
toml::parse_result result = fn();
parse_result result = fn();
if (result)
{
FAIL("Expected parsing failure"sv);
@ -143,7 +142,7 @@ void parsing_should_fail(std::basic_string_view<CHAR> toml_str) noexcept
}
else
{
SUCCEED("toml::parse_error returned OK"sv);
SUCCEED("parse_error returned OK"sv);
return true;
}
};
@ -160,7 +159,7 @@ void parsing_should_fail(std::basic_string_view<CHAR> toml_str) noexcept
}
template <typename T>
void parse_expected_value(std::string_view value_str, const T& expected) noexcept
inline void parse_expected_value(std::string_view value_str, const T& expected) noexcept
{
std::string val;
static constexpr auto key = "val = "sv;
@ -277,5 +276,66 @@ void parse_expected_value(std::string_view value_str, const T& expected) noexcep
}
CHECK(val_reparsed == val_parsed);
CHECK(val_reparsed == expected);
}
// manually instantiate some templates to reduce test compilation time (chosen using ClangBuildAnalyzer)
#define TESTS_MANUAL_INSTANTIATIONS 1
#if TESTS_MANUAL_INSTANTIATIONS
extern template void parse_expected_value(std::string_view, const int&) noexcept;
extern template void parse_expected_value(std::string_view, const unsigned int&) noexcept;
extern template void parse_expected_value(std::string_view, const bool&) noexcept;
extern template void parse_expected_value(std::string_view, const float&) noexcept;
extern template void parse_expected_value(std::string_view, const double&) noexcept;
extern template void parse_expected_value(std::string_view, const toml::string_view&) noexcept;
TOML_IMPL_START
{
extern template class formatter<char>;
}
TOML_IMPL_END
TOML_START
{
extern template class default_formatter<char>;
extern template std::ostream& operator<< (std::ostream&, const table&) TOML_MAY_THROW;
extern template std::ostream& operator<< (std::ostream&, const array&) TOML_MAY_THROW;
extern template std::ostream& operator<< (std::ostream&, const value<string>&) TOML_MAY_THROW;
extern template std::ostream& operator<< (std::ostream&, const value<int64_t>&) TOML_MAY_THROW;
extern template std::ostream& operator<< (std::ostream&, const value<double>&) TOML_MAY_THROW;
extern template std::ostream& operator<< (std::ostream&, const value<bool>&) TOML_MAY_THROW;
extern template std::ostream& operator<< (std::ostream&, const value<date>&) TOML_MAY_THROW;
extern template std::ostream& operator<< (std::ostream&, const value<time>&) TOML_MAY_THROW;
extern template std::ostream& operator<< (std::ostream&, const value<date_time>&) TOML_MAY_THROW;
extern template std::ostream& operator<< (std::ostream&, const node_view<node>&) TOML_MAY_THROW;
extern template std::ostream& operator<< (std::ostream&, const node_view<const node>&) TOML_MAY_THROW;
extern template std::ostream& operator<< (std::ostream&, node_type) TOML_MAY_THROW;
extern template std::ostream& operator<< (std::ostream&, const source_region&) TOML_MAY_THROW;
extern template std::ostream& operator<< (std::ostream&, const source_position&) TOML_MAY_THROW;
extern template std::ostream& operator<< (std::ostream&, const parse_error&) TOML_MAY_THROW;
extern template std::ostream& operator<< (std::ostream&, const date&) TOML_MAY_THROW;
extern template std::ostream& operator<< (std::ostream&, const time&) TOML_MAY_THROW;
extern template std::ostream& operator<< (std::ostream&, const time_offset&) TOML_MAY_THROW;
extern template std::ostream& operator<< (std::ostream&, const date_time&) TOML_MAY_THROW;
extern template std::ostream& operator<< (std::ostream&, default_formatter<char>&) TOML_MAY_THROW;
extern template std::ostream& operator<< (std::ostream&, default_formatter<char>&&) TOML_MAY_THROW;
}
TOML_END
extern template class std::unique_ptr<const Catch::IExceptionTranslator>;
namespace Catch
{
extern template struct StringMaker<node_view<node>>;
extern template struct StringMaker<node_view<const node>>;
extern template ReusableStringStream& ReusableStringStream::operator << (node_view<node> const&);
extern template ReusableStringStream& ReusableStringStream::operator << (node_view<const node> const&);
namespace Detail
{
extern template std::string stringify(const node_view<node>&);
extern template std::string stringify(const node_view<const node>&);
}
}
#endif // TESTS_MANUAL_INSTANTIATIONS

311
toml.hpp
View File

@ -1,6 +1,6 @@
//----------------------------------------------------------------------------------------------------------------------
//
// toml++ v0.3.1
// toml++ v0.3.2
// https://github.com/marzer/tomlplusplus
// SPDX-License-Identifier: MIT
//
@ -303,7 +303,7 @@
#define TOML_LIB_MAJOR 0
#define TOML_LIB_MINOR 3
#define TOML_LIB_PATCH 1
#define TOML_LIB_PATCH 2
#define TOML_LANG_MAJOR 0
#define TOML_LANG_MINOR 5
@ -413,10 +413,12 @@ TOML_START
struct time_offset;
struct date_time;
class node;
template <typename T> class node_view;
template <typename T> class value;
class array;
class table;
template <typename> class node_view;
template <typename> class value;
template <typename> class default_formatter;
template <typename> class json_formatter;
enum class node_type : uint8_t
{
@ -918,16 +920,15 @@ TOML_START
{
return pack(lhs) >= pack(rhs);
}
template <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const date& rhs)
TOML_MAY_THROW
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
};
template <typename CHAR>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const date& rhs) TOML_MAY_THROW
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
struct time final
{
uint8_t hour;
@ -986,16 +987,15 @@ TOML_START
{
return pack(lhs) >= pack(rhs);
}
template <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const time& rhs)
TOML_MAY_THROW
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
};
template <typename CHAR>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const time& rhs) TOML_MAY_THROW
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
struct time_offset final
{
int16_t minutes;
@ -1045,16 +1045,15 @@ TOML_START
{
return lhs.minutes >= rhs.minutes;
}
template <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const time_offset& rhs)
TOML_MAY_THROW
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
};
template <typename CHAR>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const time_offset& rhs) TOML_MAY_THROW
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
struct date_time final
{
toml::date date;
@ -1131,15 +1130,14 @@ TOML_START
{
return !(lhs < rhs);
}
template <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const date_time& rhs)
TOML_MAY_THROW
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
};
template <typename CHAR>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const date_time& rhs) TOML_MAY_THROW
{
impl::print_to_stream(rhs, lhs);
return lhs;
}
}
TOML_END
@ -1822,6 +1820,9 @@ TOML_END
TOML_START
{
template <typename CHAR, typename T>
std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>&, const value<T>&) TOML_MAY_THROW;
template <typename T>
class TOML_API value final : public node
{
@ -1912,24 +1913,8 @@ TOML_START
[[nodiscard]] explicit operator T&& () && noexcept { return std::move(val_); }
[[nodiscard]] explicit operator const T& () const& noexcept { return val_; }
template <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const value& rhs) TOML_MAY_THROW
{
// 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;
}
template <typename CHAR, typename U>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const value<U>& rhs) TOML_MAY_THROW;
value& operator= (value_arg rhs) noexcept
{
if constexpr (std::is_same_v<T, string>)
@ -2009,6 +1994,16 @@ TOML_START
}
};
#if !TOML_ALL_INLINE
extern template class TOML_API value<string>;
extern template class TOML_API value<int64_t>;
extern template class TOML_API value<double>;
extern template class TOML_API value<bool>;
extern template class TOML_API value<date>;
extern template class TOML_API value<time>;
extern template class TOML_API value<date_time>;
#endif
template <size_t N> value(const string_char(&)[N]) -> value<string>;
template <size_t N> value(const string_char(&&)[N]) -> value<string>;
value(const string_char*) -> value<string>;
@ -2037,15 +2032,23 @@ TOML_START
value(TOML_SMALL_INT_TYPE) -> value<int64_t>;
#endif
#if !TOML_ALL_INLINE
extern template class TOML_API value<string>;
extern template class TOML_API value<int64_t>;
extern template class TOML_API value<double>;
extern template class TOML_API value<bool>;
extern template class TOML_API value<date>;
extern template class TOML_API value<time>;
extern template class TOML_API value<date_time>;
#endif
template <typename CHAR, typename T>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const value<T>& rhs) TOML_MAY_THROW
{
// 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;
}
template <typename T>
inline std::optional<T> node::value() const noexcept
@ -2941,14 +2944,18 @@ TOML_END
TOML_START
{
template <typename CHAR, typename T>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>&, const node_view<T>&) TOML_MAY_THROW;
template <typename T>
class node_view final
class TOML_API node_view final
{
public:
using viewed_type = T;
private:
friend class toml::table;
template <typename U> friend class toml::node_view;
viewed_type* node_;
@ -3131,20 +3138,14 @@ TOML_START
return arr && *arr == rhs;
}
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const std::vector<U>&, template <typename U>)
[[nodiscard]] node_view<viewed_type> operator[] (string_view key) noexcept
[[nodiscard]] node_view operator[] (string_view key) noexcept
{
if (auto tbl = this->as_table())
return { tbl->get(key) };
return { nullptr };
}
[[nodiscard]] node_view<viewed_type> operator[] (size_t index) noexcept
{
if (auto tbl = this->as_array())
return { tbl->get(index) };
return { nullptr };
}
[[nodiscard]] node_view<const viewed_type> operator[] (string_view key) const noexcept
{
if (auto tbl = this->as_table())
@ -3152,26 +3153,41 @@ TOML_START
return { nullptr };
}
[[nodiscard]] node_view<const viewed_type> operator[] (size_t index) const noexcept
[[nodiscard]] node_view operator[] (size_t index) noexcept
{
if (auto tbl = this->as_array())
return { tbl->get(index) };
if (auto arr = this->as_array())
return { arr->get(index) };
return { nullptr };
}
template <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& os, const node_view& nv) TOML_MAY_THROW
[[nodiscard]] node_view<const viewed_type> operator[] (size_t index) const noexcept
{
if (nv.node_)
{
nv.node_->visit([&os](const auto& n) TOML_MAY_THROW
{
os << n;
});
}
return os;
if (auto arr = this->as_array())
return { arr->get(index) };
return { nullptr };
}
template <typename CHAR, typename U>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>&, const node_view<U>&) TOML_MAY_THROW;
};
#if !TOML_ALL_INLINE
extern template class TOML_API node_view<node>;
extern template class TOML_API node_view<const node>;
#endif
template <typename CHAR, typename T>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& os, const node_view<T>& nv) TOML_MAY_THROW
{
if (nv.node_)
{
nv.node_->visit([&os](const auto& n) TOML_MAY_THROW
{
os << n;
});
}
return os;
}
}
TOML_END
@ -5282,6 +5298,11 @@ TOML_IMPL_END
TOML_START
{
template <typename T, typename U>
std::basic_ostream<T>& operator << (std::basic_ostream<T>&, default_formatter<U>&) TOML_MAY_THROW;
template <typename T, typename U>
std::basic_ostream<T>& operator << (std::basic_ostream<T>&, default_formatter<U>&&) TOML_MAY_THROW;
template <typename CHAR = char>
class default_formatter final : impl::formatter<CHAR>
{
@ -5541,23 +5562,10 @@ TOML_START
: base{ source, flags }
{}
template <typename T>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<T>& lhs, default_formatter& rhs)
TOML_MAY_THROW
{
rhs.attach(lhs);
rhs.key_path.clear();
rhs.print();
rhs.detach();
return lhs;
}
template <typename T>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<T>& lhs, default_formatter&& rhs)
TOML_MAY_THROW
{
return lhs << rhs; //as lvalue
}
template <typename T, typename U>
friend std::basic_ostream<T>& operator << (std::basic_ostream<T>&, default_formatter<U>&) TOML_MAY_THROW;
template <typename T, typename U>
friend std::basic_ostream<T>& operator << (std::basic_ostream<T>&, default_formatter<U>&&) TOML_MAY_THROW;
};
template <typename CHAR>
@ -5594,6 +5602,22 @@ TOML_START
base::clear_naked_newline();
}
template <typename T, typename U>
inline std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, default_formatter<U>& rhs) TOML_MAY_THROW
{
rhs.attach(lhs);
rhs.key_path.clear();
rhs.print();
rhs.detach();
return lhs;
}
template <typename T, typename U>
inline std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, default_formatter<U>&& rhs) TOML_MAY_THROW
{
return lhs << rhs; //as lvalue
}
template <typename CHAR>
inline std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const table& rhs) TOML_MAY_THROW
{
@ -5616,6 +5640,11 @@ TOML_END
TOML_START
{
template <typename T, typename U>
std::basic_ostream<T>& operator << (std::basic_ostream<T>&, json_formatter<U>&) TOML_MAY_THROW;
template <typename T, typename U>
std::basic_ostream<T>& operator << (std::basic_ostream<T>&, json_formatter<U>&&) TOML_MAY_THROW;
template <typename CHAR = char>
class json_formatter final : impl::formatter<CHAR>
{
@ -5676,22 +5705,10 @@ TOML_START
: base{ source, flags }
{}
template <typename T>
friend std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, json_formatter& rhs)
TOML_MAY_THROW
{
rhs.attach(lhs);
rhs.print();
rhs.detach();
return lhs;
}
template <typename T>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<T>& lhs, json_formatter&& rhs)
TOML_MAY_THROW
{
return lhs << rhs; //as lvalue
}
template <typename T, typename U>
friend std::basic_ostream<T>& operator << (std::basic_ostream<T>&, json_formatter<U>&) TOML_MAY_THROW;
template <typename T, typename U>
friend std::basic_ostream<T>& operator << (std::basic_ostream<T>&, json_formatter<U>&&) TOML_MAY_THROW;
};
template <typename CHAR>
@ -5732,6 +5749,21 @@ TOML_START
}
base::clear_naked_newline();
}
template <typename T, typename U>
inline std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, json_formatter<U>& rhs) TOML_MAY_THROW
{
rhs.attach(lhs);
rhs.print();
rhs.detach();
return lhs;
}
template <typename T, typename U>
inline std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, json_formatter<U>&& rhs) TOML_MAY_THROW
{
return lhs << rhs; //as lvalue
}
}
TOML_END
@ -5740,7 +5772,28 @@ TOML_END
#if TOML_IMPLEMENTATION
//----------------------------------------------------------------- ↓ toml_node_impl.h -------------------------------
//--------------------------------------------------------------- ↓ toml_instantiations.h ----------------------------
#pragma region
TOML_START
{
template class TOML_API value<string>;
template class TOML_API value<int64_t>;
template class TOML_API value<double>;
template class TOML_API value<bool>;
template class TOML_API value<date>;
template class TOML_API value<time>;
template class TOML_API value<date_time>;
template class TOML_API node_view<node>;
template class TOML_API node_view<const node>;
}
TOML_END
#pragma endregion
//--------------------------------------------------------------- ↑ toml_instantiations.h ----------------------------
//------------------------------------------------------------------------------------------ ↓ toml_node_impl.h ------
#pragma region
TOML_START
@ -5797,25 +5850,7 @@ TOML_START
TOML_END
#pragma endregion
//----------------------------------------------------------------- ↑ toml_node_impl.h -------------------------------
//------------------------------------------------------------------------------------------ ↓ toml_value_impl.h -----
#pragma region
TOML_START
{
template class TOML_API value<string>;
template class TOML_API value<int64_t>;
template class TOML_API value<double>;
template class TOML_API value<bool>;
template class TOML_API value<date>;
template class TOML_API value<time>;
template class TOML_API value<date_time>;
}
TOML_END
#pragma endregion
//------------------------------------------------------------------------------------------ ↑ toml_value_impl.h -----
//------------------------------------------------------------------------------------------ ↑ toml_node_impl.h ------
//--------------- ↓ toml_array_impl.h --------------------------------------------------------------------------------
#pragma region

View File

@ -75,8 +75,9 @@
<ClInclude Include="..\include\toml++\toml_table.h" />
<ClInclude Include="..\include\toml++\toml_utf8.h" />
<ClInclude Include="..\include\toml++\toml_value.h" />
<ClInclude Include="..\include\toml++\toml_value_impl.h" />
<ClInclude Include="..\include\toml++\toml_instantiations.h" />
<ClInclude Include="..\include\toml++\toml_version.h" />
<ClInclude Include="..\tests\catch2.h" />
</ItemGroup>
<ItemGroup>
<None Include="..\.editorconfig" />

View File

@ -58,12 +58,15 @@
<ClInclude Include="..\include\toml++\toml_table_impl.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\include\toml++\toml_value_impl.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\include\toml++\toml_parser_impl.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\include\toml++\toml_instantiations.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="..\tests\catch2.h">
<Filter>extern</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\.editorconfig" />
@ -105,5 +108,8 @@
<Filter Include="doc">
<UniqueIdentifier>{5ed0949f-6855-4664-ad86-2b38ceeb400b}</UniqueIdentifier>
</Filter>
<Filter Include="extern">
<UniqueIdentifier>{b838dba3-02f6-446f-840e-6b4c62d2fb0c}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>