1 /* 2 * Copyright (c) 2021-2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef PANDA_LIBPANDABASE_UTILS_EXPECTED_H_ 17 #define PANDA_LIBPANDABASE_UTILS_EXPECTED_H_ 18 19 #include <type_traits> 20 #include <variant> 21 22 #include "libpandabase/macros.h" 23 24 namespace ark { 25 26 template <class E> 27 class Unexpected final { 28 public: Unexpected(E e)29 explicit Unexpected(E e) noexcept(std::is_nothrow_move_constructible_v<E>) : e_(std::move(e)) {} 30 Value()31 const E &Value() const &noexcept 32 { 33 return e_; 34 } Value()35 E &Value() &noexcept 36 { 37 return e_; 38 } Value()39 E &&Value() &&noexcept 40 { 41 return std::move(e_); 42 } 43 44 ~Unexpected() = default; 45 46 DEFAULT_COPY_SEMANTIC(Unexpected); 47 NO_MOVE_SEMANTIC(Unexpected); 48 49 private: 50 E e_; 51 }; 52 53 class ExpectedConfig final { 54 public: 55 #ifdef NDEBUG 56 static constexpr bool RELEASE = true; 57 #else 58 static constexpr bool RELEASE = false; 59 #endif 60 }; 61 62 // Simplified implementation of proposed std::expected 63 // Note that as with std::expected, program that tries to instantiate 64 // Expected with T or E for a reference type is ill-formed. 65 template <class T, class E> 66 class Expected final { 67 public: 68 template <typename U = T, typename = std::enable_if_t<std::is_default_constructible_v<U>>> Expected()69 Expected() noexcept : v_(T()) 70 { 71 } 72 // The following constructors are non-explicit to be aligned with std::expected 73 // NOLINTNEXTLINE(google-explicit-constructor) noexcept(std::is_nothrow_move_constructible_v<T>)74 Expected(T v) noexcept(std::is_nothrow_move_constructible_v<T>) : v_(std::in_place_index<VALUE_INDEX>, std::move(v)) 75 { 76 } 77 // NOLINTNEXTLINE(google-explicit-constructor) noexcept(std::is_nothrow_move_constructible_v<E>)78 Expected(Unexpected<E> e) noexcept(std::is_nothrow_move_constructible_v<E>) 79 : v_(std::in_place_index<ERROR_INDEX>, std::move(e.Value())) 80 { 81 } 82 HasValue()83 bool HasValue() const noexcept 84 { 85 return v_.index() == VALUE_INDEX; 86 } 87 explicit operator bool() const noexcept 88 { 89 return HasValue(); 90 } 91 Error()92 const E &Error() const &noexcept(ExpectedConfig::RELEASE) 93 { 94 ASSERT(!HasValue()); 95 return std::get<ERROR_INDEX>(v_); 96 } 97 // NOLINTNEXTLINE(bugprone-exception-escape) Error()98 E &Error() &noexcept(ExpectedConfig::RELEASE) 99 { 100 ASSERT(!HasValue()); 101 return std::get<ERROR_INDEX>(v_); 102 } Error()103 E &&Error() &&noexcept(ExpectedConfig::RELEASE) 104 { 105 ASSERT(!HasValue()); 106 return std::move(std::get<ERROR_INDEX>(v_)); 107 } 108 Value()109 const T &Value() const &noexcept(ExpectedConfig::RELEASE) 110 { 111 ASSERT(HasValue()); 112 return std::get<VALUE_INDEX>(v_); 113 } 114 // NOTE(aemelenko): Delete next line when the issue 388 is resolved 115 // NOLINTNEXTLINE(bugprone-exception-escape) Value()116 T &Value() &noexcept(ExpectedConfig::RELEASE) 117 { 118 ASSERT(HasValue()); 119 return std::get<VALUE_INDEX>(v_); 120 } Value()121 T &&Value() &&noexcept(ExpectedConfig::RELEASE) 122 { 123 ASSERT(HasValue()); 124 return std::move(std::get<VALUE_INDEX>(v_)); 125 } noexcept(ExpectedConfig::RELEASE)126 const T &operator*() const &noexcept(ExpectedConfig::RELEASE) 127 { 128 return Value(); 129 } 130 // NOLINTNEXTLINE(bugprone-exception-escape) noexcept(ExpectedConfig::RELEASE)131 T &operator*() &noexcept(ExpectedConfig::RELEASE) 132 { 133 return Value(); 134 } noexcept(ExpectedConfig::RELEASE)135 T &&operator*() &&noexcept(ExpectedConfig::RELEASE) 136 { 137 return std::move(*this).Value(); 138 } 139 140 const T *operator->() const noexcept(ExpectedConfig::RELEASE) 141 { 142 auto ptr = std::get_if<VALUE_INDEX>(&v_); 143 ASSERT(ptr != nullptr); 144 return ptr; 145 } 146 T *operator->() noexcept(ExpectedConfig::RELEASE) 147 { 148 auto ptr = std::get_if<VALUE_INDEX>(&v_); 149 ASSERT(ptr != nullptr); 150 return ptr; 151 } 152 153 template <class U = T> ValueOr(U && v)154 T ValueOr(U &&v) const & 155 { 156 if (HasValue()) { 157 return Value(); 158 } 159 return std::forward<U>(v); 160 } 161 template <class U = T> ValueOr(U && v)162 T ValueOr(U &&v) && 163 { 164 if (HasValue()) { 165 return Value(); 166 } 167 return std::forward<U>(v); 168 } 169 170 ~Expected() = default; 171 172 DEFAULT_COPY_SEMANTIC(Expected); 173 DEFAULT_MOVE_SEMANTIC(Expected); 174 175 private: 176 static constexpr size_t VALUE_INDEX = 0; 177 static constexpr size_t ERROR_INDEX = 1; 178 std::variant<T, E> v_; 179 }; 180 181 } // namespace ark 182 183 #endif // PANDA_LIBPANDABASE_UTILS_EXPECTED_H_ 184