expected: add trivial expected implementation

This commit is contained in:
Danny Robson 2019-02-07 17:12:59 +11:00
parent 8706c39ab7
commit fc252ee209
3 changed files with 134 additions and 0 deletions

View File

@ -280,6 +280,7 @@ list (
except.cpp
except.hpp
exe.hpp
expected.hpp
extent.cpp
extent.hpp
fixed.cpp
@ -558,6 +559,7 @@ if (TESTS)
encode/base
endian
exe
expected
extent
fixed
float

98
expected.hpp Normal file
View File

@ -0,0 +1,98 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2019 Danny Robson <danny@nerdcruft.net>
*/
#include <exception>
///////////////////////////////////////////////////////////////////////////////
namespace cruft {
class bad_expected_access : public std::exception {
public:
char const* what (void) const noexcept override
{
return "bad_expected_access";
}
};
template <typename ValueT, typename ErrorT>
struct expected {
using value_type = ValueT;
using error_type = ErrorT;
expected (ValueT &&_value)
{
::new (&m_store.value) ValueT (std::move (_value));
m_valid = true;
}
expected (ErrorT &&_error)
{
::new (&m_store.error) ErrorT (std::move (_error));
}
~expected ()
{
if (m_valid) {
m_store.value.~ValueT ();
m_valid = false;
} else {
m_store.error.~ErrorT ();
}
}
ValueT&
value (void)&
{
if (!m_valid)
throw bad_expected_access {};
return m_store.value;
}
ValueT&&
value (void)&&
{
if (!m_valid)
throw bad_expected_access {};
return std::move (m_store.value);
}
ErrorT&
error (void)&
{
if (m_valid)
throw bad_expected_access {};
return m_store.error;
}
ErrorT&&
error (void)&&
{
if (m_valid)
throw bad_expected_access {};
return std::move (m_store.error);
}
ValueT* operator-> (void)& { return &value (); }
ValueT& operator* (void)& { return value (); }
operator bool() const noexcept;
private:
union storage_t {
storage_t () {};
~storage_t () {};
char defer;
ValueT value;
ErrorT error;
} m_store;
bool m_valid = false;
};
};

34
test/expected.cpp Normal file
View File

@ -0,0 +1,34 @@
#include "../expected.hpp"
#include "../tap.hpp"
int main ()
{
cruft::TAP::logger tap;
tap.expect_nothrow ([] () { cruft::expected<std::string,int> { "foo" }; }, "value construction succeeds");
tap.expect_nothrow ([] () { cruft::expected<std::string,int> { EPERM }; }, "error construction succeeds");
tap.expect_eq (cruft::expected<std::string,int> { "foo" }.value (), "foo", "value matches");
tap.expect_eq (cruft::expected<std::string,int> { EPERM }.error (), EPERM, "error matches");
tap.expect_throw<cruft::bad_expected_access> (
[] () {
cruft::expected<std::string,int> val { EPERM };
val.value ();
},
"value access fails when holding an error"
);
tap.expect_throw<cruft::bad_expected_access> (
[] () {
cruft::expected<std::string,int> val { "foo" };
val.error ();
},
"error access fails when holding a value"
);
return tap.status ();
}