/* * 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 */ #pragma once #include #include /////////////////////////////////////////////////////////////////////////////// namespace cruft { class bad_expected_access : public std::exception { public: char const* what (void) const noexcept override { return "bad_expected_access"; } }; template class unexpected { public: unexpected (ErrorT && _value): m_value (std::move (_value)) { ; } unexpected (ErrorT const &_value): m_value (_value) { ; } ErrorT& value (void)& { return m_value; } ErrorT&& value (void)&& { return std::move (m_value); } ErrorT const& value (void) const & { return m_value; } ErrorT const&& value (void) const&& { return std::move (m_value); } private: ErrorT m_value; }; template struct [[nodiscard]] expected { using value_type = ValueT; using error_type = ErrorT; expected () = delete; expected (expected &&rhs) { destroy (); if (rhs) { m_valid = true; ::new (&m_store.value) ValueT (std::move (rhs.value ())); } else { m_valid = false; ::new (&m_store.error) unexpected (std::move (rhs.error ())); } } expected& operator=(expected &&); expected (expected const&); expected& operator=(expected const&); expected (ValueT const &_value) { ::new (&m_store.value) ValueT (_value); m_valid = true; } expected (ValueT &&_value) { ::new (&m_store.value) ValueT (std::move (_value)); m_valid = true; } expected (unexpected &&_error) { ::new (&m_store.error) unexpected (std::move (_error)); m_valid = false; } ~expected () { destroy (); } ValueT& value (void)& { if (!m_valid) throw bad_expected_access {}; return m_store.value; } ValueT const& value (void) const& { 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.value (); } ErrorT const& error (void) const& { if (m_valid) throw bad_expected_access {}; return m_store.error.value (); } ErrorT&& error (void)&& { if (m_valid) throw bad_expected_access {}; return std::move (m_store.error.value ()); } ValueT* operator-> (void)& { return &value (); } ValueT& operator* (void)& { return value (); } ValueT const* operator-> (void) const& { return &value (); } ValueT const& operator* (void) const& { return value (); } bool has_value (void) const noexcept { return m_valid; } explicit operator bool() const noexcept { return has_value (); } private: void destroy (void) { if (m_valid) { m_store.value.~ValueT (); m_valid = false; } else { m_store.error.~unexpected (); } } bool m_valid = false; union storage_t { storage_t () {}; ~storage_t () {}; char defer; ValueT value; unexpected error; } m_store; }; }