| //===----------------------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| // <memory> |
| |
| // unique_ptr |
| |
| // Example move-only deleter |
| |
| #ifndef SUPPORT_DELETER_TYPES_H |
| #define SUPPORT_DELETER_TYPES_H |
| |
| #include <type_traits> |
| #include <utility> |
| #include <cassert> |
| |
| #include "test_macros.h" |
| #include "min_allocator.h" |
| |
| #if TEST_STD_VER >= 11 |
| |
| template <class T> |
| class Deleter { |
| int state_; |
| |
| Deleter(const Deleter&); |
| Deleter& operator=(const Deleter&); |
| |
| public: |
| TEST_CONSTEXPR_CXX23 Deleter(Deleter&& r) : state_(r.state_) { r.state_ = 0; } |
| TEST_CONSTEXPR_CXX23 Deleter& operator=(Deleter&& r) { |
| state_ = r.state_; |
| r.state_ = 0; |
| return *this; |
| } |
| |
| TEST_CONSTEXPR_CXX23 Deleter() : state_(0) {} |
| TEST_CONSTEXPR_CXX23 explicit Deleter(int s) : state_(s) {} |
| TEST_CONSTEXPR_CXX23 ~Deleter() { |
| assert(state_ >= 0); |
| state_ = -1; |
| } |
| |
| template <class U> |
| TEST_CONSTEXPR_CXX23 Deleter(Deleter<U>&& d, typename std::enable_if<!std::is_same<U, T>::value>::type* = 0) |
| : state_(d.state()) { |
| d.set_state(0); |
| } |
| |
| private: |
| template <class U> |
| Deleter(const Deleter<U>& d, typename std::enable_if<!std::is_same<U, T>::value>::type* = 0); |
| |
| public: |
| TEST_CONSTEXPR_CXX23 int state() const { return state_; } |
| TEST_CONSTEXPR_CXX23 void set_state(int i) { state_ = i; } |
| |
| TEST_CONSTEXPR_CXX23 void operator()(T* p) { delete p; } |
| }; |
| |
| template <class T> |
| class Deleter<T[]> { |
| int state_; |
| |
| Deleter(const Deleter&); |
| Deleter& operator=(const Deleter&); |
| |
| public: |
| TEST_CONSTEXPR_CXX23 Deleter(Deleter&& r) : state_(r.state_) { r.state_ = 0; } |
| TEST_CONSTEXPR_CXX23 Deleter& operator=(Deleter&& r) { |
| state_ = r.state_; |
| r.state_ = 0; |
| return *this; |
| } |
| |
| TEST_CONSTEXPR_CXX23 Deleter() : state_(0) {} |
| TEST_CONSTEXPR_CXX23 explicit Deleter(int s) : state_(s) {} |
| TEST_CONSTEXPR_CXX23 ~Deleter() { |
| assert(state_ >= 0); |
| state_ = -1; |
| } |
| |
| TEST_CONSTEXPR_CXX23 int state() const { return state_; } |
| TEST_CONSTEXPR_CXX23 void set_state(int i) { state_ = i; } |
| |
| TEST_CONSTEXPR_CXX23 void operator()(T* p) { delete[] p; } |
| }; |
| |
| #else // TEST_STD_VER < 11 |
| |
| template <class T> |
| class Deleter { |
| mutable int state_; |
| |
| public: |
| Deleter() : state_(0) {} |
| explicit Deleter(int s) : state_(s) {} |
| |
| Deleter(Deleter const& other) : state_(other.state_) { other.state_ = 0; } |
| Deleter& operator=(Deleter const& other) { |
| state_ = other.state_; |
| other.state_ = 0; |
| return *this; |
| } |
| |
| ~Deleter() { |
| assert(state_ >= 0); |
| state_ = -1; |
| } |
| |
| template <class U> |
| Deleter(Deleter<U> d, typename std::enable_if<!std::is_same<U, T>::value>::type* = 0) : state_(d.state()) {} |
| |
| public: |
| int state() const { return state_; } |
| void set_state(int i) { state_ = i; } |
| |
| void operator()(T* p) { delete p; } |
| }; |
| |
| template <class T> |
| class Deleter<T[]> { |
| mutable int state_; |
| |
| public: |
| Deleter(Deleter const& other) : state_(other.state_) { other.state_ = 0; } |
| Deleter& operator=(Deleter const& other) { |
| state_ = other.state_; |
| other.state_ = 0; |
| return *this; |
| } |
| |
| Deleter() : state_(0) {} |
| explicit Deleter(int s) : state_(s) {} |
| ~Deleter() { |
| assert(state_ >= 0); |
| state_ = -1; |
| } |
| |
| int state() const { return state_; } |
| void set_state(int i) { state_ = i; } |
| |
| void operator()(T* p) { delete[] p; } |
| }; |
| |
| #endif |
| |
| template <class T> |
| TEST_CONSTEXPR_CXX23 void swap(Deleter<T>& x, Deleter<T>& y) { |
| Deleter<T> t(std::move(x)); |
| x = std::move(y); |
| y = std::move(t); |
| } |
| |
| template <class T> |
| class CDeleter { |
| int state_; |
| |
| public: |
| TEST_CONSTEXPR_CXX23 CDeleter() : state_(0) {} |
| TEST_CONSTEXPR_CXX23 explicit CDeleter(int s) : state_(s) {} |
| TEST_CONSTEXPR_CXX23 ~CDeleter() { |
| assert(state_ >= 0); |
| state_ = -1; |
| } |
| |
| template <class U> |
| TEST_CONSTEXPR_CXX23 CDeleter(const CDeleter<U>& d) : state_(d.state()) {} |
| |
| TEST_CONSTEXPR_CXX23 int state() const { return state_; } |
| TEST_CONSTEXPR_CXX23 void set_state(int i) { state_ = i; } |
| |
| TEST_CONSTEXPR_CXX23 void operator()(T* p) { delete p; } |
| }; |
| |
| template <class T> |
| class CDeleter<T[]> { |
| int state_; |
| |
| public: |
| TEST_CONSTEXPR_CXX23 CDeleter() : state_(0) {} |
| TEST_CONSTEXPR_CXX23 explicit CDeleter(int s) : state_(s) {} |
| template <class U> |
| TEST_CONSTEXPR_CXX23 CDeleter(const CDeleter<U>& d) : state_(d.state()) {} |
| |
| TEST_CONSTEXPR_CXX23 ~CDeleter() { |
| assert(state_ >= 0); |
| state_ = -1; |
| } |
| |
| TEST_CONSTEXPR_CXX23 int state() const { return state_; } |
| TEST_CONSTEXPR_CXX23 void set_state(int i) { state_ = i; } |
| |
| TEST_CONSTEXPR_CXX23 void operator()(T* p) { delete[] p; } |
| }; |
| |
| template <class T> |
| TEST_CONSTEXPR_CXX23 void swap(CDeleter<T>& x, CDeleter<T>& y) { |
| CDeleter<T> t(std::move(x)); |
| x = std::move(y); |
| y = std::move(t); |
| } |
| |
| // Non-copyable deleter |
| template <class T> |
| class NCDeleter { |
| int state_; |
| NCDeleter(NCDeleter const&); |
| NCDeleter& operator=(NCDeleter const&); |
| |
| public: |
| TEST_CONSTEXPR_CXX23 NCDeleter() : state_(0) {} |
| TEST_CONSTEXPR_CXX23 explicit NCDeleter(int s) : state_(s) {} |
| TEST_CONSTEXPR_CXX23 ~NCDeleter() { |
| assert(state_ >= 0); |
| state_ = -1; |
| } |
| |
| TEST_CONSTEXPR_CXX23 int state() const { return state_; } |
| TEST_CONSTEXPR_CXX23 void set_state(int i) { state_ = i; } |
| |
| TEST_CONSTEXPR_CXX23 void operator()(T* p) { delete p; } |
| }; |
| |
| template <class T> |
| class NCDeleter<T[]> { |
| int state_; |
| NCDeleter(NCDeleter const&); |
| NCDeleter& operator=(NCDeleter const&); |
| |
| public: |
| TEST_CONSTEXPR_CXX23 NCDeleter() : state_(0) {} |
| TEST_CONSTEXPR_CXX23 explicit NCDeleter(int s) : state_(s) {} |
| TEST_CONSTEXPR_CXX23 ~NCDeleter() { |
| assert(state_ >= 0); |
| state_ = -1; |
| } |
| |
| TEST_CONSTEXPR_CXX23 int state() const { return state_; } |
| TEST_CONSTEXPR_CXX23 void set_state(int i) { state_ = i; } |
| |
| TEST_CONSTEXPR_CXX23 void operator()(T* p) { delete[] p; } |
| }; |
| |
| // Non-copyable deleter |
| template <class T> |
| class NCConstDeleter { |
| int state_; |
| NCConstDeleter(NCConstDeleter const&); |
| NCConstDeleter& operator=(NCConstDeleter const&); |
| |
| public: |
| TEST_CONSTEXPR_CXX23 NCConstDeleter() : state_(0) {} |
| TEST_CONSTEXPR_CXX23 explicit NCConstDeleter(int s) : state_(s) {} |
| TEST_CONSTEXPR_CXX23 ~NCConstDeleter() { |
| assert(state_ >= 0); |
| state_ = -1; |
| } |
| |
| TEST_CONSTEXPR_CXX23 int state() const { return state_; } |
| TEST_CONSTEXPR_CXX23 void set_state(int i) { state_ = i; } |
| |
| TEST_CONSTEXPR_CXX23 void operator()(T* p) const { delete p; } |
| }; |
| |
| template <class T> |
| class NCConstDeleter<T[]> { |
| int state_; |
| NCConstDeleter(NCConstDeleter const&); |
| NCConstDeleter& operator=(NCConstDeleter const&); |
| |
| public: |
| TEST_CONSTEXPR_CXX23 NCConstDeleter() : state_(0) {} |
| TEST_CONSTEXPR_CXX23 explicit NCConstDeleter(int s) : state_(s) {} |
| TEST_CONSTEXPR_CXX23 ~NCConstDeleter() { |
| assert(state_ >= 0); |
| state_ = -1; |
| } |
| |
| TEST_CONSTEXPR_CXX23 int state() const { return state_; } |
| TEST_CONSTEXPR_CXX23 void set_state(int i) { state_ = i; } |
| |
| TEST_CONSTEXPR_CXX23 void operator()(T* p) const { delete[] p; } |
| }; |
| |
| // Non-copyable deleter |
| template <class T> |
| class CopyDeleter { |
| int state_; |
| |
| public: |
| TEST_CONSTEXPR_CXX23 CopyDeleter() : state_(0) {} |
| TEST_CONSTEXPR_CXX23 explicit CopyDeleter(int s) : state_(s) {} |
| TEST_CONSTEXPR_CXX23 ~CopyDeleter() { |
| assert(state_ >= 0); |
| state_ = -1; |
| } |
| |
| TEST_CONSTEXPR_CXX23 CopyDeleter(CopyDeleter const& other) : state_(other.state_) {} |
| TEST_CONSTEXPR_CXX23 CopyDeleter& operator=(CopyDeleter const& other) { |
| state_ = other.state_; |
| return *this; |
| } |
| |
| TEST_CONSTEXPR_CXX23 int state() const { return state_; } |
| TEST_CONSTEXPR_CXX23 void set_state(int i) { state_ = i; } |
| |
| TEST_CONSTEXPR_CXX23 void operator()(T* p) { delete p; } |
| }; |
| |
| template <class T> |
| class CopyDeleter<T[]> { |
| int state_; |
| |
| public: |
| TEST_CONSTEXPR_CXX23 CopyDeleter() : state_(0) {} |
| TEST_CONSTEXPR_CXX23 explicit CopyDeleter(int s) : state_(s) {} |
| TEST_CONSTEXPR_CXX23 ~CopyDeleter() { |
| assert(state_ >= 0); |
| state_ = -1; |
| } |
| |
| TEST_CONSTEXPR_CXX23 CopyDeleter(CopyDeleter const& other) : state_(other.state_) {} |
| TEST_CONSTEXPR_CXX23 CopyDeleter& operator=(CopyDeleter const& other) { |
| state_ = other.state_; |
| return *this; |
| } |
| |
| TEST_CONSTEXPR_CXX23 int state() const { return state_; } |
| TEST_CONSTEXPR_CXX23 void set_state(int i) { state_ = i; } |
| |
| TEST_CONSTEXPR_CXX23 void operator()(T* p) { delete[] p; } |
| }; |
| |
| struct test_deleter_base { |
| static int count; |
| static int dealloc_count; |
| }; |
| |
| int test_deleter_base::count = 0; |
| int test_deleter_base::dealloc_count = 0; |
| |
| template <class T> |
| class test_deleter : public test_deleter_base { |
| int state_; |
| |
| public: |
| test_deleter() : state_(0) { ++count; } |
| explicit test_deleter(int s) : state_(s) { ++count; } |
| test_deleter(const test_deleter& d) : state_(d.state_) { ++count; } |
| ~test_deleter() { |
| assert(state_ >= 0); |
| --count; |
| state_ = -1; |
| } |
| |
| int state() const { return state_; } |
| void set_state(int i) { state_ = i; } |
| |
| void operator()(T* p) { |
| assert(state_ >= 0); |
| ++dealloc_count; |
| delete p; |
| } |
| #if TEST_STD_VER >= 11 |
| test_deleter* operator&() const = delete; |
| #else |
| |
| private: |
| test_deleter* operator&() const; |
| #endif |
| }; |
| |
| template <class T> |
| void swap(test_deleter<T>& x, test_deleter<T>& y) { |
| test_deleter<T> t(std::move(x)); |
| x = std::move(y); |
| y = std::move(t); |
| } |
| |
| #if TEST_STD_VER >= 11 |
| |
| template <class T, size_t ID = 0> |
| class PointerDeleter { |
| PointerDeleter(const PointerDeleter&); |
| PointerDeleter& operator=(const PointerDeleter&); |
| |
| public: |
| typedef min_pointer<T, std::integral_constant<size_t, ID>> pointer; |
| |
| TEST_CONSTEXPR_CXX23 PointerDeleter() = default; |
| TEST_CONSTEXPR_CXX23 PointerDeleter(PointerDeleter&&) = default; |
| TEST_CONSTEXPR_CXX23 PointerDeleter& operator=(PointerDeleter&&) = default; |
| TEST_CONSTEXPR_CXX23 explicit PointerDeleter(int) {} |
| |
| template <class U> |
| TEST_CONSTEXPR_CXX23 |
| PointerDeleter(PointerDeleter<U, ID>&&, typename std::enable_if<!std::is_same<U, T>::value>::type* = 0) {} |
| |
| TEST_CONSTEXPR_CXX23 void operator()(pointer p) { |
| if (p) { |
| delete std::addressof(*p); |
| } |
| } |
| |
| private: |
| template <class U> |
| PointerDeleter(const PointerDeleter<U, ID>&, typename std::enable_if<!std::is_same<U, T>::value>::type* = 0); |
| }; |
| |
| template <class T, size_t ID> |
| class PointerDeleter<T[], ID> { |
| PointerDeleter(const PointerDeleter&); |
| PointerDeleter& operator=(const PointerDeleter&); |
| |
| public: |
| typedef min_pointer<T, std::integral_constant<size_t, ID> > pointer; |
| |
| TEST_CONSTEXPR_CXX23 PointerDeleter() = default; |
| TEST_CONSTEXPR_CXX23 PointerDeleter(PointerDeleter&&) = default; |
| TEST_CONSTEXPR_CXX23 PointerDeleter& operator=(PointerDeleter&&) = default; |
| TEST_CONSTEXPR_CXX23 explicit PointerDeleter(int) {} |
| |
| template <class U> |
| TEST_CONSTEXPR_CXX23 |
| PointerDeleter(PointerDeleter<U, ID>&&, typename std::enable_if<!std::is_same<U, T>::value>::type* = 0) {} |
| |
| TEST_CONSTEXPR_CXX23 void operator()(pointer p) { |
| if (p) { |
| delete[] std::addressof(*p); |
| } |
| } |
| |
| private: |
| template <class U> |
| PointerDeleter(const PointerDeleter<U, ID>&, typename std::enable_if<!std::is_same<U, T>::value>::type* = 0); |
| }; |
| |
| #endif // TEST_STD_VER >= 11 |
| |
| template <class T> |
| class DefaultCtorDeleter { |
| int state_; |
| |
| public: |
| TEST_CONSTEXPR_CXX23 int state() const { return state_; } |
| TEST_CONSTEXPR_CXX23 void operator()(T* p) { delete p; } |
| }; |
| |
| template <class T> |
| class DefaultCtorDeleter<T[]> { |
| int state_; |
| |
| public: |
| TEST_CONSTEXPR_CXX23 int state() const { return state_; } |
| TEST_CONSTEXPR_CXX23 void operator()(T* p) { delete[] p; } |
| }; |
| |
| #endif // SUPPORT_DELETER_TYPES_H |