diff --git a/tstl/include/expected.hpp b/tstl/include/expected.hpp index 76d785cc..5d11e315 100644 --- a/tstl/include/expected.hpp +++ b/tstl/include/expected.hpp @@ -58,6 +58,24 @@ union trivial_expected_storage { ~trivial_expected_storage() = default; }; +template +union trivial_expected_storage { + typedef void value_type; + typedef E error_type; + + error_type error; + + constexpr trivial_expected_storage() { + //Nothing else to init + } + + constexpr trivial_expected_storage(const exceptional& e) : error(e.error){ + //Nothing else to init + } + + ~trivial_expected_storage() = default; +}; + template union non_trivial_expected_storage { typedef T value_type; @@ -82,6 +100,24 @@ union non_trivial_expected_storage { ~non_trivial_expected_storage() {}; }; +template +union non_trivial_expected_storage { + typedef void value_type; + typedef E error_type; + + error_type error; + + constexpr non_trivial_expected_storage(){ + //Nothing else to init + } + + constexpr non_trivial_expected_storage(exceptional& e) : error(e.error){ + //Nothing else to init + } + + ~non_trivial_expected_storage() {}; +}; + template struct trivial_expected_base { typedef T value_type; @@ -113,6 +149,28 @@ struct trivial_expected_base { ~trivial_expected_base() = default; }; +template +struct trivial_expected_base { + typedef E error_type; + + bool has_value; + trivial_expected_storage storage; + + trivial_expected_base() : has_value(true), storage(){ + //Nothing else to init + } + + trivial_expected_base(only_set_valid_t, bool hv) : has_value(hv){ + //Nothing else to init + } + + trivial_expected_base(const exceptional& e) : has_value(false), storage(e) { + //Nothing else to init + } + + ~trivial_expected_base() = default; +}; + template struct non_trivial_expected_base { typedef T value_type; @@ -150,6 +208,32 @@ struct non_trivial_expected_base { } }; +template +struct non_trivial_expected_base { + typedef E error_type; + + bool has_value; + trivial_expected_storage storage; + + non_trivial_expected_base() : has_value(true), storage(){ + //Nothing else to init + } + + non_trivial_expected_base(only_set_valid_t, bool hv) : has_value(hv){ + //Nothing else to init + } + + non_trivial_expected_base(const exceptional& e) : has_value(false), storage(e) { + //Nothing else to init + } + + ~non_trivial_expected_base(){ + if(!has_value){ + storage.error.~error_type(); + } + } +}; + template using expected_base = typename std::conditional< std::is_trivially_destructible::value && std::is_trivially_destructible::value, @@ -338,6 +422,119 @@ public: } }; +template +struct expected : expected_base { + typedef void value_type; + typedef E error_type; + + typedef expected this_type; + typedef expected_base base_type; + +private: + error_type* error_ptr() { + return std::addressof(base_type::storage.error); + } + + constexpr const error_type* error_ptr() const { + return static_addressof(base_type::storage.error); + } + + constexpr const bool& contained_has_value() const& { + return base_type::has_value; + } + + bool& contained_has_value() & { + return base_type::has_value; + } + + bool&& contained_has_value() && { + return std::move(base_type::has_value); + } + + constexpr const error_type& contained_error() const& { + return base_type::storage.error; + } + + error_type& contained_error() & { + return base_type::storage.error; + } + + error_type&& contained_error() && { + return std::move(base_type::storage.error); + } + +public: + /* Constructors */ + + expected(const expected& rhs) : base_type(only_set_valid, rhs.valid()) { + if(!rhs.valid()){ + ::new (error_ptr()) error_type(rhs.contained_error()); + } + } + + expected(expected&& rhs) : base_type(only_set_valid, rhs.valid()) { + if(!rhs.valid()){ + new (error_ptr()) error_type(std::move(rhs.contained_error())); + } + } + + expected(const exceptional& e) : base_type(e) { + //Nothing else to init + } + + expected() : base_type() {} + + ~expected() = default; + + /* Operators */ + expected& operator=(const expected& rhs){ + this_type(rhs).swap(*this); + return *this; + } + + expected& operator=(expected&& rhs){ + this_type(std::move(rhs)).swap(*this); + return *this; + } + + /* Swap */ + + void swap(expected& rhs){ + if (valid()){ + if (!rhs.valid()){ + error_type t = std::move(rhs.contained_error()); + new (error_ptr()) error_type(t); + } + } else { + if (!rhs.valid()){ + std::swap(contained_error(), rhs.contained_error()); + } + } + } + + /* Accessors */ + + constexpr bool valid() const { + return contained_has_value(); + } + + constexpr explicit operator bool() const { + return valid(); + } + + constexpr const error_type& error() const { + return contained_error(); + } + + constexpr bool has_error(const error_type& e) const { + return contained_error() == e; + } + + constexpr exceptional get_exceptional() const { + return exceptional(contained_error()); + } +}; + template inline expected make_expected(T&& v){ return expected(std::forward(v)); @@ -358,6 +555,10 @@ inline expected make_expected_from_error(E v){ return expected(exceptional(v)); } +inline expected make_expected(){ + return expected(); +} + } //end of namespace std #endif