blob: f68b842a7080dd1ed29144846da3060ffcca1b44 [file] [log] [blame]
Eric Fiselier257fd692016-05-07 01:04:55 +00001//===----------------------------------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef USES_ALLOC_TYPES_HPP
11#define USES_ALLOC_TYPES_HPP
12
13# include <experimental/memory_resource>
14# include <experimental/utility>
15# include <memory>
16# include <cassert>
17
18#include "test_memory_resource.hpp"
19#include "type_id.h"
20
21// There are two forms of uses-allocator construction:
22// (1) UA_AllocArg: 'T(allocator_arg_t, Alloc const&, Args&&...)'
23// (2) UA_AllocLast: 'T(Args&&..., Alloc const&)'
24// 'UA_None' represents non-uses allocator construction.
25enum class UsesAllocatorType {
26 UA_None = 0,
27 UA_AllocArg = 2,
28 UA_AllocLast = 4
29};
30constexpr UsesAllocatorType UA_None = UsesAllocatorType::UA_None;
31constexpr UsesAllocatorType UA_AllocArg = UsesAllocatorType::UA_AllocArg;
32constexpr UsesAllocatorType UA_AllocLast = UsesAllocatorType::UA_AllocLast;
33
34template <class Alloc, std::size_t N>
35class UsesAllocatorV1;
36 // Implements form (1) of uses-allocator construction from the specified
37 // 'Alloc' type and exactly 'N' additional arguments. It also provides
38 // non-uses allocator construction from 'N' arguments. This test type
39 // blows up when form (2) of uses-allocator is even considered.
40
41template <class Alloc, std::size_t N>
42class UsesAllocatorV2;
43 // Implements form (2) of uses-allocator construction from the specified
44 // 'Alloc' type and exactly 'N' additional arguments. It also provides
45 // non-uses allocator construction from 'N' arguments.
46
47template <class Alloc, std::size_t N>
48class UsesAllocatorV3;
49 // Implements both form (1) and (2) of uses-allocator construction from
50 // the specified 'Alloc' type and exactly 'N' additional arguments. It also
51 // provides non-uses allocator construction from 'N' arguments.
52
53template <class Alloc, std::size_t>
54class NotUsesAllocator;
55 // Implements both form (1) and (2) of uses-allocator construction from
56 // the specified 'Alloc' type and exactly 'N' additional arguments. It also
57 // provides non-uses allocator construction from 'N' arguments. However
58 // 'NotUsesAllocator' never provides a 'allocator_type' typedef so it is
59 // never automatically uses-allocator constructed.
60
61
62template <class ...ArgTypes, class TestType>
63bool checkConstruct(TestType& value, UsesAllocatorType form,
64 typename TestType::CtorAlloc const& alloc)
65 // Check that 'value' was constructed using the specified 'form' of
66 // construction and with the specified 'ArgTypes...'. Additionally
67 // check that 'value' was constructed using the specified 'alloc'.
68{
69 if (form == UA_None) {
70 return value.template checkConstruct<ArgTypes&&...>(form);
71 } else {
72 return value.template checkConstruct<ArgTypes&&...>(form, alloc);
73 }
74}
75
76
77template <class ...ArgTypes, class TestType>
78bool checkConstruct(TestType& value, UsesAllocatorType form) {
79 return value.template checkConstruct<ArgTypes&&...>(form);
80}
81
82template <class TestType>
83bool checkConstructionEquiv(TestType& T, TestType& U)
84 // check that 'T' and 'U' where initialized in the exact same manner.
85{
86 return T.checkConstructEquiv(U);
87}
88
89////////////////////////////////////////////////////////////////////////////////
90namespace detail {
91
92template <bool IsZero, size_t N, class ArgList, class ...Args>
93struct TakeNImp;
94
95template <class ArgList, class ...Args>
96struct TakeNImp<true, 0, ArgList, Args...> {
97 typedef ArgList type;
98};
99
100template <size_t N, class ...A1, class F, class ...R>
101struct TakeNImp<false, N, ArgumentListID<A1...>, F, R...>
102 : TakeNImp<N-1 == 0, N - 1, ArgumentListID<A1..., F>, R...> {};
103
104template <size_t N, class ...Args>
105struct TakeNArgs : TakeNImp<N == 0, N, ArgumentListID<>, Args...> {};
106
107template <class T>
108struct Identity { typedef T type; };
109
110template <class T>
111using IdentityT = typename Identity<T>::type;
112
113template <bool Value>
114using EnableIfB = typename std::enable_if<Value, bool>::type;
115
116} // end namespace detail
117
118using detail::EnableIfB;
119
120struct AllocLastTag {};
121
122template <class Alloc>
123struct UsesAllocatorTestBase {
124public:
125 using CtorAlloc = typename std::conditional<
126 std::is_same<Alloc, std::experimental::erased_type>::value,
127 std::experimental::pmr::memory_resource*,
128 Alloc
129 >::type;
130
131 template <class ...ArgTypes>
132 bool checkConstruct(UsesAllocatorType expectType) const {
133 return expectType == constructor_called &&
134 makeArgumentID<ArgTypes...>() == *args_id;
135 }
136
137 template <class ...ArgTypes>
138 bool checkConstruct(UsesAllocatorType expectType,
139 CtorAlloc const& expectAlloc) const {
140 return expectType == constructor_called &&
141 makeArgumentID<ArgTypes...>() == *args_id &&
142 expectAlloc == allocator;
143 }
144
145 bool checkConstructEquiv(UsesAllocatorTestBase& O) const {
146 return constructor_called == O.constructor_called
147 && *args_id == *O.args_id
148 && allocator == O.allocator;
149 }
150
151protected:
152 explicit UsesAllocatorTestBase(const TypeID* aid)
153 : args_id(aid), constructor_called(UA_None), allocator()
154 {}
155
156 template <class ...Args>
157 UsesAllocatorTestBase(std::allocator_arg_t, CtorAlloc const& a, Args&&...)
158 : args_id(&makeArgumentID<Args&&...>()),
159 constructor_called(UA_AllocArg),
160 allocator(a)
161 {}
162
163 template <class ...Args>
164 UsesAllocatorTestBase(AllocLastTag, Args&&... args)
165 : args_id(nullptr),
166 constructor_called(UA_AllocLast)
167 {
168 typedef typename detail::TakeNArgs<sizeof...(Args) - 1, Args&&...>::type
169 ArgIDL;
170 args_id = &makeTypeID<ArgIDL>();
171 getAllocatorFromPack(ArgIDL{}, std::forward<Args>(args)...);
172 }
173
174private:
175 template <class ...LArgs, class ...Args>
176 void getAllocatorFromPack(ArgumentListID<LArgs...>, Args&&... args) {
177 getAllocatorFromPackImp<LArgs const&...>(args...);
178 }
179
180 template <class ...LArgs>
181 void getAllocatorFromPackImp(typename detail::Identity<LArgs>::type..., CtorAlloc const& alloc) {
182 allocator = alloc;
183 }
184
185 const TypeID* args_id;
186 UsesAllocatorType constructor_called = UA_None;
187 CtorAlloc allocator;
188};
189
190template <class Alloc, size_t Arity>
191class UsesAllocatorV1 : public UsesAllocatorTestBase<Alloc>
192{
193public:
194 typedef Alloc allocator_type;
195
196 using Base = UsesAllocatorTestBase<Alloc>;
197 using CtorAlloc = typename Base::CtorAlloc;
198
199 UsesAllocatorV1() : Base(&makeArgumentID<>()) {}
200
201 // Non-Uses Allocator Ctor
202 template <class ...Args, EnableIfB<sizeof...(Args) == Arity> = false>
203 UsesAllocatorV1(Args&&... args) : Base(&makeArgumentID<Args&&...>()) {};
204
205 // Uses Allocator Arg Ctor
206 template <class ...Args>
207 UsesAllocatorV1(std::allocator_arg_t tag, CtorAlloc const & a, Args&&... args)
208 : Base(tag, a, std::forward<Args>(args)...)
209 { }
210
211 // BLOWS UP: Uses Allocator Last Ctor
212 template <class _First, class ...Args, EnableIfB<sizeof...(Args) == Arity> _Dummy = false>
213 constexpr UsesAllocatorV1(_First&& __first, Args&&... args)
214 {
215 static_assert(!std::is_same<_First, _First>::value, "");
216 }
217};
218
219
220template <class Alloc, size_t Arity>
221class UsesAllocatorV2 : public UsesAllocatorTestBase<Alloc>
222{
223public:
224 typedef Alloc allocator_type;
225
226 using Base = UsesAllocatorTestBase<Alloc>;
227 using CtorAlloc = typename Base::CtorAlloc;
228
229 UsesAllocatorV2() : Base(&makeArgumentID<>()) {}
230
231 // Non-Uses Allocator Ctor
232 template <class ...Args, EnableIfB<sizeof...(Args) == Arity> = false>
233 UsesAllocatorV2(Args&&... args) : Base(&makeArgumentID<Args&&...>()) {};
234
235 // Uses Allocator Last Ctor
236 template <class ...Args, EnableIfB<sizeof...(Args) == Arity + 1> = false>
237 UsesAllocatorV2(Args&&... args)
238 : Base(AllocLastTag{}, std::forward<Args>(args)...)
239 {}
240};
241
242template <class Alloc, size_t Arity>
243class UsesAllocatorV3 : public UsesAllocatorTestBase<Alloc>
244{
245public:
246 typedef Alloc allocator_type;
247
248 using Base = UsesAllocatorTestBase<Alloc>;
249 using CtorAlloc = typename Base::CtorAlloc;
250
251 UsesAllocatorV3() : Base(&makeArgumentID<>()) {}
252
253 // Non-Uses Allocator Ctor
254 template <class ...Args, EnableIfB<sizeof...(Args) == Arity> = false>
255 UsesAllocatorV3(Args&&... args) : Base(&makeArgumentID<Args&&...>()) {};
256
257 // Uses Allocator Arg Ctor
258 template <class ...Args>
259 UsesAllocatorV3(std::allocator_arg_t tag, CtorAlloc const& alloc, Args&&... args)
260 : Base(tag, alloc, std::forward<Args>(args)...)
261 {}
262
263 // Uses Allocator Last Ctor
264 template <class ...Args, EnableIfB<sizeof...(Args) == Arity + 1> = false>
265 UsesAllocatorV3(Args&&... args)
266 : Base(AllocLastTag{}, std::forward<Args>(args)...)
267 {}
268};
269
270template <class Alloc, size_t Arity>
271class NotUsesAllocator : public UsesAllocatorTestBase<Alloc>
272{
273public:
274 // no allocator_type typedef provided
275
276 using Base = UsesAllocatorTestBase<Alloc>;
277 using CtorAlloc = typename Base::CtorAlloc;
278
279 NotUsesAllocator() : Base(&makeArgumentID<>()) {}
280
281 // Non-Uses Allocator Ctor
282 template <class ...Args, EnableIfB<sizeof...(Args) == Arity> = false>
283 NotUsesAllocator(Args&&... args) : Base(&makeArgumentID<Args&&...>()) {};
284
285 // Uses Allocator Arg Ctor
286 template <class ...Args>
287 NotUsesAllocator(std::allocator_arg_t tag, CtorAlloc const& alloc, Args&&... args)
288 : Base(tag, alloc, std::forward<Args>(args)...)
289 {}
290
291 // Uses Allocator Last Ctor
292 template <class ...Args, EnableIfB<sizeof...(Args) == Arity + 1> = false>
293 NotUsesAllocator(Args&&... args)
294 : Base(AllocLastTag{}, std::forward<Args>(args)...)
295 {}
296};
297
298#endif /* USES_ALLOC_TYPES_HPP */