Skip to content

Instantly share code, notes, and snippets.

@madebyjeffrey
Created January 5, 2014 21:33
Show Gist options
  • Save madebyjeffrey/8274219 to your computer and use it in GitHub Desktop.
Save madebyjeffrey/8274219 to your computer and use it in GitHub Desktop.
//
// expected.hpp
// LiveNet
//
// Created by Jeffrey Drake on 1/3/2014.
// Copyright (c) 2014 Jeffrey Drake. All rights reserved.
//
#ifndef LiveNet_expected_hpp
#define LiveNet_expected_hpp
#include <exception>
// create a void specialization
namespace iaefai {
// derived from Andrei Alexandrescu's slides
template<typename T>
class expected {
union {
T result;
std::exception_ptr error;
};
bool haveResult;
expected() {} // internal
public:
expected(T const& rhs) : result(rhs), haveResult(true) { }
expected(T && rhs) : result(std::move(rhs)), haveResult(true) {}
expected(expected const& rhs) : haveResult(rhs.haveResult) {
if (haveResult) {
new (&result) T(rhs.result);
} else {
new (&error) std::exception_ptr(rhs.error);
}
}
expected(expected&& rhs) : haveResult(rhs.haveResult) {
if (haveResult) {
new (&result) T(std::move(rhs.result));
} else {
new (&error) std::exception_ptr(std::move(rhs.error));
}
}
~expected() {
using std::exception_ptr; // because ~std::exception_ptr doesn't parse
if (haveResult) result.~T();
else error.~exception_ptr();
}
void swap(expected& rhs) {
if (haveResult) {
if (rhs.haveResult) {
using std::swap;
swap(result, rhs.result);
} else {
auto t = std::move(rhs.error);
new (&rhs.result) T(std::move(result));
new (&error) std::exception_ptr(t);
std::swap(haveResult, rhs.haveResult);
}
} else {
if (rhs.haveResult) {
rhs.swap(*this);
} else {
// deviation from slides: Apparently there is nothing saying (according to edoceo` / #C++)
// exception_ptr has to have a swap member, but it must be swappable
//error.swap(rhs.error);
using std::swap;
swap(error, rhs.error);
std::swap(haveResult, rhs.haveResult);
}
}
}
template<typename E>
static expected<T> from_exception(E const& exception) {
if (typeid(exception) == typeid(E)) {
throw std::invalid_argument("slicing detected");
}
return from_exception(std::make_exception_ptr(exception));
}
static expected<T> from_exception(std::exception_ptr p) { // universal reference?
expected<T> result;
result.haveResult = false;
new(&result.error) std::exception_ptr(std::move(p));
return result;
}
static expected<T> from_exception() {
return from_exception(std::current_exception());
}
// access
bool valid() const {
return haveResult;
}
T& get() {
if (not haveResult){
std::rethrow_exception(error);
}
return result;
}
T const& get() const {
if (not haveResult) {
std::rethrow_exception(error);
}
return result;
}
// probing type
template<typename E>
bool has_exception() const {
try {
if (not haveResult) {
std::rethrow_exception(error); // is this necessary? Probably because of the pattern matching
}
} catch (E const& object) {
return true;
} catch (...) {
}
return false;
}
// icing?
template<class F>
static expected from_code(F fun) {
try {
return expected(fun());
} catch (...) {
return from_exception();
}
}
// ex. auto r = expected<string>::fromCode([] { ... });
// adding...
operator bool() {
return not has_exception<std::exception>(); // this probably isn't the best type to use
}
};
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment