2017-02-26 19:29:50 +01:00
|
|
|
|
#ifndef EXPECTED_H
|
|
|
|
|
|
#define EXPECTED_H
|
|
|
|
|
|
|
2017-08-22 12:45:45 +02:00
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
#include <typeinfo>
|
|
|
|
|
|
#include <utility>
|
2017-02-26 19:29:50 +01:00
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
|
class Expected {
|
|
|
|
|
|
union {
|
|
|
|
|
|
T m_value;
|
|
|
|
|
|
std::exception_ptr m_error;
|
|
|
|
|
|
};
|
|
|
|
|
|
bool m_valid;
|
|
|
|
|
|
Expected() {} // internal use
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
|
|
|
|
Expected(const T& rhs)
|
|
|
|
|
|
: m_value(rhs), m_valid(true)
|
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
Expected(T&& rhs)
|
|
|
|
|
|
: m_value(std::move(rhs))
|
|
|
|
|
|
, m_valid(true)
|
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Expected(const Expected& rhs)
|
|
|
|
|
|
: m_valid(rhs.valid)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_valid) {
|
|
|
|
|
|
new (&m_value) T(rhs.m_value);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
new (&m_error) std::exception_ptr(rhs.m_error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
~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)
|
2017-08-22 12:45:45 +02:00
|
|
|
|
: m_error(rhs.m_error)
|
|
|
|
|
|
, m_valid(rhs.m_valid)
|
2017-02-26 19:29:50 +01:00
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
Expected(Expected<void> &&rhs)
|
2017-08-22 12:45:45 +02:00
|
|
|
|
: m_error(std::move(rhs.m_error))
|
|
|
|
|
|
, m_valid(rhs.m_valid)
|
2017-02-26 19:29:50 +01:00
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
~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
|