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 } Error()92 E &Error() & noexcept(ExpectedConfig::RELEASE) 93 { 94 ASSERT(!HasValue()); 95 return std::get<E>(v_); 96 } Error()97 E &&Error() && noexcept(ExpectedConfig::RELEASE) 98 { 99 ASSERT(!HasValue()); 100 return std::move(std::get<E>(v_)); 101 } 102 Value()103 const T &Value() const &noexcept(ExpectedConfig::RELEASE) 104 { 105 ASSERT(HasValue()); 106 return std::get<T>(v_); 107 } 108 // TODO(aemelenko): Delete next line when the issue 388 is resolved 109 // NOLINTNEXTLINE(bugprone-exception-escape) Value()110 T &Value() & noexcept(ExpectedConfig::RELEASE) 111 { 112 ASSERT(HasValue()); 113 return std::get<T>(v_); 114 } Value()115 T &&Value() && noexcept(ExpectedConfig::RELEASE) 116 { 117 ASSERT(HasValue()); 118 return std::move(std::get<T>(v_)); 119 } noexcept(ExpectedConfig::RELEASE)120 const T &operator*() const &noexcept(ExpectedConfig::RELEASE) 121 { 122 return Value(); 123 } noexcept(ExpectedConfig::RELEASE)124 T &operator*() & noexcept(ExpectedConfig::RELEASE) 125 { 126 return Value(); 127 } noexcept(ExpectedConfig::RELEASE)128 T &&operator*() && noexcept(ExpectedConfig::RELEASE) 129 { 130 return std::move(*this).Value(); 131 } 132 133 template <class U = T> ValueOr(U && v)134 T ValueOr(U &&v) const & 135 { 136 if (HasValue()) { 137 return Value(); 138 } 139 return std::forward<U>(v); 140 } 141 template <class U = T> ValueOr(U && v)142 T ValueOr(U &&v) && 143 { 144 if (HasValue()) { 145 return Value(); 146 } 147 return std::forward<U>(v); 148 } 149 150 ~Expected() = default; 151 152 DEFAULT_COPY_SEMANTIC(Expected); 153 DEFAULT_MOVE_SEMANTIC(Expected); 154 155 private: 156 std::variant<T, E> v_; 157 }; 158 159 } // namespace panda 160 161 #endif // PANDA_LIBPANDABASE_UTILS_EXPECTED_H_ 162