aboutsummaryrefslogtreecommitdiff
path: root/include/cru/base/Guard.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/cru/base/Guard.h')
-rw-r--r--include/cru/base/Guard.h112
1 files changed, 103 insertions, 9 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