#include <exception>
#include <stdexcept>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <iostream>
#include <chrono>
using error_type = std::exception_ptr;
struct ResultBase
{
bool hasError() const
{
return *reinterpret_cast<const bool*>(this);
}
std::exception_ptr error() const
{
return *reinterpret_cast<const error_type*>(
reinterpret_cast<const char*>(this)
+ sizeof(std::max_align_t));
}
protected:
ResultBase() { }
};
template <class T>
struct Result : ResultBase
{
Result(error_type error)
: mHasError(true) { new (&mError) error_type(error); }
Result(T value)
: mHasError(false) { new (&mValue) T(value); }
~Result()
{
if (mHasError)
mError.~error_type();
else
mValue.~T();
}
void setError(error_type error)
{
if (mHasError) {
mError = error;
} else {
mValue.~T();
new (&mError) error_type(error);
mHasError = true;
}
}
void setValue(T value)
{
if (mHasError) {
mError.~error_type();
new (&mValue) T(value);
mHasError = false;
} else {
mValue = value;
}
}
private:
union {
bool mHasError;
std::max_align_t mAligner;
};
union {
error_type mError;
T mValue;
};
};
static_assert(std::is_standard_layout<Result<int>>::value, "");
void check(bool condition)
{
if (!condition) std::terminate();
}
class ResultBase2
{
public:
virtual ~ResultBase2() {}
virtual bool hasError() const = 0;
virtual std::exception_ptr error() const = 0;
protected:
ResultBase2() {}
};
template <class T>
class Result2 : public ResultBase2
{
public:
Result2(error_type error)
{
this->construct(error);
}
Result2(T value)
{
this->construct(value);
}
~Result2()
{
if (this->mHasError)
this->mData.mError.~error_type();
else
this->mData.mValue.~T();
}
bool hasError() const override { return mHasError; }
std::exception_ptr error() const override { return mData.mError; }
void setError(error_type error)
{
if (this->mHasError)
{
this->mData.mError = error;
}
else
{
this->mData.mValue.~T();
this->construct(error);
}
}
void setValue(T value)
{
if (not this->mHasError)
{
this->mData.mValue = value;
}
else
{
this->mData.mError.~error_type();
this->construct(value);
}
}
private:
bool mHasError;
union Data
{
Data() {}
~Data() {}
error_type mError;
T mValue;
} mData;
void construct(error_type error)
{
mHasError = true;
new (&mData.mError) error_type(error);
}
void construct(T value)
{
mHasError = false;
new (&mData.mValue) T(value);
}
};
class ResultBase3;
struct ResultBase3Vtable
{
bool (*hasError)(const ResultBase3&);
error_type (*error)(const ResultBase3&);
};
class ResultBase3
{
public:
bool hasError() const { return vtable->hasError(*this); }
std::exception_ptr error() const { return vtable->error(*this); }
protected:
ResultBase3(ResultBase3Vtable* vtable) : vtable(vtable) {}
private:
ResultBase3Vtable* vtable;
};
template <class T>
class Result3 : public ResultBase3
{
public:
Result3(error_type error) : ResultBase3(&Result3<T>::vtable)
{
this->construct(error);
}
Result3(T value) : ResultBase3(&Result3<T>::vtable)
{
this->construct(value);
}
~Result3()
{
if (this->mHasError)
this->mData.mError.~error_type();
else
this->mData.mValue.~T();
}
bool hasError() const { return mHasError; }
std::exception_ptr error() const { return mData.mError; }
void setError(error_type error)
{
if (this->mHasError)
{
this->mData.mError = error;
}
else
{
this->mData.mValue.~T();
this->construct(error);
}
}
void setValue(T value)
{
if (not this->mHasError)
{
this->mData.mValue = value;
}
else
{
this->mData.mError.~error_type();
this->construct(value);
}
}
private:
bool mHasError;
union Data
{
Data() {}
~Data() {}
error_type mError;
T mValue;
} mData;
void construct(error_type error)
{
mHasError = true;
new (&mData.mError) error_type(error);
}
void construct(T value)
{
mHasError = false;
new (&mData.mValue) T(value);
}
static bool hasErrorVTable(const ResultBase3& result)
{
return static_cast<const Result3&>(result).hasError();
}
static error_type errorVTable(const ResultBase3& result)
{
return static_cast<const Result3&>(result).error();
}
static ResultBase3Vtable vtable;
};
template <typename T>
ResultBase3Vtable Result3<T>::vtable{
&Result3<T>::hasErrorVTable,
&Result3<T>::errorVTable,
};
template <typename Base, typename Result>
void f(const Base& alias, Result& r)
{
check(!alias.hasError());
r.setError(std::exception_ptr());
check(alias.hasError());
check(alias.error() == nullptr);
r.setValue(1);
check(!alias.hasError());
r.setError(std::make_exception_ptr(std::runtime_error("!")));
check(alias.hasError());
check(alias.error() != nullptr);
}
template <std::size_t N, typename Operation>
auto checkTime(Operation op)
{
using namespace std::chrono;
high_resolution_clock::time_point t1 = high_resolution_clock::now();
for (std::size_t i = 0u; i < N; ++i)
op();
high_resolution_clock::time_point t2 = high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count();
return duration;
}
int main()
{
std::cout << checkTime<1>([] { Result<int> r(0); f(r, r); }) << std::endl;
std::cout << checkTime<1>([] { Result2<int> r(0); f(r, r); }) << std::endl;
std::cout << checkTime<1>([] { Result3<int> r(0); f(r, r); }) << std::endl;
std::cout << sizeof(Result<int>) << std::endl;
std::cout << sizeof(Result2<int>) << std::endl;
std::cout << sizeof(Result3<int>) << std::endl;
}