1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 #ifndef SUPPORT_CONTAINER_TEST_TYPES_H
9 #define SUPPORT_CONTAINER_TEST_TYPES_H
10 
11 // container_test_types.h - A set of types used for testing STL containers.
12 // The types container within this header are used to test the requirements in
13 // [container.requirements.general]. The header is made up of 3 main components:
14 //
15 // * test-types: 'CopyInsertable', 'MoveInsertable' and 'EmplaceConstructible' -
16 //    These test types are used to test the container requirements of the same
17 //    name. These test types use the global 'AllocatorConstructController' to
18 //    assert that they are only constructed by the containers allocator.
19 //
20 // * test-allocator: 'ContainerTestAllocator' - This test allocator is used to
21 //    test the portions of [container.requirements.general] that pertain to the
22 //    containers allocator. The three primary jobs of the test allocator are:
23 //      1. Enforce that 'a.construct(...)' and 'a.destroy(...)' are only ever
24 //         instantiated for 'Container::value_type'.
25 //      2. Provide a mechanism of checking calls to 'a.construct(Args...)'.
26 //         Including controlling when and with what types 'a.construct(...)'
27 //         may be called with.
28 //      3. Support the test types internals by controlling the global
29 //        'AllocatorConstructController' object.
30 //
31 // * 'AllocatorConstructController' - This type defines an interface for testing
32 //   the construction of types using an allocator. This type is used to communicate
33 //   between the test author, the containers allocator, and the types
34 //   being constructed by the container.
35 //   The controller's primary functions are:
36 //     1. Allow calls to 'a.construct(p, args...)' to be checked by a test.
37 //        The test uses 'cc->expect<Args...>()' to specify that the allocator
38 //        should expect one call to 'a.construct' with the specified argument
39 //        types.
40 //     2. Controlling the value of 'cc->isInAllocatorConstruct()' within the
41 //        'construct' method. The test-types use this value to assert that
42 //         they are being constructed by the allocator.
43 //
44 //   'AllocatorConstructController' enforces the Singleton pattern since the
45 //    test-types, test-allocator and test need to share the same controller
46 //    object. A pointer to the global controller is returned by
47 //   'getConstructController()'.
48 //
49 //----------------------------------------------------------------------------
50 /*
51  * Usage: The following example checks that 'unordered_map::emplace(Args&&...)'
52  *        with 'Args = [CopyInsertable<1> const&, CopyInsertable<2>&&]'
53  *        calls 'alloc.construct(value_type*, Args&&...)' with the same types.
54  *
55  * // Typedefs for container
56  * using Key = CopyInsertable<1>;
57  * using Value = CopyInsertable<2>;
58  * using ValueTp = std::pair<const Key, Value>;
59  * using Alloc = ContainerTestAllocator<ValueTp, ValueTp>;
60  * using Map = std::unordered_map<Key, Value, std::hash<Key>, std::equal_to<Key>, Alloc>;
61  *
62  * // Get the global controller, reset it, and construct an allocator with
63  * // the controller.
64  * ConstructController* cc = getConstructController();
65  * cc->reset();
66  *
67  * // Create a Map and a Key and Value to insert. Note that the test-allocator
68  * // does not need to be given 'cc'.
69  * Map m;
70  * const Key k(1);
71  * Value v(1);
72  *
73  * // Tell the controller to expect a construction from the specified types.
74  * cc->expect<Key const&, Value&&>();
75  *
76  * // Emplace the objects into the container. 'Alloc.construct(p, UArgs...)'
77  * // will assert 'cc->check<UArgs&&>()' is true which will consume
78  * // the call to 'cc->expect<...>()'.
79  * m.emplace(k, std::move(v));
80  *
81  * // Assert that the "expect" was consumed by a matching "check" call within
82  * // Alloc.
83  * assert(!cc->unexpected());
84  *
85  */
86 
87 #include <functional>
88 #include <cassert>
89 
90 #include "test_macros.h"
91 
92 #if TEST_STD_VER < 11
93 #error This header requires C++11 or greater
94 #endif
95 
96 namespace detail {
97 // TypeID - Represent a unique identifier for a type. TypeID allows equality
98 // comparisons between different types.
99 struct TypeID {
100   friend bool operator==(TypeID const& LHS, TypeID const& RHS)
101   {return LHS.m_id == RHS.m_id; }
102   friend bool operator!=(TypeID const& LHS, TypeID const& RHS)
103   {return LHS.m_id != RHS.m_id; }
104 private:
TypeIDTypeID105   explicit constexpr TypeID(const int* xid) : m_id(xid) {}
106   const int* const m_id;
107   template <class T> friend class TypeInfo;
108 };
109 
110 // TypeInfo - Represent information for the specified type 'T', including a
111 // unique TypeID.
112 template <class T>
113 class TypeInfo {
114 public:
115   typedef T value_type;
116   typedef TypeID ID;
GetID()117   static  ID const& GetID() { static ID id(&dummy_addr); return id; }
118 
119 private:
120   static const int dummy_addr;
121 };
122 
123 template <class L, class R>
124 inline bool operator==(TypeInfo<L> const&, TypeInfo<R> const&)
125 { return std::is_same<L, R>::value; }
126 
127 template <class L, class R>
128 inline bool operator!=(TypeInfo<L> const& lhs, TypeInfo<R> const& rhs)
129 { return !(lhs == rhs); }
130 
131 template <class T>
132 const int TypeInfo<T>::dummy_addr = 42;
133 
134 // makeTypeID - Return the TypeID for the specified type 'T'.
135 template <class T>
makeTypeID()136 inline constexpr TypeID const& makeTypeID() { return TypeInfo<T>::GetID(); }
137 
138 template <class ...Args>
139 struct ArgumentListID {};
140 
141 // makeArgumentID - Create and return a unique identifier for a given set
142 // of arguments.
143 template <class ...Args>
makeArgumentID()144 inline constexpr TypeID const& makeArgumentID() {
145   return makeTypeID<ArgumentListID<Args...>>();
146 }
147 
148 } // namespace detail
149 
150 //===----------------------------------------------------------------------===//
151 //                        AllocatorConstructController
152 //===----------------------------------------------------------------------===//
153 
154 struct AllocatorConstructController {
155   const detail::TypeID* m_expected_args;
156   bool m_allow_constructions;
157   bool m_allow_unchecked;
158   int m_expected_count;
159 
clearAllocatorConstructController160   void clear() {
161     m_expected_args = nullptr;
162     m_expected_count = -1;
163   }
164 
165   // Check for and consume an expected construction added by 'expect'.
166   // Return true if the construction was expected and false otherwise.
167   // This should only be called by 'Allocator.construct'.
checkAllocatorConstructController168   bool check(detail::TypeID const& tid) {
169     if (!m_expected_args) {
170       assert(m_allow_unchecked);
171       return m_allow_unchecked;
172     }
173     bool res = *m_expected_args == tid;
174     if (m_expected_count == -1 || --m_expected_count == -1)
175       m_expected_args = nullptr;
176     return res;
177   }
178 
179   // Return true iff there is an unchecked construction expression.
uncheckedAllocatorConstructController180   bool unchecked() {
181     return m_expected_args != nullptr;
182   }
183 
184   // Expect a call to Allocator::construct with Args that match 'tid'.
expectAllocatorConstructController185   void expect(detail::TypeID const& tid) {
186     assert(!unchecked());
187     m_expected_args = &tid;
188   }
189 
190   template <class ...Args>
191   void expect(int times = 1) {
192     assert(!unchecked());
193     assert(times > 0);
194     m_expected_count = times - 1;
195     m_expected_args = &detail::makeArgumentID<Args...>();
196   }
197   template <class ...Args>
checkAllocatorConstructController198   bool check() {
199     return check(detail::makeArgumentID<Args...>());
200   }
201 
202 
203   // Return true iff the program is currently within a call to "Allocator::construct"
isInAllocatorConstructAllocatorConstructController204   bool isInAllocatorConstruct() const {
205     return m_allow_constructions;
206   }
207 
208   void inAllocatorConstruct(bool value = true) {
209     m_allow_constructions = value;
210   }
211 
212   void allowUnchecked(bool value = true) {
213     m_allow_unchecked = value;
214   }
215 
resetAllocatorConstructController216   void reset() {
217     m_allow_constructions = false;
218     m_expected_args = nullptr;
219     m_allow_unchecked = false;
220     m_expected_count = -1;
221   }
222 
223 private:
224   friend AllocatorConstructController* getConstructController();
AllocatorConstructControllerAllocatorConstructController225   AllocatorConstructController()  { reset(); }
226   AllocatorConstructController(AllocatorConstructController const&);
227   AllocatorConstructController& operator=(AllocatorConstructController const&);
228 };
229 
230 typedef AllocatorConstructController ConstructController;
231 
232 // getConstructController - Return the global allocator construction controller.
getConstructController()233 inline ConstructController* getConstructController() {
234   static ConstructController c;
235   return &c;
236 }
237 
238 template <class ...Args>
239 struct ExpectConstructGuard {
ExpectConstructGuardExpectConstructGuard240   ExpectConstructGuard(int N)  {
241     auto CC = getConstructController();
242     assert(!CC->unchecked());
243     CC->expect<Args...>(N);
244   }
245 
~ExpectConstructGuardExpectConstructGuard246   ~ExpectConstructGuard() {
247     assert(!getConstructController()->unchecked());
248   }
249 };
250 
251 //===----------------------------------------------------------------------===//
252 //                       ContainerTestAllocator
253 //===----------------------------------------------------------------------===//
254 
255 // ContainerTestAllocator - A STL allocator type that only allows 'construct'
256 // and 'destroy' to be called for 'AllowConstructT' types. ContainerTestAllocator
257 // uses the 'AllocatorConstructionController' interface.
258 template <class T, class AllowConstructT>
259 class ContainerTestAllocator
260 {
261   struct InAllocatorConstructGuard {
262     ConstructController *m_cc;
263     bool m_old;
InAllocatorConstructGuardInAllocatorConstructGuard264     InAllocatorConstructGuard(ConstructController* cc) : m_cc(cc) {
265       if (m_cc) {
266         m_old = m_cc->isInAllocatorConstruct();
267         m_cc->inAllocatorConstruct(true);
268       }
269     }
~InAllocatorConstructGuardInAllocatorConstructGuard270     ~InAllocatorConstructGuard() {
271       if (m_cc) m_cc->inAllocatorConstruct(m_old);
272     }
273   private:
274     InAllocatorConstructGuard(InAllocatorConstructGuard const&);
275     InAllocatorConstructGuard& operator=(InAllocatorConstructGuard const&);
276   };
277 
278 public:
279     typedef T value_type;
280 
281     int construct_called;
282     int destroy_called;
283     ConstructController* controller;
284 
ContainerTestAllocator()285     ContainerTestAllocator() TEST_NOEXCEPT
286         : controller(getConstructController()) {}
287 
ContainerTestAllocator(ConstructController * c)288     explicit ContainerTestAllocator(ConstructController* c)
289        : controller(c)
290     {}
291 
292     template <class U>
ContainerTestAllocator(ContainerTestAllocator<U,AllowConstructT> other)293     ContainerTestAllocator(ContainerTestAllocator<U, AllowConstructT> other) TEST_NOEXCEPT
294       : controller(other.controller)
295     {}
296 
allocate(std::size_t n)297     T* allocate(std::size_t n)
298     {
299         return static_cast<T*>(::operator new(n*sizeof(T)));
300     }
301 
deallocate(T * p,std::size_t)302     void deallocate(T* p, std::size_t)
303     {
304         return ::operator delete(static_cast<void*>(p));
305     }
306 
307     template <class Up, class ...Args>
construct(Up * p,Args &&...args)308     void construct(Up* p, Args&&... args) {
309       static_assert((std::is_same<Up, AllowConstructT>::value),
310                     "Only allowed to construct Up");
311       assert(controller->check<Args&&...>());
312       {
313         InAllocatorConstructGuard g(controller);
314         ::new ((void*)p) Up(std::forward<Args>(args)...);
315       }
316     }
317 
318     template <class Up>
destroy(Up * p)319     void destroy(Up* p) {
320       static_assert((std::is_same<Up, AllowConstructT>::value),
321                     "Only allowed to destroy Up");
322       {
323         InAllocatorConstructGuard g(controller);
324         p->~Up();
325       }
326     }
327 
328     friend bool operator==(ContainerTestAllocator, ContainerTestAllocator) {return true;}
329     friend bool operator!=(ContainerTestAllocator x, ContainerTestAllocator y) {return !(x == y);}
330 };
331 
332 
333 namespace test_detail {
334 typedef ContainerTestAllocator<int, int> A1;
335 typedef std::allocator_traits<A1> A1T;
336 typedef ContainerTestAllocator<float, int> A2;
337 typedef std::allocator_traits<A2> A2T;
338 
339 static_assert(std::is_same<A1T::rebind_traits<float>, A2T>::value, "");
340 static_assert(std::is_same<A2T::rebind_traits<int>, A1T>::value, "");
341 } // end namespace test_detail
342 
343 //===----------------------------------------------------------------------===//
344 //  'CopyInsertable', 'MoveInsertable' and 'EmplaceConstructible' test types
345 //===----------------------------------------------------------------------===//
346 
347 template <int Dummy = 0>
348 struct CopyInsertable {
349   int data;
350   mutable bool copied_once;
351   bool constructed_under_allocator;
352 
CopyInsertableCopyInsertable353   explicit CopyInsertable(int val) : data(val), copied_once(false),
354                                      constructed_under_allocator(false) {
355     if (getConstructController()->isInAllocatorConstruct()) {
356       copied_once = true;
357       constructed_under_allocator = true;
358     }
359   }
360 
CopyInsertableCopyInsertable361   CopyInsertable() : data(0), copied_once(false), constructed_under_allocator(true)
362   {
363     assert(getConstructController()->isInAllocatorConstruct());
364   }
365 
CopyInsertableCopyInsertable366   CopyInsertable(CopyInsertable const& other) : data(other.data),
367                                                 copied_once(true),
368                                                 constructed_under_allocator(true) {
369     assert(getConstructController()->isInAllocatorConstruct());
370     assert(other.copied_once == false);
371     other.copied_once = true;
372   }
373 
CopyInsertableCopyInsertable374   CopyInsertable(CopyInsertable& other) : data(other.data), copied_once(true),
375                                           constructed_under_allocator(true) {
376     assert(getConstructController()->isInAllocatorConstruct());
377     assert(other.copied_once == false);
378     other.copied_once = true;
379   }
380 
CopyInsertableCopyInsertable381   CopyInsertable(CopyInsertable&& other) : CopyInsertable(other) {}
382 
383   // Forgive pair for not downcasting this to an lvalue in its constructors.
CopyInsertableCopyInsertable384   CopyInsertable(CopyInsertable const && other) : CopyInsertable(other) {}
385 
386 
387   template <class ...Args>
CopyInsertableCopyInsertable388   CopyInsertable(Args&&...) {
389     assert(false);
390   }
391 
~CopyInsertableCopyInsertable392   ~CopyInsertable() {
393     assert(constructed_under_allocator == getConstructController()->isInAllocatorConstruct());
394   }
395 
resetCopyInsertable396   void reset(int value) {
397     data = value;
398     copied_once = false;
399     constructed_under_allocator = false;
400   }
401 };
402 
403 template <int ID>
404 bool operator==(CopyInsertable<ID> const& L, CopyInsertable<ID> const& R) {
405   return L.data == R.data;
406 }
407 
408 
409 template <int ID>
410 bool operator!=(CopyInsertable<ID> const& L, CopyInsertable<ID> const& R) {
411   return L.data != R.data;
412 }
413 
414 template <int ID>
415 bool operator <(CopyInsertable<ID> const& L, CopyInsertable<ID> const& R) {
416   return L.data < R.data;
417 }
418 
419 
420 #ifdef _LIBCPP_BEGIN_NAMESPACE_STD
421 _LIBCPP_BEGIN_NAMESPACE_STD
422 #else
423 namespace std {
424 #endif
425   template <int ID>
426   struct hash< ::CopyInsertable<ID> > {
427     typedef ::CopyInsertable<ID> argument_type;
428     typedef size_t result_type;
429 
430     size_t operator()(argument_type const& arg) const {
431       return arg.data;
432     }
433   };
434   template <class T, class Alloc>
435   class vector;
436   template <class T, class Alloc>
437   class deque;
438   template <class T, class Alloc>
439   class list;
440   template <class _Key, class _Value, class _Less, class _Alloc>
441   class map;
442   template <class _Key, class _Value, class _Less, class _Alloc>
443   class multimap;
444   template <class _Value, class _Less, class _Alloc>
445   class set;
446   template <class _Value, class _Less, class _Alloc>
447   class multiset;
448   template <class _Key, class _Value, class _Hash, class _Equals, class _Alloc>
449   class unordered_map;
450   template <class _Key, class _Value, class _Hash, class _Equals, class _Alloc>
451   class unordered_multimap;
452   template <class _Value, class _Hash, class _Equals, class _Alloc>
453   class unordered_set;
454   template <class _Value, class _Hash, class _Equals, class _Alloc>
455   class unordered_multiset;
456 
457 #ifdef _LIBCPP_END_NAMESPACE_STD
458 _LIBCPP_END_NAMESPACE_STD
459 #else
460 } // end namespace std
461 #endif
462 
463 // TCT - Test container type
464 namespace TCT {
465 
466 template <class T = CopyInsertable<1>>
467 using vector = std::vector<T, ContainerTestAllocator<T, T> >;
468 template <class T = CopyInsertable<1>>
469 using deque = std::deque<T, ContainerTestAllocator<T, T> >;
470 template <class T = CopyInsertable<1>>
471 using list = std::list<T, ContainerTestAllocator<T, T> >;
472 
473 template <class Key = CopyInsertable<1>, class Value = CopyInsertable<2>,
474           class ValueTp = std::pair<const Key, Value> >
475 using unordered_map =
476       std::unordered_map<Key, Value, std::hash<Key>, std::equal_to<Key>,
477                               ContainerTestAllocator<ValueTp, ValueTp> >;
478 
479 template <class Key = CopyInsertable<1>, class Value = CopyInsertable<2>,
480           class ValueTp = std::pair<const Key, Value> >
481 using map =
482       std::map<Key, Value, std::less<Key>,
483                               ContainerTestAllocator<ValueTp, ValueTp> >;
484 
485 template <class Key = CopyInsertable<1>, class Value = CopyInsertable<2>,
486           class ValueTp = std::pair<const Key, Value> >
487 using unordered_multimap =
488       std::unordered_multimap<Key, Value, std::hash<Key>, std::equal_to<Key>,
489                                    ContainerTestAllocator<ValueTp, ValueTp> >;
490 
491 template <class Key = CopyInsertable<1>, class Value = CopyInsertable<2>,
492           class ValueTp = std::pair<const Key, Value> >
493 using multimap =
494       std::multimap<Key, Value, std::less<Key>,
495                               ContainerTestAllocator<ValueTp, ValueTp> >;
496 
497 template <class Value = CopyInsertable<1> >
498 using unordered_set =
499   std::unordered_set<Value, std::hash<Value>, std::equal_to<Value>,
500                                ContainerTestAllocator<Value, Value> >;
501 
502 template <class Value = CopyInsertable<1> >
503 using set =
504     std::set<Value, std::less<Value>, ContainerTestAllocator<Value, Value> >;
505 
506 template <class Value = CopyInsertable<1> >
507 using unordered_multiset =
508     std::unordered_multiset<Value, std::hash<Value>, std::equal_to<Value>,
509                                     ContainerTestAllocator<Value, Value> >;
510 
511 template <class Value = CopyInsertable<1> >
512 using multiset =
513     std::multiset<Value, std::less<Value>, ContainerTestAllocator<Value, Value> >;
514 
515 } // end namespace TCT
516 
517 #endif // SUPPORT_CONTAINER_TEST_TYPES_H
518