#ifndef unique_ptr_hh_INCLUDED #define unique_ptr_hh_INCLUDED #include #include #include namespace Kakoune { template class UniquePtr { using Type = std::remove_extent_t; public: explicit UniquePtr(Type* ptr = nullptr) : m_ptr{ptr} {} UniquePtr(nullptr_t) : m_ptr{nullptr} {} UniquePtr(const UniquePtr&) = delete; UniquePtr& operator=(const UniquePtr&) = delete; template requires std::is_convertible_v UniquePtr(UniquePtr&& other) noexcept { m_ptr = other.release(); } template requires std::is_convertible_v UniquePtr& operator=(UniquePtr&& other) noexcept(noexcept(std::declval().~Type())) { destroy(); m_ptr = other.release(); return *this; } ~UniquePtr() { destroy(); } Type* get() const { return m_ptr; } Type* operator->() const { return m_ptr; }; Type& operator*() const { return *m_ptr; }; Type& operator[](size_t i) const requires std::is_array_v { return m_ptr[i]; } Type* release() { auto ptr = m_ptr; m_ptr = nullptr; return ptr; } void reset(Type* ptr = nullptr) { destroy(); m_ptr = ptr; } explicit operator bool() const { return m_ptr != nullptr; } friend bool operator==(const UniquePtr&, const UniquePtr&) = default; friend bool operator==(const UniquePtr& lhs, const Type* rhs) { return lhs.get() == rhs; } private: void destroy() { if constexpr (std::is_array_v) delete[] m_ptr; else delete m_ptr; m_ptr = nullptr; } Type* m_ptr; }; template UniquePtr make_unique_ptr(Args&&... args) { return UniquePtr(new T(std::forward(args)...)); } } #endif // unique_ptr_hh_INCLUDED