• 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     }
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