xbot/myirc/include/ref.hpp
2025-01-30 16:39:23 -08:00

59 lines
1.5 KiB
C++

#pragma once
#include <openssl/evp.h>
#include <openssl/x509.h>
#include <memory>
// Specializations must Free to release a reference
// Specializations can implement UpRef to increase a reference count on copy
template <typename> struct RefTraits {};
template <> struct RefTraits<EVP_PKEY> {
static constexpr void (*Free)(EVP_PKEY*) = EVP_PKEY_free;
static constexpr int (*UpRef)(EVP_PKEY*) = EVP_PKEY_up_ref;
};
template <> struct RefTraits<X509> {
static constexpr void (*Free)(X509*) = X509_free;
static constexpr int (*UpRef)(X509*) = X509_up_ref;
};
template <> struct RefTraits<EVP_PKEY_CTX> {
static constexpr void (*Free)(EVP_PKEY_CTX*) = EVP_PKEY_CTX_free;
// this type does not implement UpRef
};
template <typename T>
struct RefDeleter {
auto operator()(T *ptr) const -> void { RefTraits<T>::Free(ptr); }
};
template <typename T>
struct Ref : std::unique_ptr<T, RefDeleter<T>>
{
using base = std::unique_ptr<T, RefDeleter<T>>;
/// Owns nothing
Ref() noexcept = default;
/// Takes ownership of the pointer
explicit Ref(T *x) noexcept : base{x} {}
Ref(Ref &&ref) noexcept = default;
Ref(const Ref &ref) noexcept : base{ref.get()} {
if (*this) {
RefTraits<T>::UpRef(this->get());
}
}
Ref &operator=(Ref&&) noexcept = default;
Ref &operator=(const Ref &ref) noexcept {
if (ref) {
RefTraits<T>::UpRef(ref.get());
}
this->reset(ref.get());
return *this;
}
};