]> git.proxmox.com Git - ceph.git/blame - ceph/src/include/uses_allocator.h
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / include / uses_allocator.h
CommitLineData
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
19namespace ceph {
20
21namespace internal {
22template <class T, class Tuple, std::size_t... Indexes>
23T 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
29template<class T, class Tuple>
30T 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
41template <class T, class Alloc, class... Args>
42auto uses_allocator_construction_args(const Alloc& a, Args&&... args);
43
44namespace internal {
45
46template <class T, class A>
47struct has_allocator : std::uses_allocator<T, A> { };
48
49// Specialization of `has_allocator` for `std::pair`
50template <class T1, class T2, class A>
51struct 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
57template <bool V> using boolean_constant = std::integral_constant<bool, V>;
58
59template <class T> struct is_pair : std::false_type { };
60
61template <class T1, class T2>
62struct 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.
67template <class T, class Unused1, class Unused2, class Alloc, class... Args>
68auto 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.
82template <class T, class Alloc, class... Args>
83auto 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.
99template <class T1, class Alloc, class... Args>
100auto 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.
115template <class T, class Alloc, class Tuple1, class Tuple2>
116auto 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.
144template <class T, class Alloc>
145auto 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.
166template <class T, class Alloc, class U1, class U2>
167auto 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.
190template <class T, class Alloc, class U1, class U2>
191auto 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.
214template <class T, class Alloc, class U1, class U2>
215auto 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
236template <class T, class Alloc, class... Args>
237auto 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
247template <class T, class Alloc, class... Args>
248T 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
254template <class T, class Alloc, class... Args>
255T* 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