pgLab/core/Expected.h

276 lines
4.3 KiB
C
Raw Permalink Normal View History

#ifndef EXPECTED_H
#define EXPECTED_H
#include <stdexcept>
#include <typeinfo>
#include <utility>
template <typename T>
class Expected {
union {
T m_value;
std::exception_ptr m_error;
};
bool m_valid;
Expected() {} // internal use
public:
2017-12-26 07:34:08 +01:00
/** Constructor that receives a valid result value */
Expected(const T& rhs)
: m_value(rhs), m_valid(true)
{}
2017-12-26 07:34:08 +01:00
/** Move constructor for a valid result value */
Expected(T&& rhs)
: m_value(std::move(rhs))
, m_valid(true)
{}
2017-12-26 07:34:08 +01:00
/** Copy constructor */
Expected(const Expected& rhs)
: m_valid(rhs.m_valid)
{
if (m_valid) {
new (&m_value) T(rhs.m_value);
}
else {
new (&m_error) std::exception_ptr(rhs.m_error);
}
}
2017-12-26 07:34:08 +01:00
/** Move constructor */
Expected(Expected &&rhs)
: m_valid(rhs.m_valid)
{
if (m_valid) {
new (&m_value) T(std::move(rhs.m_value));
}
else {
new (&m_error) std::exception_ptr(std::move(rhs.m_error));
}
}
2017-12-26 07:34:08 +01:00
/** destructor */
~Expected()
{
if (m_valid) {
m_value.~T();
}
else {
using std::exception_ptr;
m_error.~exception_ptr();
}
}
// void swap(Expected& rhs)
// {
// if (m_valid) {
// if (rhs.m_valid) {
// using std::swap;
// swap(m_value, rhs.m_value);
// }
// else {
// auto t = std::move(rhs.m_error);
// new(&rhs.m_value) T(std::move(m_value));
// new(&m_error) std::exception_ptr(t);
// std::swap(m_valid, rhs.m_valid);
// }
// }
// else {
// if (rhs.m_valid) {
// rhs.swap(*this);
// }
// else {
// using std::swap;
// swap(m_error, rhs.m_error);
// std::swap(m_valid, rhs.m_valid);
// }
// }
// }
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.m_valid = false;
new (&result.m_error) std::exception_ptr(std::move(p));
return result;
}
static Expected<T> fromException()
{
return fromException(std::current_exception());
}
bool valid() const
{
return m_valid;
}
T& get()
{
if (!m_valid) {
std::rethrow_exception(m_error);
}
return m_value;
}
const T& get() const
{
if (!m_valid) {
std::rethrow_exception(m_error);
}
return m_value;
}
template <class E>
bool hasException() const
{
try {
if (!m_valid) {
std::rethrow_exception(m_error);
}
}
catch (const E& ) {
return true;
}
catch (...) {
}
return false;
}
template <class F>
static Expected fromCode(F fun)
{
try {
return Expected(fun());
}
catch (...) {
return fromException();
}
}
};
template <>
class Expected<void> {
std::exception_ptr m_error;
bool m_valid;
public:
Expected<void>()
: m_valid(true)
{}
Expected(const Expected& rhs)
: m_error(rhs.m_error)
, m_valid(rhs.m_valid)
{}
Expected(Expected<void> &&rhs)
: m_error(std::move(rhs.m_error))
, m_valid(rhs.m_valid)
{}
~Expected()
{}
// void swap(Expected& rhs)
// {
// if (m_valid) {
// if (!rhs.m_valid) {
// m_error = rhs.m_error;
// std::swap(m_valid, rhs.m_valid);
// }
// }
// else {
// if (rhs.m_valid) {
// rhs.swap(*this);
// }
// else {
// using std::swap;
// swap(m_error, rhs.m_error);
// std::swap(m_valid, rhs.m_valid);
// }
// }
// }
template <class E>
static Expected<void> fromException(const E& exception)
{
if (typeid(exception) != typeid(E)) {
throw std::invalid_argument("slicing detected");
}
return fromException(std::make_exception_ptr(exception));
}
static Expected<void> fromException(std::exception_ptr p)
{
Expected<void> result;
result.m_valid = false;
result.m_error = std::exception_ptr(std::move(p));
return result;
}
static Expected<void> fromException()
{
return fromException(std::current_exception());
}
bool valid() const
{
return m_valid;
}
void get() const
{
if (!m_valid) {
std::rethrow_exception(m_error);
}
}
template <class E>
bool hasException() const
{
try {
if (!m_valid) {
std::rethrow_exception(m_error);
}
}
catch (const E& ) {
return true;
}
catch (...) {
}
return false;
}
template <class F>
static Expected fromCode(F fun)
{
try {
fun();
return Expected<void>();
}
catch (...) {
return fromException();
}
}
};
#endif // EXPECTED_H