common: merge dup_handle and handle and use traits

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
Simon Rozman 2025-06-20 10:22:00 +02:00
parent 96ae46eaa9
commit bf4dd4a1d0
4 changed files with 131 additions and 248 deletions

View File

@ -12,41 +12,37 @@
namespace macstd {
///
/// IOKit handle wrapper class
/// Core Foundation object traits
///
template <typename T, const T INVAL>
class cf_object : public handle<T, INVAL>
template <typename T>
struct cfobject_traits
{
MACSTD_HANDLE_IMPL(cf_object, T, INVAL)
static inline constexpr T invalid = static_cast<T>(NULL);
public:
///
/// Releases a Core Foundation object
///
/// \sa [CFRelease function](https://developer.apple.com/documentation/corefoundation/1521153-cfrelease)
///
virtual ~cf_object()
static void free(T h)
{
if (this->m_h != INVAL)
free_internal();
CFRelease(h);
}
protected:
///
/// Releases a Core Foundation object
///
/// \sa [CFRelease function](https://developer.apple.com/documentation/corefoundation/1521153-cfrelease)
///
void free_internal() noexcept override
{
CFRelease(this->m_h);
}
private:
static T duplicate(T h);
};
using cfarray = cf_object<CFArrayRef, static_cast<CFArrayRef>(NULL)>;
using cfdictionary = cf_object<CFDictionaryRef, static_cast<CFDictionaryRef>(NULL)>;
using cferror = cf_object<CFErrorRef, static_cast<CFErrorRef>(NULL)>;
using cfstring = cf_object<CFStringRef, static_cast<CFStringRef>(NULL)>;
///
/// Core Foundation object traits
///
template <typename T>
using cfobject = handle<T, cfobject_traits<T>>;
using cfarray = cfobject<CFArrayRef>;
using cfdictionary = cfobject<CFDictionaryRef>;
using cferror = cfobject<CFErrorRef>;
using cfstring = cfobject<CFStringRef>;
///
/// Core Foundation runtime error

View File

@ -6,41 +6,37 @@
#pragma once
#include "common.hpp"
#import <IOKit/IOKitLib.h>
#include <IOKit/IOKitLib.h>
namespace macstd {
///
/// IOKit handle wrapper class
/// IOKit handle traits
///
template <typename T>
class io_object : public handle<T, 0>
struct io_object_traits
{
MACSTD_HANDLE_IMPL(io_object, T, 0)
static inline constexpr T invalid = 0;
public:
///
/// Releases an object handle
///
/// \sa [IOObjectRelease function](https://developer.apple.com/documentation/iokit/1514627-ioobjectrelease)
///
virtual ~io_object()
static void free(T h) noexcept
{
if (this->m_h != 0)
free_internal();
IOObjectRelease(h);
}
protected:
///
/// Releases an object handle
///
/// \sa [IOObjectRelease function](https://developer.apple.com/documentation/iokit/1514627-ioobjectrelease)
///
void free_internal() noexcept override
{
IOObjectRelease(this->m_h);
}
private:
static T duplicate(T h);
};
///
/// IOKit handle traits
///
template <typename T>
using io_object = handle<T, io_object_traits<T>>;
using io_connect = io_object<io_connect_t>;
using io_enumerator = io_object<io_enumerator_t>;
using io_ident = io_object<io_ident_t>;

View File

@ -73,13 +73,32 @@ namespace macstd
}
};
///
/// Authorization traits
///
struct authorization_traits
{
static inline constexpr AuthorizationRef invalid = static_cast<AuthorizationRef>(NULL);
///
/// Releases an object handle
///
/// \sa [AuthorizationFree function](https://developer.apple.com/documentation/security/authorizationfree)
///
static void free(AuthorizationRef h) noexcept
{
AuthorizationFree(h, kAuthorizationFlagDefaults);
}
private:
static AuthorizationRef duplicate(AuthorizationRef h);
};
///
/// Authorization reference wrapper class
///
class authorization : public handle<AuthorizationRef, static_cast<AuthorizationRef>(NULL)>
class authorization : public handle<AuthorizationRef, authorization_traits>
{
MACSTD_HANDLE_IMPL(authorization, AuthorizationRef, static_cast<AuthorizationRef>(NULL))
public:
///
/// Creates a new authorization reference and provides an option to authorize or preauthorize rights
@ -108,30 +127,8 @@ namespace macstd
throw security_runtime_error(status, "AuthorizationCreateFromExternalForm failed");
this->m_h = h;
}
///
/// Releases an object handle
///
/// \sa [AuthorizationFree function](https://developer.apple.com/documentation/security/authorizationfree)
///
virtual ~authorization()
{
if (this->m_h != static_cast<AuthorizationRef>(NULL))
free_internal();
}
protected:
///
/// Releases an object handle
///
/// \sa [AuthorizationFree function](https://developer.apple.com/documentation/security/authorizationfree)
///
void free_internal() noexcept override
{
AuthorizationFree(this->m_h, kAuthorizationFlagDefaults);
}
};
using sec_keychain = cf_object<SecKeychainRef, static_cast<SecKeychainRef>(NULL)>;
using sec_certificate = cf_object<SecCertificateRef, static_cast<SecCertificateRef>(NULL)>;
using sec_keychain = cfobject<SecKeychainRef>;
using sec_certificate = cfobject<SecCertificateRef>;
}

