PrOSess/kernel/include/util/optional.h

122 lines
3.1 KiB
C++

#pragma once
#include "memory/pointer.h"
#include "util/number.h"
#include "util/utility.h"
// Ported from legacy/CrackOS3 (include/features/optional.h), adapted to the
// PrOSess freestanding environment: uses the in-tree move/forward (util/utility.h)
// instead of <utility>. The CrackOS3 value_or_panic() helper is omitted because
// there is no global panic() in this tree yet.
template<typename T>
struct optional {
private:
char buffer[sizeof(T)];
bool initialized;
void destroy() {
if (initialized) {
((T*)buffer)->~T();
initialized = false;
}
}
public:
using value_type = T;
constexpr optional() : initialized(false) {}
optional(const T& value) : initialized(true) { new (buffer) T(value); }
optional(T&& value) : initialized(true) { new (buffer) T(move(value)); }
optional(const optional& other) : initialized(other.initialized) {
if (initialized) {
new (buffer) T(*other);
}
}
optional(optional&& other) : initialized(other.initialized) {
if (initialized) {
new (buffer) T(move(*other));
}
other.initialized = false;
}
~optional() { destroy(); }
T* operator->() { return (T*)buffer; }
T& operator*() { return *((T*)buffer); }
const T* operator->() const { return (const T*)buffer; }
const T& operator*() const { return *((const T*)buffer); }
optional& operator=(const optional& other) {
if (this == &other)
return *this;
destroy();
if (other.initialized) {
new (buffer) T(*other);
initialized = true;
}
return *this;
}
optional& operator=(optional&& other) noexcept {
if (this == &other)
return *this;
destroy();
if (other.initialized) {
new (buffer) T(move(*other));
initialized = true;
}
other.initialized = false;
return *this;
}
[[nodiscard]] bool has_value() const { return initialized; }
T& value() { return *((T*)buffer); }
const T& value() const { return *((const T*)buffer); }
template<typename Func, typename... ArgT>
T value_or_create(Func func, ArgT... args) {
if (initialized) {
return value();
} else {
return func(args...);
}
}
template<typename Func, typename... ArgT>
T value_or_create(Func func, ArgT... args) const {
if (initialized) {
return value();
} else {
return func(args...);
}
}
const T& value_or(const T& default_value) const {
if (initialized) {
return *((const T*)buffer);
} else {
return default_value;
}
}
operator bool() const { return initialized; }
bool operator!() const { return !initialized; }
template<typename R, typename Func, typename... ArgT>
optional<R> map(Func func, ArgT... args) {
if (initialized) {
return func(value(), forward<ArgT>(args)...);
} else {
return {};
}
}
};