@@ -54,36 +54,6 @@ safeString(dom::Value const& str);
54
54
55
55
namespace dom {
56
56
57
- /* * Mapping traits to convert types into dom::Object.
58
-
59
- This class should be specialized by any type that needs to be converted
60
- to/from a @ref dom::Object. For example:
61
-
62
- @code
63
- template<>
64
- struct MappingTraits<MyStruct> {
65
- template <class IO>
66
- static void map(IO &io, MyStruct const& s)
67
- {
68
- io.map("name", s.name);
69
- io.map("size", s.size);
70
- io.map("age", s.age);
71
- }
72
- };
73
- @endcode
74
- */
75
- template <class T >
76
- struct ToValue {
77
- // Value operator()(T const& o) const;
78
- };
79
-
80
- // / Concept to determine if @ref ToValue is defined for a type T
81
- template <class T >
82
- concept HasToValue = requires (T const & o)
83
- {
84
- { Value (std::declval<ToValue<T>>()(o)) } -> std::same_as<Value>;
85
- };
86
-
87
57
/* * A variant container for any kind of Dom value.
88
58
*/
89
59
class MRDOCS_DECL
@@ -120,14 +90,12 @@ class MRDOCS_DECL
120
90
121
91
template <class F >
122
92
requires
123
- function_traits_convertible_to_value<F> &&
124
- (!HasToValue<F>)
93
+ function_traits_convertible_to_value<F>
125
94
Value (F const & f)
126
95
: Value(Function(f))
127
96
{}
128
97
129
98
template <std::same_as<bool > Boolean>
130
- requires (!HasToValue<Boolean>)
131
99
Value (Boolean const & b) noexcept
132
100
: kind_(Kind::Boolean)
133
101
, b_(b)
@@ -137,21 +105,18 @@ class MRDOCS_DECL
137
105
template <std::integral T>
138
106
requires
139
107
(!std::same_as<T, bool >) &&
140
- (!std::same_as<T, char >) &&
141
- (!HasToValue<T>)
108
+ (!std::same_as<T, char >)
142
109
Value (T v) noexcept : Value(std::int64_t (v)) {}
143
110
144
111
template <std::floating_point T>
145
- requires (!HasToValue<T>)
146
112
Value (T v) noexcept : Value(std::int64_t (v)) {}
147
113
148
114
Value (char c) noexcept : Value(std::string_view(&c, 1 )) {}
149
115
150
116
template <class Enum >
151
117
requires
152
118
std::is_enum_v<Enum> &&
153
- (!std::same_as<Enum, dom::Kind>) &&
154
- (!HasToValue<Enum>)
119
+ (!std::same_as<Enum, dom::Kind>)
155
120
Value (Enum v) noexcept
156
121
: Value(static_cast <std::underlying_type_t <Enum>>(v))
157
122
{}
@@ -169,7 +134,6 @@ class MRDOCS_DECL
169
134
}
170
135
171
136
template <std::convertible_to<String> StringLike>
172
- requires (!HasToValue<StringLike>)
173
137
Value (StringLike const & s)
174
138
: Value(String(s))
175
139
{
@@ -194,12 +158,6 @@ class MRDOCS_DECL
194
158
{
195
159
}
196
160
197
- template <HasToValue T>
198
- Value (T const & t)
199
- : Value(ToValue<T>{}(t))
200
- {
201
- }
202
-
203
161
Value& operator =(Value const & other);
204
162
Value& operator =(Value&& other) noexcept ;
205
163
@@ -607,13 +565,241 @@ stringOrNull(
607
565
{
608
566
if (!s.empty ())
609
567
{
610
- return s ;
568
+ return {s} ;
611
569
}
612
570
return nullptr ;
613
571
}
614
572
615
573
// ------------------------------------------------
616
574
575
+ /* * Customization point tag.
576
+
577
+ This tag type is used by the function
578
+ @ref dom::ValueFrom to select overloads
579
+ of `tag_invoke`.
580
+
581
+ @note This type is empty; it has no members.
582
+
583
+ @see @ref dom::ValueFrom, @ref dom::ValueTo, @ref dom::ValueToTag,
584
+ <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1895r0.pdf">
585
+ tag_invoke: A general pattern for supporting customisable functions</a>
586
+ */
587
+ struct ValueFromTag { };
588
+
589
+ /* * Concept to determine if a type can be converted to a @ref dom::Value
590
+ with a user-provided conversion.
591
+
592
+ This concept determines if the user-provided conversion is
593
+ defined as:
594
+
595
+ @code
596
+ void tag_invoke( ValueFromTag, dom::Value&, T );
597
+ @endcode
598
+ */
599
+ template <class T >
600
+ concept HasValueFromWithoutContext = requires (
601
+ Value& v,
602
+ T const & t)
603
+ {
604
+ tag_invoke (ValueFromTag{}, v, t);
605
+ };
606
+
607
+ /* * Concept to determine if a type can be converted to a @ref dom::Value
608
+ with a user-provided conversion.
609
+
610
+ This concept determines if the user-provided conversion is
611
+ defined as:
612
+
613
+ @code
614
+ void tag_invoke( ValueFromTag, dom::Value&, T, Context const& );
615
+ @endcode
616
+ */
617
+ template <class T , class Context >
618
+ concept HasValueFromWithContext = requires (
619
+ Value& v,
620
+ T const & t,
621
+ Context const & ctx)
622
+ {
623
+ tag_invoke (ValueFromTag{}, v, t, ctx);
624
+ };
625
+
626
+ /* * Determine if `T` can be converted to @ref dom::Value.
627
+
628
+ If `T` can be converted to @ref dom::Value via a
629
+ call to @ref dom::ValueFrom, the static data member `value`
630
+ is defined as `true`. Otherwise, `value` is
631
+ defined as `false`.
632
+
633
+ @see @ref dom::ValueFrom
634
+ */
635
+ template <class T , class Context >
636
+ concept HasValueFrom =
637
+ HasValueFromWithContext<T, Context> ||
638
+ HasValueFromWithoutContext<T> ||
639
+ std::constructible_from<Value, T>;
640
+
641
+ /* * Determine if ` T` can be converted to @ref dom::Value
642
+ without a context.
643
+
644
+ This concept determines if there is a user-provided
645
+ conversion to @ref dom::Value that does not require
646
+ a context or if @ref dom::Value has a constructor
647
+ that can be used to convert `T` to a @ref dom::Value.
648
+ */
649
+ template <class T >
650
+ concept HasStandaloneValueFrom =
651
+ HasValueFromWithoutContext<T> ||
652
+ std::constructible_from<Value, T>;
653
+
654
+ /* * Convert an object of type `T` to @ref dom::Value.
655
+
656
+ This function attempts to convert an object
657
+ of type `T` to @ref dom::Value using
658
+
659
+ @li a user-provided overload of `tag_invoke`.
660
+
661
+ @li one of @ref dom::Value's constructors,
662
+
663
+ Conversion of user-provided types is done by calling an overload of
664
+ `tag_invoke` found by argument-dependent lookup. Its signature should
665
+ be similar to:
666
+
667
+ @code
668
+ void tag_invoke( ValueFromTag, dom::Value&, T, Context const& );
669
+ @endcode
670
+
671
+ or
672
+
673
+ @code
674
+ void tag_invoke( ValueFromTag, dom::Value&, T );
675
+ @endcode
676
+
677
+ The overloads are checked for existence in that order and the first that
678
+ matches will be selected.
679
+
680
+ The `ctx` argument can be used either as a tag type to provide conversions
681
+ for third-party types, or to pass extra data to the conversion function.
682
+
683
+ @par Exception Safety
684
+ Strong guarantee.
685
+
686
+ @tparam T The type of the object to convert.
687
+
688
+ @tparam Context The type of context passed to the conversion function.
689
+
690
+ @param t The object to convert.
691
+
692
+ @param ctx Context passed to the conversion function.
693
+
694
+ @param jv @ref dom::Value out parameter.
695
+
696
+ @see @ref dom::ValueFromTag, @ref dom::ValueTo,
697
+ <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1895r0.pdf">
698
+ tag_invoke: A general pattern for supporting customisable functions</a>
699
+ */
700
+ template <class Context , HasValueFrom<Context> T>
701
+ void
702
+ ValueFrom (
703
+ T&& t,
704
+ Context const & ctx,
705
+ Value& v)
706
+ {
707
+ using BT = std::remove_cvref_t <T>;
708
+ if constexpr (HasValueFromWithContext<BT, Context>)
709
+ {
710
+ tag_invoke (ValueFromTag{}, v, static_cast <T&&>(t), ctx);
711
+ }
712
+ else {
713
+ ValueFrom (static_cast <T&&>(t), v);
714
+ }
715
+ }
716
+
717
+ /* * Convert an object of type `T` to @ref dom::Value.
718
+
719
+ This function attempts to convert an object
720
+ of type `T` to @ref dom::Value using
721
+
722
+ @li a user-provided overload of `tag_invoke`.
723
+
724
+ @li one of @ref dom::Value's constructors,
725
+
726
+ Conversion of other types is done by calling an overload of `tag_invoke`
727
+ found by argument-dependent lookup. Its signature should be similar to:
728
+
729
+ @code
730
+ void tag_invoke( ValueFromTag, dom::Value&, T );
731
+ @endcode
732
+
733
+ @par Exception Safety
734
+ Strong guarantee.
735
+
736
+ @tparam T The type of the object to convert.
737
+
738
+ @param t The object to convert.
739
+
740
+ @param jv @ref dom::Value out parameter.
741
+
742
+ @see @ref dom::ValueFromTag, @ref dom::ValueTo,
743
+ <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1895r0.pdf">
744
+ tag_invoke: A general pattern for supporting customisable functions</a>
745
+ */
746
+ template <class T >
747
+ requires HasStandaloneValueFrom<T>
748
+ void
749
+ ValueFrom (
750
+ T&& t,
751
+ Value& v)
752
+ {
753
+ using BT = std::remove_cvref_t <T>;
754
+ if constexpr (HasValueFromWithoutContext<BT>)
755
+ {
756
+ tag_invoke (ValueFromTag{}, v, static_cast <T&&>(t));
757
+ }
758
+ else /* if constexpr (std::constructible_from<Value, T>) */
759
+ {
760
+ v = Value (static_cast <T&&>(t));
761
+ }
762
+ }
763
+
764
+ /* * Convert an object of type `T` to @ref dom::Value.
765
+
766
+ This function attempts to convert an object
767
+ of type `T` to @ref dom::Value using
768
+
769
+ @li a user-provided overload of `tag_invoke`.
770
+
771
+ @li one of @ref dom::Value's constructors,
772
+
773
+ Conversion of other types is done by calling an overload of `tag_invoke`
774
+ found by argument-dependent lookup. Its signature should be similar to:
775
+
776
+ @code
777
+ void tag_invoke( ValueFromTag, dom::Value&, T );
778
+ @endcode
779
+
780
+ @par Exception Safety
781
+ Strong guarantee.
782
+
783
+ @tparam T The type of the object to convert.
784
+
785
+ @param t The object to convert.
786
+
787
+ @return @ref dom::Value out parameter.
788
+
789
+ @see @ref dom::ValueFromTag, @ref dom::ValueTo,
790
+ <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1895r0.pdf">
791
+ tag_invoke: A general pattern for supporting customisable functions</a>
792
+ */
793
+ template <class T >
794
+ requires HasStandaloneValueFrom<T>
795
+ Value
796
+ ValueFrom (T&& t)
797
+ {
798
+ dom::Value v;
799
+ ValueFrom (static_cast <T&&>(t), v);
800
+ return v;
801
+ }
802
+
617
803
} // dom
618
804
619
805
template <std::convertible_to<std::string_view> SV>
0 commit comments