brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.3 KiB · ff6402e Raw
189 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9 10// <memory>11 12// To allow checking that self-move works correctly.13// ADDITIONAL_COMPILE_FLAGS: -Wno-self-move14 15// template<class _Alloc>16// struct __allocation_guard;17 18#include <__cxx03/__memory/allocation_guard.h>19#include <cassert>20#include <type_traits>21#include <utility>22 23#include "test_allocator.h"24 25using A = test_allocator<int>;26 27// A trimmed-down version of `test_allocator` that is copy-assignable (in general allocators don't have to support copy28// assignment).29template <class T>30struct AssignableAllocator {31  using size_type = unsigned;32  using difference_type = int;33  using value_type = T;34  using pointer = value_type*;35  using const_pointer = const value_type*;36  using reference = typename std::add_lvalue_reference<value_type>::type;37  using const_reference = typename std::add_lvalue_reference<const value_type>::type;38 39  template <class U>40  struct rebind {41    using other = test_allocator<U>;42  };43 44  test_allocator_statistics* stats_ = nullptr;45 46  explicit AssignableAllocator(test_allocator_statistics& stats) : stats_(&stats) {47    ++stats_->count;48  }49 50  TEST_CONSTEXPR_CXX14 AssignableAllocator(const AssignableAllocator& rhs) TEST_NOEXCEPT51      : stats_(rhs.stats_) {52    if (stats_ != nullptr) {53      ++stats_->count;54      ++stats_->copied;55    }56  }57 58  TEST_CONSTEXPR_CXX14 AssignableAllocator& operator=(const AssignableAllocator& rhs) TEST_NOEXCEPT {59    stats_ = rhs.stats_;60    if (stats_ != nullptr) {61      ++stats_->count;62      ++stats_->copied;63    }64 65    return *this;66  }67 68  TEST_CONSTEXPR_CXX14 pointer allocate(size_type n, const void* = nullptr) {69    if (stats_ != nullptr) {70      ++stats_->alloc_count;71    }72    return std::allocator<value_type>().allocate(n);73  }74 75  TEST_CONSTEXPR_CXX14 void deallocate(pointer p, size_type s) {76    if (stats_ != nullptr) {77      --stats_->alloc_count;78    }79    std::allocator<value_type>().deallocate(p, s);80  }81 82  TEST_CONSTEXPR size_type max_size() const TEST_NOEXCEPT { return UINT_MAX / sizeof(T); }83 84  template <class U>85  TEST_CONSTEXPR_CXX20 void construct(pointer p, U&& val) {86    if (stats_ != nullptr)87      ++stats_->construct_count;88    ::new (static_cast<void*>(p)) T(std::forward<U>(val));89  }90 91  TEST_CONSTEXPR_CXX14 void destroy(pointer p) {92    if (stats_ != nullptr) {93      ++stats_->destroy_count;94    }95    p->~T();96  }97};98 99// Move-only.100static_assert(!std::is_copy_constructible<std::__allocation_guard<A> >::value, "");101static_assert(std::is_move_constructible<std::__allocation_guard<A> >::value, "");102static_assert(!std::is_copy_assignable<std::__allocation_guard<A> >::value, "");103static_assert(std::is_move_assignable<std::__allocation_guard<A> >::value, "");104 105int main(int, char**) {106  const int size = 42;107 108  { // The constructor allocates using the given allocator.109    test_allocator_statistics stats;110    std::__allocation_guard<A> guard(A(&stats), size);111    assert(stats.alloc_count == 1);112    assert(guard.__get() != nullptr);113  }114 115  { // The destructor deallocates using the given allocator.116    test_allocator_statistics stats;117    {118      std::__allocation_guard<A> guard(A(&stats), size);119      assert(stats.alloc_count == 1);120    }121    assert(stats.alloc_count == 0);122  }123 124  { // `__release_ptr` prevents deallocation.125    test_allocator_statistics stats;126    A alloc(&stats);127    int* ptr = nullptr;128    {129      std::__allocation_guard<A> guard(alloc, size);130      assert(stats.alloc_count == 1);131      ptr = guard.__release_ptr();132    }133    assert(stats.alloc_count == 1);134    alloc.deallocate(ptr, size);135  }136 137  { // Using the move constructor doesn't lead to double deletion.138    test_allocator_statistics stats;139    {140      std::__allocation_guard<A> guard1(A(&stats), size);141      assert(stats.alloc_count == 1);142      auto* ptr1 = guard1.__get();143 144      std::__allocation_guard<A> guard2 = std::move(guard1);145      assert(stats.alloc_count == 1);146      assert(guard1.__get() == nullptr);147      assert(guard2.__get() == ptr1);148    }149    assert(stats.alloc_count == 0);150  }151 152  { // Using the move assignment operator doesn't lead to double deletion.153    using A2 = AssignableAllocator<int>;154 155    test_allocator_statistics stats;156    {157      std::__allocation_guard<A2> guard1(A2(stats), size);158      assert(stats.alloc_count == 1);159      std::__allocation_guard<A2> guard2(A2(stats), size);160      assert(stats.alloc_count == 2);161      auto* ptr1 = guard1.__get();162 163      guard2 = std::move(guard1);164      assert(stats.alloc_count == 1);165      assert(guard1.__get() == nullptr);166      assert(guard2.__get() == ptr1);167    }168    assert(stats.alloc_count == 0);169  }170 171  { // Self-assignment is a no-op.172    using A2 = AssignableAllocator<int>;173 174    test_allocator_statistics stats;175    {176      std::__allocation_guard<A2> guard(A2(stats), size);177      assert(stats.alloc_count == 1);178      auto* ptr = guard.__get();179 180      guard = std::move(guard);181      assert(stats.alloc_count == 1);182      assert(guard.__get() == ptr);183    }184    assert(stats.alloc_count == 0);185  }186 187  return 0;188}189