// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*- // vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi #ifndef COSMOPOLITAN_CTL_OPTIONAL_H_ #define COSMOPOLITAN_CTL_OPTIONAL_H_ #include "new.h" #include "utility.h" namespace ctl { template class optional { public: using value_type = T; ~optional() { if (present_) value_.~T(); } optional() noexcept : present_(false) { } optional(const T& value) : present_(true) { new (&value_) T(value); } optional(T&& value) : present_(true) { new (&value_) T(ctl::move(value)); } optional(const optional& other) : present_(other.present_) { if (other.present_) new (&value_) T(other.value_); } optional(optional&& other) noexcept : present_(other.present_) { if (other.present_) new (&value_) T(ctl::move(other.value_)); } optional& operator=(const optional& other) { if (this != &other) { reset(); if (other.present_) new (&value_) T(other.value_); present_ = other.present_; } return *this; } optional& operator=(optional&& other) noexcept { if (this != &other) { reset(); if (other.present_) new (&value_) T(ctl::move(other.value_)); present_ = other.present_; } return *this; } T& value() & { if (!present_) __builtin_trap(); return value_; } const T& value() const& { if (!present_) __builtin_trap(); return value_; } T&& value() && { if (!present_) __builtin_trap(); return ctl::move(value_); } explicit operator bool() const noexcept { return present_; } bool has_value() const noexcept { return present_; } void reset() noexcept { if (present_) { value_.~T(); present_ = false; } } template void emplace(Args&&... args) { reset(); present_ = true; new (&value_) T(ctl::forward(args)...); } void swap(optional& other) noexcept { using ctl::swap; if (present_ && other.present_) { swap(value_, other.value_); } else if (present_) { other.emplace(ctl::move(value_)); reset(); } else if (other.present_) { emplace(ctl::move(other.value_)); other.reset(); } } private: union { T value_; }; bool present_; }; } // namespace ctl #endif // COSMOPOLITAN_CTL_OPTIONAL_H_