aboutsummaryrefslogtreecommitdiff
path: root/include/cru/base/ClonePtr.h
blob: 452c2cdd4c83dbf7d02b7082b715ee59a9d1b095 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#pragma once

#include <cstddef>
#include <functional>
#include <memory>
#include <type_traits>

namespace cru {
template <typename T>
class ClonePtr {
  template <typename O>
  friend class ClonePtr;

 public:
  using element_type = typename std::unique_ptr<T>::element_type;
  using pointer = typename std::unique_ptr<T>::pointer;

  ClonePtr() = default;
  ClonePtr(std::nullptr_t) noexcept : ptr_(nullptr) {}
  explicit ClonePtr(pointer p) noexcept : ptr_(p) {}
  ClonePtr(std::unique_ptr<element_type>&& p) noexcept : ptr_(std::move(p)) {}
  template <typename O,
            std::enable_if_t<
                std::is_convertible_v<typename ClonePtr<O>::pointer, pointer>,
                int> = 0>
  ClonePtr(std::unique_ptr<O>&& p) : ptr_(std::move(p)) {}
  ClonePtr(const ClonePtr& other) : ptr_(other.ptr_->Clone()) {}
  ClonePtr(ClonePtr&& other) = default;
  template <typename O,
            std::enable_if_t<
                std::is_convertible_v<typename ClonePtr<O>::pointer, pointer>,
                int> = 0>
  ClonePtr(const ClonePtr<O>& other) : ptr_(other.ptr_->Clone()) {}
  template <typename O,
            std::enable_if_t<
                std::is_convertible_v<typename ClonePtr<O>::pointer, pointer>,
                int> = 0>
  ClonePtr(ClonePtr<O>&& other) noexcept : ptr_(std::move(other.ptr_)) {}
  ClonePtr& operator=(std::nullptr_t) noexcept {
    ptr_ = nullptr;
    return *this;
  }
  ClonePtr& operator=(std::unique_ptr<element_type>&& other) noexcept {
    ptr_ = std::move(other);
    return *this;
  }
  template <typename O,
            std::enable_if_t<
                std::is_convertible_v<typename ClonePtr<O>::pointer, pointer>,
                int> = 0>
  ClonePtr& operator=(std::unique_ptr<O>&& p) noexcept {
    ptr_ = std::move(p);
    return *this;
  }
  ClonePtr& operator=(const ClonePtr& other) {
    if (this != &other) {
      ptr_ = std::unique_ptr<element_type>(other.ptr_->Clone());
    }
    return *this;
  }
  ClonePtr& operator=(ClonePtr&& other) = default;
  template <typename O,
            std::enable_if_t<
                std::is_convertible_v<typename ClonePtr<O>::pointer, pointer>,
                int> = 0>
  ClonePtr& operator=(const ClonePtr<O>& other) noexcept {
    if (this != &other) {
      ptr_ = std::unique_ptr<element_type>(other.ptr_->Clone());
    }
    return *this;
  }
  template <typename O,
            std::enable_if_t<
                std::is_convertible_v<typename ClonePtr<O>::pointer, pointer>,
                int> = 0>
  ClonePtr& operator=(ClonePtr<O>&& other) noexcept {
    ptr_ = std::move(other.ptr_);
  }

  ~ClonePtr() = default;

 public:
  pointer release() noexcept { return ptr_.release(); }
  void reset(pointer p = pointer()) noexcept { ptr_.reset(p); }
  void swap(ClonePtr& other) noexcept { ptr_.swap(other.ptr_); }

 public:
  pointer get() const noexcept { return ptr_.get(); }

  operator bool() const noexcept { return ptr_ != nullptr; }

  element_type& operator*() const noexcept { return *ptr_; }
  pointer operator->() const noexcept { return ptr_.get(); }

  auto operator<=>(std::nullptr_t) const { return ptr_.operator<=>(nullptr); }

  auto operator<=>(const ClonePtr& other) const {
    return ptr_.operator<=>(other.ptr_);
  }

 private:
  std::unique_ptr<element_type> ptr_;
};

template <typename T>
void swap(ClonePtr<T>& left, ClonePtr<T>& right) noexcept {
  left.swap(right);
}

}  // namespace cru

namespace std {
template <typename T>
struct hash<cru::ClonePtr<T>> {
  std::size_t operator()(const cru::ClonePtr<T>& p) const {
    return std::hash<typename cru::ClonePtr<T>::pointer>(p.get());
  }
};
}  // namespace std