View File

@ -32,32 +32,6 @@ private: \
///
#define MACSTD_STACK_BUFFER_BYTES 1024
///
/// Implements default constructors and operators to prevent their auto-generation by compiler.
///
#define MACSTD_HANDLE_IMPL(C, T, INVAL) \
public: \
C ( ) noexcept {} \
C (_In_opt_ T h) noexcept : handle<T, INVAL>( h ) {} \
C (_Inout_ C &&h) noexcept : handle<T, INVAL>(std::move(h)) {} \
C& operator=(_In_opt_ T h) noexcept { handle<T, INVAL>::operator=( h ); return *this; } \
C& operator=(_Inout_ C &&h) noexcept { handle<T, INVAL>::operator=(std::move(h)); return *this; } \
MACSTD_NONCOPYABLE(C)
///
/// Implements default constructors and operators to prevent their auto-generation by compiler.
///
#define MACSTD_DPLHANDLE_IMPL(C, T, INVAL) \
public: \
C ( ) noexcept {} \
C (_In_opt_ T h) noexcept : dplhandle<T, INVAL>( h ) {} \
C (_In_ const C &h) noexcept : dplhandle<T, INVAL>(duplicate_internal(h.m_h)) {} \
C (_Inout_ C &&h) noexcept : dplhandle<T, INVAL>(std::move (h )) {} \
C& operator=(_In_opt_ T h) noexcept { dplhandle<T, INVAL>::operator=( h ); return *this; } \
C& operator=(_In_ const C &h) noexcept { dplhandle<T, INVAL>::operator=( h ); return *this; } \
C& operator=(_Inout_ C &&h) noexcept { dplhandle<T, INVAL>::operator=(std::move(h)); return *this; } \
private:
namespace macstd
{
///
@ -65,14 +39,14 @@ namespace macstd
///
/// It provides basic operators and methods common to all descendands of this class establishing a base to ease the replacement of native object handle type with classes in object-oriented approach.
///
template <class T, const T INVAL>
template <class T, class TR>
class handle
{
public:
///
/// Initializes a new class instance with the object handle set to INVAL.
/// Initializes a new class instance with the object handle set to TR::invalid.
///
handle() noexcept : m_h(INVAL)
handle() noexcept : m_h(TR::invalid)
{}
///
@ -83,49 +57,74 @@ namespace macstd
handle(_In_opt_ T h) noexcept : m_h(h)
{}
///
/// Copy constructor
///
/// \param[in,out] h A reference of another object
///
handle(const handle<T, TR> &h) : m_h(TR::duplicate(h.m_h))
{}
///
/// Move constructor
///
/// \param[in,out] h A rvalue reference of another object
///
handle(_Inout_ handle<T, INVAL> &&h) noexcept
handle(handle<T, TR> &&h) noexcept
{
// Transfer handle.
m_h = h.m_h;
h.m_h = INVAL;
h.m_h = TR::invalid;
}
private:
// This class is noncopyable.
handle(_In_ const handle<T, INVAL> &h) noexcept {};
handle<T, INVAL>& operator=(_In_ const handle<T, INVAL> &h) noexcept {};
public:
///
/// Attaches already available object handle.
///
/// \param[in] h Object handle value
///
handle<T, INVAL>& operator=(_In_opt_ T h) noexcept
handle<T, TR>& operator=(_In_opt_ T h) noexcept
{
attach(h);
return *this;
}
///
/// Duplicates the object.
///
/// \param[in] h Object
///
handle<T, TR>& operator=(const handle<T, TR> &h) noexcept
{
if (this != std::addressof(h)) {
if (h.m_h != TR::invalid) {
T h_new = TR::duplicate(h.m_h);
if (this->m_h != TR::invalid)
TR::free(this->m_h);
this->m_h = h_new;
} else {
if (this->m_h != TR::invalid)
TR::free(this->m_h);
this->m_h = TR::invalid;
}
}
return *this;
}
///
/// Move assignment
///
/// \param[inout] h A rvalue reference of another object
/// \param[in,out] h A rvalue reference of another object
///
#pragma warning(suppress: 26432) // Move constructor is also present, but not detected by code analysis somehow.
handle<T, INVAL>& operator=(_Inout_ handle<T, INVAL> &&h) noexcept
handle<T, TR>& operator=(handle<T, TR> &&h) noexcept
{
if (this != std::addressof(h)) {
// Transfer handle.
if (m_h != INVAL)
free_internal();
if (m_h != TR::invalid)
TR::free(this->m_h);
m_h = h.m_h;
h.m_h = INVAL;
h.m_h = TR::invalid;
}
return *this;
}
@ -147,7 +146,7 @@ namespace macstd
///
T*& operator*() const
{
assert(m_h != INVAL);
assert(m_h != TR::invalid);
return *m_h;
}
@ -157,7 +156,7 @@ namespace macstd
///
T* operator&()
{
assert(m_h == INVAL);
assert(m_h == TR::invalid);
return &m_h;
}
@ -168,7 +167,7 @@ namespace macstd
///
T operator->() const
{
assert(m_h != INVAL);
assert(m_h != TR::invalid);
return m_h;
}
@ -183,7 +182,7 @@ namespace macstd
///
bool valid() const
{
return m_h != INVAL;
return m_h != TR::invalid;
}
///
@ -264,20 +263,42 @@ namespace macstd
return m_h == h;
}
///
/// Duplicates and returns a new object handle.
///
/// \return Duplicated object handle
///
T duplicate() const
{
return this->m_h != TR::invalid ? TR::duplicate(this->m_h) : TR::invalid;
}
///
/// Sets a new object handle for the class
///
/// When the current object handle of the class is non-INVAL, the object is destroyed first.
/// When the current object handle of the class is non-TR::invalid, the object is destroyed first.
///
/// \param[in] h New object handle
///
void attach(_In_opt_ T h) noexcept
{
if (m_h != INVAL)
free_internal();
if (m_h != TR::invalid)
TR::free(m_h);
m_h = h;
}
///
/// Duplicates an object handle and sets a new object handle.
///
/// \param[in] h Object handle of existing object
///
void attach_duplicated(_In_opt_ T h)
{
if (this->m_h != TR::invalid)
TR::free(this->m_h);
this->m_h = h != TR::invalid ? TR::duplicate(h) : TR::invalid;
}
///
/// Dismisses the object handle from this class
///
@ -286,7 +307,7 @@ namespace macstd
T detach()
{
T h = m_h;
m_h = INVAL;
m_h = TR::invalid;
return h;
}
@ -295,143 +316,16 @@ namespace macstd
///
void free()
{
if (m_h != INVAL) {
free_internal();
m_h = INVAL;
if (m_h != TR::invalid) {
TR::free(m_h);
m_h = TR::invalid;
}
}
protected:
///
/// Abstract member function that must be implemented by child classes to do the actual object destruction.
///
virtual void free_internal() noexcept = 0;
protected:
T m_h; ///< Object handle
};
///
/// Base abstract template class to support object handle keeping for objects that support trivial handle duplication
///
template <class T, T INVAL>
class dplhandle : public handle<T, INVAL>
{
public:
///
/// Initializes a new class instance with the object handle set to INVAL.
///
dplhandle() noexcept
{}
///
/// Initializes a new class instance with an already available object handle.
///
/// \param[in] h Initial object handle value
///
dplhandle(_In_opt_ T h) noexcept : handle<T, INVAL>(h)
{}
///
/// Copy constructor
///
/// \param[in,out] h A reference of another object
///
dplhandle<T, INVAL>(_In_ const dplhandle<T, INVAL> &h) : handle<T, INVAL>(duplicate_internal(h.m_h))
{}
///
/// Move constructor
///
/// \param[in,out] h A rvalue reference of another object
///
dplhandle<T, INVAL>(_Inout_ dplhandle<T, INVAL> &&h) noexcept : handle<T, INVAL>(std::move(h))
{}
///
/// Attaches already available object handle.
///
/// \param[in] h Object handle value
///
dplhandle<T, INVAL>& operator=(_In_opt_ T h) noexcept
{
handle<T, INVAL>::operator=(h);
return *this;
}
///
/// Duplicates the object.
///
/// \param[in] h Object
///
dplhandle<T, INVAL>& operator=(_In_ const dplhandle<T, INVAL> &h) noexcept
{
if (this != std::addressof(h)) {
if (h.m_h != INVAL) {
T h_new = duplicate_internal(h.m_h);
if (this->m_h != INVAL)
this->free_internal();
this->m_h = h_new;
} else {
if (this->m_h != INVAL)
this->free_internal();
this->m_h = INVAL;
}
}
return *this;
}
///
/// Moves the object.
///
/// \param[inout] h A rvalue reference of another object
///
#pragma warning(disable: 26432) // Move constructor is also present, but not detected by code analysis somehow.
dplhandle<T, INVAL>& operator=(_Inout_ dplhandle<T, INVAL> &&h) noexcept
{
handle<T, INVAL>::operator=(std::move(h));
return *this;
}
///
/// Duplicates and returns a new object handle.
///
/// \return Duplicated object handle
///
T duplicate() const
{
return this->m_h != INVAL ? duplicate_internal(this->m_h) : INVAL;
}
///
/// Duplicates an object handle and sets a new object handle.
///
/// \param[in] h Object handle of existing object
///
void attach_duplicated(_In_opt_ T h)
{
if (this->m_h != INVAL)
this->free_internal();
this->m_h = h != INVAL ? duplicate_internal(h) : INVAL;
}
protected:
///
/// Abstract member function that must be implemented by child classes to do the actual object handle duplication.
/// On failure, it should throw appropriate exception describing the cause, rather than return an invalid handle.
///
/// \param[in] h Object handle of existing object
///
/// \return Duplicated object handle
///
virtual T duplicate_internal(_In_ T h) const = 0;
};
///
/// Numerical runtime error
///