1 /* 2 * Copyright (c) 2021 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 <variant> 20 21 #include "macros.h" 22 23 namespace panda { 24 25 template <class E> 26 class Unexpected final { 27 public: Unexpected(E e)28 explicit Unexpected(E e) noexcept(std::is_nothrow_move_constructible_v<E>) : e_(std::move(e)) {} 29 Value()30 const E &Value() const &noexcept 31 { 32 return e_; 33 } Value()34 E &Value() & noexcept 35 { 36 return e_; 37 } Value()38 E &&Value() && noexcept 39 { 40 return std::move(e_); 41 } 42 43 ~Unexpected() = default; 44 45 DEFAULT_COPY_SEMANTIC(Unexpected); 46 NO_MOVE_SEMANTIC(Unexpected); 47 48 private: 49 E e_; 50 }; 51 52 class ExpectedConfig final { 53 public: 54 #ifdef NDEBUG 55 static constexpr bool RELEASE = true; 56 #else 57 static constexpr bool RELEASE = false; 58 #endif 59 }; 60 61 // Simplified implementation of proposed std::expected 62 // Note that as with std::expected, program that tries to instantiate 63 // Expected with T or E for a reference type is ill-formed. 64 template <class T, class E> 65 class Expected final { 66 public: Expected()67 Expected() noexcept : v_(T()) {} 68 // The following constructors are non-explicit to be aligned with std::expected 69 // NOLINTNEXTLINE(google-explicit-constructor) noexcept(std::is_nothrow_move_constructible_v<T>)70 Expected(T v) noexcept(std::is_nothrow_move_constructible_v<T>) : v_(std::move(v)) {} 71 // NOLINTNEXTLINE(google-explicit-constructor) noexcept(std::is_nothrow_move_constructible_v<E>)72 Expected(Unexpected<E> e) noexcept(std::is_nothrow_move_constructible_v<E>) : v_(std::move(e.Value())) {} 73 HasValue()74 bool HasValue() const noexcept 75 { 76 return std::holds_alternative<T>(v_); 77 } 78 79 explicit operator bool() const noexcept 80 { 81 return HasValue(); 82 } 83 Error()84 const E &Error() const &noexcept(ExpectedConfig::RELEASE) 85 { 86 ASSERT(!HasValue()); 87 return std::get<E>(v_); 88 } 89 Error()90 E &Error() & noexcept(ExpectedConfig::RELEASE) 91 { 92 ASSERT(!HasValue()); 93 return std::get<E>(v_); 94 } 95 Error()96 E &&Error() && noexcept(ExpectedConfig::RELEASE) 97 { 98 ASSERT(!HasValue()); 99 return std::move(std::get<E>(v_)); 100 } 101 Value()102 const T &Value() const &noexcept(ExpectedConfig::RELEASE) 103 { 104 ASSERT(HasValue()); 105 return std::get<T>(v_); 106 } 107 108 // NOLINTNEXTLINE(bugprone-exception-escape) Value()109 T &Value() & noexcept(ExpectedConfig::RELEASE) 110 { 111 ASSERT(HasValue()); 112 return std::get<T>(v_); 113 } 114 Value()115 T &&Value() && noexcept(ExpectedConfig::RELEASE) 116 { 117 ASSERT(HasValue()); 118 return std::move(std::get<T>(v_)); 119 } 120 noexcept(ExpectedConfig::RELEASE)121 const T &operator*() const &noexcept(ExpectedConfig::RELEASE) 122 { 123 return Value(); 124 } 125 noexcept(ExpectedConfig::RELEASE)126 T &operator*() & noexcept(ExpectedConfig::RELEASE) 127 { 128 return Value(); 129 } 130 noexcept(ExpectedConfig::RELEASE)131 T &&operator*() && noexcept(ExpectedConfig::RELEASE) 132 { 133 return std::move(*this).Value(); 134 } 135 136 template <class U = T> ValueOr(U && v)137 T ValueOr(U &&v) const & 138 { 139 if (HasValue()) { 140 return Value(); 141 } 142 return std::forward<U>(v); 143 } 144 145 template <class U = T> ValueOr(U && v)146 T ValueOr(U &&v) && 147 { 148 if (HasValue()) { 149 return Value(); 150 } 151 return std::forward<U>(v); 152 } 153 154 ~Expected() = default; 155 156 DEFAULT_COPY_SEMANTIC(Expected); 157 DEFAULT_MOVE_SEMANTIC(Expected); 158 159 private: 160 std::variant<T, E> v_; 161 }; 162 163 } // namespace panda 164 165 #endif // PANDA_LIBPANDABASE_UTILS_EXPECTED_H_ 166