/src/glaze/include/glaze/tuplet/tuple.hpp
Line | Count | Source |
1 | | // Glaze Library |
2 | | // For the license information refer to glaze.hpp |
3 | | |
4 | | // original source (significantly refactored): https://github.com/codeinred/tuplet |
5 | | |
6 | | #pragma once |
7 | | |
8 | | #include <compare> |
9 | | #include <concepts> |
10 | | #include <cstddef> |
11 | | #include <type_traits> |
12 | | #include <utility> |
13 | | |
14 | | #include "glaze/util/inline.hpp" |
15 | | |
16 | | #if (__has_cpp_attribute(no_unique_address)) |
17 | | #define GLZ_NO_UNIQUE_ADDRESS [[no_unique_address]] |
18 | | #elif (__has_cpp_attribute(msvc::no_unique_address)) || ((defined _MSC_VER) && (!defined __clang__)) |
19 | | // Note __has_cpp_attribute(msvc::no_unique_address) itself doesn't work as |
20 | | // of 19.30.30709, even though the attribute itself is supported. See |
21 | | // https://github.com/llvm/llvm-project/issues/49358#issuecomment-981041089 |
22 | | #define GLZ_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] |
23 | | #else |
24 | | // no_unique_address is not available. |
25 | | #define GLZ_NO_UNIQUE_ADDRESS |
26 | | #endif |
27 | | |
28 | | namespace glz |
29 | | { |
30 | | // tuplet concepts and traits |
31 | | namespace tuplet |
32 | | { |
33 | | template <class T> |
34 | | using identity_t = T; |
35 | | |
36 | | template <class T> |
37 | | using type_t = typename T::type; |
38 | | |
39 | | template <size_t I> |
40 | | using tag = std::integral_constant<size_t, I>; |
41 | | |
42 | | template <size_t N> |
43 | | using tag_range = std::make_index_sequence<N>; |
44 | | |
45 | | template <class T, class U> |
46 | | concept other_than = !std::is_same_v<std::decay_t<T>, U>; |
47 | | |
48 | | template <class Tup> |
49 | | using base_list_t = typename std::decay_t<Tup>::base_list; |
50 | | |
51 | | template <class Tuple> |
52 | | concept base_list_tuple = requires() { typename std::decay_t<Tuple>::base_list; }; |
53 | | |
54 | | template <class T> |
55 | | concept stateless = std::is_empty_v<std::decay_t<T>>; |
56 | | |
57 | | template <class T> |
58 | | concept indexable = stateless<T> || requires(T t) { t[tag<0>()]; }; |
59 | | |
60 | | template <class U, class T> |
61 | | concept assignable_to = requires(U u, T t) { t = u; }; |
62 | | |
63 | | template <class T> |
64 | | concept ordered = requires(const T& t) { |
65 | | { t <=> t }; |
66 | | }; |
67 | | template <class T> |
68 | | concept equality_comparable = requires(const T& t) { |
69 | | { t == t } -> std::same_as<bool>; |
70 | | }; |
71 | | } // namespace tuplet |
72 | | |
73 | | template <class... T> |
74 | | struct tuple; |
75 | | |
76 | | // tuplet::type_list implementation |
77 | | // tuplet::type_map implementation |
78 | | // tuplet::tuple_elem implementation |
79 | | // tuplet::deduce_elems |
80 | | namespace tuplet |
81 | | { |
82 | | template <class... T> |
83 | | struct type_list |
84 | | {}; |
85 | | |
86 | | template <class... Ls, class... Rs> |
87 | | constexpr auto operator+(type_list<Ls...>, type_list<Rs...>) |
88 | | { |
89 | | return type_list<Ls..., Rs...>{}; |
90 | | } |
91 | | |
92 | | template <class... Bases> |
93 | | struct type_map : Bases... |
94 | | { |
95 | | using base_list = type_list<Bases...>; |
96 | | using Bases::operator[]...; |
97 | | using Bases::decl_elem...; |
98 | | auto operator<=>(const type_map&) const = default; |
99 | | bool operator==(const type_map&) const = default; |
100 | | }; |
101 | | |
102 | | template <size_t I, class T> |
103 | | struct tuple_elem |
104 | | { |
105 | | // Like declval, but with the element |
106 | | static T decl_elem(tag<I>); |
107 | | using type = T; |
108 | | |
109 | | GLZ_NO_UNIQUE_ADDRESS T value; |
110 | | |
111 | 0 | constexpr decltype(auto) operator[](tag<I>) & { return (value); }Unexecuted instantiation: glz::tuplet::tuple_elem<0ul, int const&>::operator[](std::__1::integral_constant<unsigned long, 0ul>) & Unexecuted instantiation: glz::tuplet::tuple_elem<0ul, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&>::operator[](std::__1::integral_constant<unsigned long, 0ul>) & Unexecuted instantiation: glz::tuplet::tuple_elem<0ul, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&>::operator[](std::__1::integral_constant<unsigned long, 0ul>) & |
112 | | constexpr decltype(auto) operator[](tag<I>) const& { return (value); } |
113 | 16.0k | constexpr decltype(auto) operator[](tag<I>) && { return (std::move(*this).value); }glz::tuplet::tuple_elem<0ul, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&>::operator[](std::__1::integral_constant<unsigned long, 0ul>) && Line | Count | Source | 113 | 2.41k | constexpr decltype(auto) operator[](tag<I>) && { return (std::move(*this).value); } |
glz::tuplet::tuple_elem<1ul, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&>::operator[](std::__1::integral_constant<unsigned long, 1ul>) && Line | Count | Source | 113 | 4.02k | constexpr decltype(auto) operator[](tag<I>) && { return (std::move(*this).value); } |
glz::tuplet::tuple_elem<2ul, unsigned short&>::operator[](std::__1::integral_constant<unsigned long, 2ul>) && Line | Count | Source | 113 | 9.59k | constexpr decltype(auto) operator[](tag<I>) && { return (std::move(*this).value); } |
Unexecuted instantiation: glz::tuplet::tuple_elem<0ul, int const&>::operator[](std::__1::integral_constant<unsigned long, 0ul>) && Unexecuted instantiation: glz::tuplet::tuple_elem<0ul, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&>::operator[](std::__1::integral_constant<unsigned long, 0ul>) && Unexecuted instantiation: glz::tuplet::tuple_elem<1ul, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&>::operator[](std::__1::integral_constant<unsigned long, 1ul>) && Unexecuted instantiation: glz::tuplet::tuple_elem<2ul, unsigned short const&>::operator[](std::__1::integral_constant<unsigned long, 2ul>) && |
114 | | auto operator<=>(const tuple_elem&) const = default; |
115 | | bool operator==(const tuple_elem&) const = default; |
116 | | // Implements comparison for tuples containing reference types |
117 | | constexpr auto operator<=>(const tuple_elem& other) const noexcept(noexcept(value <=> other.value)) |
118 | | requires(std::is_reference_v<T> && ordered<T>) |
119 | 0 | { |
120 | 0 | return value <=> other.value; |
121 | 0 | } Unexecuted instantiation: _ZNK3glz6tuplet10tuple_elemILm0ERKiEssERKS4_Qaasr3stdE14is_reference_vIT0_E7orderedIS7_E Unexecuted instantiation: _ZNK3glz6tuplet10tuple_elemILm0ERNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEssERKSA_Qaasr3stdE14is_reference_vIT0_E7orderedISD_E Unexecuted instantiation: _ZNK3glz6tuplet10tuple_elemILm1ERNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEssERKSA_Qaasr3stdE14is_reference_vIT0_E7orderedISD_E Unexecuted instantiation: _ZNK3glz6tuplet10tuple_elemILm2ERtEssERKS3_Qaasr3stdE14is_reference_vIT0_E7orderedIS6_E Unexecuted instantiation: _ZNK3glz6tuplet10tuple_elemILm0ERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEssERKSB_Qaasr3stdE14is_reference_vIT0_E7orderedISE_E Unexecuted instantiation: _ZNK3glz6tuplet10tuple_elemILm1ERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEssERKSB_Qaasr3stdE14is_reference_vIT0_E7orderedISE_E Unexecuted instantiation: _ZNK3glz6tuplet10tuple_elemILm2ERKtEssERKS4_Qaasr3stdE14is_reference_vIT0_E7orderedIS7_E |
122 | | constexpr bool operator==(const tuple_elem& other) const noexcept(noexcept(value == other.value)) |
123 | | requires(std::is_reference_v<T> && equality_comparable<T>) |
124 | | { |
125 | | return value == other.value; |
126 | | } |
127 | | }; |
128 | | } // namespace tuplet |
129 | | |
130 | | template <class T> |
131 | | using unwrap_ref_decay_t = typename std::unwrap_ref_decay<T>::type; |
132 | | |
133 | | // tuplet::get_tuple_base implementation |
134 | | // tuplet::apply_impl |
135 | | namespace tuplet |
136 | | { |
137 | | template <class A, class... T> |
138 | | struct get_tuple_base; |
139 | | |
140 | | template <size_t... I, class... T> |
141 | | struct get_tuple_base<std::index_sequence<I...>, T...> |
142 | | { |
143 | | using type = type_map<tuple_elem<I, T>...>; |
144 | | }; |
145 | | |
146 | | template <class F, class T, class... Bases> |
147 | | constexpr decltype(auto) apply_impl(F&& f, T&& t, type_list<Bases...>) |
148 | | { |
149 | | return static_cast<F&&>(f)(static_cast<T&&>(t).identity_t<Bases>::value...); |
150 | | } |
151 | | |
152 | | template <class First, class> |
153 | | using first_t = First; |
154 | | |
155 | | template <class T, class... Q> |
156 | | constexpr auto repeat_type(type_list<Q...>) |
157 | | { |
158 | | return type_list<first_t<T, Q>...>{}; |
159 | | } |
160 | | template <class... Outer> |
161 | | constexpr auto get_outer_bases(type_list<Outer...>) |
162 | | { |
163 | | return (repeat_type<Outer>(base_list_t<type_t<Outer>>{}) + ...); |
164 | | } |
165 | | template <class... Outer> |
166 | | constexpr auto get_inner_bases(type_list<Outer...>) |
167 | | { |
168 | | return (base_list_t<type_t<Outer>>{} + ...); |
169 | | } |
170 | | |
171 | | // This takes a forwarding tuple as a parameter. The forwarding tuple only |
172 | | // contains references, so it should just be taken by value. |
173 | | template <class T, class... Outer, class... Inner> |
174 | | constexpr auto cat_impl([[maybe_unused]] T tup, type_list<Outer...>, type_list<Inner...>) |
175 | | -> tuple<type_t<Inner>...> |
176 | | { |
177 | | return {{{static_cast<type_t<Outer>&&>(tup.identity_t<Outer>::value).identity_t<Inner>::value}...}}; |
178 | | } |
179 | | |
180 | | template <class... T> |
181 | | using tuple_base_t = typename get_tuple_base<tag_range<sizeof...(T)>, T...>::type; |
182 | | } |
183 | | |
184 | | template <class... T> |
185 | | struct tuple : tuplet::tuple_base_t<T...> |
186 | | { |
187 | | static constexpr auto glaze_reflect = false; |
188 | | static constexpr size_t N = sizeof...(T); |
189 | | using super = tuplet::tuple_base_t<T...>; |
190 | | using super::operator[]; |
191 | | using base_list = typename super::base_list; |
192 | | using super::decl_elem; |
193 | | |
194 | | template <tuplet::other_than<tuple> U> // Preserves default assignments |
195 | | constexpr auto& operator=(U&& tup) |
196 | | { |
197 | | using tuple2 = std::decay_t<U>; |
198 | | if constexpr (tuplet::base_list_tuple<tuple2>) { |
199 | | eq_impl(static_cast<U&&>(tup), base_list(), typename tuple2::base_list()); |
200 | | } |
201 | | else { |
202 | | eq_impl(static_cast<U&&>(tup), tuplet::tag_range<N>()); |
203 | | } |
204 | | return *this; |
205 | | } |
206 | | |
207 | | // TODO: currently segfaults clang |
208 | | /*template <assignable_to<T>... U> |
209 | | constexpr auto& assign(U&&... values) { |
210 | | assign_impl(base_list(), static_cast<U&&>(values)...); |
211 | | return *this; |
212 | | }*/ |
213 | | |
214 | | auto operator<=>(const tuple&) const = default; |
215 | | bool operator==(const tuple&) const = default; |
216 | | |
217 | | // Applies a function to every element of the tuple. The order is the |
218 | | // declaration order, so first the function will be applied to element 0, |
219 | | // then element 1, then element 2, and so on, where element N is identified |
220 | | // by get<N> |
221 | | template <class F> |
222 | | constexpr void for_each(F&& func) & |
223 | | { |
224 | | for_each_impl(base_list(), static_cast<F&&>(func)); |
225 | | } |
226 | | template <class F> |
227 | | constexpr void for_each(F&& func) const& |
228 | | { |
229 | | for_each_impl(base_list(), static_cast<F&&>(func)); |
230 | | } |
231 | | template <class F> |
232 | | constexpr void for_each(F&& func) && |
233 | | { |
234 | | static_cast<tuple&&>(*this).for_each_impl(base_list(), static_cast<F&&>(func)); |
235 | | } |
236 | | |
237 | | // Applies a function to each element successively, until one returns a |
238 | | // truthy value. Returns true if any application returned a truthy value, |
239 | | // and false otherwise |
240 | | template <class F> |
241 | | constexpr bool any(F&& func) & |
242 | | { |
243 | | return any_impl(base_list(), static_cast<F&&>(func)); |
244 | | } |
245 | | template <class F> |
246 | | constexpr bool any(F&& func) const& |
247 | | { |
248 | | return any_impl(base_list(), static_cast<F&&>(func)); |
249 | | } |
250 | | template <class F> |
251 | | constexpr bool any(F&& func) && |
252 | | { |
253 | | return static_cast<tuple&&>(*this).any_impl(base_list(), static_cast<F&&>(func)); |
254 | | } |
255 | | |
256 | | // Applies a function to each element successively, until one returns a |
257 | | // falsy value. Returns true if every application returned a truthy value, |
258 | | // and false otherwise |
259 | | template <class F> |
260 | | constexpr bool all(F&& func) & |
261 | | { |
262 | | return all_impl(base_list(), static_cast<F&&>(func)); |
263 | | } |
264 | | template <class F> |
265 | | constexpr bool all(F&& func) const& |
266 | | { |
267 | | return all_impl(base_list(), static_cast<F&&>(func)); |
268 | | } |
269 | | template <class F> |
270 | | constexpr bool all(F&& func) && |
271 | | { |
272 | | return static_cast<tuple&&>(*this).all_impl(base_list(), static_cast<F&&>(func)); |
273 | | } |
274 | | |
275 | | private: |
276 | | template <class U, class... B1, class... B2> |
277 | | constexpr void eq_impl(U&& u, tuplet::type_list<B1...>, tuplet::type_list<B2...>) |
278 | | { |
279 | | // See: |
280 | | // https://developercommunity.visualstudio.com/t/fold-expressions-unreliable-in-171-with-c20/1676476 |
281 | | (void(B1::value = static_cast<U&&>(u).B2::value), ...); |
282 | | } |
283 | | template <class U, size_t... I> |
284 | | constexpr void eq_impl(U&& u, std::index_sequence<I...>) |
285 | | { |
286 | | (void(tuplet::tuple_elem<I, T>::value = get<I>(static_cast<U&&>(u))), ...); |
287 | | } |
288 | | template <class... U, class... B> |
289 | | constexpr void assign_impl(tuplet::type_list<B...>, U&&... u) |
290 | | { |
291 | | (void(B::value = static_cast<U&&>(u)), ...); |
292 | | } |
293 | | |
294 | | template <class F, class... B> |
295 | | constexpr void for_each_impl(tuplet::type_list<B...>, F&& func) & |
296 | | { |
297 | | (void(func(B::value)), ...); |
298 | | } |
299 | | template <class F, class... B> |
300 | | constexpr void for_each_impl(tuplet::type_list<B...>, F&& func) const& |
301 | | { |
302 | | (void(func(B::value)), ...); |
303 | | } |
304 | | template <class F, class... B> |
305 | | constexpr void for_each_impl(tuplet::type_list<B...>, F&& func) && |
306 | | { |
307 | | (void(func(static_cast<T&&>(B::value))), ...); |
308 | | } |
309 | | |
310 | | template <class F, class... B> |
311 | | constexpr bool any_impl(tuplet::type_list<B...>, F&& func) & |
312 | | { |
313 | | return (bool(func(B::value)) || ...); |
314 | | } |
315 | | template <class F, class... B> |
316 | | constexpr bool any_impl(tuplet::type_list<B...>, F&& func) const& |
317 | | { |
318 | | return (bool(func(B::value)) || ...); |
319 | | } |
320 | | template <class F, class... B> |
321 | | constexpr bool any_impl(tuplet::type_list<B...>, F&& func) && |
322 | | { |
323 | | return (bool(func(static_cast<T&&>(B::value))) || ...); |
324 | | } |
325 | | |
326 | | template <class F, class... B> |
327 | | constexpr bool all_impl(tuplet::type_list<B...>, F&& func) & |
328 | | { |
329 | | return (bool(func(B::value)) && ...); |
330 | | } |
331 | | template <class F, class... B> |
332 | | constexpr bool all_impl(tuplet::type_list<B...>, F&& func) const& |
333 | | { |
334 | | return (bool(func(B::value)) && ...); |
335 | | } |
336 | | template <class F, class... B> |
337 | | constexpr bool all_impl(tuplet::type_list<B...>, F&& func) && |
338 | | { |
339 | | return (bool(func(static_cast<T&&>(B::value))) && ...); |
340 | | } |
341 | | }; |
342 | | template <> |
343 | | struct tuple<> : tuplet::tuple_base_t<> |
344 | | { |
345 | | constexpr static size_t N = 0; |
346 | | using super = tuplet::tuple_base_t<>; |
347 | | using base_list = tuplet::type_list<>; |
348 | | |
349 | | template <tuplet::other_than<tuple> U> // Preserves default assignments |
350 | | requires tuplet::stateless<U> // Check that U is similarly stateless |
351 | | constexpr auto& operator=(U&&) noexcept |
352 | | { |
353 | | return *this; |
354 | | } |
355 | | |
356 | 0 | constexpr auto& assign() noexcept { return *this; } |
357 | | auto operator<=>(const tuple&) const = default; |
358 | | bool operator==(const tuple&) const = default; |
359 | | |
360 | | // Applies a function to every element of the tuple. The order is the |
361 | | // declaration order, so first the function will be applied to element 0, |
362 | | // then element 1, then element 2, and so on, where element N is identified |
363 | | // by get<N> |
364 | | // |
365 | | // (Does nothing when invoked on empty tuple) |
366 | | template <class F> |
367 | | constexpr void for_each(F&&) const noexcept |
368 | | {} |
369 | | |
370 | | // Applies a function to each element successively, until one returns a |
371 | | // truthy value. Returns true if any application returned a truthy value, |
372 | | // and false otherwise |
373 | | // |
374 | | // (Returns false for empty tuple) |
375 | | template <class F> |
376 | | constexpr bool any(F&&) const noexcept |
377 | | { |
378 | | return false; |
379 | | } |
380 | | |
381 | | // Applies a function to each element successively, until one returns a |
382 | | // falsy value. Returns true if every application returned a truthy value, |
383 | | // and false otherwise |
384 | | // |
385 | | // (Returns true for empty tuple) |
386 | | template <class F> |
387 | | constexpr bool all(F&&) const noexcept |
388 | | { |
389 | | return true; |
390 | | } |
391 | | }; |
392 | | template <class... Ts> |
393 | | tuple(Ts...) -> tuple<unwrap_ref_decay_t<Ts>...>; |
394 | | |
395 | | // tuplet::convert implementation |
396 | | namespace tuplet |
397 | | { |
398 | | // Converts from one tuple type to any other tuple or U |
399 | | template <class Tuple> |
400 | | struct convert final |
401 | | { |
402 | | using base_list = typename std::decay_t<Tuple>::base_list; |
403 | | Tuple tuple; |
404 | | template <class U> |
405 | | constexpr operator U() && |
406 | | { |
407 | | return convert_impl<U>(base_list{}); |
408 | | } |
409 | | |
410 | | private: |
411 | | template <class U, class... Bases> |
412 | | constexpr U convert_impl(type_list<Bases...>) |
413 | | { |
414 | | return U{static_cast<Tuple&&>(tuple).identity_t<Bases>::value...}; |
415 | | } |
416 | | }; |
417 | | template <class Tuple> |
418 | | convert(Tuple&) -> convert<Tuple&>; |
419 | | template <class Tuple> |
420 | | convert(const Tuple&) -> convert<const Tuple&>; |
421 | | template <class Tuple> |
422 | | convert(Tuple&&) -> convert<Tuple>; |
423 | | } // namespace tuplet |
424 | | |
425 | | // glz::get implementation |
426 | | // glz::tie implementation |
427 | | // glz::apply implementation |
428 | | template <size_t I, tuplet::indexable Tup> |
429 | | GLZ_ALWAYS_INLINE constexpr decltype(auto) get(Tup&& tup) noexcept |
430 | 16.0k | { |
431 | 16.0k | return static_cast<Tup&&>(tup)[tuplet::tag<I>()]; |
432 | 16.0k | } _ZN3glz3getILm0ETkNS_6tuplet9indexableENS_5tupleIJRNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEESA_RtEEEEEDcOT0_ Line | Count | Source | 430 | 2.41k | { | 431 | 2.41k | return static_cast<Tup&&>(tup)[tuplet::tag<I>()]; | 432 | 2.41k | } |
_ZN3glz3getILm1ETkNS_6tuplet9indexableENS_5tupleIJRNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEESA_RtEEEEEDcOT0_ Line | Count | Source | 430 | 4.02k | { | 431 | 4.02k | return static_cast<Tup&&>(tup)[tuplet::tag<I>()]; | 432 | 4.02k | } |
_ZN3glz3getILm2ETkNS_6tuplet9indexableENS_5tupleIJRNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEESA_RtEEEEEDcOT0_ Line | Count | Source | 430 | 9.59k | { | 431 | 9.59k | return static_cast<Tup&&>(tup)[tuplet::tag<I>()]; | 432 | 9.59k | } |
Unexecuted instantiation: _ZN3glz3getILm0ETkNS_6tuplet9indexableENS_5tupleIJRKiEEEEEDcOT0_ Unexecuted instantiation: _ZN3glz3getILm0ETkNS_6tuplet9indexableENS_5tupleIJRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEESB_RKtEEEEEDcOT0_ Unexecuted instantiation: _ZN3glz3getILm1ETkNS_6tuplet9indexableENS_5tupleIJRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEESB_RKtEEEEEDcOT0_ Unexecuted instantiation: _ZN3glz3getILm2ETkNS_6tuplet9indexableENS_5tupleIJRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEESB_RKtEEEEEDcOT0_ |
433 | | |
434 | | #if defined(__clang__) |
435 | | #pragma clang diagnostic push |
436 | | #pragma clang diagnostic ignored "-Wmissing-braces" |
437 | | #endif |
438 | | template <class... T> |
439 | | constexpr tuple<T&...> tie(T&... t) |
440 | 16.0k | { |
441 | 16.0k | return {t...}; |
442 | 16.0k | } glz::tuple<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, unsigned short&> glz::tie<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, unsigned short>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, unsigned short&) Line | Count | Source | 440 | 16.0k | { | 441 | 16.0k | return {t...}; | 442 | 16.0k | } |
Unexecuted instantiation: glz::tuple<int const&> glz::tie<int const>(int const&) Unexecuted instantiation: glz::tuple<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned short const&> glz::tie<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, unsigned short const>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned short const&) |
443 | | #if defined(__clang__) |
444 | | #pragma clang diagnostic pop |
445 | | #endif |
446 | | |
447 | | template <class F, tuplet::base_list_tuple Tup> |
448 | | constexpr decltype(auto) apply(F&& func, Tup&& tup) |
449 | | { |
450 | | return tuplet::apply_impl(static_cast<F&&>(func), static_cast<Tup&&>(tup), |
451 | | typename std::decay_t<Tup>::base_list()); |
452 | | } |
453 | | |
454 | | // tuplet::tuple_cat implementation |
455 | | // tuplet::make_tuple implementation |
456 | | // tuplet::forward_as_tuple implementation |
457 | | namespace tuplet |
458 | | { |
459 | | template <base_list_tuple... T> |
460 | | constexpr auto tuple_cat(T&&... ts) |
461 | | { |
462 | | if constexpr (sizeof...(T) == 0) { |
463 | | return tuple<>(); |
464 | | } |
465 | | else { |
466 | | /** |
467 | | * It appears that Clang produces better assembly when |
468 | | * TUPLET_CAT_BY_FORWARDING_TUPLE == 0, while GCC produces better assembly when |
469 | | * TUPLET_CAT_BY_FORWARDING_TUPLE == 1. MSVC always produces terrible assembly |
470 | | * in either case. This will set TUPLET_CAT_BY_FORWARDING_TUPLE to the correct |
471 | | * value (0 for clang, 1 for everyone else) |
472 | | * |
473 | | * See: https://github.com/codeinred/tuplet/discussions/14 |
474 | | */ |
475 | | #if !defined(TUPLET_CAT_BY_FORWARDING_TUPLE) |
476 | | #if defined(__clang__) |
477 | | #define TUPLET_CAT_BY_FORWARDING_TUPLE 0 |
478 | | #else |
479 | | #define TUPLET_CAT_BY_FORWARDING_TUPLE 1 |
480 | | #endif |
481 | | #endif |
482 | | #if TUPLET_CAT_BY_FORWARDING_TUPLE |
483 | | using big_tuple = tuple<T&&...>; |
484 | | #else |
485 | | using big_tuple = tuple<std::decay_t<T>...>; |
486 | | #endif |
487 | | using outer_bases = base_list_t<big_tuple>; |
488 | | constexpr auto outer = get_outer_bases(outer_bases{}); |
489 | | constexpr auto inner = get_inner_bases(outer_bases{}); |
490 | | return cat_impl(big_tuple{{{std::forward<T>(ts)}...}}, outer, inner); |
491 | | } |
492 | | } |
493 | | |
494 | | template <typename... Ts> |
495 | | constexpr auto make_tuple(Ts&&... args) |
496 | | { |
497 | | return tuple<unwrap_ref_decay_t<Ts>...>{{{std::forward<Ts>(args)}...}}; |
498 | | } |
499 | | |
500 | | template <typename... T> |
501 | | constexpr auto forward_as_tuple(T&&... a) noexcept |
502 | | { |
503 | | return tuple<T&&...>{static_cast<T&&>(a)...}; |
504 | | } |
505 | | } // namespace tuplet |
506 | | } // namespace glz |
507 | | |
508 | | #include <array> |
509 | | #include <tuple> |
510 | | #include <variant> |
511 | | |
512 | | namespace glz |
513 | | { |
514 | | template <class... T> |
515 | | struct tuple_size; |
516 | | |
517 | | template <class T> |
518 | | constexpr size_t tuple_size_v = tuple_size<std::remove_const_t<T>>::value; |
519 | | |
520 | | template <class T, size_t N> |
521 | | struct tuple_size<std::array<T, N>> |
522 | | { |
523 | | static constexpr size_t value = N; |
524 | | }; |
525 | | |
526 | | template <class... Types> |
527 | | struct tuple_size<std::tuple<Types...>> |
528 | | { |
529 | | static constexpr size_t value = sizeof...(Types); |
530 | | }; |
531 | | |
532 | | template <size_t I, class... T> |
533 | | struct tuple_element; |
534 | | |
535 | | template <size_t I, class Tuple> |
536 | | using tuple_element_t = typename tuple_element<I, Tuple>::type; |
537 | | |
538 | | template <size_t I, class... T> |
539 | | struct tuple_element<I, std::tuple<T...>> |
540 | | { |
541 | | using type = typename std::tuple_element<I, std::tuple<T...>>::type; |
542 | | }; |
543 | | |
544 | | template <std::size_t I, typename T1, typename T2> |
545 | | struct tuple_element<I, std::pair<T1, T2>> |
546 | | { |
547 | | using type = typename std::conditional<I == 0, T1, T2>::type; |
548 | | }; |
549 | | |
550 | | template <class... T> |
551 | | struct tuple_size<glz::tuple<T...>> : std::integral_constant<size_t, sizeof...(T)> |
552 | | {}; |
553 | | |
554 | | template <size_t I, class... T> |
555 | | struct tuple_element<I, glz::tuple<T...>> |
556 | | { |
557 | | using type = decltype(glz::tuple<T...>::decl_elem(glz::tuplet::tag<I>())); |
558 | | }; |
559 | | } |