Created
January 5, 2014 21:33
-
-
Save madebyjeffrey/8274219 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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