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