cosmopolitan/ctl/optional.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

142 lines
2.7 KiB
C
Raw Normal View History

// -*-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<typename T>
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<typename... Args>
void emplace(Args&&... args)
{
reset();
present_ = true;
new (&value_) T(ctl::forward<Args>(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_