raw_hash_set_allocator_test.cc
Go to the documentation of this file.
00001 // Copyright 2018 The Abseil Authors.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //      https://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 
00015 #include <limits>
00016 #include <scoped_allocator>
00017 
00018 #include "gtest/gtest.h"
00019 #include "absl/container/internal/raw_hash_set.h"
00020 #include "absl/container/internal/tracked.h"
00021 
00022 namespace absl {
00023 namespace container_internal {
00024 namespace {
00025 
00026 enum AllocSpec {
00027   kPropagateOnCopy = 1,
00028   kPropagateOnMove = 2,
00029   kPropagateOnSwap = 4,
00030 };
00031 
00032 struct AllocState {
00033   size_t num_allocs = 0;
00034   std::set<void*> owned;
00035 };
00036 
00037 template <class T,
00038           int Spec = kPropagateOnCopy | kPropagateOnMove | kPropagateOnSwap>
00039 class CheckedAlloc {
00040  public:
00041   template <class, int>
00042   friend class CheckedAlloc;
00043 
00044   using value_type = T;
00045 
00046   CheckedAlloc() {}
00047   explicit CheckedAlloc(size_t id) : id_(id) {}
00048   CheckedAlloc(const CheckedAlloc&) = default;
00049   CheckedAlloc& operator=(const CheckedAlloc&) = default;
00050 
00051   template <class U>
00052   CheckedAlloc(const CheckedAlloc<U, Spec>& that)
00053       : id_(that.id_), state_(that.state_) {}
00054 
00055   template <class U>
00056   struct rebind {
00057     using other = CheckedAlloc<U, Spec>;
00058   };
00059 
00060   using propagate_on_container_copy_assignment =
00061       std::integral_constant<bool, (Spec & kPropagateOnCopy) != 0>;
00062 
00063   using propagate_on_container_move_assignment =
00064       std::integral_constant<bool, (Spec & kPropagateOnMove) != 0>;
00065 
00066   using propagate_on_container_swap =
00067       std::integral_constant<bool, (Spec & kPropagateOnSwap) != 0>;
00068 
00069   CheckedAlloc select_on_container_copy_construction() const {
00070     if (Spec & kPropagateOnCopy) return *this;
00071     return {};
00072   }
00073 
00074   T* allocate(size_t n) {
00075     T* ptr = std::allocator<T>().allocate(n);
00076     track_alloc(ptr);
00077     return ptr;
00078   }
00079   void deallocate(T* ptr, size_t n) {
00080     memset(ptr, 0, n * sizeof(T));  // The freed memory must be unpoisoned.
00081     track_dealloc(ptr);
00082     return std::allocator<T>().deallocate(ptr, n);
00083   }
00084 
00085   friend bool operator==(const CheckedAlloc& a, const CheckedAlloc& b) {
00086     return a.id_ == b.id_;
00087   }
00088   friend bool operator!=(const CheckedAlloc& a, const CheckedAlloc& b) {
00089     return !(a == b);
00090   }
00091 
00092   size_t num_allocs() const { return state_->num_allocs; }
00093 
00094   void swap(CheckedAlloc& that) {
00095     using std::swap;
00096     swap(id_, that.id_);
00097     swap(state_, that.state_);
00098   }
00099 
00100   friend void swap(CheckedAlloc& a, CheckedAlloc& b) { a.swap(b); }
00101 
00102   friend std::ostream& operator<<(std::ostream& o, const CheckedAlloc& a) {
00103     return o << "alloc(" << a.id_ << ")";
00104   }
00105 
00106  private:
00107   void track_alloc(void* ptr) {
00108     AllocState* state = state_.get();
00109     ++state->num_allocs;
00110     if (!state->owned.insert(ptr).second)
00111       ADD_FAILURE() << *this << " got previously allocated memory: " << ptr;
00112   }
00113   void track_dealloc(void* ptr) {
00114     if (state_->owned.erase(ptr) != 1)
00115       ADD_FAILURE() << *this
00116                     << " deleting memory owned by another allocator: " << ptr;
00117   }
00118 
00119   size_t id_ = std::numeric_limits<size_t>::max();
00120 
00121   std::shared_ptr<AllocState> state_ = std::make_shared<AllocState>();
00122 };
00123 
00124 struct Identity {
00125   int32_t operator()(int32_t v) const { return v; }
00126 };
00127 
00128 struct Policy {
00129   using slot_type = Tracked<int32_t>;
00130   using init_type = Tracked<int32_t>;
00131   using key_type = int32_t;
00132 
00133   template <class allocator_type, class... Args>
00134   static void construct(allocator_type* alloc, slot_type* slot,
00135                         Args&&... args) {
00136     std::allocator_traits<allocator_type>::construct(
00137         *alloc, slot, std::forward<Args>(args)...);
00138   }
00139 
00140   template <class allocator_type>
00141   static void destroy(allocator_type* alloc, slot_type* slot) {
00142     std::allocator_traits<allocator_type>::destroy(*alloc, slot);
00143   }
00144 
00145   template <class allocator_type>
00146   static void transfer(allocator_type* alloc, slot_type* new_slot,
00147                        slot_type* old_slot) {
00148     construct(alloc, new_slot, std::move(*old_slot));
00149     destroy(alloc, old_slot);
00150   }
00151 
00152   template <class F>
00153   static auto apply(F&& f, int32_t v) -> decltype(std::forward<F>(f)(v, v)) {
00154     return std::forward<F>(f)(v, v);
00155   }
00156 
00157   template <class F>
00158   static auto apply(F&& f, const slot_type& v)
00159       -> decltype(std::forward<F>(f)(v.val(), v)) {
00160     return std::forward<F>(f)(v.val(), v);
00161   }
00162 
00163   template <class F>
00164   static auto apply(F&& f, slot_type&& v)
00165       -> decltype(std::forward<F>(f)(v.val(), std::move(v))) {
00166     return std::forward<F>(f)(v.val(), std::move(v));
00167   }
00168 
00169   static slot_type& element(slot_type* slot) { return *slot; }
00170 };
00171 
00172 template <int Spec>
00173 struct PropagateTest : public ::testing::Test {
00174   using Alloc = CheckedAlloc<Tracked<int32_t>, Spec>;
00175 
00176   using Table = raw_hash_set<Policy, Identity, std::equal_to<int32_t>, Alloc>;
00177 
00178   PropagateTest() {
00179     EXPECT_EQ(a1, t1.get_allocator());
00180     EXPECT_NE(a2, t1.get_allocator());
00181   }
00182 
00183   Alloc a1 = Alloc(1);
00184   Table t1 = Table(0, a1);
00185   Alloc a2 = Alloc(2);
00186 };
00187 
00188 using PropagateOnAll =
00189     PropagateTest<kPropagateOnCopy | kPropagateOnMove | kPropagateOnSwap>;
00190 using NoPropagateOnCopy = PropagateTest<kPropagateOnMove | kPropagateOnSwap>;
00191 using NoPropagateOnMove = PropagateTest<kPropagateOnCopy | kPropagateOnSwap>;
00192 
00193 TEST_F(PropagateOnAll, Empty) { EXPECT_EQ(0, a1.num_allocs()); }
00194 
00195 TEST_F(PropagateOnAll, InsertAllocates) {
00196   auto it = t1.insert(0).first;
00197   EXPECT_EQ(1, a1.num_allocs());
00198   EXPECT_EQ(0, it->num_moves());
00199   EXPECT_EQ(0, it->num_copies());
00200 }
00201 
00202 TEST_F(PropagateOnAll, InsertDecomposes) {
00203   auto it = t1.insert(0).first;
00204   EXPECT_EQ(1, a1.num_allocs());
00205   EXPECT_EQ(0, it->num_moves());
00206   EXPECT_EQ(0, it->num_copies());
00207 
00208   EXPECT_FALSE(t1.insert(0).second);
00209   EXPECT_EQ(1, a1.num_allocs());
00210   EXPECT_EQ(0, it->num_moves());
00211   EXPECT_EQ(0, it->num_copies());
00212 }
00213 
00214 TEST_F(PropagateOnAll, RehashMoves) {
00215   auto it = t1.insert(0).first;
00216   EXPECT_EQ(0, it->num_moves());
00217   t1.rehash(2 * t1.capacity());
00218   EXPECT_EQ(2, a1.num_allocs());
00219   it = t1.find(0);
00220   EXPECT_EQ(1, it->num_moves());
00221   EXPECT_EQ(0, it->num_copies());
00222 }
00223 
00224 TEST_F(PropagateOnAll, CopyConstructor) {
00225   auto it = t1.insert(0).first;
00226   Table u(t1);
00227   EXPECT_EQ(2, a1.num_allocs());
00228   EXPECT_EQ(0, it->num_moves());
00229   EXPECT_EQ(1, it->num_copies());
00230 }
00231 
00232 TEST_F(NoPropagateOnCopy, CopyConstructor) {
00233   auto it = t1.insert(0).first;
00234   Table u(t1);
00235   EXPECT_EQ(1, a1.num_allocs());
00236   EXPECT_EQ(1, u.get_allocator().num_allocs());
00237   EXPECT_EQ(0, it->num_moves());
00238   EXPECT_EQ(1, it->num_copies());
00239 }
00240 
00241 TEST_F(PropagateOnAll, CopyConstructorWithSameAlloc) {
00242   auto it = t1.insert(0).first;
00243   Table u(t1, a1);
00244   EXPECT_EQ(2, a1.num_allocs());
00245   EXPECT_EQ(0, it->num_moves());
00246   EXPECT_EQ(1, it->num_copies());
00247 }
00248 
00249 TEST_F(NoPropagateOnCopy, CopyConstructorWithSameAlloc) {
00250   auto it = t1.insert(0).first;
00251   Table u(t1, a1);
00252   EXPECT_EQ(2, a1.num_allocs());
00253   EXPECT_EQ(0, it->num_moves());
00254   EXPECT_EQ(1, it->num_copies());
00255 }
00256 
00257 TEST_F(PropagateOnAll, CopyConstructorWithDifferentAlloc) {
00258   auto it = t1.insert(0).first;
00259   Table u(t1, a2);
00260   EXPECT_EQ(a2, u.get_allocator());
00261   EXPECT_EQ(1, a1.num_allocs());
00262   EXPECT_EQ(1, a2.num_allocs());
00263   EXPECT_EQ(0, it->num_moves());
00264   EXPECT_EQ(1, it->num_copies());
00265 }
00266 
00267 TEST_F(NoPropagateOnCopy, CopyConstructorWithDifferentAlloc) {
00268   auto it = t1.insert(0).first;
00269   Table u(t1, a2);
00270   EXPECT_EQ(a2, u.get_allocator());
00271   EXPECT_EQ(1, a1.num_allocs());
00272   EXPECT_EQ(1, a2.num_allocs());
00273   EXPECT_EQ(0, it->num_moves());
00274   EXPECT_EQ(1, it->num_copies());
00275 }
00276 
00277 TEST_F(PropagateOnAll, MoveConstructor) {
00278   auto it = t1.insert(0).first;
00279   Table u(std::move(t1));
00280   EXPECT_EQ(1, a1.num_allocs());
00281   EXPECT_EQ(0, it->num_moves());
00282   EXPECT_EQ(0, it->num_copies());
00283 }
00284 
00285 TEST_F(NoPropagateOnMove, MoveConstructor) {
00286   auto it = t1.insert(0).first;
00287   Table u(std::move(t1));
00288   EXPECT_EQ(1, a1.num_allocs());
00289   EXPECT_EQ(0, it->num_moves());
00290   EXPECT_EQ(0, it->num_copies());
00291 }
00292 
00293 TEST_F(PropagateOnAll, MoveConstructorWithSameAlloc) {
00294   auto it = t1.insert(0).first;
00295   Table u(std::move(t1), a1);
00296   EXPECT_EQ(1, a1.num_allocs());
00297   EXPECT_EQ(0, it->num_moves());
00298   EXPECT_EQ(0, it->num_copies());
00299 }
00300 
00301 TEST_F(NoPropagateOnMove, MoveConstructorWithSameAlloc) {
00302   auto it = t1.insert(0).first;
00303   Table u(std::move(t1), a1);
00304   EXPECT_EQ(1, a1.num_allocs());
00305   EXPECT_EQ(0, it->num_moves());
00306   EXPECT_EQ(0, it->num_copies());
00307 }
00308 
00309 TEST_F(PropagateOnAll, MoveConstructorWithDifferentAlloc) {
00310   auto it = t1.insert(0).first;
00311   Table u(std::move(t1), a2);
00312   it = u.find(0);
00313   EXPECT_EQ(a2, u.get_allocator());
00314   EXPECT_EQ(1, a1.num_allocs());
00315   EXPECT_EQ(1, a2.num_allocs());
00316   EXPECT_EQ(1, it->num_moves());
00317   EXPECT_EQ(0, it->num_copies());
00318 }
00319 
00320 TEST_F(NoPropagateOnMove, MoveConstructorWithDifferentAlloc) {
00321   auto it = t1.insert(0).first;
00322   Table u(std::move(t1), a2);
00323   it = u.find(0);
00324   EXPECT_EQ(a2, u.get_allocator());
00325   EXPECT_EQ(1, a1.num_allocs());
00326   EXPECT_EQ(1, a2.num_allocs());
00327   EXPECT_EQ(1, it->num_moves());
00328   EXPECT_EQ(0, it->num_copies());
00329 }
00330 
00331 TEST_F(PropagateOnAll, CopyAssignmentWithSameAlloc) {
00332   auto it = t1.insert(0).first;
00333   Table u(0, a1);
00334   u = t1;
00335   EXPECT_EQ(2, a1.num_allocs());
00336   EXPECT_EQ(0, it->num_moves());
00337   EXPECT_EQ(1, it->num_copies());
00338 }
00339 
00340 TEST_F(NoPropagateOnCopy, CopyAssignmentWithSameAlloc) {
00341   auto it = t1.insert(0).first;
00342   Table u(0, a1);
00343   u = t1;
00344   EXPECT_EQ(2, a1.num_allocs());
00345   EXPECT_EQ(0, it->num_moves());
00346   EXPECT_EQ(1, it->num_copies());
00347 }
00348 
00349 TEST_F(PropagateOnAll, CopyAssignmentWithDifferentAlloc) {
00350   auto it = t1.insert(0).first;
00351   Table u(0, a2);
00352   u = t1;
00353   EXPECT_EQ(a1, u.get_allocator());
00354   EXPECT_EQ(2, a1.num_allocs());
00355   EXPECT_EQ(0, a2.num_allocs());
00356   EXPECT_EQ(0, it->num_moves());
00357   EXPECT_EQ(1, it->num_copies());
00358 }
00359 
00360 TEST_F(NoPropagateOnCopy, CopyAssignmentWithDifferentAlloc) {
00361   auto it = t1.insert(0).first;
00362   Table u(0, a2);
00363   u = t1;
00364   EXPECT_EQ(a2, u.get_allocator());
00365   EXPECT_EQ(1, a1.num_allocs());
00366   EXPECT_EQ(1, a2.num_allocs());
00367   EXPECT_EQ(0, it->num_moves());
00368   EXPECT_EQ(1, it->num_copies());
00369 }
00370 
00371 TEST_F(PropagateOnAll, MoveAssignmentWithSameAlloc) {
00372   auto it = t1.insert(0).first;
00373   Table u(0, a1);
00374   u = std::move(t1);
00375   EXPECT_EQ(a1, u.get_allocator());
00376   EXPECT_EQ(1, a1.num_allocs());
00377   EXPECT_EQ(0, it->num_moves());
00378   EXPECT_EQ(0, it->num_copies());
00379 }
00380 
00381 TEST_F(NoPropagateOnMove, MoveAssignmentWithSameAlloc) {
00382   auto it = t1.insert(0).first;
00383   Table u(0, a1);
00384   u = std::move(t1);
00385   EXPECT_EQ(a1, u.get_allocator());
00386   EXPECT_EQ(1, a1.num_allocs());
00387   EXPECT_EQ(0, it->num_moves());
00388   EXPECT_EQ(0, it->num_copies());
00389 }
00390 
00391 TEST_F(PropagateOnAll, MoveAssignmentWithDifferentAlloc) {
00392   auto it = t1.insert(0).first;
00393   Table u(0, a2);
00394   u = std::move(t1);
00395   EXPECT_EQ(a1, u.get_allocator());
00396   EXPECT_EQ(1, a1.num_allocs());
00397   EXPECT_EQ(0, a2.num_allocs());
00398   EXPECT_EQ(0, it->num_moves());
00399   EXPECT_EQ(0, it->num_copies());
00400 }
00401 
00402 TEST_F(NoPropagateOnMove, MoveAssignmentWithDifferentAlloc) {
00403   auto it = t1.insert(0).first;
00404   Table u(0, a2);
00405   u = std::move(t1);
00406   it = u.find(0);
00407   EXPECT_EQ(a2, u.get_allocator());
00408   EXPECT_EQ(1, a1.num_allocs());
00409   EXPECT_EQ(1, a2.num_allocs());
00410   EXPECT_EQ(1, it->num_moves());
00411   EXPECT_EQ(0, it->num_copies());
00412 }
00413 
00414 TEST_F(PropagateOnAll, Swap) {
00415   auto it = t1.insert(0).first;
00416   Table u(0, a2);
00417   u.swap(t1);
00418   EXPECT_EQ(a1, u.get_allocator());
00419   EXPECT_EQ(a2, t1.get_allocator());
00420   EXPECT_EQ(1, a1.num_allocs());
00421   EXPECT_EQ(0, a2.num_allocs());
00422   EXPECT_EQ(0, it->num_moves());
00423   EXPECT_EQ(0, it->num_copies());
00424 }
00425 
00426 }  // namespace
00427 }  // namespace container_internal
00428 }  // namespace absl


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:15