/** * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef LIBPANDABASE_UTILS_EXPECTED_H #define LIBPANDABASE_UTILS_EXPECTED_H #include #include #include "macros.h" namespace panda { template class Unexpected final { public: explicit Unexpected(E e) noexcept(std::is_nothrow_move_constructible_v) : e_(std::move(e)) {} const E &Value() const &noexcept { return e_; } E &Value() & noexcept { return e_; } E &&Value() && noexcept { return std::move(e_); } ~Unexpected() = default; DEFAULT_COPY_SEMANTIC(Unexpected); NO_MOVE_SEMANTIC(Unexpected); private: E e_; }; class ExpectedConfig final { public: #ifdef NDEBUG static constexpr bool RELEASE = true; #else static constexpr bool RELEASE = false; #endif }; // Simplified implementation of proposed std::expected // Note that as with std::expected, program that tries to instantiate // Expected with T or E for a reference type is ill-formed. template class Expected final { public: template >> Expected() noexcept : v_(T()) { } // The following constructors are non-explicit to be aligned with std::expected // NOLINTNEXTLINE(google-explicit-constructor) Expected(T v) noexcept(std::is_nothrow_move_constructible_v) : v_(std::move(v)) {} // NOLINTNEXTLINE(google-explicit-constructor) Expected(Unexpected e) noexcept(std::is_nothrow_move_constructible_v) : v_(std::move(e.Value())) {} bool HasValue() const noexcept { return std::holds_alternative(v_); } explicit operator bool() const noexcept { return HasValue(); } const E &Error() const &noexcept(ExpectedConfig::RELEASE) { ASSERT(!HasValue()); return std::get(v_); } E &Error() & noexcept(ExpectedConfig::RELEASE) { ASSERT(!HasValue()); return std::get(v_); } E &&Error() && noexcept(ExpectedConfig::RELEASE) { ASSERT(!HasValue()); return std::move(std::get(v_)); } const T &Value() const &noexcept(ExpectedConfig::RELEASE) { ASSERT(HasValue()); return std::get(v_); } // TODO(aemelenko): Delete next line when the issue 388 is resolved // NOLINTNEXTLINE(bugprone-exception-escape) T &Value() & noexcept(ExpectedConfig::RELEASE) { ASSERT(HasValue()); return std::get(v_); } T &&Value() && noexcept(ExpectedConfig::RELEASE) { ASSERT(HasValue()); return std::move(std::get(v_)); } const T &operator*() const &noexcept(ExpectedConfig::RELEASE) { return Value(); } T &operator*() & noexcept(ExpectedConfig::RELEASE) { return Value(); } T &&operator*() && noexcept(ExpectedConfig::RELEASE) { return std::move(*this).Value(); } template T ValueOr(U &&v) const & { if (HasValue()) { return Value(); } return std::forward(v); } template T ValueOr(U &&v) && { if (HasValue()) { return Value(); } return std::forward(v); } ~Expected() = default; DEFAULT_COPY_SEMANTIC(Expected); DEFAULT_MOVE_SEMANTIC(Expected); private: std::variant v_; }; } // namespace panda #endif // LIBPANDABASE_UTILS_EXPECTED_H