diff --git a/expected.h b/expected.h new file mode 100644 index 0000000..18de30d --- /dev/null +++ b/expected.h @@ -0,0 +1,155 @@ +#ifndef EXPECTED_H +#define EXPECTED_H + +template +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 + static Expected fromException(const E& exception) + { + if (typeid(exception) != typeid(E)) { + throw std::invalid_argument("slicing detected"); + } + return fromException(std::make_exception_ptr(exception)); + } + + static Expected fromException(std::exception_ptr p) + { + Expected result; + result.gotHam = false; + new (&result.spam) std::exception_ptr(std::move(p)); + return result; + } + + static Expected 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 + bool hasException() const + { + try { + if (!gotHam) { + std::rethrow_exception(spam); + } + } + catch (const E& object) { + return true; + } + catch (...) { + } + return false; + } + + template + static Expected fromCode(F fun) + { + try { + return Expected(fun()); + } + catch (...) { + return fromException(); + } + } +}; + + + +#endif // EXPECTED_H