52736559d2
auto table = toml::table{{{"value", 10}}}; const toml::node *value = table.get("value"); if(value && value->is_number()) { double number = value->value_or<double>(0); cout << number << endl; } The original output was 0. This change will output 10.0. The old way would see that it was an integer (a native type), then use the integer conversion, but since the type being requested was a double, it would return the default value.
868 lines
30 KiB
C++
868 lines
30 KiB
C++
//# 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
|
|
|
|
#pragma once
|
|
#include "toml_node.h"
|
|
#include "toml_print_to_stream.h"
|
|
|
|
TOML_PUSH_WARNINGS
|
|
TOML_DISABLE_ARITHMETIC_WARNINGS
|
|
TOML_DISABLE_PADDING_WARNINGS
|
|
TOML_DISABLE_MISC_WARNINGS
|
|
|
|
TOML_IMPL_NAMESPACE_START
|
|
{
|
|
template <typename T, typename...>
|
|
struct native_value_maker
|
|
{
|
|
template <typename... Args>
|
|
[[nodiscard]]
|
|
static T make(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args&&...>)
|
|
{
|
|
return T(std::forward<Args>(args)...);
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct native_value_maker<T, T>
|
|
{
|
|
template <typename U>
|
|
[[nodiscard]]
|
|
TOML_ALWAYS_INLINE
|
|
static U&& make(U&& val) noexcept
|
|
{
|
|
return std::forward<U>(val);
|
|
}
|
|
};
|
|
|
|
#if defined(__cpp_lib_char8_t) || TOML_WINDOWS_COMPAT
|
|
|
|
struct string_maker
|
|
{
|
|
template <typename T>
|
|
[[nodiscard]]
|
|
static std::string make(T&& arg) noexcept
|
|
{
|
|
#ifdef __cpp_lib_char8_t
|
|
if constexpr (is_one_of<std::decay_t<T>, char8_t*, const char8_t*>)
|
|
return std::string(reinterpret_cast<const char*>(static_cast<const char8_t*>(arg)));
|
|
else if constexpr (is_one_of<remove_cvref_t<T>, std::u8string, std::u8string_view>)
|
|
return std::string(reinterpret_cast<const char*>(static_cast<const char8_t*>(arg.data())), arg.length());
|
|
#endif // __cpp_lib_char8_t
|
|
|
|
#if TOML_WINDOWS_COMPAT
|
|
if constexpr (is_wide_string<T>)
|
|
return narrow(std::forward<T>(arg));
|
|
#endif // TOML_WINDOWS_COMPAT
|
|
}
|
|
};
|
|
#ifdef __cpp_lib_char8_t
|
|
template <> struct native_value_maker<std::string, char8_t*> : string_maker {};
|
|
template <> struct native_value_maker<std::string, const char8_t*> : string_maker {};
|
|
template <> struct native_value_maker<std::string, std::u8string> : string_maker {};
|
|
template <> struct native_value_maker<std::string, std::u8string_view> : string_maker {};
|
|
#endif // __cpp_lib_char8_t
|
|
#if TOML_WINDOWS_COMPAT
|
|
template <> struct native_value_maker<std::string, wchar_t*> : string_maker {};
|
|
template <> struct native_value_maker<std::string, const wchar_t*> : string_maker {};
|
|
template <> struct native_value_maker<std::string, std::wstring> : string_maker {};
|
|
template <> struct native_value_maker<std::string, std::wstring_view> : string_maker {};
|
|
#endif // TOML_WINDOWS_COMPAT
|
|
|
|
#endif // defined(__cpp_lib_char8_t) || TOML_WINDOWS_COMPAT
|
|
|
|
template <typename T>
|
|
[[nodiscard]]
|
|
TOML_ATTR(const)
|
|
inline optional<T> node_integer_cast(int64_t val) noexcept
|
|
{
|
|
static_assert(node_type_of<T> == node_type::integer);
|
|
static_assert(!is_cvref<T>);
|
|
|
|
using traits = value_traits<T>;
|
|
if constexpr (!traits::is_signed)
|
|
{
|
|
if constexpr ((sizeof(T) * CHAR_BIT) < 63) // 63 bits == int64_max
|
|
{
|
|
using common_t = decltype(int64_t{} + T{});
|
|
if (val < int64_t{} || static_cast<common_t>(val) > static_cast<common_t>(traits::max))
|
|
return {};
|
|
}
|
|
else
|
|
{
|
|
if (val < int64_t{})
|
|
return {};
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (val < traits::min || val > traits::max)
|
|
return {};
|
|
}
|
|
return { static_cast<T>(val) };
|
|
}
|
|
}
|
|
TOML_IMPL_NAMESPACE_END
|
|
|
|
TOML_NAMESPACE_START
|
|
{
|
|
/// \brief A TOML value.
|
|
///
|
|
/// \tparam ValueType The value's native TOML data type. Can be one of:
|
|
/// - std::string
|
|
/// - toml::date
|
|
/// - toml::time
|
|
/// - toml::date_time
|
|
/// - int64_t
|
|
/// - double
|
|
/// - bool
|
|
template <typename ValueType>
|
|
class TOML_API value final : public node
|
|
{
|
|
static_assert(
|
|
impl::is_native<ValueType> && !impl::is_cvref<ValueType>,
|
|
"A toml::value<> must model one of the native TOML value types:"
|
|
TOML_SA_NATIVE_VALUE_TYPE_LIST
|
|
);
|
|
|
|
private:
|
|
friend class TOML_PARSER_TYPENAME;
|
|
|
|
template <typename T, typename U>
|
|
[[nodiscard]]
|
|
TOML_ALWAYS_INLINE
|
|
TOML_ATTR(const)
|
|
static auto as_value([[maybe_unused]] U* ptr) noexcept
|
|
{
|
|
if constexpr (std::is_same_v<value_type, T>)
|
|
return ptr;
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
ValueType val_;
|
|
|
|
public:
|
|
|
|
/// \brief The value's underlying data type.
|
|
using value_type = ValueType;
|
|
|
|
/// \brief A type alias for 'value arguments'.
|
|
/// \details This differs according to the value's type argument:
|
|
/// - ints, floats, booleans: `value_type`
|
|
/// - strings: `string_view`
|
|
/// - everything else: `const value_type&`
|
|
using value_arg = std::conditional_t<
|
|
std::is_same_v<value_type, std::string>,
|
|
std::string_view,
|
|
std::conditional_t<impl::is_one_of<value_type, double, int64_t, bool>, value_type, const value_type&>
|
|
>;
|
|
|
|
/// \brief Constructs a toml value.
|
|
///
|
|
/// \tparam Args Constructor argument types.
|
|
/// \param args Arguments to forward to the internal value's constructor.
|
|
template <typename... Args>
|
|
TOML_NODISCARD_CTOR
|
|
explicit value(Args&&... args)
|
|
noexcept(noexcept(value_type(
|
|
impl::native_value_maker<value_type, std::decay_t<Args>...>::make(std::forward<Args>(args)...)
|
|
)))
|
|
: val_(impl::native_value_maker<value_type, std::decay_t<Args>...>::make(std::forward<Args>(args)...))
|
|
{}
|
|
|
|
/// \brief Copy constructor.
|
|
TOML_NODISCARD_CTOR
|
|
value(const value& other) noexcept
|
|
: node{ other },
|
|
val_{ other.val_ }
|
|
{}
|
|
|
|
/// \brief Move constructor.
|
|
TOML_NODISCARD_CTOR
|
|
value(value&& other) noexcept
|
|
: node{ std::move(other) },
|
|
val_{ std::move(other.val_) }
|
|
{}
|
|
|
|
/// \brief Copy-assignment operator.
|
|
value& operator= (const value& rhs) noexcept
|
|
{
|
|
node::operator=(rhs);
|
|
val_ = rhs.val_;
|
|
return *this;
|
|
}
|
|
|
|
/// \brief Move-assignment operator.
|
|
value& operator= (value&& rhs) noexcept
|
|
{
|
|
if (&rhs != this)
|
|
{
|
|
node::operator=(std::move(rhs));
|
|
val_ = std::move(rhs.val_);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
/// \brief Returns the value's node type identifier.
|
|
///
|
|
/// \returns One of:
|
|
/// - node_type::string
|
|
/// - node_type::integer
|
|
/// - node_type::floating_point
|
|
/// - node_type::boolean
|
|
/// - node_type::date
|
|
/// - node_type::time
|
|
/// - node_type::date_time
|
|
[[nodiscard]] node_type type() const noexcept override { return impl::node_type_of<value_type>; }
|
|
|
|
/// \brief Always returns `false` for value nodes.
|
|
[[nodiscard]] bool is_table() const noexcept override { return false; }
|
|
/// \brief Always returns `false` for value nodes.
|
|
[[nodiscard]] bool is_array() const noexcept override { return false; }
|
|
/// \brief Always returns `true` for value nodes.
|
|
[[nodiscard]] bool is_value() const noexcept override { return true; }
|
|
|
|
[[nodiscard]] bool is_string() const noexcept override { return std::is_same_v<value_type, std::string>; }
|
|
[[nodiscard]] bool is_integer() const noexcept override { return std::is_same_v<value_type, int64_t>; }
|
|
[[nodiscard]] bool is_floating_point() const noexcept override { return std::is_same_v<value_type, double>; }
|
|
[[nodiscard]] bool is_number() const noexcept override { return impl::is_one_of<value_type, int64_t, double>; }
|
|
[[nodiscard]] bool is_boolean() const noexcept override { return std::is_same_v<value_type, bool>; }
|
|
[[nodiscard]] bool is_date() const noexcept override { return std::is_same_v<value_type, date>; }
|
|
[[nodiscard]] bool is_time() const noexcept override { return std::is_same_v<value_type, time>; }
|
|
[[nodiscard]] bool is_date_time() const noexcept override { return std::is_same_v<value_type, date_time>; }
|
|
|
|
/// \brief Returns a pointer to the value if the data type is a string.
|
|
[[nodiscard]] value<std::string>* as_string() noexcept override { return as_value<std::string>(this); }
|
|
/// \brief Returns a pointer to the value if the data type is an integer.
|
|
[[nodiscard]] value<int64_t>* as_integer() noexcept override { return as_value<int64_t>(this); }
|
|
/// \brief Returns a pointer to the value if the data type is a floating-point.
|
|
[[nodiscard]] value<double>* as_floating_point() noexcept override { return as_value<double>(this); }
|
|
/// \brief Returns a pointer to the value if the data type is boolean.
|
|
[[nodiscard]] value<bool>* as_boolean() noexcept override { return as_value<bool>(this); }
|
|
/// \brief Returns a pointer to the value if the data type is a date.
|
|
[[nodiscard]] value<date>* as_date() noexcept override { return as_value<date>(this); }
|
|
/// \brief Returns a pointer to the value if the data type is a time.
|
|
[[nodiscard]] value<time>* as_time() noexcept override { return as_value<time>(this); }
|
|
/// \brief Returns a pointer to the value if the data type is date-time.
|
|
[[nodiscard]] value<date_time>* as_date_time() noexcept override { return as_value<date_time>(this); }
|
|
|
|
/// \brief Returns a const pointer to the value if the data type is a string.
|
|
[[nodiscard]] const value<std::string>* as_string() const noexcept override { return as_value<std::string>(this); }
|
|
/// \brief Returns a const pointer to the value if the data type is an integer.
|
|
[[nodiscard]] const value<int64_t>* as_integer() const noexcept override { return as_value<int64_t>(this); }
|
|
/// \brief Returns a const pointer to the value if the data type is a floating-point.
|
|
[[nodiscard]] const value<double>* as_floating_point() const noexcept override { return as_value<double>(this); }
|
|
/// \brief Returns a const pointer to the value if the data type is a boolean.
|
|
[[nodiscard]] const value<bool>* as_boolean() const noexcept override { return as_value<bool>(this); }
|
|
/// \brief Returns a const pointer to the value if the data type is a date.
|
|
[[nodiscard]] const value<date>* as_date() const noexcept override { return as_value<date>(this); }
|
|
/// \brief Returns a const pointer to the value if the data type is a time.
|
|
[[nodiscard]] const value<time>* as_time() const noexcept override { return as_value<time>(this); }
|
|
/// \brief Returns a const pointer to the value if the data type is a date-time.
|
|
[[nodiscard]] const value<date_time>* as_date_time() const noexcept override { return as_value<date_time>(this); }
|
|
|
|
/// \brief Returns a reference to the underlying value.
|
|
[[nodiscard]] value_type& get() & noexcept { return val_; }
|
|
/// \brief Returns a reference to the underlying value (rvalue overload).
|
|
[[nodiscard]] value_type&& get() && noexcept { return std::move(val_); }
|
|
/// \brief Returns a reference to the underlying value (const overload).
|
|
[[nodiscard]] const value_type& get() const & noexcept { return val_; }
|
|
|
|
/// \brief Returns a reference to the underlying value.
|
|
[[nodiscard]] value_type& operator* () & noexcept { return val_; }
|
|
/// \brief Returns a reference to the underlying value (rvalue overload).
|
|
[[nodiscard]] value_type&& operator* () && noexcept { return std::move(val_); }
|
|
/// \brief Returns a reference to the underlying value (const overload).
|
|
[[nodiscard]] const value_type& operator* () const& noexcept { return val_; }
|
|
|
|
/// \brief Returns a reference to the underlying value.
|
|
[[nodiscard]] explicit operator value_type& () & noexcept { return val_; }
|
|
/// \brief Returns a reference to the underlying value (rvalue overload).
|
|
[[nodiscard]] explicit operator value_type && () && noexcept { return std::move(val_); }
|
|
/// \brief Returns a reference to the underlying value (const overload).
|
|
[[nodiscard]] explicit operator const value_type& () const& noexcept { return val_; }
|
|
|
|
/// \brief Prints the value out to a stream as formatted TOML.
|
|
template <typename Char, typename T>
|
|
friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>& lhs, const value<T>& rhs);
|
|
|
|
/// \brief Value-assignment operator.
|
|
value& operator= (value_arg rhs) noexcept
|
|
{
|
|
if constexpr (std::is_same_v<value_type, std::string>)
|
|
val_.assign(rhs);
|
|
else
|
|
val_ = rhs;
|
|
return *this;
|
|
}
|
|
|
|
template <typename T = value_type, typename = std::enable_if_t<std::is_same_v<T, std::string>>>
|
|
value& operator= (std::string&& rhs) noexcept
|
|
{
|
|
val_ = std::move(rhs);
|
|
return *this;
|
|
}
|
|
|
|
/// \brief Value equality operator.
|
|
[[nodiscard]]
|
|
friend bool operator == (const value& lhs, value_arg rhs) noexcept
|
|
{
|
|
if constexpr (std::is_same_v<value_type, double>)
|
|
{
|
|
using namespace impl;
|
|
static constexpr auto pack = [](auto l, auto r) constexpr noexcept
|
|
{
|
|
return (static_cast<uint64_t>(unbox_enum(l)) << 32)
|
|
| static_cast<uint64_t>(unbox_enum(r));
|
|
};
|
|
|
|
switch (pack(impl::fpclassify(lhs.val_), impl::fpclassify(rhs)))
|
|
{
|
|
case pack(fp_class::pos_inf, fp_class::neg_inf): [[fallthrough]];
|
|
case pack(fp_class::pos_inf, fp_class::nan): [[fallthrough]];
|
|
case pack(fp_class::neg_inf, fp_class::pos_inf): [[fallthrough]];
|
|
case pack(fp_class::neg_inf, fp_class::nan): [[fallthrough]];
|
|
case pack(fp_class::nan, fp_class::pos_inf): [[fallthrough]];
|
|
case pack(fp_class::nan, fp_class::neg_inf):
|
|
return false;
|
|
|
|
case pack(fp_class::pos_inf, fp_class::pos_inf): [[fallthrough]];
|
|
case pack(fp_class::neg_inf, fp_class::neg_inf): [[fallthrough]];
|
|
case pack(fp_class::nan, fp_class::nan):
|
|
return true;
|
|
|
|
case pack(fp_class::ok, fp_class::ok):
|
|
return lhs.val_ == rhs;
|
|
|
|
TOML_NO_DEFAULT_CASE;
|
|
}
|
|
|
|
TOML_UNREACHABLE;
|
|
}
|
|
else
|
|
return lhs.val_ == rhs;
|
|
|
|
}
|
|
TOML_ASYMMETRICAL_EQUALITY_OPS(const value&, value_arg, )
|
|
|
|
/// \brief Value less-than operator.
|
|
[[nodiscard]] friend bool operator < (const value& lhs, value_arg rhs) noexcept { return lhs.val_ < rhs; }
|
|
/// \brief Value less-than operator.
|
|
[[nodiscard]] friend bool operator < (value_arg lhs, const value& rhs) noexcept { return lhs < rhs.val_; }
|
|
/// \brief Value less-than-or-equal-to operator.
|
|
[[nodiscard]] friend bool operator <= (const value& lhs, value_arg rhs) noexcept { return lhs.val_ <= rhs; }
|
|
/// \brief Value less-than-or-equal-to operator.
|
|
[[nodiscard]] friend bool operator <= (value_arg lhs, const value& rhs) noexcept { return lhs <= rhs.val_; }
|
|
|
|
/// \brief Value greater-than operator.
|
|
[[nodiscard]] friend bool operator > (const value& lhs, value_arg rhs) noexcept { return lhs.val_ > rhs; }
|
|
/// \brief Value greater-than operator.
|
|
[[nodiscard]] friend bool operator > (value_arg lhs, const value& rhs) noexcept { return lhs > rhs.val_; }
|
|
/// \brief Value greater-than-or-equal-to operator.
|
|
[[nodiscard]] friend bool operator >= (const value& lhs, value_arg rhs) noexcept { return lhs.val_ >= rhs; }
|
|
/// \brief Value greater-than-or-equal-to operator.
|
|
[[nodiscard]] friend bool operator >= (value_arg lhs, const value& rhs) noexcept { return lhs >= rhs.val_; }
|
|
|
|
/// \brief Equality operator.
|
|
///
|
|
/// \param lhs The LHS value.
|
|
/// \param rhs The RHS value.
|
|
///
|
|
/// \returns True if the values were of the same type and contained the same value.
|
|
template <typename T>
|
|
[[nodiscard]]
|
|
friend bool operator == (const value& lhs, const value<T>& rhs) noexcept
|
|
{
|
|
if constexpr (std::is_same_v<value_type, T>)
|
|
return lhs == rhs.val_; //calls asymmetrical value-equality operator defined above
|
|
else
|
|
return false;
|
|
}
|
|
|
|
/// \brief Inequality operator.
|
|
///
|
|
/// \param lhs The LHS value.
|
|
/// \param rhs The RHS value.
|
|
///
|
|
/// \returns True if the values were not of the same type, or did not contain the same value.
|
|
template <typename T>
|
|
[[nodiscard]]
|
|
friend bool operator != (const value& lhs, const value<T>& rhs) noexcept
|
|
{
|
|
return !(lhs == rhs);
|
|
}
|
|
|
|
/// \brief Less-than operator.
|
|
///
|
|
/// \param lhs The LHS toml::value.
|
|
/// \param rhs The RHS toml::value.
|
|
///
|
|
/// \returns <strong><em>Same value types:</em></strong> `lhs.get() < rhs.get()` <br>
|
|
/// <strong><em>Different value types:</em></strong> `lhs.type() < rhs.type()`
|
|
template <typename T>
|
|
[[nodiscard]]
|
|
friend bool operator < (const value& lhs, const value<T>& rhs) noexcept
|
|
{
|
|
if constexpr (std::is_same_v<value_type, T>)
|
|
return lhs.val_ < rhs.val_;
|
|
else
|
|
return impl::node_type_of<value_type> < impl::node_type_of<T>;
|
|
}
|
|
|
|
/// \brief Less-than-or-equal-to operator.
|
|
///
|
|
/// \param lhs The LHS toml::value.
|
|
/// \param rhs The RHS toml::value.
|
|
///
|
|
/// \returns <strong><em>Same value types:</em></strong> `lhs.get() <= rhs.get()` <br>
|
|
/// <strong><em>Different value types:</em></strong> `lhs.type() <= rhs.type()`
|
|
template <typename T>
|
|
[[nodiscard]]
|
|
friend bool operator <= (const value& lhs, const value<T>& rhs) noexcept
|
|
{
|
|
if constexpr (std::is_same_v<value_type, T>)
|
|
return lhs.val_ <= rhs.val_;
|
|
else
|
|
return impl::node_type_of<value_type> <= impl::node_type_of<T>;
|
|
}
|
|
|
|
/// \brief Greater-than operator.
|
|
///
|
|
/// \param lhs The LHS toml::value.
|
|
/// \param rhs The RHS toml::value.
|
|
///
|
|
/// \returns <strong><em>Same value types:</em></strong> `lhs.get() > rhs.get()` <br>
|
|
/// <strong><em>Different value types:</em></strong> `lhs.type() > rhs.type()`
|
|
template <typename T>
|
|
[[nodiscard]]
|
|
friend bool operator > (const value& lhs, const value<T>& rhs) noexcept
|
|
{
|
|
if constexpr (std::is_same_v<value_type, T>)
|
|
return lhs.val_ > rhs.val_;
|
|
else
|
|
return impl::node_type_of<value_type> > impl::node_type_of<T>;
|
|
}
|
|
|
|
/// \brief Greater-than-or-equal-to operator.
|
|
///
|
|
/// \param lhs The LHS toml::value.
|
|
/// \param rhs The RHS toml::value.
|
|
///
|
|
/// \returns <strong><em>Same value types:</em></strong> `lhs.get() >= rhs.get()` <br>
|
|
/// <strong><em>Different value types:</em></strong> `lhs.type() >= rhs.type()`
|
|
template <typename T>
|
|
[[nodiscard]]
|
|
friend bool operator >= (const value& lhs, const value<T>& rhs) noexcept
|
|
{
|
|
if constexpr (std::is_same_v<value_type, T>)
|
|
return lhs.val_ >= rhs.val_;
|
|
else
|
|
return impl::node_type_of<value_type> >= impl::node_type_of<T>;
|
|
}
|
|
};
|
|
template <typename T>
|
|
value(T) -> value<impl::native_type_of<impl::remove_cvref_t<T>>>;
|
|
|
|
#ifndef DOXYGEN
|
|
|
|
#if !TOML_HEADER_ONLY
|
|
extern template class TOML_API value<std::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
|
|
|
|
TOML_PUSH_WARNINGS
|
|
TOML_DISABLE_INIT_WARNINGS
|
|
TOML_DISABLE_SWITCH_WARNINGS
|
|
|
|
template <typename T>
|
|
[[nodiscard]]
|
|
inline decltype(auto) node::get_value_exact() const noexcept
|
|
{
|
|
using namespace impl;
|
|
|
|
static_assert(node_type_of<T> != node_type::none);
|
|
static_assert(node_type_of<T> != node_type::table);
|
|
static_assert(node_type_of<T> != node_type::array);
|
|
static_assert(is_native<T> || can_represent_native<T>);
|
|
static_assert(!is_cvref<T>);
|
|
TOML_ASSERT(this->type() == node_type_of<T>);
|
|
|
|
if constexpr (node_type_of<T> == node_type::string)
|
|
{
|
|
const auto& str = *ref_cast<std::string>();
|
|
if constexpr (std::is_same_v<T, std::string>)
|
|
return str;
|
|
else if constexpr (std::is_same_v<T, std::string_view>)
|
|
return T{ str };
|
|
else if constexpr (std::is_same_v<T, const char*>)
|
|
return str.c_str();
|
|
|
|
else if constexpr (std::is_same_v<T, std::wstring>)
|
|
{
|
|
#if TOML_WINDOWS_COMPAT
|
|
return widen(str);
|
|
#else
|
|
static_assert(dependent_false<T>, "Evaluated unreachable branch!");
|
|
#endif
|
|
}
|
|
|
|
#ifdef __cpp_lib_char8_t
|
|
|
|
// char -> char8_t (potentially unsafe - the feature is 'experimental'!)
|
|
else if constexpr (is_one_of<T, std::u8string, std::u8string_view>)
|
|
return T(reinterpret_cast<const char8_t*>(str.c_str()), str.length());
|
|
else if constexpr (std::is_same_v<T, const char8_t*>)
|
|
return reinterpret_cast<const char8_t*>(str.c_str());
|
|
else
|
|
static_assert(dependent_false<T>, "Evaluated unreachable branch!");
|
|
|
|
#endif
|
|
}
|
|
else
|
|
return static_cast<T>(*ref_cast<native_type_of<T>>());
|
|
}
|
|
|
|
template <typename T>
|
|
inline optional<T> node::value_exact() const noexcept
|
|
{
|
|
using namespace impl;
|
|
|
|
static_assert(
|
|
!is_wide_string<T> || TOML_WINDOWS_COMPAT,
|
|
"Retrieving values as wide-character strings with node::value_exact() is only "
|
|
"supported on Windows with TOML_WINDOWS_COMPAT enabled."
|
|
);
|
|
|
|
static_assert(
|
|
(is_native<T> || can_represent_native<T>) && !is_cvref<T>,
|
|
"The return type of node::value_exact() must be one of:"
|
|
TOML_SA_LIST_NEW "A native TOML value type"
|
|
TOML_SA_NATIVE_VALUE_TYPE_LIST
|
|
|
|
TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type"
|
|
TOML_SA_LIST_BEG "std::string"
|
|
#if TOML_WINDOWS_COMPAT
|
|
TOML_SA_LIST_SEP "std::wstring"
|
|
#endif
|
|
TOML_SA_LIST_SEP "any signed integer type >= 64 bits"
|
|
TOML_SA_LIST_SEP "any floating-point type >= 64 bits of precision"
|
|
TOML_SA_LIST_END
|
|
|
|
TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage"
|
|
TOML_SA_LIST_BEG "std::string_view"
|
|
TOML_SA_LIST_SEP "const char*"
|
|
#ifdef __cpp_lib_char8_t
|
|
TOML_SA_LIST_SEP "std::u8string_view"
|
|
TOML_SA_LIST_SEP "const char8_t*"
|
|
#endif
|
|
TOML_SA_LIST_END
|
|
);
|
|
|
|
// prevent additional compiler error spam when the static_assert fails by gating behind if constexpr
|
|
if constexpr ((is_native<T> || can_represent_native<T>) && !is_cvref<T>)
|
|
{
|
|
if (type() == node_type_of<T>)
|
|
return { this->get_value_exact<T>() };
|
|
else
|
|
return {};
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
inline optional<T> node::value() const noexcept
|
|
{
|
|
using namespace impl;
|
|
|
|
static_assert(
|
|
!is_wide_string<T> || TOML_WINDOWS_COMPAT,
|
|
"Retrieving values as wide-character strings with node::value() is only "
|
|
"supported on Windows with TOML_WINDOWS_COMPAT enabled."
|
|
);
|
|
static_assert(
|
|
(is_native<T> || can_represent_native<T> || can_partially_represent_native<T>) && !is_cvref<T>,
|
|
"The return type of node::value() must be one of:"
|
|
TOML_SA_LIST_NEW "A native TOML value type"
|
|
TOML_SA_NATIVE_VALUE_TYPE_LIST
|
|
|
|
TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type"
|
|
TOML_SA_LIST_BEG "std::string"
|
|
#if TOML_WINDOWS_COMPAT
|
|
TOML_SA_LIST_SEP "std::wstring"
|
|
#endif
|
|
TOML_SA_LIST_SEP "any signed integer type >= 64 bits"
|
|
TOML_SA_LIST_SEP "any floating-point type >= 64 bits of precision"
|
|
TOML_SA_LIST_END
|
|
|
|
TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type"
|
|
TOML_SA_LIST_BEG "any other integer type"
|
|
TOML_SA_LIST_SEP "any floating-point type >= 32 bits of precision"
|
|
TOML_SA_LIST_END
|
|
|
|
TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage"
|
|
TOML_SA_LIST_BEG "std::string_view"
|
|
TOML_SA_LIST_SEP "const char*"
|
|
#ifdef __cpp_lib_char8_t
|
|
TOML_SA_LIST_SEP "std::u8string_view"
|
|
TOML_SA_LIST_SEP "const char8_t*"
|
|
#endif
|
|
TOML_SA_LIST_END
|
|
);
|
|
|
|
// when asking for strings, dates, times and date_times there's no 'fuzzy' conversion
|
|
// semantics to be mindful of so the exact retrieval is enough.
|
|
if constexpr (is_natively_one_of<T, std::string, time, date, date_time>)
|
|
{
|
|
if (type() == node_type_of<T>)
|
|
return { this->get_value_exact<T>() };
|
|
else
|
|
return {};
|
|
}
|
|
|
|
// everything else requires a bit of logicking.
|
|
else
|
|
{
|
|
switch (type())
|
|
{
|
|
// int -> *
|
|
case node_type::integer:
|
|
{
|
|
// int -> int
|
|
if constexpr (is_natively_one_of<T, int64_t>)
|
|
{
|
|
if constexpr (is_native<T> || can_represent_native<T>)
|
|
return static_cast<T>(*ref_cast<int64_t>());
|
|
else
|
|
return node_integer_cast<T>(*ref_cast<int64_t>());
|
|
}
|
|
|
|
// int -> float
|
|
else if constexpr (is_natively_one_of<T, double>)
|
|
{
|
|
const int64_t val = *ref_cast<int64_t>();
|
|
if constexpr (std::numeric_limits<T>::digits < 64)
|
|
{
|
|
constexpr auto largest_whole_float = (int64_t{ 1 } << std::numeric_limits<T>::digits);
|
|
if (val < -largest_whole_float || val > largest_whole_float)
|
|
return {};
|
|
}
|
|
return static_cast<T>(val);
|
|
}
|
|
|
|
// int -> bool
|
|
else if constexpr (is_natively_one_of<T, bool>)
|
|
return static_cast<bool>(*ref_cast<int64_t>());
|
|
|
|
// int -> anything else
|
|
else
|
|
return {};
|
|
}
|
|
|
|
// float -> *
|
|
case node_type::floating_point:
|
|
{
|
|
// float -> float
|
|
if constexpr (is_natively_one_of<T, double>)
|
|
{
|
|
if constexpr (is_native<T> || can_represent_native<T>)
|
|
return { static_cast<T>(*ref_cast<double>()) };
|
|
else
|
|
{
|
|
const double val = *ref_cast<double>();
|
|
if (val < (std::numeric_limits<T>::lowest)() || val > (std::numeric_limits<T>::max)())
|
|
return {};
|
|
return { static_cast<T>(val) };
|
|
}
|
|
}
|
|
|
|
// float -> int
|
|
else if constexpr (is_natively_one_of<T, int64_t>)
|
|
{
|
|
const double val = *ref_cast<double>();
|
|
if (static_cast<double>(static_cast<int64_t>(val)) == val)
|
|
return node_integer_cast<T>(static_cast<int64_t>(val));
|
|
else
|
|
return {};
|
|
}
|
|
|
|
// float -> anything else
|
|
else
|
|
return {};
|
|
}
|
|
|
|
// bool -> *
|
|
case node_type::boolean:
|
|
{
|
|
// bool -> bool
|
|
if constexpr (is_natively_one_of<T, bool>)
|
|
return { *ref_cast<bool>() };
|
|
|
|
// bool -> int
|
|
else if constexpr (is_natively_one_of<T, int64_t>)
|
|
return { static_cast<T>(*ref_cast<bool>()) };
|
|
|
|
// bool -> anything else
|
|
else
|
|
return {};
|
|
}
|
|
}
|
|
|
|
// non-values, or 'exact' types covered above
|
|
return {};
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
inline auto node::value_or(T&& default_value) const noexcept
|
|
{
|
|
using namespace impl;
|
|
|
|
static_assert(
|
|
!is_wide_string<T> || TOML_WINDOWS_COMPAT,
|
|
"Retrieving values as wide-character strings with node::value_or() is only "
|
|
"supported on Windows with TOML_WINDOWS_COMPAT enabled."
|
|
);
|
|
|
|
|
|
if constexpr (is_wide_string<T>)
|
|
{
|
|
#if TOML_WINDOWS_COMPAT
|
|
|
|
if (type() == node_type::string)
|
|
return widen(*ref_cast<std::string>());
|
|
return std::wstring{ std::forward<T>(default_value) };
|
|
|
|
#else
|
|
|
|
static_assert(dependent_false<T>, "Evaluated unreachable branch!");
|
|
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
using value_type = std::conditional_t<
|
|
std::is_pointer_v<std::decay_t<T>>,
|
|
std::add_pointer_t<std::add_const_t<std::remove_pointer_t<std::decay_t<T>>>>,
|
|
std::decay_t<T>
|
|
>;
|
|
using traits = value_traits<value_type>;
|
|
|
|
static_assert(
|
|
traits::is_native || traits::can_represent_native || traits::can_partially_represent_native,
|
|
"The default return value type of node::value_or() must be one of:"
|
|
TOML_SA_LIST_NEW "A native TOML value type"
|
|
TOML_SA_NATIVE_VALUE_TYPE_LIST
|
|
|
|
TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type"
|
|
TOML_SA_LIST_BEG "std::string"
|
|
#if TOML_WINDOWS_COMPAT
|
|
TOML_SA_LIST_SEP "std::wstring"
|
|
#endif
|
|
TOML_SA_LIST_SEP "any signed integer type >= 64 bits"
|
|
TOML_SA_LIST_SEP "any floating-point type >= 64 bits of precision"
|
|
TOML_SA_LIST_END
|
|
|
|
TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type"
|
|
TOML_SA_LIST_BEG "any other integer type"
|
|
TOML_SA_LIST_SEP "any floating-point type >= 32 bits of precision"
|
|
TOML_SA_LIST_END
|
|
|
|
TOML_SA_LIST_NXT "A compatible view type"
|
|
TOML_SA_LIST_BEG "std::string_view"
|
|
TOML_SA_LIST_SEP "const char*"
|
|
TOML_SA_LIST_SEP "const char[]" TOML_SA_LIST_CAP(" (returned as const char*)")
|
|
TOML_SA_LIST_SEP "char*" TOML_SA_LIST_CAP(" (returned as const char*)")
|
|
TOML_SA_LIST_SEP "char[]" TOML_SA_LIST_CAP(" (returned as const char*)")
|
|
#ifdef __cpp_lib_char8_t
|
|
TOML_SA_LIST_SEP "std::u8string_view"
|
|
TOML_SA_LIST_SEP "const char8_t*"
|
|
TOML_SA_LIST_SEP "const char8_t[]" TOML_SA_LIST_CAP(" (returned as const char8_t*)")
|
|
TOML_SA_LIST_SEP "char8_t*" TOML_SA_LIST_CAP(" (returned as const char8_t*)")
|
|
TOML_SA_LIST_SEP "char8_t[]" TOML_SA_LIST_CAP(" (returned as const char8_t*)")
|
|
#endif
|
|
#if TOML_WINDOWS_COMPAT
|
|
TOML_SA_LIST_SEP "std::wstring_view" TOML_SA_LIST_CAP(" (returned as std::wstring)")
|
|
TOML_SA_LIST_SEP "const wchar_t*" TOML_SA_LIST_CAP(" (returned as std::wstring)")
|
|
TOML_SA_LIST_SEP "const wchar_t[]" TOML_SA_LIST_CAP(" (returned as std::wstring)")
|
|
TOML_SA_LIST_SEP "wchar_t*" TOML_SA_LIST_CAP(" (returned as std::wstring)")
|
|
TOML_SA_LIST_SEP "wchar_t[]" TOML_SA_LIST_CAP(" (returned as std::wstring)")
|
|
#endif
|
|
TOML_SA_LIST_END
|
|
);
|
|
|
|
// prevent additional compiler error spam when the static_assert fails by gating behind if constexpr
|
|
if constexpr (traits::is_native || traits::can_represent_native || traits::can_partially_represent_native)
|
|
{
|
|
if (auto val = this->value<value_type>())
|
|
return *val;
|
|
if constexpr (std::is_pointer_v<value_type>)
|
|
return value_type{ default_value };
|
|
else
|
|
return std::forward<T>(default_value);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if !TOML_HEADER_ONLY
|
|
|
|
#define TOML_EXTERN(name, T) \
|
|
extern template TOML_API optional<T> node::name<T>() const noexcept
|
|
TOML_EXTERN(value_exact, std::string_view);
|
|
TOML_EXTERN(value_exact, std::string);
|
|
TOML_EXTERN(value_exact, const char*);
|
|
TOML_EXTERN(value_exact, int64_t);
|
|
TOML_EXTERN(value_exact, double);
|
|
TOML_EXTERN(value_exact, date);
|
|
TOML_EXTERN(value_exact, time);
|
|
TOML_EXTERN(value_exact, date_time);
|
|
TOML_EXTERN(value_exact, bool);
|
|
TOML_EXTERN(value, std::string_view);
|
|
TOML_EXTERN(value, std::string);
|
|
TOML_EXTERN(value, const char*);
|
|
TOML_EXTERN(value, signed char);
|
|
TOML_EXTERN(value, signed short);
|
|
TOML_EXTERN(value, signed int);
|
|
TOML_EXTERN(value, signed long);
|
|
TOML_EXTERN(value, signed long long);
|
|
TOML_EXTERN(value, unsigned char);
|
|
TOML_EXTERN(value, unsigned short);
|
|
TOML_EXTERN(value, unsigned int);
|
|
TOML_EXTERN(value, unsigned long);
|
|
TOML_EXTERN(value, unsigned long long);
|
|
TOML_EXTERN(value, double);
|
|
TOML_EXTERN(value, float);
|
|
TOML_EXTERN(value, date);
|
|
TOML_EXTERN(value, time);
|
|
TOML_EXTERN(value, date_time);
|
|
TOML_EXTERN(value, bool);
|
|
#ifdef __cpp_lib_char8_t
|
|
TOML_EXTERN(value_exact, std::u8string_view);
|
|
TOML_EXTERN(value_exact, std::u8string);
|
|
TOML_EXTERN(value_exact, const char8_t*);
|
|
TOML_EXTERN(value, std::u8string_view);
|
|
TOML_EXTERN(value, std::u8string);
|
|
TOML_EXTERN(value, const char8_t*);
|
|
#endif
|
|
#if TOML_WINDOWS_COMPAT
|
|
TOML_EXTERN(value_exact, std::wstring);
|
|
TOML_EXTERN(value, std::wstring);
|
|
#endif
|
|
#undef TOML_EXTERN
|
|
|
|
#endif // !TOML_HEADER_ONLY
|
|
|
|
TOML_POP_WARNINGS // TOML_DISABLE_INIT_WARNINGS, TOML_DISABLE_SWITCH_WARNINGS
|
|
|
|
#endif // !DOXYGEN
|
|
}
|
|
TOML_NAMESPACE_END
|
|
|
|
TOML_POP_WARNINGS // TOML_DISABLE_ARITHMETIC_WARNINGS, TOML_DISABLE_PADDING_WARNINGS
|