]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | // Derived from: | |
5 | /* uses_allocator.h -*-C++-*- | |
6 | * | |
7 | * Copyright (C) 2016 Pablo Halpern <phalpern@halpernwightsoftware.com> | |
8 | * Distributed under the Boost Software License - Version 1.0 | |
9 | */ | |
10 | // Downloaded from https://github.com/phalpern/uses-allocator.git | |
11 | ||
12 | #pragma once | |
13 | ||
14 | #include <memory> | |
15 | #include <tuple> | |
16 | #include <type_traits> | |
17 | #include <utility> | |
18 | ||
19 | namespace ceph { | |
20 | ||
21 | namespace internal { | |
22 | template <class T, class Tuple, std::size_t... Indexes> | |
23 | T make_from_tuple_imp(Tuple&& t, std::index_sequence<Indexes...>) | |
24 | { | |
25 | return T(std::get<Indexes>(std::forward<Tuple>(t))...); | |
26 | } | |
27 | } // namespace internal | |
28 | ||
29 | template<class T, class Tuple> | |
30 | T make_from_tuple(Tuple&& args_tuple) | |
31 | { | |
32 | using namespace internal; | |
33 | using Indices = std::make_index_sequence<std::tuple_size_v< | |
34 | std::decay_t<Tuple>>>; | |
35 | return make_from_tuple_imp<T>(std::forward<Tuple>(args_tuple), Indices{}); | |
36 | } | |
37 | ||
38 | //////////////////////////////////////////////////////////////////////// | |
39 | ||
40 | // Forward declaration | |
41 | template <class T, class Alloc, class... Args> | |
42 | auto uses_allocator_construction_args(const Alloc& a, Args&&... args); | |
43 | ||
44 | namespace internal { | |
45 | ||
46 | template <class T, class A> | |
47 | struct has_allocator : std::uses_allocator<T, A> { }; | |
48 | ||
49 | // Specialization of `has_allocator` for `std::pair` | |
50 | template <class T1, class T2, class A> | |
51 | struct has_allocator<std::pair<T1, T2>, A> | |
52 | : std::integral_constant<bool, has_allocator<T1, A>::value || | |
53 | has_allocator<T2, A>::value> | |
54 | { | |
55 | }; | |
56 | ||
57 | template <bool V> using boolean_constant = std::integral_constant<bool, V>; | |
58 | ||
59 | template <class T> struct is_pair : std::false_type { }; | |
60 | ||
61 | template <class T1, class T2> | |
62 | struct is_pair<std::pair<T1, T2>> : std::true_type { }; | |
63 | ||
64 | // Return a tuple of arguments appropriate for uses-allocator construction | |
65 | // with allocator `Alloc` and ctor arguments `Args`. | |
66 | // This overload is handles types for which `has_allocator<T, Alloc>` is false. | |
67 | template <class T, class Unused1, class Unused2, class Alloc, class... Args> | |
68 | auto uses_allocator_args_imp(Unused1 /* is_pair */, | |
69 | std::false_type /* has_allocator */, | |
70 | Unused2 /* uses prefix allocator arg */, | |
71 | const Alloc& /* ignored */, | |
72 | Args&&... args) | |
73 | { | |
74 | // Allocator is ignored | |
75 | return std::forward_as_tuple(std::forward<Args>(args)...); | |
76 | } | |
77 | ||
78 | // Return a tuple of arguments appropriate for uses-allocator construction | |
79 | // with allocator `Alloc` and ctor arguments `Args`. | |
80 | // This overload handles non-pair `T` for which `has_allocator<T, Alloc>` is | |
81 | // true and constructor `T(allocator_arg_t, a, args...)` is valid. | |
82 | template <class T, class Alloc, class... Args> | |
83 | auto uses_allocator_args_imp(std::false_type /* is_pair */, | |
84 | std::true_type /* has_allocator */, | |
85 | std::true_type /* uses prefix allocator arg */, | |
86 | const Alloc& a, | |
87 | Args&&... args) | |
88 | { | |
89 | // Allocator added to front of argument list, after `allocator_arg`. | |
90 | return std::tuple<std::allocator_arg_t, const Alloc&, | |
91 | Args&&...>(std::allocator_arg, a, std::forward<Args>(args)...); | |
92 | } | |
93 | ||
94 | // Return a tuple of arguments appropriate for uses-allocator construction | |
95 | // with allocator `Alloc` and ctor arguments `Args`. | |
96 | // This overload handles non-pair `T` for which `has_allocator<T, Alloc>` is | |
97 | // true and constructor `T(allocator_arg_t, a, args...)` NOT valid. | |
98 | // This function will produce invalid results unless `T(args..., a)` is valid. | |
99 | template <class T1, class Alloc, class... Args> | |
100 | auto uses_allocator_args_imp(std::false_type /* is_pair */, | |
101 | std::true_type /* has_allocator */, | |
102 | std::false_type /* prefix allocator arg */, | |
103 | const Alloc& a, | |
104 | Args&&... args) | |
105 | { | |
106 | // Allocator added to end of argument list | |
107 | return std::forward_as_tuple(std::forward<Args>(args)..., a); | |
108 | } | |
109 | ||
110 | // Return a tuple of arguments appropriate for uses-allocator construction | |
111 | // with allocator `Alloc` and ctor arguments `Args`. | |
112 | // This overload handles specializations of `T` = `std::pair` for which | |
113 | // `has_allocator<T, Alloc>` is true for either or both of the elements and | |
114 | // piecewise_construct arguments are passed in. | |
115 | template <class T, class Alloc, class Tuple1, class Tuple2> | |
116 | auto uses_allocator_args_imp(std::true_type /* is_pair */, | |
117 | std::true_type /* has_allocator */, | |
118 | std::false_type /* prefix allocator arg */, | |
119 | const Alloc& a, | |
120 | std::piecewise_construct_t, | |
121 | Tuple1&& x, Tuple2&& y) | |
122 | { | |
123 | using T1 = typename T::first_type; | |
124 | using T2 = typename T::second_type; | |
125 | ||
126 | return std::make_tuple( | |
127 | std::piecewise_construct, | |
128 | std::apply([&a](auto&&... args1) -> auto { | |
129 | return uses_allocator_construction_args<T1>( | |
130 | a, std::forward<decltype(args1)>(args1)...); | |
131 | }, std::forward<Tuple1>(x)), | |
132 | std::apply([&a](auto&&... args2) -> auto { | |
133 | return uses_allocator_construction_args<T2>( | |
134 | a, std::forward<decltype(args2)>(args2)...); | |
135 | }, std::forward<Tuple2>(y)) | |
136 | ); | |
137 | } | |
138 | ||
139 | // Return a tuple of arguments appropriate for uses-allocator construction | |
140 | // with allocator `Alloc` and ctor arguments `Args`. | |
141 | // This overload handles specializations of `T` = `std::pair` for which | |
142 | // `has_allocator<T, Alloc>` is true for either or both of the elements and | |
143 | // no other constructor arguments are passed in. | |
144 | template <class T, class Alloc> | |
145 | auto uses_allocator_args_imp(std::true_type /* is_pair */, | |
146 | std::true_type /* has_allocator */, | |
147 | std::false_type /* prefix allocator arg */, | |
148 | const Alloc& a) | |
149 | { | |
150 | // using T1 = typename T::first_type; | |
151 | // using T2 = typename T::second_type; | |
152 | ||
153 | // return std::make_tuple( | |
154 | // piecewise_construct, | |
155 | // uses_allocator_construction_args<T1>(a), | |
156 | // uses_allocator_construction_args<T2>(a)); | |
157 | return uses_allocator_construction_args<T>(a, std::piecewise_construct, | |
158 | std::tuple<>{}, std::tuple<>{}); | |
159 | } | |
160 | ||
161 | // Return a tuple of arguments appropriate for uses-allocator construction | |
162 | // with allocator `Alloc` and ctor arguments `Args`. | |
163 | // This overload handles specializations of `T` = `std::pair` for which | |
164 | // `has_allocator<T, Alloc>` is true for either or both of the elements and | |
165 | // a single argument of type const-lvalue-of-pair is passed in. | |
166 | template <class T, class Alloc, class U1, class U2> | |
167 | auto uses_allocator_args_imp(std::true_type /* is_pair */, | |
168 | std::true_type /* has_allocator */, | |
169 | std::false_type /* prefix allocator arg */, | |
170 | const Alloc& a, | |
171 | const std::pair<U1, U2>& arg) | |
172 | { | |
173 | // using T1 = typename T::first_type; | |
174 | // using T2 = typename T::second_type; | |
175 | ||
176 | // return std::make_tuple( | |
177 | // piecewise_construct, | |
178 | // uses_allocator_construction_args<T1>(a, arg.first), | |
179 | // uses_allocator_construction_args<T2>(a, arg.second)); | |
180 | return uses_allocator_construction_args<T>(a, std::piecewise_construct, | |
181 | std::forward_as_tuple(arg.first), | |
182 | std::forward_as_tuple(arg.second)); | |
183 | } | |
184 | ||
185 | // Return a tuple of arguments appropriate for uses-allocator construction | |
186 | // with allocator `Alloc` and ctor arguments `Args`. | |
187 | // This overload handles specializations of `T` = `std::pair` for which | |
188 | // `has_allocator<T, Alloc>` is true for either or both of the elements and | |
189 | // a single argument of type rvalue-of-pair is passed in. | |
190 | template <class T, class Alloc, class U1, class U2> | |
191 | auto uses_allocator_args_imp(std::true_type /* is_pair */, | |
192 | std::true_type /* has_allocator */, | |
193 | std::false_type /* prefix allocator arg */, | |
194 | const Alloc& a, | |
195 | std::pair<U1, U2>&& arg) | |
196 | { | |
197 | // using T1 = typename T::first_type; | |
198 | // using T2 = typename T::second_type; | |
199 | ||
200 | // return std::make_tuple( | |
201 | // piecewise_construct, | |
202 | // uses_allocator_construction_args<T1>(a, forward<U1>(arg.first)), | |
203 | // uses_allocator_construction_args<T2>(a, forward<U2>(arg.second))); | |
204 | return uses_allocator_construction_args<T>(a, std::piecewise_construct, | |
205 | std::forward_as_tuple(std::forward<U1>(arg.first)), | |
206 | std::forward_as_tuple(std::forward<U2>(arg.second))); | |
207 | } | |
208 | ||
209 | // Return a tuple of arguments appropriate for uses-allocator construction | |
210 | // with allocator `Alloc` and ctor arguments `Args`. | |
211 | // This overload handles specializations of `T` = `std::pair` for which | |
212 | // `has_allocator<T, Alloc>` is true for either or both of the elements and | |
213 | // two additional constructor arguments are passed in. | |
214 | template <class T, class Alloc, class U1, class U2> | |
215 | auto uses_allocator_args_imp(std::true_type /* is_pair */, | |
216 | std::true_type /* has_allocator */, | |
217 | std::false_type /* prefix allocator arg */, | |
218 | const Alloc& a, | |
219 | U1&& arg1, U2&& arg2) | |
220 | { | |
221 | // using T1 = typename T::first_type; | |
222 | // using T2 = typename T::second_type; | |
223 | ||
224 | // return std::make_tuple( | |
225 | // piecewise_construct, | |
226 | // uses_allocator_construction_args<T1>(a, forward<U1>(arg1)), | |
227 | // uses_allocator_construction_args<T2>(a, forward<U2>(arg2))); | |
228 | return uses_allocator_construction_args<T>( | |
229 | a, std::piecewise_construct, | |
230 | std::forward_as_tuple(std::forward<U1>(arg1)), | |
231 | std::forward_as_tuple(std::forward<U2>(arg2))); | |
232 | } | |
233 | ||
234 | } // close namespace internal | |
235 | ||
236 | template <class T, class Alloc, class... Args> | |
237 | auto uses_allocator_construction_args(const Alloc& a, Args&&... args) | |
238 | { | |
239 | using namespace internal; | |
240 | return uses_allocator_args_imp<T>(is_pair<T>(), | |
241 | has_allocator<T, Alloc>(), | |
242 | std::is_constructible<T, std::allocator_arg_t, | |
243 | Alloc, Args...>(), | |
244 | a, std::forward<Args>(args)...); | |
245 | } | |
246 | ||
247 | template <class T, class Alloc, class... Args> | |
248 | T make_obj_using_allocator(const Alloc& a, Args&&... args) | |
249 | { | |
250 | return make_from_tuple<T>( | |
251 | uses_allocator_construction_args<T>(a, std::forward<Args>(args)...)); | |
252 | } | |
253 | ||
254 | template <class T, class Alloc, class... Args> | |
255 | T* uninitialized_construct_using_allocator(T* p, | |
256 | const Alloc& a, | |
257 | Args&&... args) | |
258 | { | |
259 | return std::apply([p](auto&&... args2){ | |
260 | return ::new(static_cast<void*>(p)) | |
261 | T(std::forward<decltype(args2)>(args2)...); | |
262 | }, uses_allocator_construction_args<T>( | |
263 | a, std::forward<Args>(args)...)); | |
264 | } | |
265 | ||
266 | } // namespace ceph |