/* * 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 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 (); } template expected then (FunctionT &&func, ArgsT &&...args) { if (!m_valid) return *this; else return expected (std::invoke (func, args..., value ())); } explicit operator bool() const noexcept { return m_valid; } private: union storage_t { storage_t () {}; ~storage_t () {}; char defer; ValueT value; ErrorT error; } m_store; bool m_valid = false; }; };