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 LIBPANDABASE_UTILS_EXPECTED_H 17#define LIBPANDABASE_UTILS_EXPECTED_H 18 19#include <type_traits> 20#include <variant> 21 22#include "macros.h" 23 24namespace panda { 25 26template <class E> 27class Unexpected final { 28public: 29 explicit Unexpected(E e) noexcept(std::is_nothrow_move_constructible_v<E>) : e_(std::move(e)) {} 30 31 const E &Value() const &noexcept 32 { 33 return e_; 34 } 35 E &Value() & noexcept 36 { 37 return e_; 38 } 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 49private: 50 E e_; 51}; 52 53class ExpectedConfig final { 54public: 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. 65template <class T, class E> 66class Expected final { 67public: 68 template <typename U = T, typename = std::enable_if_t<std::is_default_constructible_v<U>>> 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) 74 Expected(T v) noexcept(std::is_nothrow_move_constructible_v<T>) : v_(std::move(v)) {} 75 // NOLINTNEXTLINE(google-explicit-constructor) 76 Expected(Unexpected<E> e) noexcept(std::is_nothrow_move_constructible_v<E>) : v_(std::move(e.Value())) {} 77 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 87 const E &Error() const &noexcept(ExpectedConfig::RELEASE) 88 { 89 ASSERT(!HasValue()); 90 return std::get<E>(v_); 91 } 92 E &Error() & noexcept(ExpectedConfig::RELEASE) 93 { 94 ASSERT(!HasValue()); 95 return std::get<E>(v_); 96 } 97 E &&Error() && noexcept(ExpectedConfig::RELEASE) 98 { 99 ASSERT(!HasValue()); 100 return std::move(std::get<E>(v_)); 101 } 102 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) 110 T &Value() & noexcept(ExpectedConfig::RELEASE) 111 { 112 ASSERT(HasValue()); 113 return std::get<T>(v_); 114 } 115 T &&Value() && noexcept(ExpectedConfig::RELEASE) 116 { 117 ASSERT(HasValue()); 118 return std::move(std::get<T>(v_)); 119 } 120 const T &operator*() const &noexcept(ExpectedConfig::RELEASE) 121 { 122 return Value(); 123 } 124 T &operator*() & noexcept(ExpectedConfig::RELEASE) 125 { 126 return Value(); 127 } 128 T &&operator*() && noexcept(ExpectedConfig::RELEASE) 129 { 130 return std::move(*this).Value(); 131 } 132 133 template <class U = T> 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> 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 155private: 156 std::variant<T, E> v_; 157}; 158 159} // namespace panda 160 161#endif // LIBPANDABASE_UTILS_EXPECTED_H 162