Skip to content

Instantly share code, notes, and snippets.

@JonathanCline
Last active June 7, 2021 11:40
Show Gist options
  • Save JonathanCline/301922c7e1ba46d9cade85d018d34f4c to your computer and use it in GitHub Desktop.
Save JonathanCline/301922c7e1ba46d9cade85d018d34f4c to your computer and use it in GitHub Desktop.
PIMPL
#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