#pragma once #include #include #include #include namespace cru { template class ClonePtr { template friend class ClonePtr; public: using element_type = typename std::unique_ptr::element_type; using pointer = typename std::unique_ptr::pointer; ClonePtr() = default; ClonePtr(std::nullptr_t) noexcept : ptr_(nullptr) {} explicit ClonePtr(pointer p) noexcept : ptr_(p) {} ClonePtr(std::unique_ptr&& p) noexcept : ptr_(std::move(p)) {} template ::pointer, pointer>, int> = 0> ClonePtr(std::unique_ptr&& p) : ptr_(std::move(p)) {} ClonePtr(const ClonePtr& other) : ptr_(other.ptr_->Clone()) {} ClonePtr(ClonePtr&& other) = default; template ::pointer, pointer>, int> = 0> ClonePtr(const ClonePtr& other) : ptr_(other.ptr_->Clone()) {} template ::pointer, pointer>, int> = 0> ClonePtr(ClonePtr&& other) noexcept : ptr_(std::move(other.ptr_)) {} ClonePtr& operator=(std::nullptr_t) noexcept { ptr_ = nullptr; return *this; } ClonePtr& operator=(std::unique_ptr&& other) noexcept { ptr_ = std::move(other); return *this; } template ::pointer, pointer>, int> = 0> ClonePtr& operator=(std::unique_ptr&& p) noexcept { ptr_ = std::move(p); return *this; } ClonePtr& operator=(const ClonePtr& other) { if (this != &other) { ptr_ = std::unique_ptr(other.ptr_->Clone()); } return *this; } ClonePtr& operator=(ClonePtr&& other) = default; template ::pointer, pointer>, int> = 0> ClonePtr& operator=(const ClonePtr& other) noexcept { if (this != &other) { ptr_ = std::unique_ptr(other.ptr_->Clone()); } return *this; } template ::pointer, pointer>, int> = 0> ClonePtr& operator=(ClonePtr&& 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 ptr_; }; template void swap(ClonePtr& left, ClonePtr& right) noexcept { left.swap(right); } } // namespace cru namespace std { template struct hash> { std::size_t operator()(const cru::ClonePtr& p) const { return std::hash::pointer>(p.get()); } }; } // namespace std