1*993b0882SAndroid Build Coastguard Worker /*
2*993b0882SAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project
3*993b0882SAndroid Build Coastguard Worker *
4*993b0882SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*993b0882SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*993b0882SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*993b0882SAndroid Build Coastguard Worker *
8*993b0882SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*993b0882SAndroid Build Coastguard Worker *
10*993b0882SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*993b0882SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*993b0882SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*993b0882SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*993b0882SAndroid Build Coastguard Worker * limitations under the License.
15*993b0882SAndroid Build Coastguard Worker */
16*993b0882SAndroid Build Coastguard Worker
17*993b0882SAndroid Build Coastguard Worker #ifndef LIBTEXTCLASSIFIER_UTILS_BASE_STATUSOR_H_
18*993b0882SAndroid Build Coastguard Worker #define LIBTEXTCLASSIFIER_UTILS_BASE_STATUSOR_H_
19*993b0882SAndroid Build Coastguard Worker
20*993b0882SAndroid Build Coastguard Worker #include <type_traits>
21*993b0882SAndroid Build Coastguard Worker #include <utility>
22*993b0882SAndroid Build Coastguard Worker
23*993b0882SAndroid Build Coastguard Worker #include "utils/base/logging.h"
24*993b0882SAndroid Build Coastguard Worker #include "utils/base/macros.h"
25*993b0882SAndroid Build Coastguard Worker #include "utils/base/status.h"
26*993b0882SAndroid Build Coastguard Worker
27*993b0882SAndroid Build Coastguard Worker namespace libtextclassifier3 {
28*993b0882SAndroid Build Coastguard Worker
29*993b0882SAndroid Build Coastguard Worker // A StatusOr holds a Status (in the case of an error), or a value T.
30*993b0882SAndroid Build Coastguard Worker template <typename T>
31*993b0882SAndroid Build Coastguard Worker class StatusOr {
32*993b0882SAndroid Build Coastguard Worker public:
33*993b0882SAndroid Build Coastguard Worker // Has status UNKNOWN.
34*993b0882SAndroid Build Coastguard Worker inline StatusOr();
35*993b0882SAndroid Build Coastguard Worker
36*993b0882SAndroid Build Coastguard Worker // Builds from a non-OK status. Crashes if an OK status is specified.
37*993b0882SAndroid Build Coastguard Worker inline StatusOr(const Status& status); // NOLINT
38*993b0882SAndroid Build Coastguard Worker
39*993b0882SAndroid Build Coastguard Worker // Builds from the specified value.
40*993b0882SAndroid Build Coastguard Worker inline StatusOr(const T& value); // NOLINT
41*993b0882SAndroid Build Coastguard Worker inline StatusOr(T&& value); // NOLINT
42*993b0882SAndroid Build Coastguard Worker
43*993b0882SAndroid Build Coastguard Worker // Copy constructor.
44*993b0882SAndroid Build Coastguard Worker inline StatusOr(const StatusOr& other);
45*993b0882SAndroid Build Coastguard Worker // Move constructor.
46*993b0882SAndroid Build Coastguard Worker inline StatusOr(StatusOr&& other);
47*993b0882SAndroid Build Coastguard Worker
48*993b0882SAndroid Build Coastguard Worker // Conversion copy constructor, T must be copy constructible from U.
49*993b0882SAndroid Build Coastguard Worker template <typename U,
50*993b0882SAndroid Build Coastguard Worker std::enable_if_t<
51*993b0882SAndroid Build Coastguard Worker std::conjunction<std::negation<std::is_same<T, U>>,
52*993b0882SAndroid Build Coastguard Worker std::is_constructible<T, const U&>,
53*993b0882SAndroid Build Coastguard Worker std::is_convertible<const U&, T>>::value,
54*993b0882SAndroid Build Coastguard Worker int> = 0>
55*993b0882SAndroid Build Coastguard Worker inline StatusOr(const StatusOr<U>& other); // NOLINT
56*993b0882SAndroid Build Coastguard Worker
57*993b0882SAndroid Build Coastguard Worker // Conversion move constructor, T must by move constructible from U.
58*993b0882SAndroid Build Coastguard Worker template <
59*993b0882SAndroid Build Coastguard Worker typename U,
60*993b0882SAndroid Build Coastguard Worker std::enable_if_t<std::conjunction<std::negation<std::is_same<T, U>>,
61*993b0882SAndroid Build Coastguard Worker std::is_constructible<T, U&&>,
62*993b0882SAndroid Build Coastguard Worker std::is_convertible<U&&, T>>::value,
63*993b0882SAndroid Build Coastguard Worker int> = 0>
64*993b0882SAndroid Build Coastguard Worker inline StatusOr(StatusOr<U>&& other); // NOLINT
65*993b0882SAndroid Build Coastguard Worker
66*993b0882SAndroid Build Coastguard Worker // Value conversion copy constructor, T must by copy constructible from U.
67*993b0882SAndroid Build Coastguard Worker template <typename U,
68*993b0882SAndroid Build Coastguard Worker std::enable_if_t<
69*993b0882SAndroid Build Coastguard Worker std::conjunction<std::negation<std::is_same<T, U>>,
70*993b0882SAndroid Build Coastguard Worker std::is_constructible<T, const U&>,
71*993b0882SAndroid Build Coastguard Worker std::is_convertible<const U&, T>>::value,
72*993b0882SAndroid Build Coastguard Worker int> = 0>
73*993b0882SAndroid Build Coastguard Worker inline StatusOr(const U& value); // NOLINT
74*993b0882SAndroid Build Coastguard Worker
75*993b0882SAndroid Build Coastguard Worker // Value conversion move constructor, T must by move constructible from U.
76*993b0882SAndroid Build Coastguard Worker template <
77*993b0882SAndroid Build Coastguard Worker typename U,
78*993b0882SAndroid Build Coastguard Worker std::enable_if_t<std::conjunction<std::negation<std::is_same<T, U>>,
79*993b0882SAndroid Build Coastguard Worker std::is_constructible<T, U&&>,
80*993b0882SAndroid Build Coastguard Worker std::is_convertible<U&&, T>>::value,
81*993b0882SAndroid Build Coastguard Worker int> = 0>
82*993b0882SAndroid Build Coastguard Worker inline StatusOr(U&& value); // NOLINT
83*993b0882SAndroid Build Coastguard Worker
84*993b0882SAndroid Build Coastguard Worker // Assignment operator.
85*993b0882SAndroid Build Coastguard Worker inline StatusOr& operator=(const StatusOr& other);
86*993b0882SAndroid Build Coastguard Worker inline StatusOr& operator=(StatusOr&& other);
87*993b0882SAndroid Build Coastguard Worker
88*993b0882SAndroid Build Coastguard Worker // Conversion assignment operator, T must be assignable from U
89*993b0882SAndroid Build Coastguard Worker template <typename U>
90*993b0882SAndroid Build Coastguard Worker inline StatusOr& operator=(const StatusOr<U>& other);
91*993b0882SAndroid Build Coastguard Worker template <typename U>
92*993b0882SAndroid Build Coastguard Worker inline StatusOr& operator=(StatusOr<U>&& other);
93*993b0882SAndroid Build Coastguard Worker
94*993b0882SAndroid Build Coastguard Worker inline ~StatusOr();
95*993b0882SAndroid Build Coastguard Worker
96*993b0882SAndroid Build Coastguard Worker // Accessors.
status()97*993b0882SAndroid Build Coastguard Worker inline const Status& status() const& { return status_; }
status()98*993b0882SAndroid Build Coastguard Worker inline Status status() && { return std::move(status_); }
99*993b0882SAndroid Build Coastguard Worker
100*993b0882SAndroid Build Coastguard Worker // Shorthand for status().ok().
ok()101*993b0882SAndroid Build Coastguard Worker inline bool ok() const { return status_.ok(); }
102*993b0882SAndroid Build Coastguard Worker
103*993b0882SAndroid Build Coastguard Worker // Returns value or crashes if ok() is false.
ValueOrDie()104*993b0882SAndroid Build Coastguard Worker inline const T& ValueOrDie() const& {
105*993b0882SAndroid Build Coastguard Worker if (!ok()) {
106*993b0882SAndroid Build Coastguard Worker TC3_LOG(FATAL) << "Attempting to fetch value of non-OK StatusOr: "
107*993b0882SAndroid Build Coastguard Worker << status();
108*993b0882SAndroid Build Coastguard Worker exit(1);
109*993b0882SAndroid Build Coastguard Worker }
110*993b0882SAndroid Build Coastguard Worker return value_;
111*993b0882SAndroid Build Coastguard Worker }
ValueOrDie()112*993b0882SAndroid Build Coastguard Worker inline T& ValueOrDie() & {
113*993b0882SAndroid Build Coastguard Worker if (!ok()) {
114*993b0882SAndroid Build Coastguard Worker TC3_LOG(FATAL) << "Attempting to fetch value of non-OK StatusOr: "
115*993b0882SAndroid Build Coastguard Worker << status();
116*993b0882SAndroid Build Coastguard Worker exit(1);
117*993b0882SAndroid Build Coastguard Worker }
118*993b0882SAndroid Build Coastguard Worker return value_;
119*993b0882SAndroid Build Coastguard Worker }
ValueOrDie()120*993b0882SAndroid Build Coastguard Worker inline const T&& ValueOrDie() const&& {
121*993b0882SAndroid Build Coastguard Worker if (!ok()) {
122*993b0882SAndroid Build Coastguard Worker TC3_LOG(FATAL) << "Attempting to fetch value of non-OK StatusOr: "
123*993b0882SAndroid Build Coastguard Worker << status();
124*993b0882SAndroid Build Coastguard Worker exit(1);
125*993b0882SAndroid Build Coastguard Worker }
126*993b0882SAndroid Build Coastguard Worker return std::move(value_);
127*993b0882SAndroid Build Coastguard Worker }
ValueOrDie()128*993b0882SAndroid Build Coastguard Worker inline T&& ValueOrDie() && {
129*993b0882SAndroid Build Coastguard Worker if (!ok()) {
130*993b0882SAndroid Build Coastguard Worker TC3_LOG(FATAL) << "Attempting to fetch value of non-OK StatusOr: "
131*993b0882SAndroid Build Coastguard Worker << status();
132*993b0882SAndroid Build Coastguard Worker exit(1);
133*993b0882SAndroid Build Coastguard Worker }
134*993b0882SAndroid Build Coastguard Worker return std::move(value_);
135*993b0882SAndroid Build Coastguard Worker }
136*993b0882SAndroid Build Coastguard Worker
137*993b0882SAndroid Build Coastguard Worker template <typename U>
138*993b0882SAndroid Build Coastguard Worker friend class StatusOr;
139*993b0882SAndroid Build Coastguard Worker
140*993b0882SAndroid Build Coastguard Worker private:
Clear()141*993b0882SAndroid Build Coastguard Worker void Clear() {
142*993b0882SAndroid Build Coastguard Worker if (ok()) {
143*993b0882SAndroid Build Coastguard Worker value_.~T();
144*993b0882SAndroid Build Coastguard Worker }
145*993b0882SAndroid Build Coastguard Worker }
146*993b0882SAndroid Build Coastguard Worker
147*993b0882SAndroid Build Coastguard Worker // Construct the value through placement new with the passed argument.
148*993b0882SAndroid Build Coastguard Worker template <typename... Arg>
MakeValue(Arg &&...arg)149*993b0882SAndroid Build Coastguard Worker void MakeValue(Arg&&... arg) {
150*993b0882SAndroid Build Coastguard Worker new (&value_) T(std::forward<Arg>(arg)...);
151*993b0882SAndroid Build Coastguard Worker }
152*993b0882SAndroid Build Coastguard Worker
153*993b0882SAndroid Build Coastguard Worker // Creates a valid instance of type T constructed with U and assigns it to
154*993b0882SAndroid Build Coastguard Worker // value_. Handles how to properly assign to value_ if value_ was never
155*993b0882SAndroid Build Coastguard Worker // actually initialized (if this is currently non-OK).
156*993b0882SAndroid Build Coastguard Worker template <typename U>
AssignValue(U && value)157*993b0882SAndroid Build Coastguard Worker void AssignValue(U&& value) {
158*993b0882SAndroid Build Coastguard Worker if (ok()) {
159*993b0882SAndroid Build Coastguard Worker value_ = std::forward<U>(value);
160*993b0882SAndroid Build Coastguard Worker } else {
161*993b0882SAndroid Build Coastguard Worker MakeValue(std::forward<U>(value));
162*993b0882SAndroid Build Coastguard Worker status_ = Status::OK;
163*993b0882SAndroid Build Coastguard Worker }
164*993b0882SAndroid Build Coastguard Worker }
165*993b0882SAndroid Build Coastguard Worker
166*993b0882SAndroid Build Coastguard Worker // Creates a status constructed with U and assigns it to status_. It also
167*993b0882SAndroid Build Coastguard Worker // properly destroys value_ if this is OK and value_ represents a valid
168*993b0882SAndroid Build Coastguard Worker // instance of T.
169*993b0882SAndroid Build Coastguard Worker template <typename U>
AssignStatus(U && v)170*993b0882SAndroid Build Coastguard Worker void AssignStatus(U&& v) {
171*993b0882SAndroid Build Coastguard Worker Clear();
172*993b0882SAndroid Build Coastguard Worker status_ = static_cast<Status>(std::forward<U>(v));
173*993b0882SAndroid Build Coastguard Worker }
174*993b0882SAndroid Build Coastguard Worker
175*993b0882SAndroid Build Coastguard Worker Status status_;
176*993b0882SAndroid Build Coastguard Worker // The members of unions do not require initialization and are not destructed
177*993b0882SAndroid Build Coastguard Worker // unless specifically called. This allows us to construct instances of
178*993b0882SAndroid Build Coastguard Worker // StatusOr with only error statuses where T is not default constructible.
179*993b0882SAndroid Build Coastguard Worker union {
180*993b0882SAndroid Build Coastguard Worker // value_ is active iff status_.ok()==true
181*993b0882SAndroid Build Coastguard Worker // WARNING: The destructor of value_ is called ONLY if status_ is OK.
182*993b0882SAndroid Build Coastguard Worker T value_;
183*993b0882SAndroid Build Coastguard Worker };
184*993b0882SAndroid Build Coastguard Worker };
185*993b0882SAndroid Build Coastguard Worker
186*993b0882SAndroid Build Coastguard Worker // Implementation.
187*993b0882SAndroid Build Coastguard Worker
188*993b0882SAndroid Build Coastguard Worker template <typename T>
StatusOr()189*993b0882SAndroid Build Coastguard Worker inline StatusOr<T>::StatusOr() : status_(StatusCode::UNKNOWN, "") {}
190*993b0882SAndroid Build Coastguard Worker
191*993b0882SAndroid Build Coastguard Worker template <typename T>
StatusOr(const Status & status)192*993b0882SAndroid Build Coastguard Worker inline StatusOr<T>::StatusOr(const Status& status) : status_(status) {
193*993b0882SAndroid Build Coastguard Worker if (status.ok()) {
194*993b0882SAndroid Build Coastguard Worker TC3_LOG(FATAL) << "OkStatus() is not a valid argument to StatusOr";
195*993b0882SAndroid Build Coastguard Worker exit(1);
196*993b0882SAndroid Build Coastguard Worker }
197*993b0882SAndroid Build Coastguard Worker }
198*993b0882SAndroid Build Coastguard Worker
199*993b0882SAndroid Build Coastguard Worker template <typename T>
StatusOr(const T & value)200*993b0882SAndroid Build Coastguard Worker inline StatusOr<T>::StatusOr(const T& value) : value_(value) {}
201*993b0882SAndroid Build Coastguard Worker
202*993b0882SAndroid Build Coastguard Worker template <typename T>
StatusOr(T && value)203*993b0882SAndroid Build Coastguard Worker inline StatusOr<T>::StatusOr(T&& value) : value_(std::move(value)) {}
204*993b0882SAndroid Build Coastguard Worker
205*993b0882SAndroid Build Coastguard Worker template <typename T>
StatusOr(const StatusOr & other)206*993b0882SAndroid Build Coastguard Worker inline StatusOr<T>::StatusOr(const StatusOr& other)
207*993b0882SAndroid Build Coastguard Worker : status_(other.status_), value_(other.value_) {}
208*993b0882SAndroid Build Coastguard Worker
209*993b0882SAndroid Build Coastguard Worker template <typename T>
StatusOr(StatusOr && other)210*993b0882SAndroid Build Coastguard Worker inline StatusOr<T>::StatusOr(StatusOr&& other)
211*993b0882SAndroid Build Coastguard Worker : status_(other.status_), value_(std::move(other.value_)) {}
212*993b0882SAndroid Build Coastguard Worker
213*993b0882SAndroid Build Coastguard Worker template <typename T>
214*993b0882SAndroid Build Coastguard Worker template <
215*993b0882SAndroid Build Coastguard Worker typename U,
216*993b0882SAndroid Build Coastguard Worker std::enable_if_t<std::conjunction<std::negation<std::is_same<T, U>>,
217*993b0882SAndroid Build Coastguard Worker std::is_constructible<T, const U&>,
218*993b0882SAndroid Build Coastguard Worker std::is_convertible<const U&, T>>::value,
219*993b0882SAndroid Build Coastguard Worker int>>
StatusOr(const StatusOr<U> & other)220*993b0882SAndroid Build Coastguard Worker inline StatusOr<T>::StatusOr(const StatusOr<U>& other)
221*993b0882SAndroid Build Coastguard Worker : status_(other.status_), value_(other.value_) {}
222*993b0882SAndroid Build Coastguard Worker
223*993b0882SAndroid Build Coastguard Worker template <typename T>
224*993b0882SAndroid Build Coastguard Worker template <typename U,
225*993b0882SAndroid Build Coastguard Worker std::enable_if_t<std::conjunction<std::negation<std::is_same<T, U>>,
226*993b0882SAndroid Build Coastguard Worker std::is_constructible<T, U&&>,
227*993b0882SAndroid Build Coastguard Worker std::is_convertible<U&&, T>>::value,
228*993b0882SAndroid Build Coastguard Worker int>>
StatusOr(StatusOr<U> && other)229*993b0882SAndroid Build Coastguard Worker inline StatusOr<T>::StatusOr(StatusOr<U>&& other)
230*993b0882SAndroid Build Coastguard Worker : status_(other.status_), value_(std::move(other.value_)) {}
231*993b0882SAndroid Build Coastguard Worker
232*993b0882SAndroid Build Coastguard Worker template <typename T>
233*993b0882SAndroid Build Coastguard Worker template <
234*993b0882SAndroid Build Coastguard Worker typename U,
235*993b0882SAndroid Build Coastguard Worker std::enable_if_t<std::conjunction<std::negation<std::is_same<T, U>>,
236*993b0882SAndroid Build Coastguard Worker std::is_constructible<T, const U&>,
237*993b0882SAndroid Build Coastguard Worker std::is_convertible<const U&, T>>::value,
238*993b0882SAndroid Build Coastguard Worker int>>
StatusOr(const U & value)239*993b0882SAndroid Build Coastguard Worker inline StatusOr<T>::StatusOr(const U& value) : StatusOr(T(value)) {}
240*993b0882SAndroid Build Coastguard Worker
241*993b0882SAndroid Build Coastguard Worker template <typename T>
242*993b0882SAndroid Build Coastguard Worker template <typename U,
243*993b0882SAndroid Build Coastguard Worker std::enable_if_t<std::conjunction<std::negation<std::is_same<T, U>>,
244*993b0882SAndroid Build Coastguard Worker std::is_constructible<T, U&&>,
245*993b0882SAndroid Build Coastguard Worker std::is_convertible<U&&, T>>::value,
246*993b0882SAndroid Build Coastguard Worker int>>
StatusOr(U && value)247*993b0882SAndroid Build Coastguard Worker inline StatusOr<T>::StatusOr(U&& value) : StatusOr(T(std::forward<U>(value))) {}
248*993b0882SAndroid Build Coastguard Worker
249*993b0882SAndroid Build Coastguard Worker template <typename T>
250*993b0882SAndroid Build Coastguard Worker inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr& other) {
251*993b0882SAndroid Build Coastguard Worker if (other.ok()) {
252*993b0882SAndroid Build Coastguard Worker AssignValue(other.value_);
253*993b0882SAndroid Build Coastguard Worker } else {
254*993b0882SAndroid Build Coastguard Worker AssignStatus(other.status_);
255*993b0882SAndroid Build Coastguard Worker }
256*993b0882SAndroid Build Coastguard Worker return *this;
257*993b0882SAndroid Build Coastguard Worker }
258*993b0882SAndroid Build Coastguard Worker
259*993b0882SAndroid Build Coastguard Worker template <typename T>
260*993b0882SAndroid Build Coastguard Worker inline StatusOr<T>& StatusOr<T>::operator=(StatusOr&& other) {
261*993b0882SAndroid Build Coastguard Worker if (other.ok()) {
262*993b0882SAndroid Build Coastguard Worker AssignValue(std::move(other.value_));
263*993b0882SAndroid Build Coastguard Worker } else {
264*993b0882SAndroid Build Coastguard Worker AssignStatus(std::move(other.status_));
265*993b0882SAndroid Build Coastguard Worker }
266*993b0882SAndroid Build Coastguard Worker return *this;
267*993b0882SAndroid Build Coastguard Worker }
268*993b0882SAndroid Build Coastguard Worker
269*993b0882SAndroid Build Coastguard Worker template <typename T>
~StatusOr()270*993b0882SAndroid Build Coastguard Worker inline StatusOr<T>::~StatusOr() {
271*993b0882SAndroid Build Coastguard Worker Clear();
272*993b0882SAndroid Build Coastguard Worker }
273*993b0882SAndroid Build Coastguard Worker
274*993b0882SAndroid Build Coastguard Worker template <typename T>
275*993b0882SAndroid Build Coastguard Worker template <typename U>
276*993b0882SAndroid Build Coastguard Worker inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) {
277*993b0882SAndroid Build Coastguard Worker if (other.ok()) {
278*993b0882SAndroid Build Coastguard Worker AssignValue(other.value_);
279*993b0882SAndroid Build Coastguard Worker } else {
280*993b0882SAndroid Build Coastguard Worker AssignStatus(other.status_);
281*993b0882SAndroid Build Coastguard Worker }
282*993b0882SAndroid Build Coastguard Worker return *this;
283*993b0882SAndroid Build Coastguard Worker }
284*993b0882SAndroid Build Coastguard Worker
285*993b0882SAndroid Build Coastguard Worker template <typename T>
286*993b0882SAndroid Build Coastguard Worker template <typename U>
287*993b0882SAndroid Build Coastguard Worker inline StatusOr<T>& StatusOr<T>::operator=(StatusOr<U>&& other) {
288*993b0882SAndroid Build Coastguard Worker if (other.ok()) {
289*993b0882SAndroid Build Coastguard Worker AssignValue(std::move(other.value_));
290*993b0882SAndroid Build Coastguard Worker } else {
291*993b0882SAndroid Build Coastguard Worker AssignStatus(std::move(other.status_));
292*993b0882SAndroid Build Coastguard Worker }
293*993b0882SAndroid Build Coastguard Worker return *this;
294*993b0882SAndroid Build Coastguard Worker }
295*993b0882SAndroid Build Coastguard Worker
296*993b0882SAndroid Build Coastguard Worker } // namespace libtextclassifier3
297*993b0882SAndroid Build Coastguard Worker
298*993b0882SAndroid Build Coastguard Worker #define TC3_ASSIGN_OR_RETURN(...) \
299*993b0882SAndroid Build Coastguard Worker TC_STATUS_MACROS_IMPL_GET_VARIADIC_( \
300*993b0882SAndroid Build Coastguard Worker (__VA_ARGS__, TC_STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_3_, \
301*993b0882SAndroid Build Coastguard Worker TC_STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_2_)) \
302*993b0882SAndroid Build Coastguard Worker (__VA_ARGS__)
303*993b0882SAndroid Build Coastguard Worker
304*993b0882SAndroid Build Coastguard Worker #define TC3_ASSIGN_OR_RETURN_NULL(lhs, rexpr) \
305*993b0882SAndroid Build Coastguard Worker TC3_ASSIGN_OR_RETURN(lhs, rexpr, nullptr)
306*993b0882SAndroid Build Coastguard Worker
307*993b0882SAndroid Build Coastguard Worker #define TC3_ASSIGN_OR_RETURN_FALSE(lhs, rexpr) \
308*993b0882SAndroid Build Coastguard Worker TC3_ASSIGN_OR_RETURN(lhs, rexpr, false)
309*993b0882SAndroid Build Coastguard Worker
310*993b0882SAndroid Build Coastguard Worker #define TC3_ASSIGN_OR_RETURN_0(...) \
311*993b0882SAndroid Build Coastguard Worker TC_STATUS_MACROS_IMPL_GET_VARIADIC_( \
312*993b0882SAndroid Build Coastguard Worker (__VA_ARGS__, TC_STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_0_3_, \
313*993b0882SAndroid Build Coastguard Worker TC_STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_0_2_)) \
314*993b0882SAndroid Build Coastguard Worker (__VA_ARGS__)
315*993b0882SAndroid Build Coastguard Worker
316*993b0882SAndroid Build Coastguard Worker #define TC_STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_0_2_(lhs, rexpr) \
317*993b0882SAndroid Build Coastguard Worker TC3_ASSIGN_OR_RETURN(lhs, rexpr, 0)
318*993b0882SAndroid Build Coastguard Worker #define TC_STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_0_3_(lhs, rexpr, \
319*993b0882SAndroid Build Coastguard Worker log_expression) \
320*993b0882SAndroid Build Coastguard Worker TC3_ASSIGN_OR_RETURN(lhs, rexpr, (log_expression, 0))
321*993b0882SAndroid Build Coastguard Worker
322*993b0882SAndroid Build Coastguard Worker // =================================================================
323*993b0882SAndroid Build Coastguard Worker // == Implementation details, do not rely on anything below here. ==
324*993b0882SAndroid Build Coastguard Worker // =================================================================
325*993b0882SAndroid Build Coastguard Worker
326*993b0882SAndroid Build Coastguard Worker // Some builds do not support C++14 fully yet, using C++11 constexpr technique.
HasPossiblyConditionalOperator(const char * lhs,int index)327*993b0882SAndroid Build Coastguard Worker constexpr bool HasPossiblyConditionalOperator(const char* lhs, int index) {
328*993b0882SAndroid Build Coastguard Worker return (index == -1 ? false
329*993b0882SAndroid Build Coastguard Worker : (lhs[index] == '?'
330*993b0882SAndroid Build Coastguard Worker ? true
331*993b0882SAndroid Build Coastguard Worker : HasPossiblyConditionalOperator(lhs, index - 1)));
332*993b0882SAndroid Build Coastguard Worker }
333*993b0882SAndroid Build Coastguard Worker
334*993b0882SAndroid Build Coastguard Worker // MSVC incorrectly expands variadic macros, splice together a macro call to
335*993b0882SAndroid Build Coastguard Worker // work around the bug.
336*993b0882SAndroid Build Coastguard Worker #define TC_STATUS_MACROS_IMPL_GET_VARIADIC_HELPER_(_1, _2, _3, NAME, ...) NAME
337*993b0882SAndroid Build Coastguard Worker #define TC_STATUS_MACROS_IMPL_GET_VARIADIC_(args) \
338*993b0882SAndroid Build Coastguard Worker TC_STATUS_MACROS_IMPL_GET_VARIADIC_HELPER_ args
339*993b0882SAndroid Build Coastguard Worker
340*993b0882SAndroid Build Coastguard Worker #define TC_STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_2_(lhs, rexpr) \
341*993b0882SAndroid Build Coastguard Worker TC_STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_3_(lhs, rexpr, _)
342*993b0882SAndroid Build Coastguard Worker #define TC_STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_3_(lhs, rexpr, \
343*993b0882SAndroid Build Coastguard Worker error_expression) \
344*993b0882SAndroid Build Coastguard Worker TC_STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_( \
345*993b0882SAndroid Build Coastguard Worker TC_STATUS_MACROS_IMPL_CONCAT_(_status_or_value, __COUNTER__), lhs, \
346*993b0882SAndroid Build Coastguard Worker rexpr, error_expression)
347*993b0882SAndroid Build Coastguard Worker #define TC_STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_(statusor, lhs, rexpr, \
348*993b0882SAndroid Build Coastguard Worker error_expression) \
349*993b0882SAndroid Build Coastguard Worker auto statusor = (rexpr); \
350*993b0882SAndroid Build Coastguard Worker if (!statusor.ok()) { \
351*993b0882SAndroid Build Coastguard Worker ::libtextclassifier3::Status _(std::move(statusor).status()); \
352*993b0882SAndroid Build Coastguard Worker (void)_; /* error_expression is allowed to not use this variable */ \
353*993b0882SAndroid Build Coastguard Worker return (error_expression); \
354*993b0882SAndroid Build Coastguard Worker } \
355*993b0882SAndroid Build Coastguard Worker { \
356*993b0882SAndroid Build Coastguard Worker static_assert(#lhs[0] != '(' || #lhs[sizeof(#lhs) - 2] != ')' || \
357*993b0882SAndroid Build Coastguard Worker !HasPossiblyConditionalOperator(#lhs, sizeof(#lhs) - 2), \
358*993b0882SAndroid Build Coastguard Worker "Identified potential conditional operator, consider not " \
359*993b0882SAndroid Build Coastguard Worker "using ASSIGN_OR_RETURN"); \
360*993b0882SAndroid Build Coastguard Worker } \
361*993b0882SAndroid Build Coastguard Worker TC_STATUS_MACROS_IMPL_UNPARENTHESIZE_IF_PARENTHESIZED(lhs) = \
362*993b0882SAndroid Build Coastguard Worker std::move(statusor).ValueOrDie()
363*993b0882SAndroid Build Coastguard Worker
364*993b0882SAndroid Build Coastguard Worker // Internal helpers for macro expansion.
365*993b0882SAndroid Build Coastguard Worker #define TC_STATUS_MACROS_IMPL_EAT(...)
366*993b0882SAndroid Build Coastguard Worker #define TC_STATUS_MACROS_IMPL_REM(...) __VA_ARGS__
367*993b0882SAndroid Build Coastguard Worker #define TC_STATUS_MACROS_IMPL_EMPTY()
368*993b0882SAndroid Build Coastguard Worker
369*993b0882SAndroid Build Coastguard Worker // Internal helpers for emptyness arguments check.
370*993b0882SAndroid Build Coastguard Worker #define TC_STATUS_MACROS_IMPL_IS_EMPTY_INNER(...) \
371*993b0882SAndroid Build Coastguard Worker TC_STATUS_MACROS_IMPL_IS_EMPTY_INNER_I(__VA_ARGS__, 0, 1)
372*993b0882SAndroid Build Coastguard Worker #define TC_STATUS_MACROS_IMPL_IS_EMPTY_INNER_I(e0, e1, is_empty, ...) is_empty
373*993b0882SAndroid Build Coastguard Worker
374*993b0882SAndroid Build Coastguard Worker #define TC_STATUS_MACROS_IMPL_IS_EMPTY(...) \
375*993b0882SAndroid Build Coastguard Worker TC_STATUS_MACROS_IMPL_IS_EMPTY_I(__VA_ARGS__)
376*993b0882SAndroid Build Coastguard Worker #define TC_STATUS_MACROS_IMPL_IS_EMPTY_I(...) \
377*993b0882SAndroid Build Coastguard Worker TC_STATUS_MACROS_IMPL_IS_EMPTY_INNER(_, ##__VA_ARGS__)
378*993b0882SAndroid Build Coastguard Worker
379*993b0882SAndroid Build Coastguard Worker // Internal helpers for if statement.
380*993b0882SAndroid Build Coastguard Worker #define TC_STATUS_MACROS_IMPL_IF_1(_Then, _Else) _Then
381*993b0882SAndroid Build Coastguard Worker #define TC_STATUS_MACROS_IMPL_IF_0(_Then, _Else) _Else
382*993b0882SAndroid Build Coastguard Worker #define TC_STATUS_MACROS_IMPL_IF(_Cond, _Then, _Else) \
383*993b0882SAndroid Build Coastguard Worker TC_STATUS_MACROS_IMPL_CONCAT_(TC_STATUS_MACROS_IMPL_IF_, _Cond)(_Then, _Else)
384*993b0882SAndroid Build Coastguard Worker
385*993b0882SAndroid Build Coastguard Worker // Expands to 1 if the input is parenthesized. Otherwise expands to 0.
386*993b0882SAndroid Build Coastguard Worker #define TC_STATUS_MACROS_IMPL_IS_PARENTHESIZED(...) \
387*993b0882SAndroid Build Coastguard Worker TC_STATUS_MACROS_IMPL_IS_EMPTY(TC_STATUS_MACROS_IMPL_EAT __VA_ARGS__)
388*993b0882SAndroid Build Coastguard Worker
389*993b0882SAndroid Build Coastguard Worker // If the input is parenthesized, removes the parentheses. Otherwise expands to
390*993b0882SAndroid Build Coastguard Worker // the input unchanged.
391*993b0882SAndroid Build Coastguard Worker #define TC_STATUS_MACROS_IMPL_UNPARENTHESIZE_IF_PARENTHESIZED(...) \
392*993b0882SAndroid Build Coastguard Worker TC_STATUS_MACROS_IMPL_IF( \
393*993b0882SAndroid Build Coastguard Worker TC_STATUS_MACROS_IMPL_IS_PARENTHESIZED(__VA_ARGS__), \
394*993b0882SAndroid Build Coastguard Worker TC_STATUS_MACROS_IMPL_REM, TC_STATUS_MACROS_IMPL_EMPTY()) \
395*993b0882SAndroid Build Coastguard Worker __VA_ARGS__
396*993b0882SAndroid Build Coastguard Worker
397*993b0882SAndroid Build Coastguard Worker // Internal helper for concatenating macro values.
398*993b0882SAndroid Build Coastguard Worker #define TC_STATUS_MACROS_IMPL_CONCAT_INNER_(x, y) x##y
399*993b0882SAndroid Build Coastguard Worker #define TC_STATUS_MACROS_IMPL_CONCAT_(x, y) \
400*993b0882SAndroid Build Coastguard Worker TC_STATUS_MACROS_IMPL_CONCAT_INNER_(x, y)
401*993b0882SAndroid Build Coastguard Worker
402*993b0882SAndroid Build Coastguard Worker #endif // LIBTEXTCLASSIFIER_UTILS_BASE_STATUSOR_H_
403