/* * Copyright (c) 2021-2025 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 PANDA_LIBPANDABASE_UTILS_EXPECTED_H_ #define PANDA_LIBPANDABASE_UTILS_EXPECTED_H_ #include #include #include "libpandabase/macros.h" namespace ark { 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::in_place_index, std::move(v)) { } // NOLINTNEXTLINE(google-explicit-constructor) Expected(Unexpected e) noexcept(std::is_nothrow_move_constructible_v) : v_(std::in_place_index, std::move(e.Value())) { } bool HasValue() const noexcept { return v_.index() == VALUE_INDEX; } explicit operator bool() const noexcept { return HasValue(); } const E &Error() const &noexcept(ExpectedConfig::RELEASE) { ASSERT(!HasValue()); return std::get(v_); } // NOLINTNEXTLINE(bugprone-exception-escape) 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_); } // NOTE(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(); } // NOLINTNEXTLINE(bugprone-exception-escape) T &operator*() &noexcept(ExpectedConfig::RELEASE) { return Value(); } T &&operator*() &&noexcept(ExpectedConfig::RELEASE) { return std::move(*this).Value(); } const T *operator->() const noexcept(ExpectedConfig::RELEASE) { auto ptr = std::get_if(&v_); ASSERT(ptr != nullptr); return ptr; } T *operator->() noexcept(ExpectedConfig::RELEASE) { auto ptr = std::get_if(&v_); ASSERT(ptr != nullptr); return ptr; } 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: static constexpr size_t VALUE_INDEX = 0; static constexpr size_t ERROR_INDEX = 1; std::variant v_; }; } // namespace ark #endif // PANDA_LIBPANDABASE_UTILS_EXPECTED_H_