1 /* 2 * Copyright (c) 2021-2022 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 "macros.h" 23 24 namespace panda { 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::move(v)) {} 75 // NOLINTNEXTLINE(google-explicit-constructor) noexcept(std::is_nothrow_move_constructible_v<E>)76 Expected(Unexpected<E> e) noexcept(std::is_nothrow_move_constructible_v<E>) : v_(std::move(e.Value())) {} 77 HasValue()78 bool HasValue() const noexcept 79 { 80 return std::holds_alternative<T>(v_); 81 } 82 explicit operator bool() const noexcept 83 { 84 return HasValue(); 85 } 86 Error()87 const E &Error() const &noexcept(ExpectedConfig::RELEASE) 88 { 89 ASSERT(!HasValue()); 90 return std::get<E>(v_); 91 } 92 // NOLINTNEXTLINE(bugprone-exception-escape) Error()93 E &Error() &noexcept(ExpectedConfig::RELEASE) 94 { 95 ASSERT(!HasValue()); 96 return std::get<E>(v_); 97 } Error()98 E &&Error() &&noexcept(ExpectedConfig::RELEASE) 99 { 100 ASSERT(!HasValue()); 101 return std::move(std::get<E>(v_)); 102 } 103 Value()104 const T &Value() const &noexcept(ExpectedConfig::RELEASE) 105 { 106 ASSERT(HasValue()); 107 return std::get<T>(v_); 108 } 109 // NOTE(aemelenko): Delete next line when the issue 388 is resolved 110 // NOLINTNEXTLINE(bugprone-exception-escape) Value()111 T &Value() &noexcept(ExpectedConfig::RELEASE) 112 { 113 ASSERT(HasValue()); 114 return std::get<T>(v_); 115 } Value()116 T &&Value() &&noexcept(ExpectedConfig::RELEASE) 117 { 118 ASSERT(HasValue()); 119 return std::move(std::get<T>(v_)); 120 } noexcept(ExpectedConfig::RELEASE)121 const T &operator*() const &noexcept(ExpectedConfig::RELEASE) 122 { 123 return Value(); 124 } 125 // NOLINTNEXTLINE(bugprone-exception-escape) noexcept(ExpectedConfig::RELEASE)126 T &operator*() &noexcept(ExpectedConfig::RELEASE) 127 { 128 return Value(); 129 } noexcept(ExpectedConfig::RELEASE)130 T &&operator*() &&noexcept(ExpectedConfig::RELEASE) 131 { 132 return std::move(*this).Value(); 133 } 134 135 const T *operator->() const noexcept(ExpectedConfig::RELEASE) 136 { 137 auto ptr = std::get_if<T>(&v_); 138 ASSERT(ptr != nullptr); 139 return ptr; 140 } 141 T *operator->() noexcept(ExpectedConfig::RELEASE) 142 { 143 auto ptr = std::get_if<T>(&v_); 144 ASSERT(ptr != nullptr); 145 return ptr; 146 } 147 148 template <class U = T> ValueOr(U && v)149 T ValueOr(U &&v) const & 150 { 151 if (HasValue()) { 152 return Value(); 153 } 154 return std::forward<U>(v); 155 } 156 template <class U = T> ValueOr(U && v)157 T ValueOr(U &&v) && 158 { 159 if (HasValue()) { 160 return Value(); 161 } 162 return std::forward<U>(v); 163 } 164 165 ~Expected() = default; 166 167 DEFAULT_COPY_SEMANTIC(Expected); 168 DEFAULT_MOVE_SEMANTIC(Expected); 169 170 private: 171 std::variant<T, E> v_; 172 }; 173 174 } // namespace panda 175 176 #endif // PANDA_LIBPANDABASE_UTILS_EXPECTED_H 177