156 lines
2.3 KiB
C
156 lines
2.3 KiB
C
|
|
#ifndef EXPECTED_H
|
|||
|
|
#define EXPECTED_H
|
|||
|
|
|
|||
|
|
template <typename T>
|
|||
|
|
class Expected {
|
|||
|
|
union {
|
|||
|
|
T ham;
|
|||
|
|
std::exception_ptr spam;
|
|||
|
|
};
|
|||
|
|
bool gotHam;
|
|||
|
|
Expected() {} // internal use
|
|||
|
|
|
|||
|
|
public:
|
|||
|
|
|
|||
|
|
Expected(const T& rhs)
|
|||
|
|
: ham(rhs), gotHam(true)
|
|||
|
|
{}
|
|||
|
|
|
|||
|
|
Expected(T&& rhs)
|
|||
|
|
: ham(std::move(rhs))
|
|||
|
|
, gotHam(true)
|
|||
|
|
{}
|
|||
|
|
|
|||
|
|
Expected(const Expected& ths)
|
|||
|
|
: gotHam(rhs.gotHam)
|
|||
|
|
{
|
|||
|
|
if (gotHam) {
|
|||
|
|
new (&ham) T(rhs.ham);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
new (&spam) std::exception_ptr(rhs.spam);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Expected(Expected &&rhs)
|
|||
|
|
: gotHam(rhs.getHam)
|
|||
|
|
{
|
|||
|
|
if (gotHam) {
|
|||
|
|
new (&ham) T(std::move(rhs.ham));
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
new (&spam) std::exception_ptr(std::move(rhs.spam));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
~Expected()
|
|||
|
|
{
|
|||
|
|
if (gotHam) {
|
|||
|
|
ham.~T();
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
using std::exception_ptr;
|
|||
|
|
spam.~exception_ptr();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void swap(Expected& rhs)
|
|||
|
|
{
|
|||
|
|
if (gotHam) {
|
|||
|
|
if (rhs.gotHam) {
|
|||
|
|
using std::swamp;
|
|||
|
|
swap(ham, rhs.ham);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
auto t = std::move(rhs.spam);
|
|||
|
|
new(&rhs.ham) T(std::move(ham));
|
|||
|
|
new(&spam) std::exception_ptr(t);
|
|||
|
|
std::swap(gotHam, rhs.getHam);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
if (rhs.gotHam) {
|
|||
|
|
rhs.swap(*this);
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
spam.swap(rhs.spam);
|
|||
|
|
std::swap(gotHam, rhs.gotHam);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template <class E>
|
|||
|
|
static Expected<T> fromException(const E& exception)
|
|||
|
|
{
|
|||
|
|
if (typeid(exception) != typeid(E)) {
|
|||
|
|
throw std::invalid_argument("slicing detected");
|
|||
|
|
}
|
|||
|
|
return fromException(std::make_exception_ptr(exception));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static Expected<T> fromException(std::exception_ptr p)
|
|||
|
|
{
|
|||
|
|
Expected<T> result;
|
|||
|
|
result.gotHam = false;
|
|||
|
|
new (&result.spam) std::exception_ptr(std::move(p));
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static Expected<T> fromException()
|
|||
|
|
{
|
|||
|
|
return fromException(std::current_exception());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool valid() const
|
|||
|
|
{
|
|||
|
|
return gotHam;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
T& get()
|
|||
|
|
{
|
|||
|
|
if (!gotHam) {
|
|||
|
|
std::rethrow_exception(spam);
|
|||
|
|
}
|
|||
|
|
return ham;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const T& get() const
|
|||
|
|
{
|
|||
|
|
if (!gotHam) {
|
|||
|
|
std::rethrow_exception(spam);
|
|||
|
|
}
|
|||
|
|
return ham;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template <class E>
|
|||
|
|
bool hasException() const
|
|||
|
|
{
|
|||
|
|
try {
|
|||
|
|
if (!gotHam) {
|
|||
|
|
std::rethrow_exception(spam);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (const E& object) {
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
catch (...) {
|
|||
|
|
}
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template <class F>
|
|||
|
|
static Expected fromCode(F fun)
|
|||
|
|
{
|
|||
|
|
try {
|
|||
|
|
return Expected(fun());
|
|||
|
|
}
|
|||
|
|
catch (...) {
|
|||
|
|
return fromException();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
#endif // EXPECTED_H
|