17#if TOML_ENABLE_WINDOWS_COMPAT
18 #define TOML_SA_VALUE_MESSAGE_WSTRING TOML_SA_LIST_SEP "std::wstring"
20 #define TOML_SA_VALUE_MESSAGE_WSTRING
23 #define TOML_SA_VALUE_MESSAGE_U8STRING_VIEW TOML_SA_LIST_SEP "std::u8string_view"
24 #define TOML_SA_VALUE_MESSAGE_CONST_CHAR8 TOML_SA_LIST_SEP "const char8_t*"
26 #define TOML_SA_VALUE_MESSAGE_U8STRING_VIEW
27 #define TOML_SA_VALUE_MESSAGE_CONST_CHAR8
30#define TOML_SA_VALUE_EXACT_FUNC_MESSAGE(type_arg) \
31 "The " type_arg " must be one of:" \
32 TOML_SA_LIST_NEW "A native TOML value type" \
33 TOML_SA_NATIVE_VALUE_TYPE_LIST \
35 TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type" \
36 TOML_SA_LIST_BEG "std::string" \
37 TOML_SA_VALUE_MESSAGE_WSTRING \
38 TOML_SA_LIST_SEP "any signed integer type >= 64 bits" \
39 TOML_SA_LIST_SEP "any floating-point type >= 64 bits" \
42 TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage" \
43 TOML_SA_LIST_BEG "std::string_view" \
44 TOML_SA_VALUE_MESSAGE_U8STRING_VIEW \
45 TOML_SA_LIST_SEP "const char*" \
46 TOML_SA_VALUE_MESSAGE_CONST_CHAR8 \
49#define TOML_SA_VALUE_FUNC_MESSAGE(type_arg) \
50 "The " type_arg " must be one of:" \
51 TOML_SA_LIST_NEW "A native TOML value type" \
52 TOML_SA_NATIVE_VALUE_TYPE_LIST \
54 TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type" \
55 TOML_SA_LIST_BEG "std::string" \
56 TOML_SA_VALUE_MESSAGE_WSTRING \
57 TOML_SA_LIST_SEP "any signed integer type >= 64 bits" \
58 TOML_SA_LIST_SEP "any floating-point type >= 64 bits" \
61 TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type" \
62 TOML_SA_LIST_BEG "any other integral type" \
63 TOML_SA_LIST_SEP "any floating-point type" \
66 TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage" \
67 TOML_SA_LIST_BEG "std::string_view" \
68 TOML_SA_VALUE_MESSAGE_U8STRING_VIEW \
69 TOML_SA_LIST_SEP "const char*" \
70 TOML_SA_VALUE_MESSAGE_CONST_CHAR8 \
78 template <
typename T,
typename...>
79 struct native_value_maker {
80 template <
typename... Args>
82 std::is_nothrow_constructible_v<
T, Args&&...>) {
83 if constexpr (std::is_aggregate_v<T>)
84 return T{
static_cast<Args&&
>(args)...};
86 return T(
static_cast<Args&&
>(args)...);
91 struct native_value_maker<
T,
T> {
94 return static_cast<U&&
>(
val);
98#if TOML_HAS_CHAR8 || TOML_ENABLE_WINDOWS_COMPAT
100 struct string_maker {
101 template <
typename T>
103 using arg_type = std::decay_t<T>;
105 if constexpr (is_one_of<arg_type, char8_t*, const char8_t*>) {
106 return std::string(
reinterpret_cast<const char*
>(
static_cast<const char8_t*
>(
arg)));
108 if constexpr (is_one_of<arg_type, std::u8string, std::u8string_view>) {
109 return std::string(
reinterpret_cast<const char*
>(
static_cast<const char8_t*
>(
arg.data())),
114#if TOML_ENABLE_WINDOWS_COMPAT
115 if constexpr (is_wide_string<arg_type>) {
124 struct native_value_maker<
std::string, char8_t*> : string_maker {};
126 struct native_value_maker<
std::string, const char8_t*> : string_maker {};
128 struct native_value_maker<
std::string, std::u8string> : string_maker {};
130 struct native_value_maker<
std::string, std::u8string_view> : string_maker {};
133#if TOML_ENABLE_WINDOWS_COMPAT
135 struct native_value_maker<
std::string,
wchar_t*> : string_maker {};
137 struct native_value_maker<
std::string, const
wchar_t*> : string_maker {};
139 struct native_value_maker<
std::string, std::wstring> : string_maker {};
141 struct native_value_maker<
std::string, std::wstring_view> : string_maker {};
146 template <
typename T>
148 static_assert(node_type_of<T> == node_type::integer);
149 static_assert(!is_cvref<T>);
151 using traits = value_traits<T>;
152 if constexpr (!traits::is_signed) {
153 if constexpr ((
sizeof(
T) *
CHAR_BIT) < 63)
155 using common_t =
decltype(int64_t{} +
T{});
156 if (
val < int64_t{} ||
static_cast<common_t
>(
val) >
static_cast<common_t
>(traits::max))
159 if (
val < int64_t{})
return {};
162 if (val < traits::min || val > traits::max)
return {};
164 return {
static_cast<T>(
val)};
167 template <
typename...>
168 struct value_variadic_ctor_allowed : std::true_type {};
170 template <
typename T,
typename... Args>
171 struct value_variadic_ctor_allowed<
value<
T>,
value<
T>, Args...> : std::false_type {};
187 template <
typename ValueType>
188 class value :
public node {
189 static_assert(impl::is_native<ValueType> && !impl::is_cvref<ValueType>,
190 "A toml::value<> must model one of the native TOML value "
191 "types:" TOML_SA_NATIVE_VALUE_TYPE_LIST);
196 friend class TOML_PARSER_TYPENAME;
198 template <
typename T,
typename U>
200 if constexpr (std::is_same_v<value_type, T>)
213 using value_type = ValueType;
221 std::conditional_t<std::is_same_v<value_type, std::string>, std::string_view,
222 std::conditional_t<impl::is_one_of<value_type, double, int64_t, bool>,
223 value_type,
const value_type&>>);
230 (impl::value_variadic_ctor_allowed<value<ValueType>, impl::remove_cvref<Args>...>
::value),
233 explicit value(Args&&... args)
noexcept(
234 noexcept(value_type(impl::native_value_maker<value_type, std::decay_t<Args>...>::make(
235 static_cast<Args&&
>(args)...))))
236 : val_(impl::native_value_maker<value_type, std::decay_t<Args>...>::make(
237 static_cast<Args&&
>(args)...)) {
238#if TOML_LIFETIME_HOOKS
246 : node(other), val_{other.val_}, flags_{other.flags_} {
247#if TOML_LIFETIME_HOOKS
258#if TOML_LIFETIME_HOOKS
266 : node(std::move(other)),
267 val_{std::move(other.val_)},
268 flags_{std::exchange(other.flags_,
value_flags{})} {
269#if TOML_LIFETIME_HOOKS
277 : node(std::move(other)),
278 val_{std::move(other.val_)},
280#if TOML_LIFETIME_HOOKS
288 node::operator=(
rhs);
297 node::operator=(std::move(
rhs));
298 val_ = std::move(
rhs.val_);
304#if TOML_LIFETIME_HOOKS
305 ~value()
noexcept { TOML_VALUE_DESTROYED; }
322 node_type type()
const noexcept final {
return impl::node_type_of<value_type>; }
325 bool is_homogeneous(node_type ntype)
const noexcept final {
326 return ntype == node_type::none || ntype == impl::node_type_of<value_type>;
330 bool is_homogeneous(node_type ntype, node*& first_nonmatch)
noexcept final {
331 if (ntype != node_type::none && ntype != impl::node_type_of<value_type>) {
332 first_nonmatch =
this;
339 bool is_homogeneous(node_type ntype,
const node*& first_nonmatch)
const noexcept final {
340 if (ntype != node_type::none && ntype != impl::node_type_of<value_type>) {
341 first_nonmatch =
this;
348 template <
typename ElemType =
void>
350 using type = impl::remove_cvref<impl::unwrap_node<ElemType>>;
351 static_assert(std::is_void_v<type> || toml::is_value<type> || toml::is_container<type>,
352 "The template type argument of value::is_homogeneous() must be void or one "
353 "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
355 if constexpr (std::is_void_v<type>)
358 return impl::node_type_of<type> == impl::node_type_of<value_type>;
364 bool is_table()
const noexcept final {
return false; }
368 bool is_array()
const noexcept final {
return false; }
372 bool is_array_of_tables()
const noexcept final {
return false; }
376 bool is_value()
const noexcept final {
return true; }
380 bool is_string()
const noexcept final {
return std::is_same_v<value_type, std::string>; }
384 bool is_integer()
const noexcept final {
return std::is_same_v<value_type, int64_t>; }
388 bool is_floating_point()
const noexcept final {
return std::is_same_v<value_type, double>; }
392 bool is_number()
const noexcept final {
return impl::is_one_of<value_type, int64_t, double>; }
396 bool is_boolean()
const noexcept final {
return std::is_same_v<value_type, bool>; }
400 bool is_date()
const noexcept final {
return std::is_same_v<value_type, date>; }
404 bool is_time()
const noexcept final {
return std::is_same_v<value_type, time>; }
408 bool is_date_time()
const noexcept final {
return std::is_same_v<value_type, date_time>; }
417 table* as_table()
noexcept final {
return nullptr; }
421 array* as_array()
noexcept final {
return nullptr; }
425 value<std::string>* as_string()
noexcept final {
return as_value<std::string>(
this); }
429 value<int64_t>* as_integer()
noexcept final {
return as_value<int64_t>(
this); }
433 value<double>* as_floating_point()
noexcept final {
return as_value<double>(
this); }
437 value<bool>* as_boolean()
noexcept final {
return as_value<bool>(
this); }
441 value<date>* as_date()
noexcept final {
return as_value<date>(
this); }
445 value<time>* as_time()
noexcept final {
return as_value<time>(
this); }
449 value<date_time>* as_date_time()
noexcept final {
return as_value<date_time>(
this); }
453 const table* as_table()
const noexcept final {
return nullptr; }
457 const array* as_array()
const noexcept final {
return nullptr; }
462 const value<std::string>* as_string()
const noexcept final {
463 return as_value<std::string>(
this);
469 const value<int64_t>* as_integer()
const noexcept final {
return as_value<int64_t>(
this); }
474 const value<double>* as_floating_point()
const noexcept final {
return as_value<double>(
this); }
479 const value<bool>* as_boolean()
const noexcept final {
return as_value<bool>(
this); }
484 const value<date>* as_date()
const noexcept final {
return as_value<date>(
this); }
489 const value<time>* as_time()
const noexcept final {
return as_value<time>(
this); }
494 const value<date_time>* as_date_time()
const noexcept final {
495 return as_value<date_time>(
this);
505 value_type& get() &
noexcept {
return val_; }
509 value_type&& get() &&
noexcept {
return static_cast<value_type&&
>(val_); }
513 const value_type& get()
const&
noexcept {
return val_; }
517 const value_type&& get()
const&&
noexcept {
return static_cast<const value_type&&
>(val_); }
521 value_type&
operator*() &
noexcept {
return val_; }
525 value_type&&
operator*() &&
noexcept {
return static_cast<value_type&&
>(val_); }
529 const value_type&
operator*()
const&
noexcept {
return val_; }
533 const value_type&&
operator*()
const&&
noexcept {
534 return static_cast<const value_type&&
>(val_);
539 explicit operator value_type&() &
noexcept {
return val_; }
543 explicit operator value_type&&() &&
noexcept {
return static_cast<value_type&&
>(val_); }
547 explicit operator const value_type&()
const&
noexcept {
return val_; }
551 explicit operator const value_type&&() &&
noexcept {
552 return static_cast<const value_type&&
>(val_);
560 value_type* operator->()
noexcept {
return &val_; }
567 const value_type* operator->()
const noexcept {
return &val_; }
588 value& operator=(value_arg
rhs)
noexcept {
589 if constexpr (std::is_same_v<value_type, std::string>)
597 value& operator=(std::string&&
rhs)
noexcept {
598 val_ = std::move(
rhs);
608 if constexpr (std::is_same_v<value_type, double>) {
609 const auto lhs_nan = impl::fpclassify(
lhs.val_) == impl::fp_class::nan;
610 const auto rhs_nan = impl::fpclassify(
rhs) == impl::fp_class::nan;
611 if (lhs_nan != rhs_nan)
return false;
612 if (lhs_nan)
return true;
628 friend bool operator<=(
const value&
lhs, value_arg
rhs)
noexcept {
return lhs.val_ <=
rhs; }
632 friend bool operator<=(value_arg
lhs,
const value&
rhs)
noexcept {
return lhs <=
rhs.val_; }
644 friend bool operator>=(
const value&
lhs, value_arg
rhs)
noexcept {
return lhs.val_ >=
rhs; }
648 friend bool operator>=(value_arg
lhs,
const value&
rhs)
noexcept {
return lhs >=
rhs.val_; }
656 template <
typename T>
658 if constexpr (std::is_same_v<value_type, T>)
670 template <
typename T>
684 template <
typename T>
686 if constexpr (std::is_same_v<value_type, T>)
687 return lhs.val_ <
rhs.val_;
689 return impl::node_type_of<value_type> < impl::node_type_of<T>;
701 template <
typename T>
703 if constexpr (std::is_same_v<value_type, T>)
704 return lhs.val_ <=
rhs.val_;
706 return impl::node_type_of<value_type> <= impl::node_type_of<T>;
718 template <
typename T>
720 if constexpr (std::is_same_v<value_type, T>)
721 return lhs.val_ >
rhs.val_;
723 return impl::node_type_of<value_type> > impl::node_type_of<T>;
735 template <
typename T>
737 if constexpr (std::is_same_v<value_type, T>)
738 return lhs.val_ >=
rhs.val_;
740 return impl::node_type_of<value_type> >= impl::node_type_of<T>;
745#if TOML_ENABLE_FORMATTERS
751 impl::print_to_stream(
lhs,
rhs);
760 template <
typename T>
761 value(
T) -> value<impl::native_type_of<impl::remove_cvref<T>>>;
762 template <
typename T>
765 template <
typename T>
767 const noexcept(impl::value_retrieval_is_nothrow<T>) {
768 using namespace impl;
770 static_assert(node_type_of<T> != node_type::none);
771 static_assert(node_type_of<T> != node_type::table);
772 static_assert(node_type_of<T> != node_type::array);
773 static_assert(is_native<T> || can_represent_native<T>);
774 static_assert(!is_cvref<T>);
777 if constexpr (node_type_of<T> == node_type::string) {
778 const auto&
str = *ref_cast<std::string>();
779 if constexpr (std::is_same_v<T, std::string>)
781 else if constexpr (std::is_same_v<T, std::string_view>)
783 else if constexpr (std::is_same_v<T, const char*>)
786 else if constexpr (std::is_same_v<T, std::wstring>) {
787#if TOML_ENABLE_WINDOWS_COMPAT
790 static_assert(always_false<T>,
"Evaluated unreachable branch!");
797 else if constexpr (is_one_of<T, std::u8string, std::u8string_view>)
798 return T(
reinterpret_cast<const char8_t*
>(
str.c_str()),
str.length());
799 else if constexpr (std::is_same_v<T, const char8_t*>)
800 return reinterpret_cast<const char8_t*
>(
str.c_str());
802 static_assert(always_false<T>,
"Evaluated unreachable branch!");
806 return static_cast<T>(*ref_cast<native_type_of<T>>());
809 template <
typename T>
811 const noexcept(impl::value_retrieval_is_nothrow<T>) {
812 using namespace impl;
815 "Retrieving values as wide-character strings with node::value_exact() is only "
816 "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
818 static_assert((is_native<T> || can_represent_native<T>) && !is_cvref<T>,
819 TOML_SA_VALUE_EXACT_FUNC_MESSAGE(
"return type of node::value_exact()"));
823 if constexpr ((is_native<T> || can_represent_native<T>) && !is_cvref<T>) {
824 if (type() == node_type_of<T>)
825 return {this->get_value_exact<T>()};
831 template <
typename T>
833 const noexcept(impl::value_retrieval_is_nothrow<T>) {
834 using namespace impl;
837 "Retrieving values as wide-character strings with node::value() is only "
838 "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
839 static_assert((is_native<T> || can_represent_native<T> || can_partially_represent_native<T>) &&
841 TOML_SA_VALUE_FUNC_MESSAGE(
"return type of node::value()"));
845 if constexpr (is_natively_one_of<T, std::string, time, date, date_time>) {
846 if (type() == node_type_of<T>)
847 return {this->get_value_exact<T>()};
856 case node_type::integer: {
858 if constexpr (is_natively_one_of<T, int64_t>) {
859 if constexpr (is_native<T> || can_represent_native<T>)
860 return static_cast<T>(*ref_cast<int64_t>());
862 return node_integer_cast<T>(*ref_cast<int64_t>());
866 else if constexpr (is_natively_one_of<T, double>) {
867 const int64_t
val = *ref_cast<int64_t>();
868 if constexpr (std::numeric_limits<T>::digits < 64) {
869 constexpr auto largest_whole_float = (int64_t{1} << std::numeric_limits<T>::digits);
870 if (val < -largest_whole_float || val > largest_whole_float)
return {};
872 return static_cast<T>(
val);
876 else if constexpr (is_natively_one_of<T, bool>)
877 return static_cast<bool>(*ref_cast<int64_t>());
885 case node_type::floating_point: {
887 if constexpr (is_natively_one_of<T, double>) {
888 if constexpr (is_native<T> || can_represent_native<T>)
889 return {
static_cast<T>(*ref_cast<double>())};
891 const double val = *ref_cast<double>();
892 if (impl::fpclassify(
val) == fp_class::ok &&
893 (
val < (std::numeric_limits<T>::lowest)() ||
894 val > (std::numeric_limits<T>::max)()))
896 return {
static_cast<T>(
val)};
901 else if constexpr (is_natively_one_of<T, int64_t>) {
902 const double val = *ref_cast<double>();
903 if (impl::fpclassify(
val) == fp_class::ok &&
904 static_cast<double>(
static_cast<int64_t
>(
val)) ==
val)
905 return node_integer_cast<T>(
static_cast<int64_t
>(
val));
916 case node_type::boolean: {
918 if constexpr (is_natively_one_of<T, bool>)
return {*ref_cast<bool>()};
921 else if constexpr (is_natively_one_of<T, int64_t>)
922 return {
static_cast<T>(*ref_cast<bool>())};
935 template <
typename T>
937 const noexcept(impl::value_retrieval_is_nothrow<T>) {
938 using namespace impl;
941 "Retrieving values as wide-character strings with node::value_or() is only "
942 "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
944 if constexpr (is_wide_string<T>) {
945#if TOML_ENABLE_WINDOWS_COMPAT
947 if (type() == node_type::string)
return widen(*ref_cast<std::string>());
948 return std::wstring{
static_cast<T&&
>(default_value)};
952 static_assert(always_false<T>,
"Evaluated unreachable branch!");
956 using value_type = std::conditional_t<
957 std::is_pointer_v<std::decay_t<T>>,
958 std::add_pointer_t<std::add_const_t<std::remove_pointer_t<std::decay_t<T>>>>,
960 using traits = value_traits<value_type>;
965 traits::is_native || traits::can_represent_native || traits::can_partially_represent_native,
966 "The default value type of node::value_or() must be one of:"
967 TOML_SA_LIST_NEW
"A native TOML value type"
968 TOML_SA_NATIVE_VALUE_TYPE_LIST
970 TOML_SA_LIST_NXT
"A non-view type capable of losslessly representing a native TOML value type"
971 TOML_SA_LIST_BEG
"std::string"
972 #if TOML_ENABLE_WINDOWS_COMPAT
973 TOML_SA_LIST_SEP
"std::wstring"
975 TOML_SA_LIST_SEP
"any signed integer type >= 64 bits"
976 TOML_SA_LIST_SEP
"any floating-point type >= 64 bits"
979 TOML_SA_LIST_NXT
"A non-view type capable of (reasonably) representing a native TOML value type"
980 TOML_SA_LIST_BEG
"any other integral type"
981 TOML_SA_LIST_SEP
"any floating-point type"
984 TOML_SA_LIST_NXT
"A compatible view type"
985 TOML_SA_LIST_BEG
"std::string_view"
987 TOML_SA_LIST_SEP
"std::u8string_view"
989 #if TOML_ENABLE_WINDOWS_COMPAT
990 TOML_SA_LIST_SEP
"std::wstring_view"
992 TOML_SA_LIST_SEP
"const char*"
994 TOML_SA_LIST_SEP
"const char8_t*"
996 #if TOML_ENABLE_WINDOWS_COMPAT
997 TOML_SA_LIST_SEP
"const wchar_t*"
1006 if constexpr (traits::is_native || traits::can_represent_native ||
1007 traits::can_partially_represent_native) {
1008 if constexpr (traits::is_native) {
1009 if (type() == node_type_of<value_type>)
return *ref_cast<typename traits::native_type>();
1011 if (
auto val = this->value<value_type>())
return *
val;
1012 if constexpr (std::is_pointer_v<value_type>)
1013 return value_type{default_value};
1015 return static_cast<T&&
>(default_value);
const char * widen(char *dst, const char *src)
const char * narrow(char *dst, const char *src)
const plus_asgn< T > & operator*(const plus_asgn< T > &lhs, const plus_asgn< T > &rhs)
enum TOML_OPEN_FLAGS_ENUM value_flags
Metadata associated with TOML values.
constexpr bool is_number
Metafunction for determining if a type satisfies either toml::is_integer or toml::is_floating_point.
constexpr bool is_boolean
Metafunction for determining if a type is, or is a reference to, a bool or toml::value<bool>.
constexpr bool is_floating_point
Metafunction for determining if a type is, or is a reference to, a double or toml::value<double>.
constexpr bool is_date
Metafunction for determining if a type is, or is a reference to, a toml::date or toml::value<date>.
constexpr bool is_string
Metafunction for determining if a type is, or is a reference to, a std::string or toml::value<std::st...
constexpr bool is_array
Metafunction for determining if a type is, or is a reference to, a toml::array.
constexpr bool is_date_time
Metafunction for determining if a type is, or is a reference to, a toml::date_time or toml::value<dat...
constexpr bool is_integer
Metafunction for determining if a type is, or is a reference to, a int64_t or toml::value<int64_t>.
constexpr value_flags preserve_source_value_flags
Special #toml::value_flags constant used for array + table insert functions to specify that any value...
std::basic_ostream< Char > & operator<<(std::basic_ostream< Char > &lhs, node_type rhs)
Pretty-prints the value of a node_type to a stream.
constexpr bool is_time
Metafunction for determining if a type is, or is a reference to, a toml::time or toml::value<time>.
constexpr bool is_value
Metafunction for determining if a type is, or is a reference to, any of the toml value types....
bool operator>(const DistancePair &lhs, const DistancePair &rhs)
#define TOML_ASSERT(expr)
Sets the assert function used by the library. \detail Defaults to the standard C assert().
#define TOML_ENABLE_WINDOWS_COMPAT
Enables the use of wide strings (wchar_t, std::wstring) in various places throughout the library when...
bool operator==(const json_pointer< RefStringTypeLhs > &lhs, const json_pointer< RefStringTypeRhs > &rhs) noexcept
bool operator!=(const json_pointer< RefStringTypeLhs > &lhs, const json_pointer< RefStringTypeRhs > &rhs) noexcept
bool operator<(const json_pointer< RefStringTypeLhs > &lhs, const json_pointer< RefStringTypeRhs > &rhs) noexcept
#define TOML_NODISCARD_CTOR
#define POXY_IMPLEMENTATION_DETAIL(...)
#define TOML_CONSTRAINED_TEMPLATE(condition,...)
#define TOML_CONST_GETTER
#define TOML_HIDDEN_CONSTRAINT(condition,...)
#define TOML_PURE_INLINE_GETTER
#define TOML_ALWAYS_INLINE
#define TOML_IMPL_NAMESPACE_END
#define TOML_IMPL_NAMESPACE_START
#define TOML_ASYMMETRICAL_EQUALITY_OPS(LHS, RHS,...)
#define TOML_CONST_INLINE_GETTER
TOML_DISABLE_ARITHMETIC_WARNINGS