TLA Line data Source code
1 : //
2 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 : // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
4 : // Copyright (c) 2022 Dmitry Arkhipov (grisumbras@gmail.com)
5 : //
6 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
7 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 : //
9 : // Official repository: https://github.com/boostorg/json
10 : //
11 :
12 : #ifndef BOOST_JSON_DETAIL_VALUE_FROM_HPP
13 : #define BOOST_JSON_DETAIL_VALUE_FROM_HPP
14 :
15 : #include <boost/json/value.hpp>
16 : #include <boost/json/conversion.hpp>
17 : #include <boost/describe/enum_to_string.hpp>
18 : #include <boost/mp11/algorithm.hpp>
19 :
20 : #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
21 : # include <optional>
22 : #endif
23 :
24 : namespace boost {
25 : namespace json {
26 :
27 : namespace detail {
28 :
29 : template< class Ctx, class T >
30 : struct append_tuple_element {
31 : array& arr;
32 : Ctx const& ctx;
33 : T&& t;
34 :
35 : template<std::size_t I>
36 : void
37 HIT 295 : operator()(mp11::mp_size_t<I>) const
38 : {
39 : using std::get;
40 590 : arr.emplace_back(value_from(
41 600 : get<I>(std::forward<T>(t)), ctx, arr.storage() ));
42 295 : }
43 : };
44 :
45 : //----------------------------------------------------------
46 : // User-provided conversion
47 :
48 : template< class T, class Ctx >
49 : void
50 35 : value_from_impl( user_conversion_tag, value& jv, T&& from, Ctx const& )
51 : {
52 35 : tag_invoke( value_from_tag(), jv, static_cast<T&&>(from) );
53 35 : }
54 :
55 : template< class T, class Ctx >
56 : void
57 26 : value_from_impl( context_conversion_tag, value& jv, T&& from, Ctx const& ctx)
58 : {
59 : using Sup = supported_context<Ctx, T, value_from_conversion>;
60 26 : tag_invoke( value_from_tag(), jv, static_cast<T&&>(from), Sup::get(ctx) );
61 26 : }
62 :
63 : template< class T, class Ctx >
64 : void
65 2 : value_from_impl(
66 : full_context_conversion_tag, value& jv, T&& from, Ctx const& ctx)
67 : {
68 : using Sup = supported_context<Ctx, T, value_from_conversion>;
69 2 : tag_invoke(
70 2 : value_from_tag(), jv, static_cast<T&&>(from), Sup::get(ctx), ctx );
71 2 : }
72 :
73 : //----------------------------------------------------------
74 : // Native conversion
75 :
76 : template< class T, class Ctx >
77 : void
78 6622 : value_from_impl( native_conversion_tag, value& jv, T&& from, Ctx const& )
79 : {
80 6622 : jv = std::forward<T>(from);
81 6622 : }
82 :
83 : // null-like types
84 : template< class T, class Ctx >
85 : void
86 11 : value_from_impl( null_like_conversion_tag, value& jv, T&&, Ctx const& )
87 : {
88 : // do nothing
89 11 : BOOST_ASSERT(jv.is_null());
90 : (void)jv;
91 11 : }
92 :
93 : // string-like types
94 : template< class T, class Ctx >
95 : void
96 75 : value_from_impl( string_like_conversion_tag, value& jv, T&& from, Ctx const& )
97 : {
98 75 : auto sv = static_cast<string_view>(from);
99 75 : jv.emplace_string().assign(sv);
100 75 : }
101 :
102 : // map-like types
103 : template< class T, class Ctx >
104 : void
105 46 : value_from_impl( map_like_conversion_tag, value& jv, T&& from, Ctx const& ctx )
106 : {
107 : using std::get;
108 46 : object& obj = jv.emplace_object();
109 46 : obj.reserve(detail::try_size(from, size_implementation<T>()));
110 145 : for (auto&& elem : from)
111 297 : obj.emplace(
112 99 : get<0>(elem),
113 99 : value_from( get<1>(elem), ctx, obj.storage() ));
114 46 : }
115 :
116 : // ranges
117 : template< class T, class Ctx >
118 : void
119 100 : value_from_impl( sequence_conversion_tag, value& jv, T&& from, Ctx const& ctx )
120 : {
121 100 : array& result = jv.emplace_array();
122 100 : result.reserve(detail::try_size(from, size_implementation<T>()));
123 : using ForwardedValue = forwarded_value<T&&>;
124 6355 : for (auto&& elem : from)
125 6445 : result.emplace_back(
126 : value_from(
127 : // not a static_cast in order to appease clang < 4.0
128 190 : ForwardedValue(elem),
129 : ctx,
130 : result.storage() ));
131 100 : }
132 :
133 : // tuple-like types
134 : template< class T, class Ctx >
135 : void
136 139 : value_from_impl( tuple_conversion_tag, value& jv, T&& from, Ctx const& ctx )
137 : {
138 139 : constexpr std::size_t n =
139 : std::tuple_size<remove_cvref<T>>::value;
140 139 : array& arr = jv.emplace_array();
141 139 : arr.reserve(n);
142 139 : mp11::mp_for_each<mp11::mp_iota_c<n>>(
143 139 : append_tuple_element< Ctx, T >{ arr, ctx, std::forward<T>(from) });
144 139 : }
145 :
146 : // no suitable conversion implementation
147 : template< class T, class Ctx >
148 : void
149 : value_from_impl( no_conversion_tag, value&, T&&, Ctx const& )
150 : {
151 : static_assert(
152 : !std::is_same<T, T>::value,
153 : "No suitable tag_invoke overload found for the type");
154 : }
155 :
156 : template< class Ctx, class T >
157 : struct from_described_member
158 : {
159 : static_assert(
160 : uniquely_named_members< remove_cvref<T> >::value,
161 : "The type has several described members with the same name.");
162 :
163 : using Ds = described_members< remove_cvref<T> >;
164 :
165 : object& obj;
166 : Ctx const& ctx;
167 : T&& from;
168 :
169 : template< class I >
170 : void
171 : operator()(I) const
172 : {
173 : using D = mp11::mp_at<Ds, I>;
174 : obj.emplace(
175 : D::name,
176 : value_from(
177 : static_cast<T&&>(from).* D::pointer,
178 : ctx,
179 : obj.storage()));
180 : }
181 : };
182 :
183 : // described classes
184 : template< class T, class Ctx >
185 : void
186 : value_from_impl(
187 : described_class_conversion_tag, value& jv, T&& from, Ctx const& ctx )
188 : {
189 : object& obj = jv.emplace_object();
190 : from_described_member<Ctx, T> member_converter{
191 : obj, ctx, static_cast<T&&>(from)};
192 :
193 : using Ds = typename decltype(member_converter)::Ds;
194 : constexpr std::size_t N = mp11::mp_size<Ds>::value;
195 : obj.reserve(N);
196 : mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
197 : }
198 :
199 : // described enums
200 : template< class T, class Ctx >
201 : void
202 : value_from_impl(
203 : described_enum_conversion_tag, value& jv, T from, Ctx const& )
204 : {
205 : (void)jv;
206 : (void)from;
207 : #ifdef BOOST_DESCRIBE_CXX14
208 : char const* const name = describe::enum_to_string(from, nullptr);
209 : if( name )
210 : {
211 : string& str = jv.emplace_string();
212 : str.assign(name);
213 : }
214 : else
215 : {
216 : using Integer = typename std::underlying_type< remove_cvref<T> >::type;
217 : jv = static_cast<Integer>(from);
218 : }
219 : #endif
220 : }
221 :
222 : // optionals
223 : template< class T, class Ctx >
224 : void
225 : value_from_impl(
226 : optional_conversion_tag, value& jv, T&& from, Ctx const& ctx )
227 : {
228 : if( from )
229 : value_from( *from, ctx, jv );
230 : else
231 : jv = nullptr;
232 : }
233 :
234 : // variants
235 : template< class Ctx >
236 : struct value_from_visitor
237 : {
238 : value& jv;
239 : Ctx const& ctx;
240 :
241 : template<class T>
242 : void
243 : operator()(T&& t)
244 : {
245 : value_from( static_cast<T&&>(t), ctx, jv );
246 : }
247 : };
248 :
249 : template< class Ctx, class T >
250 : void
251 : value_from_impl( variant_conversion_tag, value& jv, T&& from, Ctx const& ctx )
252 : {
253 : visit( value_from_visitor<Ctx>{ jv, ctx }, static_cast<T&&>(from) );
254 : }
255 :
256 : template< class Ctx, class T >
257 : void
258 : value_from_impl( path_conversion_tag, value& jv, T&& from, Ctx const& )
259 : {
260 : std::string s = from.generic_string();
261 : string_view sv = s;
262 : jv.emplace_string().assign(sv);
263 : }
264 :
265 : //----------------------------------------------------------
266 : // Contextual conversions
267 :
268 : template< class Ctx, class T >
269 : using value_from_category = conversion_category<
270 : Ctx, T, value_from_conversion >;
271 :
272 : } // detail
273 :
274 : #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
275 : inline
276 : void
277 : tag_invoke(
278 : value_from_tag,
279 : value& jv,
280 : std::nullopt_t)
281 : {
282 : // do nothing
283 : BOOST_ASSERT(jv.is_null());
284 : (void)jv;
285 : }
286 : #endif
287 :
288 : } // namespace json
289 : } // namespace boost
290 :
291 : #endif
|