cosmopolitan/ctl/optional.h
Jōshin 32643e9fa7
Decouple swap from std (#1211)
This allows you to implement your own swap function without it having to
be part of the std namespace. std::swap is still used if it's available.
2024-06-10 03:40:17 -07:00

143 lines
2.8 KiB
C++

// -*-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/forward.h>
#include <__utility/move.h>
#include <__utility/swap.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(std::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(std::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(std::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 std::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(std::forward<Args>(args)...);
}
void swap(optional& other) noexcept
{
using std::swap;
if (present_ && other.present_) {
swap(value_, other.value_);
} else if (present_) {
other.emplace(std::move(value_));
reset();
} else if (other.present_) {
emplace(std::move(other.value_));
other.reset();
}
}
private:
union
{
T value_;
};
bool present_;
};
} // namespace ctl
#endif // COSMOPOLITAN_CTL_OPTIONAL_H_