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