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_category, 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( user_context_category, 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 : user_full_context_category, 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 Cat, class T, class Ctx >
77 : void
78 6622 : value_from_impl(
79 : Cat,
80 : value& jv,
81 : T&& from,
82 : Ctx const&,
83 : typename std::enable_if<is_native_conversion<Cat>::value>* = nullptr)
84 : {
85 6622 : jv = std::forward<T>(from);
86 6622 : }
87 :
88 : // null-like types
89 : template< class T, class Ctx >
90 : void
91 11 : value_from_impl( null_category, value& jv, T&&, Ctx const& )
92 : {
93 : // do nothing
94 11 : BOOST_ASSERT(jv.is_null());
95 : (void)jv;
96 11 : }
97 :
98 : // string-like types
99 : template< class T, class Ctx >
100 : void
101 75 : value_from_impl( string_category, value& jv, T&& from, Ctx const& )
102 : {
103 75 : auto sv = static_cast<string_view>(from);
104 75 : jv.emplace_string().assign(sv);
105 75 : }
106 :
107 : // map-like types
108 : template< class T, class Ctx >
109 : void
110 46 : value_from_impl( map_category, value& jv, T&& from, Ctx const& ctx )
111 : {
112 : using std::get;
113 46 : object& obj = jv.emplace_object();
114 46 : obj.reserve(detail::try_size(from, size_implementation<T>()));
115 145 : for (auto&& elem : from)
116 297 : obj.emplace(
117 99 : get<0>(elem),
118 99 : value_from( get<1>(elem), ctx, obj.storage() ));
119 46 : }
120 :
121 : // ranges
122 : template< class T, class Ctx >
123 : void
124 100 : value_from_impl( sequence_category, value& jv, T&& from, Ctx const& ctx )
125 : {
126 100 : array& result = jv.emplace_array();
127 100 : result.reserve(detail::try_size(from, size_implementation<T>()));
128 : using ForwardedValue = forwarded_value<T&&>;
129 6355 : for (auto&& elem : from)
130 6445 : result.emplace_back(
131 : value_from(
132 : // not a static_cast in order to appease clang < 4.0
133 190 : ForwardedValue(elem),
134 : ctx,
135 : result.storage() ));
136 100 : }
137 :
138 : // tuple-like types
139 : template< class T, class Ctx >
140 : void
141 139 : value_from_impl( tuple_category, value& jv, T&& from, Ctx const& ctx )
142 : {
143 139 : constexpr std::size_t n =
144 : std::tuple_size<remove_cvref<T>>::value;
145 139 : array& arr = jv.emplace_array();
146 139 : arr.reserve(n);
147 139 : mp11::mp_for_each<mp11::mp_iota_c<n>>(
148 139 : append_tuple_element< Ctx, T >{ arr, ctx, std::forward<T>(from) });
149 139 : }
150 :
151 : // no suitable conversion implementation
152 : template< class T, class Ctx >
153 : void
154 : value_from_impl( unknown_category, value&, T&&, Ctx const& )
155 : {
156 : static_assert(
157 : !std::is_same<T, T>::value,
158 : "No suitable tag_invoke overload found for the type");
159 : }
160 :
161 : template< class Ctx, class T >
162 : struct from_described_member
163 : {
164 : static_assert(
165 : uniquely_named_members< remove_cvref<T> >::value,
166 : "The type has several described members with the same name.");
167 :
168 : using Ds = described_members< remove_cvref<T> >;
169 :
170 : object& obj;
171 : Ctx const& ctx;
172 : T&& from;
173 :
174 : template< class I >
175 : void
176 : operator()(I) const
177 : {
178 : using D = mp11::mp_at<Ds, I>;
179 : obj.emplace(
180 : D::name,
181 : value_from(
182 : static_cast<T&&>(from).* D::pointer,
183 : ctx,
184 : obj.storage()));
185 : }
186 : };
187 :
188 : // described classes
189 : template< class T, class Ctx >
190 : void
191 : value_from_impl(
192 : described_class_category, value& jv, T&& from, Ctx const& ctx )
193 : {
194 : object& obj = jv.emplace_object();
195 : from_described_member<Ctx, T> member_converter{
196 : obj, ctx, static_cast<T&&>(from)};
197 :
198 : using Ds = typename decltype(member_converter)::Ds;
199 : constexpr std::size_t N = mp11::mp_size<Ds>::value;
200 : obj.reserve(N);
201 : mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
202 : }
203 :
204 : // described enums
205 : template< class T, class Ctx >
206 : void
207 : value_from_impl( described_enum_category, value& jv, T from, Ctx const& )
208 : {
209 : (void)jv;
210 : (void)from;
211 : #ifdef BOOST_DESCRIBE_CXX14
212 : char const* const name = describe::enum_to_string(from, nullptr);
213 : if( name )
214 : {
215 : string& str = jv.emplace_string();
216 : str.assign(name);
217 : }
218 : else
219 : {
220 : using Integer = typename std::underlying_type< remove_cvref<T> >::type;
221 : jv = static_cast<Integer>(from);
222 : }
223 : #endif
224 : }
225 :
226 : // optionals
227 : template< class T, class Ctx >
228 : void
229 : value_from_impl( optional_category, value& jv, T&& from, Ctx const& ctx )
230 : {
231 : if( from )
232 : value_from( *from, ctx, jv );
233 : else
234 : jv = nullptr;
235 : }
236 :
237 : // variants
238 : template< class Ctx >
239 : struct value_from_visitor
240 : {
241 : value& jv;
242 : Ctx const& ctx;
243 :
244 : template<class T>
245 : void
246 : operator()(T&& t)
247 : {
248 : value_from( static_cast<T&&>(t), ctx, jv );
249 : }
250 : };
251 :
252 : template< class Ctx, class T >
253 : void
254 : value_from_impl( variant_category, value& jv, T&& from, Ctx const& ctx )
255 : {
256 : visit( value_from_visitor<Ctx>{ jv, ctx }, static_cast<T&&>(from) );
257 : }
258 :
259 : template< class Ctx, class T >
260 : void
261 : value_from_impl( path_category, value& jv, T&& from, Ctx const& )
262 : {
263 : std::string s = from.generic_string();
264 : string_view sv = s;
265 : jv.emplace_string().assign(sv);
266 : }
267 :
268 : //----------------------------------------------------------
269 : // Contextual conversions
270 :
271 : template< class Ctx, class T >
272 : using value_from_category = extended_conversion_category<
273 : Ctx, T, value_from_conversion >;
274 :
275 : } // detail
276 :
277 : #ifndef BOOST_NO_CXX17_HDR_OPTIONAL
278 : inline
279 : void
280 : tag_invoke(
281 : value_from_tag,
282 : value& jv,
283 : std::nullopt_t)
284 : {
285 : // do nothing
286 : BOOST_ASSERT(jv.is_null());
287 : (void)jv;
288 : }
289 : #endif
290 :
291 : } // namespace json
292 : } // namespace boost
293 :
294 : #endif
|