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 { namespace macstd {
/// ///
/// IOKit handle wrapper class /// Core Foundation object traits
/// ///
template <typename T, const T INVAL> template <typename T>
class cf_object : public handle<T, INVAL> 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 /// Releases a Core Foundation object
/// ///
/// \sa [CFRelease function](https://developer.apple.com/documentation/corefoundation/1521153-cfrelease) /// \sa [CFRelease function](https://developer.apple.com/documentation/corefoundation/1521153-cfrelease)
/// ///
virtual ~cf_object() static void free(T h)
{ {
if (this->m_h != INVAL) CFRelease(h);
free_internal();
} }
protected: private:
/// static T duplicate(T h);
/// 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);
}
}; };
using cfarray = cf_object<CFArrayRef, static_cast<CFArrayRef>(NULL)>; ///
using cfdictionary = cf_object<CFDictionaryRef, static_cast<CFDictionaryRef>(NULL)>; /// Core Foundation object traits
using cferror = cf_object<CFErrorRef, static_cast<CFErrorRef>(NULL)>; ///
using cfstring = cf_object<CFStringRef, static_cast<CFStringRef>(NULL)>; 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 /// Core Foundation runtime error

View File

@ -6,41 +6,37 @@
#pragma once #pragma once
#include "common.hpp" #include "common.hpp"
#import <IOKit/IOKitLib.h> #include <IOKit/IOKitLib.h>
namespace macstd { namespace macstd {
/// ///
/// IOKit handle wrapper class /// IOKit handle traits
/// ///
template <typename T> 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 /// Releases an object handle
/// ///
/// \sa [IOObjectRelease function](https://developer.apple.com/documentation/iokit/1514627-ioobjectrelease) /// \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) IOObjectRelease(h);
free_internal();
} }
protected: private:
/// static T duplicate(T h);
/// Releases an object handle
///
/// \sa [IOObjectRelease function](https://developer.apple.com/documentation/iokit/1514627-ioobjectrelease)
///
void free_internal() noexcept override
{
IOObjectRelease(this->m_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_connect = io_object<io_connect_t>;
using io_enumerator = io_object<io_enumerator_t>; using io_enumerator = io_object<io_enumerator_t>;
using io_ident = io_object<io_ident_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 /// 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: public:
/// ///
/// Creates a new authorization reference and provides an option to authorize or preauthorize rights /// 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"); throw security_runtime_error(status, "AuthorizationCreateFromExternalForm failed");
this->m_h = h; 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_keychain = cfobject<SecKeychainRef>;
using sec_certificate = cf_object<SecCertificateRef, static_cast<SecCertificateRef>(NULL)>; using sec_certificate = cfobject<SecCertificateRef>;
} }

View File

@ -32,32 +32,6 @@ private: \
/// ///
#define MACSTD_STACK_BUFFER_BYTES 1024 #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 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. /// 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 class handle
{ {
public: 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) 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 /// Move constructor
/// ///
/// \param[in,out] h A rvalue reference of another object /// \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. // Transfer handle.
m_h = h.m_h; 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: public:
/// ///
/// Attaches already available object handle. /// Attaches already available object handle.
/// ///
/// \param[in] h Object handle value /// \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); attach(h);
return *this; 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 /// 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, TR>& operator=(handle<T, TR> &&h) noexcept
handle<T, INVAL>& operator=(_Inout_ handle<T, INVAL> &&h) noexcept
{ {
if (this != std::addressof(h)) { if (this != std::addressof(h)) {
// Transfer handle. // Transfer handle.
if (m_h != INVAL) if (m_h != TR::invalid)
free_internal(); TR::free(this->m_h);
m_h = h.m_h; m_h = h.m_h;
h.m_h = INVAL; h.m_h = TR::invalid;
} }
return *this; return *this;
} }
@ -147,7 +146,7 @@ namespace macstd
/// ///
T*& operator*() const T*& operator*() const
{ {
assert(m_h != INVAL); assert(m_h != TR::invalid);
return *m_h; return *m_h;
} }
@ -157,7 +156,7 @@ namespace macstd
/// ///
T* operator&() T* operator&()
{ {
assert(m_h == INVAL); assert(m_h == TR::invalid);
return &m_h; return &m_h;
} }
@ -168,7 +167,7 @@ namespace macstd
/// ///
T operator->() const T operator->() const
{ {
assert(m_h != INVAL); assert(m_h != TR::invalid);
return m_h; return m_h;
} }
@ -183,7 +182,7 @@ namespace macstd
/// ///
bool valid() const bool valid() const
{ {
return m_h != INVAL; return m_h != TR::invalid;
} }
/// ///
@ -264,20 +263,42 @@ namespace macstd
return m_h == h; 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 /// 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 /// \param[in] h New object handle
/// ///
void attach(_In_opt_ T h) noexcept void attach(_In_opt_ T h) noexcept
{ {
if (m_h != INVAL) if (m_h != TR::invalid)
free_internal(); TR::free(m_h);
m_h = 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 /// Dismisses the object handle from this class
/// ///
@ -286,7 +307,7 @@ namespace macstd
T detach() T detach()
{ {
T h = m_h; T h = m_h;
m_h = INVAL; m_h = TR::invalid;
return h; return h;
} }
@ -295,143 +316,16 @@ namespace macstd
/// ///
void free() void free()
{ {
if (m_h != INVAL) { if (m_h != TR::invalid) {
free_internal(); TR::free(m_h);
m_h = INVAL; 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: protected:
T m_h; ///< Object handle 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 /// Numerical runtime error
/// ///