diff options
| author | Yuqian Yang <crupest@crupest.life> | 2025-11-16 10:22:07 +0800 |
|---|---|---|
| committer | Yuqian Yang <crupest@crupest.life> | 2025-11-16 10:22:07 +0800 |
| commit | d7fbe9332f01153efaea40e7a35f0025c75b9a04 (patch) | |
| tree | 83cace7d4edba6453ed4749efa96921272085796 /include/cru/base | |
| parent | 246eb9266b9349b44cbe96f3f839124ab30cbb89 (diff) | |
| download | cru-d7fbe9332f01153efaea40e7a35f0025c75b9a04.tar.gz cru-d7fbe9332f01153efaea40e7a35f0025c75b9a04.tar.bz2 cru-d7fbe9332f01153efaea40e7a35f0025c75b9a04.zip | |
Abstract out AutoDestruct.
Diffstat (limited to 'include/cru/base')
| -rw-r--r-- | include/cru/base/Guard.h | 112 | ||||
| -rw-r--r-- | include/cru/base/platform/win/Base.h | 73 |
2 files changed, 105 insertions, 80 deletions
diff --git a/include/cru/base/Guard.h b/include/cru/base/Guard.h index 6b6cf851..65e2dee4 100644 --- a/include/cru/base/Guard.h +++ b/include/cru/base/Guard.h @@ -1,7 +1,11 @@ #pragma once +#include "Base.h" +#include "cru/base/Base.h" + #include <cstdlib> #include <functional> +#include <optional> namespace cru { struct Guard { @@ -25,18 +29,23 @@ struct Guard { ExitFunc on_exit; }; -template <typename T> -struct FreeLater { - FreeLater(T* ptr) : ptr(ptr) {} - ~FreeLater() { ::free(ptr); } +/** + * FreeFunc must handle nullptr correctly. + */ +template <typename T, void (*FreeFunc)(T*) noexcept> +struct TAutoFreePtr { + TAutoFreePtr(T* ptr) : ptr(ptr) {} + ~TAutoFreePtr() { FreeFunc(ptr); } - FreeLater(const FreeLater& other) = delete; - FreeLater& operator=(const FreeLater& other) = delete; + CRU_DELETE_COPY(TAutoFreePtr) - FreeLater(FreeLater&& other) : ptr(other.ptr) { other.ptr = nullptr; } - FreeLater& operator=(FreeLater&& other) { + TAutoFreePtr(TAutoFreePtr&& other) noexcept : ptr(other.ptr) { + other.ptr = nullptr; + } + + TAutoFreePtr& operator=(TAutoFreePtr&& other) noexcept { if (this != &other) { - ::free(ptr); + FreeFunc(ptr); ptr = other.ptr; other.ptr = nullptr; } @@ -49,4 +58,89 @@ struct FreeLater { T* ptr; }; +namespace details { +template <typename T> +inline void MyFree(T* p) noexcept { + ::free(p); +} +} // namespace details + +template <typename T> +using AutoFreePtr = TAutoFreePtr<T, details::MyFree<T>>; + +template <typename T, void (*DestructFunc)(T value) noexcept> +class AutoDestruct { + public: + AutoDestruct() : value_(std::nullopt), auto_destruct_(false) {} + + AutoDestruct(T value, bool auto_destruct = true) + : value_(std::move(value)), auto_destruct_(auto_destruct) {} + + CRU_DELETE_COPY(AutoDestruct) + + AutoDestruct(AutoDestruct&& other) noexcept + : value_(std::move(other.value_)), auto_destruct_(other.auto_destruct_) { + other.value_ = std::nullopt; + other.auto_destruct_ = false; + } + + AutoDestruct& operator=(AutoDestruct&& other) noexcept { + if (this != &other) { + DoDestruct(); + value_ = other.value_; + auto_destruct_ = other.auto_destruct_; + other.value_ = std::nullopt; + other.auto_destruct_ = false; + } + return *this; + } + + ~AutoDestruct() { DoDestruct(); } + + public: + bool IsValid() const { return value_.has_value(); } + + void CheckValid( + std::optional<std::string_view> additional_message = std::nullopt) const { + if (!IsValid()) { + std::string message("AutoDestruct contains no object."); + if (additional_message) { + message += " "; + message += *additional_message; + } + throw Exception(std::move(message)); + } + } + + const T& Get() const { + CheckValid(); + return *value_; + } + + T Release() { + CheckValid(); + auto value = std::move(*value_); + value_ = std::nullopt; + auto_destruct_ = false; + return value; + } + + void Reset(std::optional<T> value = std::nullopt) { + DoDestruct(); + value_ = std::move(value); + } + + explicit operator bool() const { return value_.has_value(); } + + private: + void DoDestruct() { + if (auto_destruct_ && value_) { + DestructFunc(*value_); + } + } + + private: + std::optional<T> value_; + bool auto_destruct_; +}; } // namespace cru diff --git a/include/cru/base/platform/win/Base.h b/include/cru/base/platform/win/Base.h index 8d221c83..cdd92541 100644 --- a/include/cru/base/platform/win/Base.h +++ b/include/cru/base/platform/win/Base.h @@ -6,8 +6,8 @@ #include "../../Base.h" #include "../../Bitmask.h" +#include "../../Guard.h" -#include <optional> #include <string_view> #define NOMINMAX @@ -54,80 +54,11 @@ inline void CheckWinReturn(BOOL r, std::string_view message = "") { } } -template <typename H, void (*CloseFunc)(H handle) noexcept> -class CRU_BASE_API TWin32Handle { - public: - TWin32Handle() : handle_(std::nullopt), auto_close_(false) {} - - TWin32Handle(H handle, bool auto_close) - : handle_(handle), auto_close_(auto_close) {} - - CRU_DELETE_COPY(TWin32Handle) - - TWin32Handle(TWin32Handle&& other) noexcept - : handle_(other.handle_), auto_close_(other.auto_close_) { - other.handle_ = std::nullopt; - other.auto_close_ = false; - } - - TWin32Handle& operator=(TWin32Handle&& other) noexcept { - if (this != &other) { - DoClose(); - handle_ = other.handle_; - auto_close_ = other.auto_close_; - other.handle_ = std::nullopt; - other.auto_close_ = false; - } - return *this; - } - - ~TWin32Handle() { DoClose(); } - - public: - bool IsValid() const { return handle_.has_value(); } - - void CheckValid( - std::optional<std::string_view> additional_message = std::nullopt) const { - if (!IsValid()) { - std::string message("The win32 handle is invalid."); - if (additional_message) { - message += " "; - message += *additional_message; - } - throw Exception(std::move(message)); - } - } - - H Get() const { - CheckValid(); - return *handle_; - } - - H Release() { - CheckValid(); - auto handle = *handle_; - handle_ = std::nullopt; - auto_close_ = false; - return handle; - } - - private: - void DoClose() { - if (auto_close_ && handle_) { - CloseFunc(*handle_); - } - } - - private: - std::optional<H> handle_; - bool auto_close_; -}; - namespace details { inline void MyCloseHandle(HANDLE handle) noexcept { ::CloseHandle(handle); } } // namespace details -using Win32Handle = TWin32Handle<HANDLE, details::MyCloseHandle>; +using Win32Handle = AutoDestruct<HANDLE, details::MyCloseHandle>; struct UniDirectionalWin32PipeResult { Win32Handle read; |
