PrOSess/kernel/include/util/optional.h

185 lines
4.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.
struct nullopt_t {};
inline constexpr nullopt_t nullopt{};
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) {}
constexpr optional(nullopt_t) : 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 Func>
auto map(Func&& func) -> optional<decltype(func(value()))> {
if (initialized) {
return func(value());
} else {
return {};
}
}
template<typename Func>
auto map(Func&& func) const -> optional<decltype(func(value()))> {
if (initialized) {
return func(value());
} else {
return {};
}
}
template<typename Func>
optional or_else(Func&& func) const {
if (initialized) {
return *this;
}
return func();
}
template<typename Func>
auto bind(Func&& func) -> decltype(func(value())) {
if (initialized) {
return func(value());
} else {
return {};
}
}
template<typename Func>
auto bind(Func&& func) const -> decltype(func(value())) {
if (initialized) {
return func(value());
} else {
return {};
}
}
};