• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "absl/container/internal/container_memory.h"
16 
17 #include <cstdint>
18 #include <tuple>
19 #include <typeindex>
20 #include <typeinfo>
21 #include <utility>
22 
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 #include "absl/container/internal/test_instance_tracker.h"
26 #include "absl/strings/string_view.h"
27 
28 namespace absl {
29 ABSL_NAMESPACE_BEGIN
30 namespace container_internal {
31 namespace {
32 
33 using ::absl::test_internal::CopyableMovableInstance;
34 using ::absl::test_internal::InstanceTracker;
35 using ::testing::_;
36 using ::testing::ElementsAre;
37 using ::testing::Gt;
38 using ::testing::Pair;
39 
TEST(Memory,AlignmentLargerThanBase)40 TEST(Memory, AlignmentLargerThanBase) {
41   std::allocator<int8_t> alloc;
42   void* mem = Allocate<2>(&alloc, 3);
43   EXPECT_EQ(0, reinterpret_cast<uintptr_t>(mem) % 2);
44   memcpy(mem, "abc", 3);
45   Deallocate<2>(&alloc, mem, 3);
46 }
47 
TEST(Memory,AlignmentSmallerThanBase)48 TEST(Memory, AlignmentSmallerThanBase) {
49   std::allocator<int64_t> alloc;
50   void* mem = Allocate<2>(&alloc, 3);
51   EXPECT_EQ(0, reinterpret_cast<uintptr_t>(mem) % 2);
52   memcpy(mem, "abc", 3);
53   Deallocate<2>(&alloc, mem, 3);
54 }
55 
AllocationMap()56 std::map<std::type_index, int>& AllocationMap() {
57   static auto* map = new std::map<std::type_index, int>;
58   return *map;
59 }
60 
61 template <typename T>
62 struct TypeCountingAllocator {
63   TypeCountingAllocator() = default;
64   template <typename U>
TypeCountingAllocatorabsl::container_internal::__anon6d66060e0111::TypeCountingAllocator65   TypeCountingAllocator(const TypeCountingAllocator<U>&) {}  // NOLINT
66 
67   using value_type = T;
68 
allocateabsl::container_internal::__anon6d66060e0111::TypeCountingAllocator69   T* allocate(size_t n, const void* = nullptr) {
70     AllocationMap()[typeid(T)] += n;
71     return std::allocator<T>().allocate(n);
72   }
deallocateabsl::container_internal::__anon6d66060e0111::TypeCountingAllocator73   void deallocate(T* p, std::size_t n) {
74     AllocationMap()[typeid(T)] -= n;
75     return std::allocator<T>().deallocate(p, n);
76   }
77 };
78 
TEST(Memory,AllocateDeallocateMatchType)79 TEST(Memory, AllocateDeallocateMatchType) {
80   TypeCountingAllocator<int> alloc;
81   void* mem = Allocate<1>(&alloc, 1);
82   // Verify that it was allocated
83   EXPECT_THAT(AllocationMap(), ElementsAre(Pair(_, Gt(0))));
84   Deallocate<1>(&alloc, mem, 1);
85   // Verify that the deallocation matched.
86   EXPECT_THAT(AllocationMap(), ElementsAre(Pair(_, 0)));
87 }
88 
89 class Fixture : public ::testing::Test {
90   using Alloc = std::allocator<std::string>;
91 
92  public:
Fixture()93   Fixture() { ptr_ = std::allocator_traits<Alloc>::allocate(*alloc(), 1); }
~Fixture()94   ~Fixture() override {
95     std::allocator_traits<Alloc>::destroy(*alloc(), ptr_);
96     std::allocator_traits<Alloc>::deallocate(*alloc(), ptr_, 1);
97   }
ptr()98   std::string* ptr() { return ptr_; }
alloc()99   Alloc* alloc() { return &alloc_; }
100 
101  private:
102   Alloc alloc_;
103   std::string* ptr_;
104 };
105 
TEST_F(Fixture,ConstructNoArgs)106 TEST_F(Fixture, ConstructNoArgs) {
107   ConstructFromTuple(alloc(), ptr(), std::forward_as_tuple());
108   EXPECT_EQ(*ptr(), "");
109 }
110 
TEST_F(Fixture,ConstructOneArg)111 TEST_F(Fixture, ConstructOneArg) {
112   ConstructFromTuple(alloc(), ptr(), std::forward_as_tuple("abcde"));
113   EXPECT_EQ(*ptr(), "abcde");
114 }
115 
TEST_F(Fixture,ConstructTwoArg)116 TEST_F(Fixture, ConstructTwoArg) {
117   ConstructFromTuple(alloc(), ptr(), std::forward_as_tuple(5, 'a'));
118   EXPECT_EQ(*ptr(), "aaaaa");
119 }
120 
TEST(PairArgs,NoArgs)121 TEST(PairArgs, NoArgs) {
122   EXPECT_THAT(PairArgs(),
123               Pair(std::forward_as_tuple(), std::forward_as_tuple()));
124 }
125 
TEST(PairArgs,TwoArgs)126 TEST(PairArgs, TwoArgs) {
127   EXPECT_EQ(
128       std::make_pair(std::forward_as_tuple(1), std::forward_as_tuple('A')),
129       PairArgs(1, 'A'));
130 }
131 
TEST(PairArgs,Pair)132 TEST(PairArgs, Pair) {
133   EXPECT_EQ(
134       std::make_pair(std::forward_as_tuple(1), std::forward_as_tuple('A')),
135       PairArgs(std::make_pair(1, 'A')));
136 }
137 
TEST(PairArgs,Piecewise)138 TEST(PairArgs, Piecewise) {
139   EXPECT_EQ(
140       std::make_pair(std::forward_as_tuple(1), std::forward_as_tuple('A')),
141       PairArgs(std::piecewise_construct, std::forward_as_tuple(1),
142                std::forward_as_tuple('A')));
143 }
144 
TEST(WithConstructed,Simple)145 TEST(WithConstructed, Simple) {
146   EXPECT_EQ(1, WithConstructed<absl::string_view>(
147                    std::make_tuple(std::string("a")),
148                    [](absl::string_view str) { return str.size(); }));
149 }
150 
151 template <class F, class Arg>
DecomposeValue(std::declval<F> (),std::declval<Arg> ())152 decltype(DecomposeValue(std::declval<F>(), std::declval<Arg>()))
153 DecomposeValueImpl(int, F&& f, Arg&& arg) {
154   return DecomposeValue(std::forward<F>(f), std::forward<Arg>(arg));
155 }
156 
157 template <class F, class Arg>
DecomposeValueImpl(char,F && f,Arg && arg)158 const char* DecomposeValueImpl(char, F&& f, Arg&& arg) {
159   return "not decomposable";
160 }
161 
162 template <class F, class Arg>
163 decltype(DecomposeValueImpl(0, std::declval<F>(), std::declval<Arg>()))
TryDecomposeValue(F && f,Arg && arg)164 TryDecomposeValue(F&& f, Arg&& arg) {
165   return DecomposeValueImpl(0, std::forward<F>(f), std::forward<Arg>(arg));
166 }
167 
TEST(DecomposeValue,Decomposable)168 TEST(DecomposeValue, Decomposable) {
169   auto f = [](const int& x, int&& y) {
170     EXPECT_EQ(&x, &y);
171     EXPECT_EQ(42, x);
172     return 'A';
173   };
174   EXPECT_EQ('A', TryDecomposeValue(f, 42));
175 }
176 
TEST(DecomposeValue,NotDecomposable)177 TEST(DecomposeValue, NotDecomposable) {
178   auto f = [](void*) {
179     ADD_FAILURE() << "Must not be called";
180     return 'A';
181   };
182   EXPECT_STREQ("not decomposable", TryDecomposeValue(f, 42));
183 }
184 
185 template <class F, class... Args>
DecomposePair(std::declval<F> (),std::declval<Args> ()...)186 decltype(DecomposePair(std::declval<F>(), std::declval<Args>()...))
187 DecomposePairImpl(int, F&& f, Args&&... args) {
188   return DecomposePair(std::forward<F>(f), std::forward<Args>(args)...);
189 }
190 
191 template <class F, class... Args>
DecomposePairImpl(char,F && f,Args &&...args)192 const char* DecomposePairImpl(char, F&& f, Args&&... args) {
193   return "not decomposable";
194 }
195 
196 template <class F, class... Args>
197 decltype(DecomposePairImpl(0, std::declval<F>(), std::declval<Args>()...))
TryDecomposePair(F && f,Args &&...args)198 TryDecomposePair(F&& f, Args&&... args) {
199   return DecomposePairImpl(0, std::forward<F>(f), std::forward<Args>(args)...);
200 }
201 
TEST(DecomposePair,Decomposable)202 TEST(DecomposePair, Decomposable) {
203   auto f = [](const int& x, std::piecewise_construct_t, std::tuple<int&&> k,
204               std::tuple<double>&& v) {
205     EXPECT_EQ(&x, &std::get<0>(k));
206     EXPECT_EQ(42, x);
207     EXPECT_EQ(0.5, std::get<0>(v));
208     return 'A';
209   };
210   EXPECT_EQ('A', TryDecomposePair(f, 42, 0.5));
211   EXPECT_EQ('A', TryDecomposePair(f, std::make_pair(42, 0.5)));
212   EXPECT_EQ('A', TryDecomposePair(f, std::piecewise_construct,
213                                   std::make_tuple(42), std::make_tuple(0.5)));
214 }
215 
TEST(DecomposePair,NotDecomposable)216 TEST(DecomposePair, NotDecomposable) {
217   auto f = [](...) {
218     ADD_FAILURE() << "Must not be called";
219     return 'A';
220   };
221   EXPECT_STREQ("not decomposable",
222                TryDecomposePair(f));
223   EXPECT_STREQ("not decomposable",
224                TryDecomposePair(f, std::piecewise_construct, std::make_tuple(),
225                                 std::make_tuple(0.5)));
226 }
227 
TEST(MapSlotPolicy,ConstKeyAndValue)228 TEST(MapSlotPolicy, ConstKeyAndValue) {
229   using slot_policy = map_slot_policy<const CopyableMovableInstance,
230                                       const CopyableMovableInstance>;
231   using slot_type = typename slot_policy::slot_type;
232 
233   union Slots {
234     Slots() {}
235     ~Slots() {}
236     slot_type slots[100];
237   } slots;
238 
239   std::allocator<
240       std::pair<const CopyableMovableInstance, const CopyableMovableInstance>>
241       alloc;
242   InstanceTracker tracker;
243   slot_policy::construct(&alloc, &slots.slots[0], CopyableMovableInstance(1),
244                          CopyableMovableInstance(1));
245   for (int i = 0; i < 99; ++i) {
246     slot_policy::transfer(&alloc, &slots.slots[i + 1], &slots.slots[i]);
247   }
248   slot_policy::destroy(&alloc, &slots.slots[99]);
249 
250   EXPECT_EQ(tracker.copies(), 0);
251 }
252 
253 }  // namespace
254 }  // namespace container_internal
255 ABSL_NAMESPACE_END
256 }  // namespace absl
257