2019-02-07 17:12:59 +11:00
|
|
|
/*
|
|
|
|
* 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>
|
|
|
|
*/
|
|
|
|
|
2019-02-07 17:20:35 +11:00
|
|
|
#pragma once
|
|
|
|
|
2019-02-07 17:12:59 +11:00
|
|
|
#include <exception>
|
2019-02-07 17:33:47 +11:00
|
|
|
#include <functional>
|
2019-02-07 17:12:59 +11:00
|
|
|
|
2019-03-05 23:14:47 +11:00
|
|
|
|
2019-02-07 17:12:59 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
namespace cruft {
|
|
|
|
class bad_expected_access : public std::exception {
|
|
|
|
public:
|
|
|
|
char const* what (void) const noexcept override
|
|
|
|
{
|
|
|
|
return "bad_expected_access";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2019-03-05 12:17:02 +11:00
|
|
|
template <typename ErrorT>
|
|
|
|
class unexpected {
|
|
|
|
public:
|
2021-04-19 14:52:22 +10:00
|
|
|
unexpected (ErrorT && _value)
|
|
|
|
noexcept (std::is_nothrow_constructible_v<ErrorT>)
|
|
|
|
: m_value (std::move (_value))
|
|
|
|
{ ; }
|
|
|
|
|
|
|
|
unexpected (ErrorT const &_value)
|
|
|
|
: m_value (_value)
|
|
|
|
{ ; }
|
2019-03-05 12:17:02 +11:00
|
|
|
|
|
|
|
ErrorT& value (void)& { return m_value; }
|
|
|
|
ErrorT&& value (void)&& { return std::move (m_value); }
|
|
|
|
|
2019-03-05 12:26:03 +11:00
|
|
|
ErrorT const& value (void) const & { return m_value; }
|
|
|
|
ErrorT const&& value (void) const&& { return std::move (m_value); }
|
|
|
|
|
2019-03-05 12:17:02 +11:00
|
|
|
private:
|
|
|
|
ErrorT m_value;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2019-02-07 17:12:59 +11:00
|
|
|
template <typename ValueT, typename ErrorT>
|
2019-03-05 12:17:02 +11:00
|
|
|
struct [[nodiscard]] expected {
|
2019-02-07 17:12:59 +11:00
|
|
|
using value_type = ValueT;
|
|
|
|
using error_type = ErrorT;
|
|
|
|
|
2019-03-05 12:26:03 +11:00
|
|
|
expected () = delete;
|
2021-04-20 12:10:53 +10:00
|
|
|
expected (expected &&rhs) noexcept (
|
|
|
|
std::is_nothrow_destructible_v<ValueT> &&
|
|
|
|
std::is_nothrow_destructible_v<ErrorT> &&
|
|
|
|
std::is_nothrow_move_constructible_v<ValueT> &&
|
|
|
|
std::is_nothrow_move_constructible_v<ErrorT>
|
|
|
|
) {
|
2019-03-19 17:08:35 +11:00
|
|
|
destroy ();
|
2021-04-20 12:10:53 +10:00
|
|
|
|
2019-03-19 17:08:35 +11:00
|
|
|
if (rhs) {
|
|
|
|
m_valid = true;
|
|
|
|
::new (&m_store.value) ValueT (std::move (rhs.value ()));
|
|
|
|
} else {
|
|
|
|
m_valid = false;
|
|
|
|
::new (&m_store.error) unexpected<ErrorT> (std::move (rhs.error ()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-19 14:52:22 +10:00
|
|
|
expected& operator=(expected &&) noexcept (std::is_trivially_move_assignable_v<ValueT>);
|
2019-03-05 23:14:47 +11:00
|
|
|
expected (expected const&);
|
|
|
|
expected& operator=(expected const&);
|
|
|
|
|
|
|
|
expected (ValueT const &_value)
|
|
|
|
{
|
|
|
|
::new (&m_store.value) ValueT (_value);
|
|
|
|
m_valid = true;
|
|
|
|
}
|
2019-03-05 12:26:03 +11:00
|
|
|
|
2019-02-07 17:12:59 +11:00
|
|
|
expected (ValueT &&_value)
|
|
|
|
{
|
|
|
|
::new (&m_store.value) ValueT (std::move (_value));
|
|
|
|
m_valid = true;
|
|
|
|
}
|
|
|
|
|
2019-03-05 12:17:02 +11:00
|
|
|
expected (unexpected<ErrorT> &&_error)
|
2019-02-07 17:12:59 +11:00
|
|
|
{
|
2019-03-05 12:17:02 +11:00
|
|
|
::new (&m_store.error) unexpected<ErrorT> (std::move (_error));
|
2019-03-05 23:15:21 +11:00
|
|
|
m_valid = false;
|
2019-02-07 17:12:59 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
~expected ()
|
|
|
|
{
|
2019-03-19 17:08:35 +11:00
|
|
|
destroy ();
|
2019-02-07 17:12:59 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
ValueT&
|
|
|
|
value (void)&
|
|
|
|
{
|
|
|
|
if (!m_valid)
|
|
|
|
throw bad_expected_access {};
|
|
|
|
return m_store.value;
|
|
|
|
}
|
|
|
|
|
2019-03-05 12:26:03 +11:00
|
|
|
ValueT const&
|
|
|
|
value (void) const&
|
|
|
|
{
|
|
|
|
if (!m_valid)
|
|
|
|
throw bad_expected_access {};
|
|
|
|
return m_store.value;
|
|
|
|
}
|
|
|
|
|
2019-02-07 17:12:59 +11:00
|
|
|
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 {};
|
2019-03-05 12:17:02 +11:00
|
|
|
return m_store.error.value ();
|
2019-03-05 12:26:03 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
ErrorT const&
|
|
|
|
error (void) const&
|
|
|
|
{
|
|
|
|
if (m_valid) throw bad_expected_access {};
|
|
|
|
return m_store.error.value ();
|
2019-02-07 17:12:59 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
ErrorT&&
|
|
|
|
error (void)&&
|
|
|
|
{
|
|
|
|
if (m_valid)
|
|
|
|
throw bad_expected_access {};
|
2019-03-05 12:17:02 +11:00
|
|
|
return std::move (m_store.error.value ());
|
2019-02-07 17:12:59 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
ValueT* operator-> (void)& { return &value (); }
|
|
|
|
ValueT& operator* (void)& { return value (); }
|
|
|
|
|
2019-03-05 23:15:21 +11:00
|
|
|
ValueT const* operator-> (void) const& { return &value (); }
|
|
|
|
ValueT const& operator* (void) const& { return value (); }
|
2019-02-07 17:33:47 +11:00
|
|
|
|
2019-03-05 12:17:02 +11:00
|
|
|
bool has_value (void) const noexcept { return m_valid; }
|
|
|
|
|
|
|
|
explicit operator bool() const noexcept { return has_value (); }
|
2019-02-07 17:12:59 +11:00
|
|
|
|
|
|
|
private:
|
2019-03-19 17:08:35 +11:00
|
|
|
void destroy (void)
|
|
|
|
{
|
|
|
|
if (m_valid) {
|
|
|
|
m_store.value.~ValueT ();
|
|
|
|
m_valid = false;
|
|
|
|
} else {
|
|
|
|
m_store.error.~unexpected<ErrorT> ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-05 23:15:21 +11:00
|
|
|
bool m_valid = false;
|
|
|
|
|
2019-02-07 17:12:59 +11:00
|
|
|
union storage_t {
|
|
|
|
storage_t () {};
|
|
|
|
~storage_t () {};
|
|
|
|
|
|
|
|
char defer;
|
|
|
|
ValueT value;
|
2019-03-05 12:17:02 +11:00
|
|
|
unexpected<ErrorT> error;
|
2019-02-07 17:12:59 +11:00
|
|
|
} m_store;
|
|
|
|
};
|
2019-03-05 12:17:02 +11:00
|
|
|
}
|