expected: add trivial expected implementation
This commit is contained in:
parent
8706c39ab7
commit
fc252ee209
@ -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
98
expected.hpp
Normal 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
34
test/expected.cpp
Normal 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 ();
|
||||
}
|
Loading…
Reference in New Issue
Block a user