Last active
June 7, 2021 11:40
-
-
Save JonathanCline/301922c7e1ba46d9cade85d018d34f4c to your computer and use it in GitHub Desktop.
PIMPL
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #pragma once | |
| #include <type_traits> | |
| #include <concepts> | |
| #include <utility> | |
| #include <cassert> | |
| #include <functional> | |
| namespace sae | |
| { | |
| template <typename T, auto DestroyFunc> requires std::invocable<decltype(DestroyFunc), T*&> | |
| class pimpl_ptr | |
| { | |
| public: | |
| using value_type = T; | |
| using pointer = value_type*; | |
| constexpr pointer& get() noexcept { return this->ptr_; }; | |
| constexpr const pointer& get() const noexcept { return this->ptr_; }; | |
| constexpr pointer operator->() const noexcept { return this->get(); }; | |
| constexpr auto& operator*() noexcept { return *this->get(); }; | |
| constexpr const auto& operator*() const noexcept { return *this->get(); }; | |
| constexpr bool good() const noexcept { return (bool)this->get(); }; | |
| constexpr explicit operator bool() const noexcept { return this->good(); }; | |
| constexpr void release() noexcept | |
| { | |
| this->ptr_ = nullptr; | |
| }; | |
| constexpr void reset() | |
| { | |
| if (this->good()) | |
| { | |
| std::invoke(DestroyFunc, this->ptr_); | |
| this->release(); | |
| }; | |
| assert(!this->good()); | |
| }; | |
| constexpr pointer extract() noexcept | |
| { | |
| auto _out = this->get(); | |
| this->release(); | |
| return _out; | |
| }; | |
| constexpr bool operator==(const pimpl_ptr& other) const { return this->get() == other.get(); }; | |
| constexpr bool operator!=(const pimpl_ptr& other) const { return !(*this == other); }; | |
| constexpr pimpl_ptr() noexcept = default; | |
| constexpr explicit pimpl_ptr(const pointer _ptr) noexcept : | |
| ptr_{ _ptr } | |
| {}; | |
| pimpl_ptr(const pimpl_ptr& other) = delete; | |
| pimpl_ptr& operator=(const pimpl_ptr& other) = delete; | |
| constexpr pimpl_ptr(pimpl_ptr&& other) noexcept : | |
| ptr_{ other.extract() } | |
| {}; | |
| pimpl_ptr& operator=(pimpl_ptr&& other) noexcept | |
| { | |
| this->reset(); | |
| this->ptr_ = other.extract(); | |
| return *this; | |
| }; | |
| ~pimpl_ptr() | |
| { | |
| this->reset(); | |
| }; | |
| private: | |
| pointer ptr_ = nullptr; | |
| }; | |
| /** | |
| * @brief Same as pimpl_ptr but provides an implicit cast to T* | |
| * @tparam T Type to manage pointer to | |
| */ | |
| template <typename T, auto DestroyFunc> requires std::invocable<decltype(DestroyFunc), T*&> | |
| class ipimpl_ptr : public pimpl_ptr<T, DestroyFunc> | |
| { | |
| private: | |
| using parent_type = pimpl_ptr<T, DestroyFunc>; | |
| public: | |
| constexpr operator T* () const noexcept { return this->get(); }; | |
| using parent_type::parent_type; | |
| }; | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment