@@ -54,36 +54,6 @@ safeString(dom::Value const& str);
5454
5555namespace dom {
5656
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-
8757/* * A variant container for any kind of Dom value.
8858*/
8959class MRDOCS_DECL
@@ -120,14 +90,12 @@ class MRDOCS_DECL
12090
12191 template <class F >
12292 requires
123- function_traits_convertible_to_value<F> &&
124- (!HasToValue<F>)
93+ function_traits_convertible_to_value<F>
12594 Value (F const & f)
12695 : Value(Function(f))
12796 {}
12897
12998 template <std::same_as<bool > Boolean>
130- requires (!HasToValue<Boolean>)
13199 Value (Boolean const & b) noexcept
132100 : kind_(Kind::Boolean)
133101 , b_(b)
@@ -137,21 +105,18 @@ class MRDOCS_DECL
137105 template <std::integral T>
138106 requires
139107 (!std::same_as<T, bool >) &&
140- (!std::same_as<T, char >) &&
141- (!HasToValue<T>)
108+ (!std::same_as<T, char >)
142109 Value (T v) noexcept : Value(std::int64_t (v)) {}
143110
144111 template <std::floating_point T>
145- requires (!HasToValue<T>)
146112 Value (T v) noexcept : Value(std::int64_t (v)) {}
147113
148114 Value (char c) noexcept : Value(std::string_view(&c, 1 )) {}
149115
150116 template <class Enum >
151117 requires
152118 std::is_enum_v<Enum> &&
153- (!std::same_as<Enum, dom::Kind>) &&
154- (!HasToValue<Enum>)
119+ (!std::same_as<Enum, dom::Kind>)
155120 Value (Enum v) noexcept
156121 : Value(static_cast <std::underlying_type_t <Enum>>(v))
157122 {}
@@ -169,7 +134,6 @@ class MRDOCS_DECL
169134 }
170135
171136 template <std::convertible_to<String> StringLike>
172- requires (!HasToValue<StringLike>)
173137 Value (StringLike const & s)
174138 : Value(String(s))
175139 {
@@ -194,12 +158,6 @@ class MRDOCS_DECL
194158 {
195159 }
196160
197- template <HasToValue T>
198- Value (T const & t)
199- : Value(ToValue<T>{}(t))
200- {
201- }
202-
203161 Value& operator =(Value const & other);
204162 Value& operator =(Value&& other) noexcept ;
205163
@@ -607,13 +565,241 @@ stringOrNull(
607565{
608566 if (!s.empty ())
609567 {
610- return s ;
568+ return {s} ;
611569 }
612570 return nullptr ;
613571}
614572
615573// ------------------------------------------------
616574
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+
617803} // dom
618804
619805template <std::convertible_to<std::string_view> SV>
0 commit comments