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