Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
value.hpp
Go to the documentation of this file.
1// # This file is a part of toml++ and is subject to the the terms of the MIT license.
2// # Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
3// # See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
4// SPDX-License-Identifier: MIT
5#pragma once
6
7#include "date_time.hpp"
8#include "header_start.hpp"
9#include "node.hpp"
10#include "print_to_stream.hpp"
11#include "std_utility.hpp"
13
15// clang-format off
16
17#if TOML_ENABLE_WINDOWS_COMPAT
18 #define TOML_SA_VALUE_MESSAGE_WSTRING TOML_SA_LIST_SEP "std::wstring"
19#else
20 #define TOML_SA_VALUE_MESSAGE_WSTRING
21#endif
22#if TOML_HAS_CHAR8
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*"
25#else
26 #define TOML_SA_VALUE_MESSAGE_U8STRING_VIEW
27 #define TOML_SA_VALUE_MESSAGE_CONST_CHAR8
28#endif
29
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 \
34 \
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" \
40 TOML_SA_LIST_END \
41 \
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 \
47 TOML_SA_LIST_END
48
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 \
53 \
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" \
59 TOML_SA_LIST_END \
60 \
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" \
64 TOML_SA_LIST_END \
65 \
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 \
71 TOML_SA_LIST_END
72
73// clang-format on
75
78 template <typename T, typename...>
79 struct native_value_maker {
80 template <typename... Args>
81 TOML_NODISCARD static T make(Args&&... args) noexcept(
82 std::is_nothrow_constructible_v<T, Args&&...>) {
83 if constexpr (std::is_aggregate_v<T>)
84 return T{static_cast<Args&&>(args)...};
85 else
86 return T(static_cast<Args&&>(args)...);
87 }
88 };
89
90 template <typename T>
91 struct native_value_maker<T, T> {
92 template <typename U>
93 TOML_NODISCARD TOML_ALWAYS_INLINE static U&& make(U&& val) noexcept {
94 return static_cast<U&&>(val);
95 }
96 };
97
98#if TOML_HAS_CHAR8 || TOML_ENABLE_WINDOWS_COMPAT
99
100 struct string_maker {
101 template <typename T>
102 TOML_NODISCARD static std::string make(T&& arg) {
103 using arg_type = std::decay_t<T>;
104#if TOML_HAS_CHAR8
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)));
107 }
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())),
110 arg.length());
111 }
112#endif
113
114#if TOML_ENABLE_WINDOWS_COMPAT
115 if constexpr (is_wide_string<arg_type>) {
116 return narrow(static_cast<T&&>(arg));
117 }
118#endif
119 }
120 };
121
122#if TOML_HAS_CHAR8
123 template <>
124 struct native_value_maker<std::string, char8_t*> : string_maker {};
125 template <>
126 struct native_value_maker<std::string, const char8_t*> : string_maker {};
127 template <>
128 struct native_value_maker<std::string, std::u8string> : string_maker {};
129 template <>
130 struct native_value_maker<std::string, std::u8string_view> : string_maker {};
131#endif // TOML_HAS_CHAR8
132
133#if TOML_ENABLE_WINDOWS_COMPAT
134 template <>
135 struct native_value_maker<std::string, wchar_t*> : string_maker {};
136 template <>
137 struct native_value_maker<std::string, const wchar_t*> : string_maker {};
138 template <>
139 struct native_value_maker<std::string, std::wstring> : string_maker {};
140 template <>
141 struct native_value_maker<std::string, std::wstring_view> : string_maker {};
142#endif // TOML_ENABLE_WINDOWS_COMPAT
143
144#endif // TOML_HAS_CHAR8 || TOML_ENABLE_WINDOWS_COMPAT
145
146 template <typename T>
147 TOML_CONST_GETTER inline optional<T> node_integer_cast(int64_t val) noexcept {
148 static_assert(node_type_of<T> == node_type::integer);
149 static_assert(!is_cvref<T>);
150
151 using traits = value_traits<T>;
152 if constexpr (!traits::is_signed) {
153 if constexpr ((sizeof(T) * CHAR_BIT) < 63) // 63 bits == int64_max
154 {
155 using common_t = decltype(int64_t{} + T{});
156 if (val < int64_t{} || static_cast<common_t>(val) > static_cast<common_t>(traits::max))
157 return {};
158 } else {
159 if (val < int64_t{}) return {};
160 }
161 } else {
162 if (val < traits::min || val > traits::max) return {};
163 }
164 return {static_cast<T>(val)};
165 }
166
167 template <typename...>
168 struct value_variadic_ctor_allowed : std::true_type {};
169
170 template <typename T, typename... Args>
171 struct value_variadic_ctor_allowed<value<T>, value<T>, Args...> : std::false_type {};
172}
175
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);
192
193 private:
195
196 friend class TOML_PARSER_TYPENAME;
197
198 template <typename T, typename U>
199 TOML_CONST_INLINE_GETTER static auto as_value([[maybe_unused]] U* ptr) noexcept {
200 if constexpr (std::is_same_v<value_type, T>)
201 return ptr;
202 else
203 return nullptr;
204 }
205
206 ValueType val_;
207 value_flags flags_ = value_flags::none;
208
210
211 public:
213 using value_type = ValueType;
214
220 using value_arg = POXY_IMPLEMENTATION_DETAIL(
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&>>);
224
230 (impl::value_variadic_ctor_allowed<value<ValueType>, impl::remove_cvref<Args>...>::value),
231 typename... Args)
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
239 TOML_VALUE_CREATED;
240#endif
241 }
242
245 value(const value& other) noexcept //
246 : node(other), val_{other.val_}, flags_{other.flags_} {
247#if TOML_LIFETIME_HOOKS
248 TOML_VALUE_CREATED;
249#endif
250 }
251
254 value(const value& other, value_flags flags) noexcept //
255 : node(other),
256 val_{other.val_},
257 flags_{flags == preserve_source_value_flags ? other.flags_ : flags} {
258#if TOML_LIFETIME_HOOKS
259 TOML_VALUE_CREATED;
260#endif
261 }
262
265 value(value&& other) noexcept //
266 : node(std::move(other)),
267 val_{std::move(other.val_)},
268 flags_{std::exchange(other.flags_, value_flags{})} {
269#if TOML_LIFETIME_HOOKS
270 TOML_VALUE_CREATED;
271#endif
272 }
273
276 value(value&& other, value_flags flags) noexcept //
277 : node(std::move(other)),
278 val_{std::move(other.val_)},
279 flags_{flags == preserve_source_value_flags ? other.flags_ : flags} {
280#if TOML_LIFETIME_HOOKS
281 TOML_VALUE_CREATED;
282#endif
283 other.flags_ = {};
284 }
285
287 value& operator=(const value& rhs) noexcept {
288 node::operator=(rhs);
289 val_ = rhs.val_;
290 flags_ = rhs.flags_;
291 return *this;
292 }
293
295 value& operator=(value&& rhs) noexcept {
296 if (&rhs != this) {
297 node::operator=(std::move(rhs));
298 val_ = std::move(rhs.val_);
299 flags_ = std::exchange(rhs.flags_, value_flags{});
300 }
301 return *this;
302 }
303
304#if TOML_LIFETIME_HOOKS
305 ~value() noexcept { TOML_VALUE_DESTROYED; }
306#endif
307
310
322 node_type type() const noexcept final { return impl::node_type_of<value_type>; }
323
325 bool is_homogeneous(node_type ntype) const noexcept final {
326 return ntype == node_type::none || ntype == impl::node_type_of<value_type>;
327 }
328
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;
333 return false;
334 }
335 return true;
336 }
337
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;
342 return false;
343 }
344 return true;
345 }
346
348 template <typename ElemType = void>
349 TOML_PURE_GETTER bool is_homogeneous() const noexcept {
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);
354
355 if constexpr (std::is_void_v<type>)
356 return true;
357 else
358 return impl::node_type_of<type> == impl::node_type_of<value_type>;
359 }
361
364 bool is_table() const noexcept final { return false; }
365
368 bool is_array() const noexcept final { return false; }
369
372 bool is_array_of_tables() const noexcept final { return false; }
373
376 bool is_value() const noexcept final { return true; }
377
380 bool is_string() const noexcept final { return std::is_same_v<value_type, std::string>; }
381
384 bool is_integer() const noexcept final { return std::is_same_v<value_type, int64_t>; }
385
388 bool is_floating_point() const noexcept final { return std::is_same_v<value_type, double>; }
389
392 bool is_number() const noexcept final { return impl::is_one_of<value_type, int64_t, double>; }
393
396 bool is_boolean() const noexcept final { return std::is_same_v<value_type, bool>; }
397
400 bool is_date() const noexcept final { return std::is_same_v<value_type, date>; }
401
404 bool is_time() const noexcept final { return std::is_same_v<value_type, time>; }
405
408 bool is_date_time() const noexcept final { return std::is_same_v<value_type, date_time>; }
409
411
414
417 table* as_table() noexcept final { return nullptr; }
418
421 array* as_array() noexcept final { return nullptr; }
422
425 value<std::string>* as_string() noexcept final { return as_value<std::string>(this); }
426
429 value<int64_t>* as_integer() noexcept final { return as_value<int64_t>(this); }
430
433 value<double>* as_floating_point() noexcept final { return as_value<double>(this); }
434
437 value<bool>* as_boolean() noexcept final { return as_value<bool>(this); }
438
441 value<date>* as_date() noexcept final { return as_value<date>(this); }
442
445 value<time>* as_time() noexcept final { return as_value<time>(this); }
446
449 value<date_time>* as_date_time() noexcept final { return as_value<date_time>(this); }
450
453 const table* as_table() const noexcept final { return nullptr; }
454
457 const array* as_array() const noexcept final { return nullptr; }
458
462 const value<std::string>* as_string() const noexcept final {
463 return as_value<std::string>(this);
464 }
465
469 const value<int64_t>* as_integer() const noexcept final { return as_value<int64_t>(this); }
470
474 const value<double>* as_floating_point() const noexcept final { return as_value<double>(this); }
475
479 const value<bool>* as_boolean() const noexcept final { return as_value<bool>(this); }
480
484 const value<date>* as_date() const noexcept final { return as_value<date>(this); }
485
489 const value<time>* as_time() const noexcept final { return as_value<time>(this); }
490
494 const value<date_time>* as_date_time() const noexcept final {
495 return as_value<date_time>(this);
496 }
497
499
502
505 value_type& get() & noexcept { return val_; }
506
509 value_type&& get() && noexcept { return static_cast<value_type&&>(val_); }
510
513 const value_type& get() const& noexcept { return val_; }
514
517 const value_type&& get() const&& noexcept { return static_cast<const value_type&&>(val_); }
518
521 value_type& operator*() & noexcept { return val_; }
522
525 value_type&& operator*() && noexcept { return static_cast<value_type&&>(val_); }
526
529 const value_type& operator*() const& noexcept { return val_; }
530
533 const value_type&& operator*() const&& noexcept {
534 return static_cast<const value_type&&>(val_);
535 }
536
539 explicit operator value_type&() & noexcept { return val_; }
540
543 explicit operator value_type&&() && noexcept { return static_cast<value_type&&>(val_); }
544
547 explicit operator const value_type&() const& noexcept { return val_; }
548
551 explicit operator const value_type&&() && noexcept {
552 return static_cast<const value_type&&>(val_);
553 }
554
558 TOML_HIDDEN_CONSTRAINT(std::is_class_v<T>, typename T = value_type)
560 value_type* operator->() noexcept { return &val_; }
561
565 TOML_HIDDEN_CONSTRAINT(std::is_class_v<T>, typename T = value_type)
567 const value_type* operator->() const noexcept { return &val_; }
568
570
573
576 value_flags flags() const noexcept { return flags_; }
577
580 value& flags(value_flags new_flags) noexcept {
581 flags_ = new_flags;
582 return *this;
583 }
584
586
588 value& operator=(value_arg rhs) noexcept {
589 if constexpr (std::is_same_v<value_type, std::string>)
590 val_.assign(rhs);
591 else
592 val_ = rhs;
593 return *this;
594 }
595
596 TOML_CONSTRAINED_TEMPLATE((std::is_same_v<T, std::string>), typename T = value_type)
597 value& operator=(std::string&& rhs) noexcept {
598 val_ = std::move(rhs);
599 return *this;
600 }
601
604
607 friend bool operator==(const value& lhs, value_arg rhs) noexcept {
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;
613 }
614 return lhs.val_ == rhs;
615 }
616 TOML_ASYMMETRICAL_EQUALITY_OPS(const value&, value_arg, );
617
620 friend bool operator<(const value& lhs, value_arg rhs) noexcept { return lhs.val_ < rhs; }
621
624 friend bool operator<(value_arg lhs, const value& rhs) noexcept { return lhs < rhs.val_; }
625
628 friend bool operator<=(const value& lhs, value_arg rhs) noexcept { return lhs.val_ <= rhs; }
629
632 friend bool operator<=(value_arg lhs, const value& rhs) noexcept { return lhs <= rhs.val_; }
633
636 friend bool operator>(const value& lhs, value_arg rhs) noexcept { return lhs.val_ > rhs; }
637
640 friend bool operator>(value_arg lhs, const value& rhs) noexcept { return lhs > rhs.val_; }
641
644 friend bool operator>=(const value& lhs, value_arg rhs) noexcept { return lhs.val_ >= rhs; }
645
648 friend bool operator>=(value_arg lhs, const value& rhs) noexcept { return lhs >= rhs.val_; }
649
656 template <typename T>
657 TOML_PURE_GETTER friend bool operator==(const value& lhs, const value<T>& rhs) noexcept {
658 if constexpr (std::is_same_v<value_type, T>)
659 return lhs == rhs.val_; // calls asymmetrical value-equality operator defined above
660 else
661 return false;
662 }
663
670 template <typename T>
671 TOML_PURE_INLINE_GETTER friend bool operator!=(const value& lhs, const value<T>& rhs) noexcept {
672 return !(lhs == rhs);
673 }
674
684 template <typename T>
685 TOML_PURE_GETTER friend bool operator<(const value& lhs, const value<T>& rhs) noexcept {
686 if constexpr (std::is_same_v<value_type, T>)
687 return lhs.val_ < rhs.val_;
688 else
689 return impl::node_type_of<value_type> < impl::node_type_of<T>;
690 }
691
701 template <typename T>
702 TOML_PURE_GETTER friend bool operator<=(const value& lhs, const value<T>& rhs) noexcept {
703 if constexpr (std::is_same_v<value_type, T>)
704 return lhs.val_ <= rhs.val_;
705 else
706 return impl::node_type_of<value_type> <= impl::node_type_of<T>;
707 }
708
718 template <typename T>
719 TOML_PURE_GETTER friend bool operator>(const value& lhs, const value<T>& rhs) noexcept {
720 if constexpr (std::is_same_v<value_type, T>)
721 return lhs.val_ > rhs.val_;
722 else
723 return impl::node_type_of<value_type> > impl::node_type_of<T>;
724 }
725
735 template <typename T>
736 TOML_PURE_GETTER friend bool operator>=(const value& lhs, const value<T>& rhs) noexcept {
737 if constexpr (std::is_same_v<value_type, T>)
738 return lhs.val_ >= rhs.val_;
739 else
740 return impl::node_type_of<value_type> >= impl::node_type_of<T>;
741 }
742
744
745#if TOML_ENABLE_FORMATTERS
746
750 friend std::ostream& operator<<(std::ostream& lhs, const value& rhs) {
751 impl::print_to_stream(lhs, rhs);
752 return lhs;
753 }
754
755#endif
756 };
757
759
760 template <typename T>
761 value(T) -> value<impl::native_type_of<impl::remove_cvref<T>>>;
762 template <typename T>
763 value(T, value_flags) -> value<impl::native_type_of<impl::remove_cvref<T>>>;
764
765 template <typename T>
766 TOML_NODISCARD inline decltype(auto) node::get_value_exact()
767 const noexcept(impl::value_retrieval_is_nothrow<T>) {
768 using namespace impl;
769
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>);
775 TOML_ASSERT(this->type() == node_type_of<T>);
776
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>)
780 return str;
781 else if constexpr (std::is_same_v<T, std::string_view>)
782 return T{str};
783 else if constexpr (std::is_same_v<T, const char*>)
784 return str.c_str();
785
786 else if constexpr (std::is_same_v<T, std::wstring>) {
787#if TOML_ENABLE_WINDOWS_COMPAT
788 return widen(str);
789#else
790 static_assert(always_false<T>, "Evaluated unreachable branch!");
791#endif
792 }
793
794#if TOML_HAS_CHAR8
795
796 // char -> char8_t (potentially unsafe - the feature is 'experimental'!)
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());
801 else
802 static_assert(always_false<T>, "Evaluated unreachable branch!");
803
804#endif
805 } else
806 return static_cast<T>(*ref_cast<native_type_of<T>>());
807 }
808
809 template <typename T>
810 TOML_NODISCARD inline optional<T> node::value_exact()
811 const noexcept(impl::value_retrieval_is_nothrow<T>) {
812 using namespace impl;
813
814 static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
815 "Retrieving values as wide-character strings with node::value_exact() is only "
816 "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
817
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()"));
820
821 // prevent additional compiler error spam when the static_assert fails by gating behind if
822 // constexpr
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>()};
826 else
827 return {};
828 }
829 }
830
831 template <typename T>
832 TOML_NODISCARD inline optional<T> node::value()
833 const noexcept(impl::value_retrieval_is_nothrow<T>) {
834 using namespace impl;
835
836 static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
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>) &&
840 !is_cvref<T>,
841 TOML_SA_VALUE_FUNC_MESSAGE("return type of node::value()"));
842
843 // when asking for strings, dates, times and date_times there's no 'fuzzy' conversion
844 // semantics to be mindful of so the exact retrieval is enough.
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>()};
848 else
849 return {};
850 }
851
852 // everything else requires a bit of logicking.
853 else {
854 switch (type()) {
855 // int -> *
856 case node_type::integer: {
857 // int -> int
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>());
861 else
862 return node_integer_cast<T>(*ref_cast<int64_t>());
863 }
864
865 // int -> float
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 {};
871 }
872 return static_cast<T>(val);
873 }
874
875 // int -> bool
876 else if constexpr (is_natively_one_of<T, bool>)
877 return static_cast<bool>(*ref_cast<int64_t>());
878
879 // int -> anything else
880 else
881 return {};
882 }
883
884 // float -> *
885 case node_type::floating_point: {
886 // float -> float
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>())};
890 else {
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)()))
895 return {};
896 return {static_cast<T>(val)};
897 }
898 }
899
900 // float -> int
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));
906 else
907 return {};
908 }
909
910 // float -> anything else
911 else
912 return {};
913 }
914
915 // bool -> *
916 case node_type::boolean: {
917 // bool -> bool
918 if constexpr (is_natively_one_of<T, bool>) return {*ref_cast<bool>()};
919
920 // bool -> int
921 else if constexpr (is_natively_one_of<T, int64_t>)
922 return {static_cast<T>(*ref_cast<bool>())};
923
924 // bool -> anything else
925 else
926 return {};
927 }
928 }
929
930 // non-values, or 'exact' types covered above
931 return {};
932 }
933 }
934
935 template <typename T>
936 TOML_NODISCARD inline auto node::value_or(T && default_value)
937 const noexcept(impl::value_retrieval_is_nothrow<T>) {
938 using namespace impl;
939
940 static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
941 "Retrieving values as wide-character strings with node::value_or() is only "
942 "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
943
944 if constexpr (is_wide_string<T>) {
945#if TOML_ENABLE_WINDOWS_COMPAT
946
947 if (type() == node_type::string) return widen(*ref_cast<std::string>());
948 return std::wstring{static_cast<T&&>(default_value)};
949
950#else
951
952 static_assert(always_false<T>, "Evaluated unreachable branch!");
953
954#endif
955 } else {
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>>>>,
959 std::decay_t<T>>;
960 using traits = value_traits<value_type>;
961
962 // clang-format off
963
964 static_assert(
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
969
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"
974 #endif
975 TOML_SA_LIST_SEP "any signed integer type >= 64 bits"
976 TOML_SA_LIST_SEP "any floating-point type >= 64 bits"
977 TOML_SA_LIST_END
978
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"
982 TOML_SA_LIST_END
983
984 TOML_SA_LIST_NXT "A compatible view type"
985 TOML_SA_LIST_BEG "std::string_view"
986 #if TOML_HAS_CHAR8
987 TOML_SA_LIST_SEP "std::u8string_view"
988 #endif
989 #if TOML_ENABLE_WINDOWS_COMPAT
990 TOML_SA_LIST_SEP "std::wstring_view"
991 #endif
992 TOML_SA_LIST_SEP "const char*"
993 #if TOML_HAS_CHAR8
994 TOML_SA_LIST_SEP "const char8_t*"
995 #endif
996 #if TOML_ENABLE_WINDOWS_COMPAT
997 TOML_SA_LIST_SEP "const wchar_t*"
998 #endif
999 TOML_SA_LIST_END
1000 );
1001
1002 // clang-format on
1003
1004 // prevent additional compiler error spam when the static_assert fails by gating behind if
1005 // constexpr
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>();
1010 }
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};
1014 else
1015 return static_cast<T&&>(default_value);
1016 }
1017 }
1018 }
1019
1021}
1023
1024#include "header_end.hpp"
#define T
Definition 17.names.cpp:163
#define rhs
Definition 17.names.cpp:536
#define ptr
Definition 17.names.cpp:525
#define traits
Definition 17.names.cpp:555
#define lhs
Definition 17.names.cpp:489
#define val
Definition 17.names.cpp:570
#define U
Definition 17.names.cpp:164
const char * widen(char *dst, const char *src)
const char * narrow(char *dst, const char *src)
#define flags
const plus_asgn< T > & operator*(const plus_asgn< T > &lhs, const plus_asgn< T > &rhs)
T value(const T &val)
unsigned short wchar_t
A TOML array.
Definition array.hpp:258
A TOML table.
Definition table.hpp:190
const char * str
Definition exec.cpp:170
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)
Definition graph.cpp:47
#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
Definition json.h:14737
bool operator!=(const json_pointer< RefStringTypeLhs > &lhs, const json_pointer< RefStringTypeRhs > &rhs) noexcept
Definition json.h:14762
bool operator<(const json_pointer< RefStringTypeLhs > &lhs, const json_pointer< RefStringTypeRhs > &rhs) noexcept
Definition json.h:14787
#define CHAR_BIT
Definition limits.h:40
Definition json.h:5363
#define TOML_NODISCARD_CTOR
#define POXY_IMPLEMENTATION_DETAIL(...)
#define TOML_CONSTRAINED_TEMPLATE(condition,...)
#define TOML_NODISCARD
#define TOML_CONST_GETTER
#define TOML_PURE_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
int arg
Definition locale.cpp:2806
TOML_NAMESPACE_START
Definition value.hpp:176
TOML_DISABLE_ARITHMETIC_WARNINGS
Definition value.hpp:12
TOML_NAMESPACE_END
Definition value.hpp:1022