• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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