16 #include <scoped_allocator> 18 #include "gtest/gtest.h" 23 namespace container_internal {
38 int Spec = kPropagateOnCopy | kPropagateOnMove | kPropagateOnSwap>
42 friend class CheckedAlloc;
47 explicit CheckedAlloc(
size_t id) :
id_(
id) {}
48 CheckedAlloc(
const CheckedAlloc&) =
default;
49 CheckedAlloc& operator=(
const CheckedAlloc&) =
default;
52 CheckedAlloc(
const CheckedAlloc<U, Spec>& that)
57 using other = CheckedAlloc<U, Spec>;
60 using propagate_on_container_copy_assignment =
61 std::integral_constant<bool, (Spec & kPropagateOnCopy) != 0>;
63 using propagate_on_container_move_assignment =
64 std::integral_constant<bool, (Spec & kPropagateOnMove) != 0>;
66 using propagate_on_container_swap =
67 std::integral_constant<bool, (Spec & kPropagateOnSwap) != 0>;
69 CheckedAlloc select_on_container_copy_construction()
const {
70 if (Spec & kPropagateOnCopy)
return *
this;
74 T* allocate(
size_t n) {
75 T*
ptr = std::allocator<T>().allocate(n);
79 void deallocate(T*
ptr,
size_t n) {
80 memset(ptr, 0, n *
sizeof(T));
82 return std::allocator<T>().deallocate(ptr, n);
85 friend bool operator==(
const CheckedAlloc&
a,
const CheckedAlloc&
b) {
86 return a.id_ == b.id_;
88 friend bool operator!=(
const CheckedAlloc& a,
const CheckedAlloc& b) {
94 void swap(CheckedAlloc& that) {
100 friend void swap(CheckedAlloc& a, CheckedAlloc& b) { a.swap(b); }
102 friend std::ostream&
operator<<(std::ostream&
o,
const CheckedAlloc& a) {
103 return o <<
"alloc(" << a.id_ <<
")";
107 void track_alloc(
void* ptr) {
108 AllocState* state =
state_.get();
110 if (!state->owned.insert(ptr).second)
111 ADD_FAILURE() << *
this <<
" got previously allocated memory: " <<
ptr;
113 void track_dealloc(
void* ptr) {
114 if (
state_->owned.erase(ptr) != 1)
115 ADD_FAILURE() << *
this 116 <<
" deleting memory owned by another allocator: " <<
ptr;
119 size_t id_ = std::numeric_limits<size_t>::max();
121 std::shared_ptr<AllocState>
state_ = std::make_shared<AllocState>();
125 int32_t operator()(int32_t
v)
const {
return v; }
129 using slot_type = Tracked<int32_t>;
130 using init_type = Tracked<int32_t>;
131 using key_type = int32_t;
133 template <
class allocator_type,
class... Args>
137 *alloc, slot, std::forward<Args>(args)...);
140 template <
class allocator_type>
141 static void destroy(allocator_type* alloc, slot_type* slot) {
145 template <
class allocator_type>
146 static void transfer(allocator_type* alloc, slot_type* new_slot,
147 slot_type* old_slot) {
153 static auto apply(F&& f, int32_t
v) -> decltype(std::forward<F>(f)(v, v)) {
154 return std::forward<F>(f)(v, v);
158 static auto apply(F&& f,
const slot_type& v)
159 -> decltype(std::forward<F>(f)(v.val(),
v)) {
160 return std::forward<F>(f)(v.val(),
v);
164 static auto apply(F&& f, slot_type&& v)
165 -> decltype(std::forward<F>(f)(v.val(),
std::move(v))) {
166 return std::forward<F>(f)(v.val(),
std::move(v));
169 static slot_type&
element(slot_type* slot) {
return *slot; }
173 struct PropagateTest :
public ::testing::Test {
174 using Alloc = CheckedAlloc<Tracked<int32_t>, Spec>;
176 using Table = raw_hash_set<Policy, Identity, std::equal_to<int32_t>, Alloc>;
179 EXPECT_EQ(
a1,
t1.get_allocator());
180 EXPECT_NE(
a2,
t1.get_allocator());
184 Table
t1 = Table(0, a1);
188 using PropagateOnAll =
189 PropagateTest<kPropagateOnCopy | kPropagateOnMove | kPropagateOnSwap>;
190 using NoPropagateOnCopy = PropagateTest<kPropagateOnMove | kPropagateOnSwap>;
191 using NoPropagateOnMove = PropagateTest<kPropagateOnCopy | kPropagateOnSwap>;
193 TEST_F(PropagateOnAll, Empty) { EXPECT_EQ(0,
a1.num_allocs()); }
195 TEST_F(PropagateOnAll, InsertAllocates) {
196 auto it =
t1.insert(0).first;
197 EXPECT_EQ(1,
a1.num_allocs());
198 EXPECT_EQ(0, it->num_moves());
199 EXPECT_EQ(0, it->num_copies());
202 TEST_F(PropagateOnAll, InsertDecomposes) {
203 auto it =
t1.insert(0).first;
204 EXPECT_EQ(1,
a1.num_allocs());
205 EXPECT_EQ(0, it->num_moves());
206 EXPECT_EQ(0, it->num_copies());
208 EXPECT_FALSE(
t1.insert(0).second);
209 EXPECT_EQ(1,
a1.num_allocs());
210 EXPECT_EQ(0, it->num_moves());
211 EXPECT_EQ(0, it->num_copies());
214 TEST_F(PropagateOnAll, RehashMoves) {
215 auto it =
t1.insert(0).first;
216 EXPECT_EQ(0, it->num_moves());
217 t1.rehash(2 *
t1.capacity());
218 EXPECT_EQ(2,
a1.num_allocs());
220 EXPECT_EQ(1, it->num_moves());
221 EXPECT_EQ(0, it->num_copies());
224 TEST_F(PropagateOnAll, CopyConstructor) {
225 auto it =
t1.insert(0).first;
227 EXPECT_EQ(2,
a1.num_allocs());
228 EXPECT_EQ(0, it->num_moves());
229 EXPECT_EQ(1, it->num_copies());
232 TEST_F(NoPropagateOnCopy, CopyConstructor) {
233 auto it =
t1.insert(0).first;
235 EXPECT_EQ(1,
a1.num_allocs());
236 EXPECT_EQ(1, u.get_allocator().num_allocs());
237 EXPECT_EQ(0, it->num_moves());
238 EXPECT_EQ(1, it->num_copies());
241 TEST_F(PropagateOnAll, CopyConstructorWithSameAlloc) {
242 auto it =
t1.insert(0).first;
244 EXPECT_EQ(2,
a1.num_allocs());
245 EXPECT_EQ(0, it->num_moves());
246 EXPECT_EQ(1, it->num_copies());
249 TEST_F(NoPropagateOnCopy, CopyConstructorWithSameAlloc) {
250 auto it =
t1.insert(0).first;
252 EXPECT_EQ(2,
a1.num_allocs());
253 EXPECT_EQ(0, it->num_moves());
254 EXPECT_EQ(1, it->num_copies());
257 TEST_F(PropagateOnAll, CopyConstructorWithDifferentAlloc) {
258 auto it =
t1.insert(0).first;
260 EXPECT_EQ(
a2, u.get_allocator());
261 EXPECT_EQ(1,
a1.num_allocs());
262 EXPECT_EQ(1,
a2.num_allocs());
263 EXPECT_EQ(0, it->num_moves());
264 EXPECT_EQ(1, it->num_copies());
267 TEST_F(NoPropagateOnCopy, CopyConstructorWithDifferentAlloc) {
268 auto it =
t1.insert(0).first;
270 EXPECT_EQ(
a2, u.get_allocator());
271 EXPECT_EQ(1,
a1.num_allocs());
272 EXPECT_EQ(1,
a2.num_allocs());
273 EXPECT_EQ(0, it->num_moves());
274 EXPECT_EQ(1, it->num_copies());
277 TEST_F(PropagateOnAll, MoveConstructor) {
278 auto it =
t1.insert(0).first;
280 EXPECT_EQ(1,
a1.num_allocs());
281 EXPECT_EQ(0, it->num_moves());
282 EXPECT_EQ(0, it->num_copies());
285 TEST_F(NoPropagateOnMove, MoveConstructor) {
286 auto it =
t1.insert(0).first;
288 EXPECT_EQ(1,
a1.num_allocs());
289 EXPECT_EQ(0, it->num_moves());
290 EXPECT_EQ(0, it->num_copies());
293 TEST_F(PropagateOnAll, MoveConstructorWithSameAlloc) {
294 auto it =
t1.insert(0).first;
296 EXPECT_EQ(1,
a1.num_allocs());
297 EXPECT_EQ(0, it->num_moves());
298 EXPECT_EQ(0, it->num_copies());
301 TEST_F(NoPropagateOnMove, MoveConstructorWithSameAlloc) {
302 auto it =
t1.insert(0).first;
304 EXPECT_EQ(1,
a1.num_allocs());
305 EXPECT_EQ(0, it->num_moves());
306 EXPECT_EQ(0, it->num_copies());
309 TEST_F(PropagateOnAll, MoveConstructorWithDifferentAlloc) {
310 auto it =
t1.insert(0).first;
313 EXPECT_EQ(
a2, u.get_allocator());
314 EXPECT_EQ(1,
a1.num_allocs());
315 EXPECT_EQ(1,
a2.num_allocs());
316 EXPECT_EQ(1, it->num_moves());
317 EXPECT_EQ(0, it->num_copies());
320 TEST_F(NoPropagateOnMove, MoveConstructorWithDifferentAlloc) {
321 auto it =
t1.insert(0).first;
324 EXPECT_EQ(
a2, u.get_allocator());
325 EXPECT_EQ(1,
a1.num_allocs());
326 EXPECT_EQ(1,
a2.num_allocs());
327 EXPECT_EQ(1, it->num_moves());
328 EXPECT_EQ(0, it->num_copies());
331 TEST_F(PropagateOnAll, CopyAssignmentWithSameAlloc) {
332 auto it =
t1.insert(0).first;
335 EXPECT_EQ(2,
a1.num_allocs());
336 EXPECT_EQ(0, it->num_moves());
337 EXPECT_EQ(1, it->num_copies());
340 TEST_F(NoPropagateOnCopy, CopyAssignmentWithSameAlloc) {
341 auto it =
t1.insert(0).first;
344 EXPECT_EQ(2,
a1.num_allocs());
345 EXPECT_EQ(0, it->num_moves());
346 EXPECT_EQ(1, it->num_copies());
349 TEST_F(PropagateOnAll, CopyAssignmentWithDifferentAlloc) {
350 auto it =
t1.insert(0).first;
353 EXPECT_EQ(
a1, u.get_allocator());
354 EXPECT_EQ(2,
a1.num_allocs());
355 EXPECT_EQ(0,
a2.num_allocs());
356 EXPECT_EQ(0, it->num_moves());
357 EXPECT_EQ(1, it->num_copies());
360 TEST_F(NoPropagateOnCopy, CopyAssignmentWithDifferentAlloc) {
361 auto it =
t1.insert(0).first;
364 EXPECT_EQ(
a2, u.get_allocator());
365 EXPECT_EQ(1,
a1.num_allocs());
366 EXPECT_EQ(1,
a2.num_allocs());
367 EXPECT_EQ(0, it->num_moves());
368 EXPECT_EQ(1, it->num_copies());
371 TEST_F(PropagateOnAll, MoveAssignmentWithSameAlloc) {
372 auto it =
t1.insert(0).first;
375 EXPECT_EQ(
a1, u.get_allocator());
376 EXPECT_EQ(1,
a1.num_allocs());
377 EXPECT_EQ(0, it->num_moves());
378 EXPECT_EQ(0, it->num_copies());
381 TEST_F(NoPropagateOnMove, MoveAssignmentWithSameAlloc) {
382 auto it =
t1.insert(0).first;
385 EXPECT_EQ(
a1, u.get_allocator());
386 EXPECT_EQ(1,
a1.num_allocs());
387 EXPECT_EQ(0, it->num_moves());
388 EXPECT_EQ(0, it->num_copies());
391 TEST_F(PropagateOnAll, MoveAssignmentWithDifferentAlloc) {
392 auto it =
t1.insert(0).first;
395 EXPECT_EQ(
a1, u.get_allocator());
396 EXPECT_EQ(1,
a1.num_allocs());
397 EXPECT_EQ(0,
a2.num_allocs());
398 EXPECT_EQ(0, it->num_moves());
399 EXPECT_EQ(0, it->num_copies());
402 TEST_F(NoPropagateOnMove, MoveAssignmentWithDifferentAlloc) {
403 auto it =
t1.insert(0).first;
407 EXPECT_EQ(
a2, u.get_allocator());
408 EXPECT_EQ(1,
a1.num_allocs());
409 EXPECT_EQ(1,
a2.num_allocs());
410 EXPECT_EQ(1, it->num_moves());
411 EXPECT_EQ(0, it->num_copies());
415 auto it =
t1.insert(0).first;
418 EXPECT_EQ(
a1, u.get_allocator());
419 EXPECT_EQ(
a2,
t1.get_allocator());
420 EXPECT_EQ(1,
a1.num_allocs());
421 EXPECT_EQ(0,
a2.num_allocs());
422 EXPECT_EQ(0, it->num_moves());
423 EXPECT_EQ(0, it->num_copies());
static std::function< Slot &(Slot *)> element
std::ostream & operator<<(std::ostream &os, absl::LogSeverity s)
static std::function< void(void *, Slot *)> destroy
bool operator==(const absl::InlinedVector< T, N, A > &a, const absl::InlinedVector< T, N, A > &b)
void Swap(T &lhs, T &rhs) noexcept(IsNothrowSwappable< T >::value)
bool operator!=(const absl::InlinedVector< T, N, A > &a, const absl::InlinedVector< T, N, A > &b)
TEST_F(GraphCyclesTest, NoCycle)
void swap(absl::InlinedVector< T, N, A > &a, absl::InlinedVector< T, N, A > &b) noexcept(noexcept(a.swap(b)))
static std::function< void(void *, Slot *, Slot *)> transfer
static std::function< void(void *, Slot *, Slot)> construct
auto apply(Functor &&functor, Tuple &&t) -> decltype(utility_internal::apply_helper(absl::forward< Functor >(functor), absl::forward< Tuple >(t), absl::make_index_sequence< std::tuple_size< typename std::remove_reference< Tuple >::type >::value >
std::shared_ptr< AllocState > state_
std::allocator< int > alloc
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept