373 lines
7.7 KiB
C++
373 lines
7.7 KiB
C++
/*
|
|
SPDX-License-Identifier: MIT
|
|
Copyright © 2023-2025 Amebis
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <stddef.h>
|
|
|
|
///
|
|
/// Declares a class as non-copyable
|
|
///
|
|
#define MACSTD_NONCOPYABLE(C) \
|
|
private: \
|
|
C (_In_ const C &h) noexcept; \
|
|
C& operator=(_In_ const C &h) noexcept;
|
|
|
|
///
|
|
/// Declares a class as non-movable
|
|
///
|
|
#define MACSTD_NONMOVABLE(C) \
|
|
private: \
|
|
C (_Inout_ C &&h) noexcept; \
|
|
C& operator=(_Inout_ C &&h) noexcept;
|
|
|
|
///
|
|
/// Size of the stack buffer in bytes used for initial system function call
|
|
///
|
|
/// Some system functions with variable length output data fail for insufficient buffer sizes. The function helpers use a fixed size stack buffer first. If the stack buffer really prooved sufficient, the helper allocates the exact length output on heap and copies the data without calling the system function again. Otherwise it allocates the memory on heap and retries.
|
|
///
|
|
/// \note Decrease this value in case of stack overflow.
|
|
///
|
|
#define MACSTD_STACK_BUFFER_BYTES 1024
|
|
|
|
namespace macstd
|
|
{
|
|
///
|
|
/// Base abstract template class to support generic object handle keeping
|
|
///
|
|
/// 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, class TR>
|
|
class handle
|
|
{
|
|
public:
|
|
///
|
|
/// Initializes a new class instance with the object handle set to TR::invalid.
|
|
///
|
|
handle() noexcept : m_h(TR::invalid)
|
|
{}
|
|
|
|
///
|
|
/// Initializes a new class instance with an already available object handle.
|
|
///
|
|
/// \param[in] h Initial object handle value
|
|
///
|
|
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(handle<T, TR> &&h) noexcept
|
|
{
|
|
// Transfer handle.
|
|
m_h = h.m_h;
|
|
h.m_h = TR::invalid;
|
|
}
|
|
|
|
public:
|
|
///
|
|
/// Attaches already available object handle.
|
|
///
|
|
/// \param[in] h Object handle value
|
|
///
|
|
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[in,out] h A rvalue reference of another object
|
|
///
|
|
handle<T, TR>& operator=(handle<T, TR> &&h) noexcept
|
|
{
|
|
if (this != std::addressof(h)) {
|
|
// Transfer handle.
|
|
if (m_h != TR::invalid)
|
|
TR::free(this->m_h);
|
|
m_h = h.m_h;
|
|
h.m_h = TR::invalid;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
///
|
|
/// Auto-typecasting operator
|
|
///
|
|
/// \return Object handle
|
|
///
|
|
operator T() const
|
|
{
|
|
return m_h;
|
|
}
|
|
|
|
///
|
|
/// Returns the object handle value when the object handle is a pointer to a value (class, struct, etc.).
|
|
///
|
|
/// \return Object handle value
|
|
///
|
|
T*& operator*() const
|
|
{
|
|
assert(m_h != TR::invalid);
|
|
return *m_h;
|
|
}
|
|
|
|
///
|
|
/// Returns the object handle reference.
|
|
/// \return Object handle reference
|
|
///
|
|
T* operator&()
|
|
{
|
|
assert(m_h == TR::invalid);
|
|
return &m_h;
|
|
}
|
|
|
|
///
|
|
/// Provides object handle member access when the object handle is a pointer to a class or struct.
|
|
///
|
|
/// \return Object handle
|
|
///
|
|
T operator->() const
|
|
{
|
|
assert(m_h != TR::invalid);
|
|
return m_h;
|
|
}
|
|
|
|
///
|
|
/// Tests if the object handle is valid.
|
|
///
|
|
/// \return
|
|
/// - Non zero when object handle is valid;
|
|
/// - Zero otherwise.
|
|
///
|
|
/// \note Implementing `operator bool() const` would be correct C++ approach here. Unfortunately, it would produce ambiguities where `bool` and `T` are polymorphed.
|
|
///
|
|
bool valid() const
|
|
{
|
|
return m_h != TR::invalid;
|
|
}
|
|
|
|
///
|
|
/// Is handle less than?
|
|
///
|
|
/// \param[in] h Object handle to compare against
|
|
/// \return
|
|
/// - Non zero when object handle is less than h;
|
|
/// - Zero otherwise.
|
|
///
|
|
bool operator<(_In_opt_ T h) const
|
|
{
|
|
return m_h < h;
|
|
}
|
|
|
|
///
|
|
/// Is handle less than or equal to?
|
|
///
|
|
/// \param[in] h Object handle to compare against
|
|
/// \return
|
|
/// - Non zero when object handle is less than or equal to h;
|
|
/// - Zero otherwise.
|
|
///
|
|
bool operator<=(_In_opt_ T h) const
|
|
{
|
|
return !operator>(h);
|
|
}
|
|
|
|
///
|
|
/// Is handle greater than or equal to?
|
|
///
|
|
/// \param[in] h Object handle to compare against
|
|
/// \return
|
|
/// - Non zero when object handle is greater than or equal to h;
|
|
/// - Zero otherwise.
|
|
///
|
|
bool operator>=(_In_opt_ T h) const
|
|
{
|
|
return !operator<(h);
|
|
}
|
|
|
|
///
|
|
/// Is handle greater than?
|
|
///
|
|
/// \param[in] h Object handle to compare against
|
|
/// \return
|
|
/// - Non zero when object handle is greater than h;
|
|
/// - Zero otherwise.
|
|
///
|
|
bool operator>(_In_opt_ T h) const
|
|
{
|
|
return h < m_h;
|
|
}
|
|
|
|
///
|
|
/// Is handle not equal to?
|
|
///
|
|
/// \param[in] h Object handle to compare against
|
|
/// \return
|
|
/// - Non zero when object handle is not equal to h;
|
|
/// - Zero otherwise.
|
|
///
|
|
bool operator!=(_In_opt_ T h) const
|
|
{
|
|
return !operator==(h);
|
|
}
|
|
|
|
///
|
|
/// Is handle equal to?
|
|
///
|
|
/// \param[in] h Object handle to compare against
|
|
/// \return
|
|
/// - Non zero when object handle is equal to h;
|
|
/// - Zero otherwise.
|
|
///
|
|
bool operator==(_In_opt_ T h) const
|
|
{
|
|
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-TR::invalid, the object is destroyed first.
|
|
///
|
|
/// \param[in] h New object handle
|
|
///
|
|
void attach(_In_opt_ T h) noexcept
|
|
{
|
|
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
|
|
///
|
|
/// \return Object handle
|
|
///
|
|
T detach()
|
|
{
|
|
T h = m_h;
|
|
m_h = TR::invalid;
|
|
return h;
|
|
}
|
|
|
|
///
|
|
/// Destroys the object
|
|
///
|
|
void free()
|
|
{
|
|
if (m_h != TR::invalid) {
|
|
TR::free(m_h);
|
|
m_h = TR::invalid;
|
|
}
|
|
}
|
|
|
|
protected:
|
|
T m_h; ///< Object handle
|
|
};
|
|
|
|
///
|
|
/// Numerical runtime error
|
|
///
|
|
template <typename _Tn>
|
|
class num_runtime_error : public std::runtime_error
|
|
{
|
|
public:
|
|
typedef _Tn error_type; ///< Error number type
|
|
|
|
public:
|
|
///
|
|
/// Constructs an exception
|
|
///
|
|
/// \param[in] num Numeric error code
|
|
/// \param[in] msg Error message
|
|
///
|
|
num_runtime_error(_In_ error_type num, _In_ const std::string& msg) :
|
|
m_num(num),
|
|
runtime_error(msg)
|
|
{}
|
|
|
|
///
|
|
/// Constructs an exception
|
|
///
|
|
/// \param[in] num Numeric error code
|
|
/// \param[in] msg Error message
|
|
///
|
|
num_runtime_error(_In_ error_type num, _In_z_ const char *msg) :
|
|
m_num(num),
|
|
runtime_error(msg)
|
|
{}
|
|
|
|
///
|
|
/// Returns the error number
|
|
///
|
|
error_type number() const
|
|
{
|
|
return m_num;
|
|
}
|
|
|
|
protected:
|
|
error_type m_num; ///< Numeric error code
|
|
};
|
|
}
|