diff options
Diffstat (limited to 'src/crepe/util')
-rw-r--r-- | src/crepe/util/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/crepe/util/Private.cpp | 29 | ||||
-rw-r--r-- | src/crepe/util/Private.h | 34 | ||||
-rw-r--r-- | src/crepe/util/Private.hpp | 31 |
4 files changed, 97 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..c5b5b30 --- /dev/null +++ b/src/crepe/util/Private.cpp @@ -0,0 +1,29 @@ +#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; +} + diff --git a/src/crepe/util/Private.h b/src/crepe/util/Private.h new file mode 100644 index 0000000..fc3728f --- /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(Private &&); + Private & operator=(Private &&); + Private(const Private &) = delete; + Private & operator=(const Private &) = delete; + + template <typename T> + T & get(); + + template <typename T, typename... Args> + void 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..30c8146 --- /dev/null +++ b/src/crepe/util/Private.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include <stdexcept> +#include <format> + +#include "Private.h" + +namespace crepe { + +template <typename T, typename... Args> +void Private::set(Args &&... args) { + 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); +} + +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); +} + +} |