• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
9 // UNSUPPORTED: c++03, c++11, c++14
10 
11 // <any>
12 
13 // Check that we're consistently using std::allocator_traits to
14 // allocate/deallocate/construct/destroy objects in std::any.
15 // See https://llvm.org/PR45099 for details.
16 
17 #include <any>
18 #include <cassert>
19 #include <cstddef>
20 #include <memory>
21 #include <type_traits>
22 #include <utility>
23 
24 #include "test_macros.h"
25 
26 
27 // Make sure we don't fit in std::any's SBO
28 struct Large { char big[sizeof(std::any) + 1]; };
29 
30 // Make sure we fit in std::any's SBO
31 struct Small { };
32 
33 bool Large_was_allocated = false;
34 bool Large_was_constructed = false;
35 bool Large_was_destroyed = false;
36 bool Large_was_deallocated = false;
37 
38 bool Small_was_constructed = false;
39 bool Small_was_destroyed = false;
40 
41 namespace std {
42   template <>
43   struct allocator<Large> {
44     using value_type = Large;
45     using size_type = std::size_t;
46     using difference_type = std::ptrdiff_t;
47     using propagate_on_container_move_assignment = std::true_type;
48     using is_always_equal = std::true_type;
49 
allocatestd::allocator50     Large* allocate(std::size_t n) {
51       Large_was_allocated = true;
52       return static_cast<Large*>(::operator new(n * sizeof(Large)));
53     }
54 
55     template <typename ...Args>
constructstd::allocator56     void construct(Large* p, Args&& ...args) {
57       new (p) Large(std::forward<Args>(args)...);
58       Large_was_constructed = true;
59     }
60 
destroystd::allocator61     void destroy(Large* p) {
62       p->~Large();
63       Large_was_destroyed = true;
64     }
65 
deallocatestd::allocator66     void deallocate(Large* p, std::size_t) {
67       Large_was_deallocated = true;
68       return ::operator delete(p);
69     }
70   };
71 
72   template <>
73   struct allocator<Small> {
74     using value_type = Small;
75     using size_type = std::size_t;
76     using difference_type = std::ptrdiff_t;
77     using propagate_on_container_move_assignment = std::true_type;
78     using is_always_equal = std::true_type;
79 
allocatestd::allocator80     Small* allocate(std::size_t) { assert(false); return nullptr; }
81 
82     template <typename ...Args>
constructstd::allocator83     void construct(Small* p, Args&& ...args) {
84       new (p) Small(std::forward<Args>(args)...);
85       Small_was_constructed = true;
86     }
87 
destroystd::allocator88     void destroy(Small* p) {
89       p->~Small();
90       Small_was_destroyed = true;
91     }
92 
deallocatestd::allocator93     void deallocate(Small*, std::size_t) { assert(false); }
94   };
95 } // end namespace std
96 
97 
main(int,char **)98 int main(int, char**) {
99   // Test large types
100   {
101     {
102       std::any a = Large();
103       (void)a;
104 
105       assert(Large_was_allocated);
106       assert(Large_was_constructed);
107     }
108 
109     assert(Large_was_destroyed);
110     assert(Large_was_deallocated);
111   }
112 
113   // Test small types
114   {
115     {
116       std::any a = Small();
117       (void)a;
118 
119       assert(Small_was_constructed);
120     }
121 
122     assert(Small_was_destroyed);
123   }
124 
125   return 0;
126 }
127