vari
Loading...
Searching...
No Matches
util.h
1
23
24#pragma once
25
26#include "vari/bits/typelist.h"
27
28#include <algorithm>
29#include <bit>
30#include <cstdint>
31#include <limits>
32#include <memory>
33#include <utility>
34
35namespace vari
36{
37
38struct empty_t
39{
40};
41
42static constexpr empty_t empty;
43
44
45template < template < typename... > typename T, typename TL, typename... Us >
46struct _vptr_apply;
47
48template < template < typename... > typename T, typename... Ts, typename... Us >
49struct _vptr_apply< T, typelist< Ts... >, Us... >
50{
51 using type = T< Us..., Ts... >;
52};
53
54template < template < typename... > typename T, typename TL, typename... Us >
55using _vptr_apply_t = typename _vptr_apply< T, TL, Us... >::type;
56
60template < template < typename... > typename T, typename TL, typename... Extra >
61using _define_variadic = _vptr_apply_t< T, unique_typelist_t< flatten_t< TL > >, Extra... >;
62
63template < typename F, typename... Args >
64concept invocable = requires( F&& f, Args&&... args ) { ( (F&&) f )( (Args&&) args... ); };
65
66// XXX: test
67template < typename U >
68concept _forward_nothrow_constructible =
69 ( std::is_lvalue_reference_v< U > ?
70 std::is_nothrow_copy_constructible_v< std::remove_reference_t< U > > :
71 std::is_nothrow_move_constructible_v< U > );
72
73template < typename T, typename... Fs >
74concept invocable_for_one = ( (+invocable< Fs, T >) +... ) == 1;
75
76template < typename F, typename... Ts >
77concept invocable_with_any = ( invocable< F, Ts > || ... || false );
78
79template < typename Deleter, typename... Ts >
80struct _uvref;
81
82template < typename T >
83struct _check_unique_invocability;
84
85template < typename... Ts >
86struct _check_unique_invocability< typelist< Ts... > >
87{
88 template < typename... Fs >
89 struct with_pure_value
90 {
91 static_assert(
92 ( invocable_for_one< Ts, Fs... > && ... ),
93 "For each type, there has to be one and only one callable" );
94 static_assert(
95 ( invocable_with_any< Fs, Ts... > && ... ),
96 "For each function, there has to be at least one type it is invocable with" );
97 };
98
99 template < typename... Fs >
100 struct with_pure_ref
101 {
102 static_assert(
103 ( invocable_for_one< Ts&, Fs... > && ... ),
104 "For each type, there has to be one and only one callable" );
105 static_assert(
106 ( invocable_with_any< Fs, Ts&... > && ... ),
107 "For each function, there has to be at least one type it is invocable with" );
108 };
109
110 template < typename... Fs >
111 struct with_nullable_pure_ref
112 {
113 static_assert(
114 (invocable_for_one< Ts&, Fs... > && ... && invocable_for_one< empty_t, Fs... >),
115 "For each type, there has to be one and only one callable" );
116 static_assert(
117 ( invocable_with_any< Fs, empty_t, Ts&... > && ... ),
118 "For each function, there has to be at least one type it is invocable with" );
119 };
120
121 template < typename... Fs >
122 struct with_pure_cref
123 {
124 static_assert(
125 ( invocable_for_one< Ts const&, Fs... > && ... ),
126 "For each type, there has to be one and only one callable" );
127 static_assert(
128 ( invocable_with_any< Fs, Ts const&... > && ... ),
129 "For each function, there has to be at least one type it is invocable with" );
130 };
131
132 template < typename... Fs >
133 struct with_nullable_pure_cref
134 {
135 static_assert(
136 (invocable_for_one< Ts const&, Fs... > && ... &&
137 invocable_for_one< empty_t, Fs... >),
138 "For each type, there has to be one and only one callable" );
139 static_assert(
140 ( invocable_with_any< Fs, empty_t, Ts const&... > && ... ),
141 "For each function, there has to be at least one type it is invocable with" );
142 };
143
144 template < typename Deleter >
145 struct with_deleter
146 {
147 template < typename... Fs >
148 struct with_uvref
149 {
150 static_assert(
151 ( invocable_for_one< _uvref< Deleter, Ts >, Fs... > && ... ),
152 "For each type, there has to be one and only one callable" );
153 static_assert(
154 ( invocable_with_any< Fs, _uvref< Deleter, Ts >... > && ... ),
155 "For each function, there has to be at least one type it is invocable with" );
156 };
157
158 template < typename... Fs >
159 struct with_nullable_uvref
160 {
161 static_assert(
162 (invocable_for_one< _uvref< Deleter, Ts >, Fs... > && ... &&
163 invocable_for_one< empty_t, Fs... >),
164 "For each type, there has to be one and only one callable" );
165 static_assert(
166 ( invocable_with_any< Fs, empty_t, _uvref< Deleter, Ts >... > && ... ),
167 "For each function, there has to be at least one type it is invocable with" );
168 };
169 };
170};
171
172template < typename... Args >
173struct _function_picker
174{
175 template < typename F, typename... Fs >
176 static constexpr decltype( auto ) pick( F&& f, Fs&&... fs )
177 {
178 if constexpr ( invocable< F, Args... > ) {
179 return (F&&) f;
180 } else {
181 static_assert( sizeof...( fs ) != 0 );
182 return pick( (Fs&&) fs... );
183 }
184 }
185};
186
187using index_type = uint32_t;
188static constexpr auto null_index = std::numeric_limits< index_type >::max();
189
190template < typename TL, typename UL >
191struct _vptr_cnv_map;
192
193template < typename TL, typename... Us >
194struct _vptr_cnv_map< TL, typelist< Us... > >
195{
196 static constexpr index_type conv( std::size_t i )
197 {
198 return i == null_index ? null_index : value[i];
199 }
200
201private:
202 static constexpr index_type value[sizeof...( Us )] = {
203 index_of_t_or_const_t_v< Us, TL >... };
204};
205
206template < typename UL, typename TL >
207struct _split_impl;
208
209template < typename... Us, typename T, typename... Ts >
210 requires( sizeof...( Us ) < sizeof...( Ts ) )
211struct _split_impl< typelist< Us... >, typelist< T, Ts... > >
212{
213 using sub = _split_impl< typelist< Us..., T >, typelist< Ts... > >;
214 using lh = typename sub::lh;
215 using rh = typename sub::rh;
216};
217
218template < typename... Us, typename T, typename... Ts >
219 requires( sizeof...( Us ) >= sizeof...( Ts ) )
220struct _split_impl< typelist< Us... >, typelist< T, Ts... > >
221{
222 using lh = typelist< Us... >;
223 using rh = typelist< T, Ts... >;
224};
225
226template <>
227struct _split_impl< typelist<>, typelist<> >
228{
229 using lh = typelist<>;
230 using rh = typelist<>;
231};
232
233template < typename TL >
234using split = _split_impl< typelist<>, TL >;
235
236template < typename Deleter >
237struct _deleter_box;
238
239template < typename Deleter >
240 requires( !std::is_lvalue_reference_v< Deleter > )
241struct _deleter_box< Deleter > : private Deleter
242{
243 constexpr _deleter_box() noexcept = default;
244
245 constexpr _deleter_box( Deleter&& d ) noexcept
246 : Deleter( std::move( d ) )
247 {
248 static_assert( std::is_nothrow_move_constructible_v< Deleter > );
249 }
250
251 constexpr Deleter& get() noexcept
252 {
253 return *this;
254 }
255
256 friend constexpr void swap( _deleter_box& lh, _deleter_box& rh ) noexcept
257 {
258 using std::swap;
259 swap( (Deleter&) lh, (Deleter&) rh );
260 }
261
262 friend constexpr auto operator<=>( _deleter_box const&, _deleter_box const& ) = default;
263};
264
265template < typename Deleter >
266 requires( std::is_lvalue_reference_v< Deleter& > )
267struct _deleter_box< Deleter& >
268{
269 constexpr _deleter_box() noexcept = delete;
270
271 constexpr _deleter_box( Deleter& d ) noexcept
272 : _del_ref( &d )
273 {
274 }
275
276 constexpr Deleter& get() noexcept
277 {
278 return *_del_ref;
279 }
280
281 friend constexpr void swap( _deleter_box& lh, _deleter_box& rh ) noexcept
282 {
283 using std::swap;
284 swap( lh._del_ref, rh._del_ref );
285 }
286
287 friend constexpr auto operator<=>( _deleter_box const&, _deleter_box const& ) = default;
288
289private:
290 Deleter* _del_ref;
291};
292
293template < std::size_t Align >
294constexpr std::intptr_t hash_ptr( void* p )
295{
296 return (std::intptr_t) ( p ) >> std::bit_width( Align );
297}
298
299} // namespace vari
300
301#define VARI_GET_PTR_HASH_SPECIALIZATION( TYPE ) \
302 template < typename... Ts > \
303 struct std::hash< TYPE< Ts... > > \
304 { \
305 std::size_t operator()( TYPE< Ts... > const& r ) const \
306 { \
307 return vari::hash_ptr< std::min( { alignof( Ts )... } ) >( r.get() ); \
308 } \
309 }
310
311#define VARI_REC_GET_HASH_SPECIALIZATION( TYPE ) \
312 template < typename... Ts > \
313 struct std::hash< TYPE< Ts... > > \
314 { \
315 std::size_t operator()( TYPE< Ts... > const& r ) const \
316 { \
317 auto x = r.get(); \
318 return std::hash< decltype( x ) >()( x ); \
319 } \
320 }
MIT License.
Definition: dispatch.h:32
_vptr_apply_t< T, unique_typelist_t< flatten_t< TL > >, Extra... > _define_variadic
Given a templated type T and typelist of types TL, aliases T<Us...> where Us... is flattend version o...
Definition: util.h:61