NeBuild dev
Loading...
Searching...
No Matches
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 "node.hpp"
9#include "print_to_stream.hpp"
10#include "std_utility.hpp"
11#include "header_start.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{
79 template <typename T, typename...>
80 struct native_value_maker
81 {
82 template <typename... Args>
84 static T make(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args&&...>)
85 {
86 if constexpr (std::is_aggregate_v<T>)
87 return T{ static_cast<Args&&>(args)... };
88 else
89 return T(static_cast<Args&&>(args)...);
90 }
91 };
92
93 template <typename T>
94 struct native_value_maker<T, T>
95 {
96 template <typename U>
99 static U&& make(U&& val) noexcept
100 {
101 return static_cast<U&&>(val);
102 }
103 };
104
105#if TOML_HAS_CHAR8 || TOML_ENABLE_WINDOWS_COMPAT
106
107 struct string_maker
108 {
109 template <typename T>
111 static std::string make(T&& arg)
112 {
113 using arg_type = std::decay_t<T>;
114#if TOML_HAS_CHAR8
115 if constexpr (is_one_of<arg_type, char8_t*, const char8_t*>)
116 {
117 return std::string(reinterpret_cast<const char*>(static_cast<const char8_t*>(arg)));
118 }
119 if constexpr (is_one_of<arg_type, std::u8string, std::u8string_view>)
120 {
121 return std::string(reinterpret_cast<const char*>(static_cast<const char8_t*>(arg.data())),
122 arg.length());
123 }
124#endif
125
126#if TOML_ENABLE_WINDOWS_COMPAT
127 if constexpr (is_wide_string<arg_type>)
128 {
129 return narrow(static_cast<T&&>(arg));
130 }
131#endif
132 }
133 };
134
135#if TOML_HAS_CHAR8
136 template <>
137 struct native_value_maker<std::string, char8_t*> : string_maker
138 {};
139 template <>
140 struct native_value_maker<std::string, const char8_t*> : string_maker
141 {};
142 template <>
143 struct native_value_maker<std::string, std::u8string> : string_maker
144 {};
145 template <>
146 struct native_value_maker<std::string, std::u8string_view> : string_maker
147 {};
148#endif // TOML_HAS_CHAR8
149
150#if TOML_ENABLE_WINDOWS_COMPAT
151 template <>
152 struct native_value_maker<std::string, wchar_t*> : string_maker
153 {};
154 template <>
155 struct native_value_maker<std::string, const wchar_t*> : string_maker
156 {};
157 template <>
158 struct native_value_maker<std::string, std::wstring> : string_maker
159 {};
160 template <>
161 struct native_value_maker<std::string, std::wstring_view> : string_maker
162 {};
163#endif // TOML_ENABLE_WINDOWS_COMPAT
164
165#endif // TOML_HAS_CHAR8 || TOML_ENABLE_WINDOWS_COMPAT
166
167 template <typename T>
169 inline optional<T> node_integer_cast(int64_t val) noexcept
170 {
171 static_assert(node_type_of<T> == node_type::integer);
172 static_assert(!is_cvref<T>);
173
174 using traits = value_traits<T>;
175 if constexpr (!traits::is_signed)
176 {
177 if constexpr ((sizeof(T) * CHAR_BIT) < 63) // 63 bits == int64_max
178 {
179 using common_t = decltype(int64_t{} + T{});
180 if (val < int64_t{} || static_cast<common_t>(val) > static_cast<common_t>(traits::max))
181 return {};
182 }
183 else
184 {
185 if (val < int64_t{})
186 return {};
187 }
188 }
189 else
190 {
191 if (val < traits::min || val > traits::max)
192 return {};
193 }
194 return { static_cast<T>(val) };
195 }
196
197 template <typename...>
198 struct value_variadic_ctor_allowed : std::true_type
199 {};
200
201 template <typename T, typename... Args>
202 struct value_variadic_ctor_allowed<value<T>, value<T>, Args...> : std::false_type
203 {};
204}
207
209{
220 template <typename ValueType>
221 class value : public node
222 {
223 static_assert(impl::is_native<ValueType> && !impl::is_cvref<ValueType>,
224 "A toml::value<> must model one of the native TOML value types:" TOML_SA_NATIVE_VALUE_TYPE_LIST);
225
226 private:
228
229 friend class TOML_PARSER_TYPENAME;
230
231 template <typename T, typename U>
233 static auto as_value([[maybe_unused]] U* ptr) noexcept
234 {
235 if constexpr (std::is_same_v<value_type, T>)
236 return ptr;
237 else
238 return nullptr;
239 }
240
241 ValueType val_;
242 value_flags flags_ = value_flags::none;
243
245
246 public:
248 using value_type = ValueType;
249
255 using value_arg = POXY_IMPLEMENTATION_DETAIL(
256 std::conditional_t<
257 std::is_same_v<value_type, std::string>,
258 std::string_view,
259 std::conditional_t<impl::is_one_of<value_type, double, int64_t, bool>, value_type, const value_type&>>);
260
266 (impl::value_variadic_ctor_allowed<value<ValueType>, impl::remove_cvref<Args>...>::value),
267 typename... Args)
269 explicit value(Args&&... args) noexcept(noexcept(value_type(
270 impl::native_value_maker<value_type, std::decay_t<Args>...>::make(static_cast<Args&&>(args)...))))
271 : val_(impl::native_value_maker<value_type, std::decay_t<Args>...>::make(static_cast<Args&&>(args)...))
272 {
273#if TOML_LIFETIME_HOOKS
274 TOML_VALUE_CREATED;
275#endif
276 }
277
280 value(const value& other) noexcept //
281 : node(other),
282 val_{ other.val_ },
283 flags_{ other.flags_ }
284 {
285#if TOML_LIFETIME_HOOKS
286 TOML_VALUE_CREATED;
287#endif
288 }
289
292 value(const value& other, value_flags flags) noexcept //
293 : node(other),
294 val_{ other.val_ },
295 flags_{ flags == preserve_source_value_flags ? other.flags_ : flags }
296 {
297#if TOML_LIFETIME_HOOKS
298 TOML_VALUE_CREATED;
299#endif
300 }
301
304 value(value&& other) noexcept //
305 : node(std::move(other)),
306 val_{ std::move(other.val_) },
307 flags_{ std::exchange(other.flags_, value_flags{}) }
308 {
309#if TOML_LIFETIME_HOOKS
310 TOML_VALUE_CREATED;
311#endif
312 }
313
316 value(value&& other, value_flags flags) noexcept //
317 : node(std::move(other)),
318 val_{ std::move(other.val_) },
319 flags_{ flags == preserve_source_value_flags ? other.flags_ : flags }
320 {
321#if TOML_LIFETIME_HOOKS
322 TOML_VALUE_CREATED;
323#endif
324 other.flags_ = {};
325 }
326
328 value& operator=(const value& rhs) noexcept
329 {
330 node::operator=(rhs);
331 val_ = rhs.val_;
332 flags_ = rhs.flags_;
333 return *this;
334 }
335
337 value& operator=(value&& rhs) noexcept
338 {
339 if (&rhs != this)
340 {
341 node::operator=(std::move(rhs));
342 val_ = std::move(rhs.val_);
343 flags_ = std::exchange(rhs.flags_, value_flags{});
344 }
345 return *this;
346 }
347
348#if TOML_LIFETIME_HOOKS
349 ~value() noexcept
350 {
351 TOML_VALUE_DESTROYED;
352 }
353#endif
354
357
369 node_type type() const noexcept final
370 {
371 return impl::node_type_of<value_type>;
372 }
373
375 bool is_homogeneous(node_type ntype) const noexcept final
376 {
377 return ntype == node_type::none || ntype == impl::node_type_of<value_type>;
378 }
379
381 bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final
382 {
383 if (ntype != node_type::none && ntype != impl::node_type_of<value_type>)
384 {
385 first_nonmatch = this;
386 return false;
387 }
388 return true;
389 }
390
392 bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final
393 {
394 if (ntype != node_type::none && ntype != impl::node_type_of<value_type>)
395 {
396 first_nonmatch = this;
397 return false;
398 }
399 return true;
400 }
401
403 template <typename ElemType = void>
405 bool is_homogeneous() const noexcept
406 {
407 using type = impl::remove_cvref<impl::unwrap_node<ElemType>>;
408 static_assert(std::is_void_v<type> || toml::is_value<type> || toml::is_container<type>,
409 "The template type argument of value::is_homogeneous() must be void or one "
410 "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
411
412 if constexpr (std::is_void_v<type>)
413 return true;
414 else
415 return impl::node_type_of<type> == impl::node_type_of<value_type>;
416 }
418
421 bool is_table() const noexcept final
422 {
423 return false;
424 }
425
428 bool is_array() const noexcept final
429 {
430 return false;
431 }
432
435 bool is_array_of_tables() const noexcept final
436 {
437 return false;
438 }
439
442 bool is_value() const noexcept final
443 {
444 return true;
445 }
446
449 bool is_string() const noexcept final
450 {
451 return std::is_same_v<value_type, std::string>;
452 }
453
456 bool is_integer() const noexcept final
457 {
458 return std::is_same_v<value_type, int64_t>;
459 }
460
463 bool is_floating_point() const noexcept final
464 {
465 return std::is_same_v<value_type, double>;
466 }
467
470 bool is_number() const noexcept final
471 {
472 return impl::is_one_of<value_type, int64_t, double>;
473 }
474
477 bool is_boolean() const noexcept final
478 {
479 return std::is_same_v<value_type, bool>;
480 }
481
484 bool is_date() const noexcept final
485 {
486 return std::is_same_v<value_type, date>;
487 }
488
491 bool is_time() const noexcept final
492 {
493 return std::is_same_v<value_type, time>;
494 }
495
498 bool is_date_time() const noexcept final
499 {
500 return std::is_same_v<value_type, date_time>;
501 }
502
504
507
510 table* as_table() noexcept final
511 {
512 return nullptr;
513 }
514
517 array* as_array() noexcept final
518 {
519 return nullptr;
520 }
521
524 value<std::string>* as_string() noexcept final
525 {
526 return as_value<std::string>(this);
527 }
528
531 value<int64_t>* as_integer() noexcept final
532 {
533 return as_value<int64_t>(this);
534 }
535
538 value<double>* as_floating_point() noexcept final
539 {
540 return as_value<double>(this);
541 }
542
545 value<bool>* as_boolean() noexcept final
546 {
547 return as_value<bool>(this);
548 }
549
552 value<date>* as_date() noexcept final
553 {
554 return as_value<date>(this);
555 }
556
559 value<time>* as_time() noexcept final
560 {
561 return as_value<time>(this);
562 }
563
566 value<date_time>* as_date_time() noexcept final
567 {
568 return as_value<date_time>(this);
569 }
570
573 const table* as_table() const noexcept final
574 {
575 return nullptr;
576 }
577
580 const array* as_array() const noexcept final
581 {
582 return nullptr;
583 }
584
587 const value<std::string>* as_string() const noexcept final
588 {
589 return as_value<std::string>(this);
590 }
591
594 const value<int64_t>* as_integer() const noexcept final
595 {
596 return as_value<int64_t>(this);
597 }
598
601 const value<double>* as_floating_point() const noexcept final
602 {
603 return as_value<double>(this);
604 }
605
608 const value<bool>* as_boolean() const noexcept final
609 {
610 return as_value<bool>(this);
611 }
612
615 const value<date>* as_date() const noexcept final
616 {
617 return as_value<date>(this);
618 }
619
622 const value<time>* as_time() const noexcept final
623 {
624 return as_value<time>(this);
625 }
626
629 const value<date_time>* as_date_time() const noexcept final
630 {
631 return as_value<date_time>(this);
632 }
633
635
638
641 value_type& get() & noexcept
642 {
643 return val_;
644 }
645
648 value_type&& get() && noexcept
649 {
650 return static_cast<value_type&&>(val_);
651 }
652
655 const value_type& get() const& noexcept
656 {
657 return val_;
658 }
659
662 const value_type&& get() const&& noexcept
663 {
664 return static_cast<const value_type&&>(val_);
665 }
666
669 value_type& operator*() & noexcept
670 {
671 return val_;
672 }
673
676 value_type&& operator*() && noexcept
677 {
678 return static_cast<value_type&&>(val_);
679 }
680
683 const value_type& operator*() const& noexcept
684 {
685 return val_;
686 }
687
690 const value_type&& operator*() const&& noexcept
691 {
692 return static_cast<const value_type&&>(val_);
693 }
694
697 explicit operator value_type&() & noexcept
698 {
699 return val_;
700 }
701
704 explicit operator value_type&&() && noexcept
705 {
706 return static_cast<value_type&&>(val_);
707 }
708
711 explicit operator const value_type&() const& noexcept
712 {
713 return val_;
714 }
715
718 explicit operator const value_type&&() && noexcept
719 {
720 return static_cast<const value_type&&>(val_);
721 }
722
726 TOML_HIDDEN_CONSTRAINT(std::is_class_v<T>, typename T = value_type)
728 value_type* operator->() noexcept
729 {
730 return &val_;
731 }
732
736 TOML_HIDDEN_CONSTRAINT(std::is_class_v<T>, typename T = value_type)
738 const value_type* operator->() const noexcept
739 {
740 return &val_;
741 }
742
744
747
750 value_flags flags() const noexcept
751 {
752 return flags_;
753 }
754
757 value& flags(value_flags new_flags) noexcept
758 {
759 flags_ = new_flags;
760 return *this;
761 }
762
764
766 value& operator=(value_arg rhs) noexcept
767 {
768 if constexpr (std::is_same_v<value_type, std::string>)
769 val_.assign(rhs);
770 else
771 val_ = rhs;
772 return *this;
773 }
774
775 TOML_CONSTRAINED_TEMPLATE((std::is_same_v<T, std::string>), typename T = value_type)
776 value& operator=(std::string&& rhs) noexcept
777 {
778 val_ = std::move(rhs);
779 return *this;
780 }
781
784
787 friend bool operator==(const value& lhs, value_arg rhs) noexcept
788 {
789 if constexpr (std::is_same_v<value_type, double>)
790 {
791 const auto lhs_nan = impl::fpclassify(lhs.val_) == impl::fp_class::nan;
792 const auto rhs_nan = impl::fpclassify(rhs) == impl::fp_class::nan;
793 if (lhs_nan != rhs_nan)
794 return false;
795 if (lhs_nan)
796 return true;
797 }
798 return lhs.val_ == rhs;
799 }
800 TOML_ASYMMETRICAL_EQUALITY_OPS(const value&, value_arg, );
801
804 friend bool operator<(const value& lhs, value_arg rhs) noexcept
805 {
806 return lhs.val_ < rhs;
807 }
808
811 friend bool operator<(value_arg lhs, const value& rhs) noexcept
812 {
813 return lhs < rhs.val_;
814 }
815
818 friend bool operator<=(const value& lhs, value_arg rhs) noexcept
819 {
820 return lhs.val_ <= rhs;
821 }
822
825 friend bool operator<=(value_arg lhs, const value& rhs) noexcept
826 {
827 return lhs <= rhs.val_;
828 }
829
832 friend bool operator>(const value& lhs, value_arg rhs) noexcept
833 {
834 return lhs.val_ > rhs;
835 }
836
839 friend bool operator>(value_arg lhs, const value& rhs) noexcept
840 {
841 return lhs > rhs.val_;
842 }
843
846 friend bool operator>=(const value& lhs, value_arg rhs) noexcept
847 {
848 return lhs.val_ >= rhs;
849 }
850
853 friend bool operator>=(value_arg lhs, const value& rhs) noexcept
854 {
855 return lhs >= rhs.val_;
856 }
857
864 template <typename T>
866 friend bool operator==(const value& lhs, const value<T>& rhs) noexcept
867 {
868 if constexpr (std::is_same_v<value_type, T>)
869 return lhs == rhs.val_; // calls asymmetrical value-equality operator defined above
870 else
871 return false;
872 }
873
880 template <typename T>
882 friend bool operator!=(const value& lhs, const value<T>& rhs) noexcept
883 {
884 return !(lhs == rhs);
885 }
886
896 template <typename T>
898 friend bool operator<(const value& lhs, const value<T>& rhs) noexcept
899 {
900 if constexpr (std::is_same_v<value_type, T>)
901 return lhs.val_ < rhs.val_;
902 else
903 return impl::node_type_of<value_type> < impl::node_type_of<T>;
904 }
905
915 template <typename T>
917 friend bool operator<=(const value& lhs, const value<T>& rhs) noexcept
918 {
919 if constexpr (std::is_same_v<value_type, T>)
920 return lhs.val_ <= rhs.val_;
921 else
922 return impl::node_type_of<value_type> <= impl::node_type_of<T>;
923 }
924
934 template <typename T>
936 friend bool operator>(const value& lhs, const value<T>& rhs) noexcept
937 {
938 if constexpr (std::is_same_v<value_type, T>)
939 return lhs.val_ > rhs.val_;
940 else
941 return impl::node_type_of<value_type> > impl::node_type_of<T>;
942 }
943
953 template <typename T>
955 friend bool operator>=(const value& lhs, const value<T>& rhs) noexcept
956 {
957 if constexpr (std::is_same_v<value_type, T>)
958 return lhs.val_ >= rhs.val_;
959 else
960 return impl::node_type_of<value_type> >= impl::node_type_of<T>;
961 }
962
964
965#if TOML_ENABLE_FORMATTERS
966
970 friend std::ostream& operator<<(std::ostream& lhs, const value& rhs)
971 {
972 impl::print_to_stream(lhs, rhs);
973 return lhs;
974 }
975
976#endif
977 };
978
980
981 template <typename T>
982 value(T) -> value<impl::native_type_of<impl::remove_cvref<T>>>;
983 template <typename T>
984 value(T, value_flags) -> value<impl::native_type_of<impl::remove_cvref<T>>>;
985
986 template <typename T>
988 inline decltype(auto) node::get_value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>)
989 {
990 using namespace impl;
991
992 static_assert(node_type_of<T> != node_type::none);
993 static_assert(node_type_of<T> != node_type::table);
994 static_assert(node_type_of<T> != node_type::array);
995 static_assert(is_native<T> || can_represent_native<T>);
996 static_assert(!is_cvref<T>);
997 TOML_ASSERT(this->type() == node_type_of<T>);
998
999 if constexpr (node_type_of<T> == node_type::string)
1000 {
1001 const auto& str = *ref_cast<std::string>();
1002 if constexpr (std::is_same_v<T, std::string>)
1003 return str;
1004 else if constexpr (std::is_same_v<T, std::string_view>)
1005 return T{ str };
1006 else if constexpr (std::is_same_v<T, const char*>)
1007 return str.c_str();
1008
1009 else if constexpr (std::is_same_v<T, std::wstring>)
1010 {
1011#if TOML_ENABLE_WINDOWS_COMPAT
1012 return widen(str);
1013#else
1014 static_assert(always_false<T>, "Evaluated unreachable branch!");
1015#endif
1016 }
1017
1018#if TOML_HAS_CHAR8
1019
1020 // char -> char8_t (potentially unsafe - the feature is 'experimental'!)
1021 else if constexpr (is_one_of<T, std::u8string, std::u8string_view>)
1022 return T(reinterpret_cast<const char8_t*>(str.c_str()), str.length());
1023 else if constexpr (std::is_same_v<T, const char8_t*>)
1024 return reinterpret_cast<const char8_t*>(str.c_str());
1025 else
1026 static_assert(always_false<T>, "Evaluated unreachable branch!");
1027
1028#endif
1029 }
1030 else
1031 return static_cast<T>(*ref_cast<native_type_of<T>>());
1032 }
1033
1034 template <typename T>
1036 inline optional<T> node::value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>)
1037 {
1038 using namespace impl;
1039
1040 static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
1041 "Retrieving values as wide-character strings with node::value_exact() is only "
1042 "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
1043
1044 static_assert((is_native<T> || can_represent_native<T>)&&!is_cvref<T>,
1045 TOML_SA_VALUE_EXACT_FUNC_MESSAGE("return type of node::value_exact()"));
1046
1047 // prevent additional compiler error spam when the static_assert fails by gating behind if constexpr
1048 if constexpr ((is_native<T> || can_represent_native<T>)&&!is_cvref<T>)
1049 {
1050 if (type() == node_type_of<T>)
1051 return { this->get_value_exact<T>() };
1052 else
1053 return {};
1054 }
1055 }
1056
1057 template <typename T>
1059 inline optional<T> node::value() const noexcept(impl::value_retrieval_is_nothrow<T>)
1060 {
1061 using namespace impl;
1062
1063 static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
1064 "Retrieving values as wide-character strings with node::value() is only "
1065 "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
1066 static_assert((is_native<T> || can_represent_native<T> || can_partially_represent_native<T>)&&!is_cvref<T>,
1067 TOML_SA_VALUE_FUNC_MESSAGE("return type of node::value()"));
1068
1069 // when asking for strings, dates, times and date_times there's no 'fuzzy' conversion
1070 // semantics to be mindful of so the exact retrieval is enough.
1071 if constexpr (is_natively_one_of<T, std::string, time, date, date_time>)
1072 {
1073 if (type() == node_type_of<T>)
1074 return { this->get_value_exact<T>() };
1075 else
1076 return {};
1077 }
1078
1079 // everything else requires a bit of logicking.
1080 else
1081 {
1082 switch (type())
1083 {
1084 // int -> *
1085 case node_type::integer:
1086 {
1087 // int -> int
1088 if constexpr (is_natively_one_of<T, int64_t>)
1089 {
1090 if constexpr (is_native<T> || can_represent_native<T>)
1091 return static_cast<T>(*ref_cast<int64_t>());
1092 else
1093 return node_integer_cast<T>(*ref_cast<int64_t>());
1094 }
1095
1096 // int -> float
1097 else if constexpr (is_natively_one_of<T, double>)
1098 {
1099 const int64_t val = *ref_cast<int64_t>();
1100 if constexpr (std::numeric_limits<T>::digits < 64)
1101 {
1102 constexpr auto largest_whole_float = (int64_t{ 1 } << std::numeric_limits<T>::digits);
1103 if (val < -largest_whole_float || val > largest_whole_float)
1104 return {};
1105 }
1106 return static_cast<T>(val);
1107 }
1108
1109 // int -> bool
1110 else if constexpr (is_natively_one_of<T, bool>)
1111 return static_cast<bool>(*ref_cast<int64_t>());
1112
1113 // int -> anything else
1114 else
1115 return {};
1116 }
1117
1118 // float -> *
1119 case node_type::floating_point:
1120 {
1121 // float -> float
1122 if constexpr (is_natively_one_of<T, double>)
1123 {
1124 if constexpr (is_native<T> || can_represent_native<T>)
1125 return { static_cast<T>(*ref_cast<double>()) };
1126 else
1127 {
1128 const double val = *ref_cast<double>();
1129 if (impl::fpclassify(val) == fp_class::ok
1130 && (val < (std::numeric_limits<T>::lowest)() || val > (std::numeric_limits<T>::max)()))
1131 return {};
1132 return { static_cast<T>(val) };
1133 }
1134 }
1135
1136 // float -> int
1137 else if constexpr (is_natively_one_of<T, int64_t>)
1138 {
1139 const double val = *ref_cast<double>();
1140 if (impl::fpclassify(val) == fp_class::ok
1141 && static_cast<double>(static_cast<int64_t>(val)) == val)
1142 return node_integer_cast<T>(static_cast<int64_t>(val));
1143 else
1144 return {};
1145 }
1146
1147 // float -> anything else
1148 else
1149 return {};
1150 }
1151
1152 // bool -> *
1153 case node_type::boolean:
1154 {
1155 // bool -> bool
1156 if constexpr (is_natively_one_of<T, bool>)
1157 return { *ref_cast<bool>() };
1158
1159 // bool -> int
1160 else if constexpr (is_natively_one_of<T, int64_t>)
1161 return { static_cast<T>(*ref_cast<bool>()) };
1162
1163 // bool -> anything else
1164 else
1165 return {};
1166 }
1167 }
1168
1169 // non-values, or 'exact' types covered above
1170 return {};
1171 }
1172 }
1173
1174 template <typename T>
1176 inline auto node::value_or(T && default_value) const noexcept(impl::value_retrieval_is_nothrow<T>)
1177 {
1178 using namespace impl;
1179
1180 static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
1181 "Retrieving values as wide-character strings with node::value_or() is only "
1182 "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
1183
1184 if constexpr (is_wide_string<T>)
1185 {
1186#if TOML_ENABLE_WINDOWS_COMPAT
1187
1188 if (type() == node_type::string)
1189 return widen(*ref_cast<std::string>());
1190 return std::wstring{ static_cast<T&&>(default_value) };
1191
1192#else
1193
1194 static_assert(always_false<T>, "Evaluated unreachable branch!");
1195
1196#endif
1197 }
1198 else
1199 {
1200 using value_type =
1201 std::conditional_t<std::is_pointer_v<std::decay_t<T>>,
1202 std::add_pointer_t<std::add_const_t<std::remove_pointer_t<std::decay_t<T>>>>,
1203 std::decay_t<T>>;
1204 using traits = value_traits<value_type>;
1205
1206 // clang-format off
1207
1208 static_assert(
1209 traits::is_native || traits::can_represent_native || traits::can_partially_represent_native,
1210 "The default value type of node::value_or() must be one of:"
1211 TOML_SA_LIST_NEW "A native TOML value type"
1212 TOML_SA_NATIVE_VALUE_TYPE_LIST
1213
1214 TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type"
1215 TOML_SA_LIST_BEG "std::string"
1216 #if TOML_ENABLE_WINDOWS_COMPAT
1217 TOML_SA_LIST_SEP "std::wstring"
1218 #endif
1219 TOML_SA_LIST_SEP "any signed integer type >= 64 bits"
1220 TOML_SA_LIST_SEP "any floating-point type >= 64 bits"
1221 TOML_SA_LIST_END
1222
1223 TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type"
1224 TOML_SA_LIST_BEG "any other integral type"
1225 TOML_SA_LIST_SEP "any floating-point type"
1226 TOML_SA_LIST_END
1227
1228 TOML_SA_LIST_NXT "A compatible view type"
1229 TOML_SA_LIST_BEG "std::string_view"
1230 #if TOML_HAS_CHAR8
1231 TOML_SA_LIST_SEP "std::u8string_view"
1232 #endif
1233 #if TOML_ENABLE_WINDOWS_COMPAT
1234 TOML_SA_LIST_SEP "std::wstring_view"
1235 #endif
1236 TOML_SA_LIST_SEP "const char*"
1237 #if TOML_HAS_CHAR8
1238 TOML_SA_LIST_SEP "const char8_t*"
1239 #endif
1240 #if TOML_ENABLE_WINDOWS_COMPAT
1241 TOML_SA_LIST_SEP "const wchar_t*"
1242 #endif
1243 TOML_SA_LIST_END
1244 );
1245
1246 // clang-format on
1247
1248 // prevent additional compiler error spam when the static_assert fails by gating behind if constexpr
1249 if constexpr (traits::is_native || traits::can_represent_native || traits::can_partially_represent_native)
1250 {
1251 if constexpr (traits::is_native)
1252 {
1253 if (type() == node_type_of<value_type>)
1254 return *ref_cast<typename traits::native_type>();
1255 }
1256 if (auto val = this->value<value_type>())
1257 return *val;
1258 if constexpr (std::is_pointer_v<value_type>)
1259 return value_type{ default_value };
1260 else
1261 return static_cast<T&&>(default_value);
1262 }
1263 }
1264 }
1265
1267}
1269
1270#include "header_end.hpp"
A TOML array.
Definition array.hpp:285
A TOML table.
Definition table.hpp:220
enum TOML_OPEN_FLAGS_ENUM value_flags
Metadata associated with TOML values.
Definition forward_declarations.hpp:272
constexpr bool is_number
Metafunction for determining if a type satisfies either toml::is_integer or toml::is_floating_point.
Definition forward_declarations.hpp:986
constexpr bool is_boolean
Metafunction for determining if a type is, or is a reference to, a bool or toml::value<bool>.
Definition forward_declarations.hpp:990
constexpr bool is_floating_point
Metafunction for determining if a type is, or is a reference to, a double or toml::value<double>.
Definition forward_declarations.hpp:980
constexpr bool is_date
Metafunction for determining if a type is, or is a reference to, a toml::date or toml::value<date>.
Definition forward_declarations.hpp:996
constexpr bool is_string
Metafunction for determining if a type is, or is a reference to, a std::string or toml::value<std::st...
Definition forward_declarations.hpp:968
constexpr bool is_array
Metafunction for determining if a type is, or is a reference to, a toml::array.
Definition forward_declarations.hpp:960
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...
Definition forward_declarations.hpp:1008
constexpr bool is_integer
Metafunction for determining if a type is, or is a reference to, a int64_t or toml::value<int64_t>.
Definition forward_declarations.hpp:974
constexpr value_flags preserve_source_value_flags
Special #toml::value_flags constant used for array + table insert functions to specify that any value...
Definition forward_declarations.hpp:290
std::basic_ostream< Char > & operator<<(std::basic_ostream< Char > &lhs, node_type rhs)
Pretty-prints the value of a node_type to a stream.
Definition forward_declarations.hpp:256
constexpr bool is_time
Metafunction for determining if a type is, or is a reference to, a toml::time or toml::value<time>.
Definition forward_declarations.hpp:1002
constexpr bool is_value
Metafunction for determining if a type is, or is a reference to, any of the toml value types....
Definition forward_declarations.hpp:1018
#define TOML_ASSERT(expr)
Sets the assert function used by the library. \detail Defaults to the standard C assert().
Definition preprocessor.hpp:1185
#define TOML_ENABLE_WINDOWS_COMPAT
Enables the use of wide strings (wchar_t, std::wstring) in various places throughout the library when...
Definition preprocessor.hpp:1074
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
Definition json.h:5363
#define TOML_NODISCARD_CTOR
Definition preprocessor.hpp:446
#define POXY_IMPLEMENTATION_DETAIL(...)
Definition preprocessor.hpp:633
#define TOML_CONSTRAINED_TEMPLATE(condition,...)
Definition preprocessor.hpp:1260
#define TOML_NODISCARD
Definition preprocessor.hpp:439
#define TOML_CONST_GETTER
Definition preprocessor.hpp:485
#define TOML_PURE_GETTER
Definition preprocessor.hpp:474
#define TOML_HIDDEN_CONSTRAINT(condition,...)
Definition preprocessor.hpp:1263
#define TOML_PURE_INLINE_GETTER
Definition preprocessor.hpp:479
#define TOML_ALWAYS_INLINE
Definition preprocessor.hpp:405
#define TOML_IMPL_NAMESPACE_END
Definition preprocessor.hpp:1334
#define TOML_IMPL_NAMESPACE_START
Definition preprocessor.hpp:1333
#define TOML_ASYMMETRICAL_EQUALITY_OPS(LHS, RHS,...)
Definition preprocessor.hpp:611
#define TOML_CONST_INLINE_GETTER
Definition preprocessor.hpp:490
TOML_NAMESPACE_START
Definition value.hpp:209
TOML_DISABLE_ARITHMETIC_WARNINGS
Definition value.hpp:12
TOML_NAMESPACE_END
Definition value.hpp:1268