aboutsummaryrefslogtreecommitdiff
path: root/src/crepe/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/crepe/util')
-rw-r--r--src/crepe/util/CMakeLists.txt3
-rw-r--r--src/crepe/util/Private.cpp34
-rw-r--r--src/crepe/util/Private.h34
-rw-r--r--src/crepe/util/Private.hpp33
4 files changed, 104 insertions, 0 deletions
diff --git a/src/crepe/util/CMakeLists.txt b/src/crepe/util/CMakeLists.txt
index 94ed906..f49d851 100644
--- a/src/crepe/util/CMakeLists.txt
+++ b/src/crepe/util/CMakeLists.txt
@@ -1,6 +1,7 @@
target_sources(crepe PUBLIC
LogColor.cpp
Log.cpp
+ Private.cpp
)
target_sources(crepe PUBLIC FILE_SET HEADERS FILES
@@ -11,5 +12,7 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES
Proxy.hpp
OptionalRef.h
OptionalRef.hpp
+ Private.h
+ Private.hpp
)
diff --git a/src/crepe/util/Private.cpp b/src/crepe/util/Private.cpp
new file mode 100644
index 0000000..cb4cb5b
--- /dev/null
+++ b/src/crepe/util/Private.cpp
@@ -0,0 +1,34 @@
+#include "Private.h"
+
+using namespace crepe;
+
+bool Private::empty() const noexcept {
+ return this->instance == nullptr;
+}
+
+Private::~Private() {
+ if (this->instance == nullptr) return;
+ this->destructor(this->instance);
+}
+
+Private::Private(Private && other) {
+ *this = std::move(other);
+}
+
+Private & Private::operator=(Private && other) {
+ // TODO: ideally this function checks for self-assignment
+ this->instance = other.instance;
+ this->destructor = other.destructor;
+ this->type = other.type;
+
+ other.instance = nullptr;
+ other.destructor = [](void*){};
+
+ return *this;
+}
+
+Private::Private(const Private & other) { }
+Private & Private::operator=(const Private & other) {
+ return *this;
+}
+
diff --git a/src/crepe/util/Private.h b/src/crepe/util/Private.h
new file mode 100644
index 0000000..6dd28bb
--- /dev/null
+++ b/src/crepe/util/Private.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <typeindex>
+#include <functional>
+
+namespace crepe {
+
+class Private {
+public:
+ Private() = default;
+ ~Private();
+ Private(const Private &);
+ Private(Private &&);
+ Private & operator=(const Private &);
+ Private & operator=(Private &&);
+
+ template <typename T>
+ T & get();
+
+ template <typename T, typename... Args>
+ T & set(Args &&... args);
+
+ bool empty() const noexcept;
+
+private:
+ std::function<void(void *)> destructor;
+ std::type_index type = typeid(void);
+ void * instance = nullptr;
+};
+
+}
+
+#include "Private.hpp"
+
diff --git a/src/crepe/util/Private.hpp b/src/crepe/util/Private.hpp
new file mode 100644
index 0000000..d6ab23f
--- /dev/null
+++ b/src/crepe/util/Private.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <stdexcept>
+#include <format>
+
+#include "Private.h"
+
+namespace crepe {
+
+template <typename T, typename... Args>
+T & Private::set(Args &&... args) {
+ if (!this->empty()) this->destructor(this->instance);
+ T * instance = new T(std::forward<Args>(args)...);
+ this->instance = static_cast<void*>(instance);
+ this->destructor = [](void * instance) {
+ delete static_cast<T*>(instance);
+ };
+ this->type = typeid(T);
+ return *instance;
+}
+
+template <typename T>
+T & Private::get() {
+ using namespace std;
+ if (this->empty())
+ throw out_of_range("Private: get() called on empty object");
+ type_index requested_type = typeid(T);
+ if (this->type != requested_type)
+ throw logic_error(format("Private: get() called with [T = {}] (actual is [T = {}])", requested_type.name(), this->type.name()));
+ return *static_cast<T*>(this->instance);
+}
+
+}