1 // Copyright (C) 2019 Google LLC 2 // 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 #ifndef ICING_TEXT_CLASSIFIER_LIB3_UTILS_BASE_STATUS_MACROS_H_ 16 #define ICING_TEXT_CLASSIFIER_LIB3_UTILS_BASE_STATUS_MACROS_H_ 17 18 #include <utility> 19 20 #include "icing/text_classifier/lib3/utils/base/status.h" 21 #include "icing/text_classifier/lib3/utils/base/statusor.h" 22 23 namespace libtextclassifier3 { 24 25 // An adapter to enable TC3_RETURN_IF_ERROR to be used with either Status or 26 // StatusOr. 27 class StatusAdapter { 28 public: StatusAdapter(const Status & s)29 explicit StatusAdapter(const Status& s) : s_(s) {} StatusAdapter(Status && s)30 explicit StatusAdapter(Status&& s) : s_(std::move(s)) {} 31 template <typename T> StatusAdapter(const StatusOr<T> & s)32 explicit StatusAdapter(const StatusOr<T>& s) : s_(s.status()) {} 33 template <typename T> StatusAdapter(StatusOr<T> && s)34 explicit StatusAdapter(StatusOr<T>&& s) : s_(std::move(s).status()) {} 35 ok()36 bool ok() const { return s_.ok(); } 37 explicit operator bool() const { return ok(); } 38 status()39 const Status& status() const& { return s_; } status()40 Status status() && { return std::move(s_); } 41 42 private: 43 Status s_; 44 }; 45 46 } // namespace libtextclassifier3 47 48 // Evaluates an expression that produces a `libtextclassifier3::Status`. If the 49 // status is not ok, returns it from the current function. 50 // 51 // For example: 52 // libtextclassifier3::Status MultiStepFunction() { 53 // TC3_RETURN_IF_ERROR(Function(args...)); 54 // TC3_RETURN_IF_ERROR(foo.Method(args...)); 55 // return libtextclassifier3::Status(); 56 // } 57 #define TC3_RETURN_IF_ERROR(expr) \ 58 TC3_RETURN_IF_ERROR_INTERNAL(expr, std::move(adapter).status()) 59 60 #define TC3_RETURN_NULL_IF_ERROR(expr) \ 61 TC3_RETURN_IF_ERROR_INTERNAL(expr, nullptr) 62 63 #define TC3_RETURN_FALSE_IF_ERROR(expr) \ 64 TC3_RETURN_IF_ERROR_INTERNAL(expr, false) 65 66 #define TC3_RETURN_IF_ERROR_INTERNAL(expr, return_value) \ 67 TC3_STATUS_MACROS_IMPL_ELSE_BLOCKER_ \ 68 if (::libtextclassifier3::StatusAdapter adapter{expr}) { \ 69 } else /* NOLINT */ \ 70 return return_value 71 72 // The GNU compiler emits a warning for code like: 73 // 74 // if (foo) 75 // if (bar) { } else baz; 76 // 77 // because it thinks you might want the else to bind to the first if. This 78 // leads to problems with code like: 79 // 80 // if (do_expr) TC3_RETURN_IF_ERROR(expr); 81 // 82 // The "switch (0) case 0:" idiom is used to suppress this. 83 #define TC3_STATUS_MACROS_IMPL_ELSE_BLOCKER_ \ 84 switch (0) \ 85 case 0: \ 86 default: // NOLINT 87 88 #endif // ICING_TEXT_CLASSIFIER_LIB3_UTILS_BASE_STATUS_MACROS_H_ 89