• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ANDROID_FRAMEWORKS_ML_NN_COMMON_NNAPI_RESULT_H
18 #define ANDROID_FRAMEWORKS_ML_NN_COMMON_NNAPI_RESULT_H
19 
20 #include <android-base/expected.h>
21 
22 #include <optional>
23 #include <sstream>
24 #include <string>
25 #include <tuple>
26 #include <utility>
27 
28 namespace android::nn {
29 
30 /**
31  * Type alias for `::android::base::expected` where the unexpected state is represented by a
32  * std::string describing the error.
33  *
34  * See the following file for more information on ::android::base::expected:
35  *   system/libbase/include/android-base/expected.h
36  */
37 template <typename Type>
38 using Result = base::expected<Type, std::string>;
39 
40 namespace detail {
41 
42 template <typename... Ts>
43 class ErrorBuilder {
44    public:
45     template <typename... Us>
ErrorBuilder(Us &&...args)46     explicit ErrorBuilder(Us&&... args) : mArgs(std::forward<Us>(args)...) {}
47 
48     template <typename T, typename E>
49     operator base::expected<T, E>() /* NOLINT(google-explicit-constructor) */ {
50         return std::apply(
51                 [this](Ts&&... args) {
52                     return base::unexpected<E>(E{std::move(mStream).str(), std::move(args)...});
53                 },
54                 std::move(mArgs));
55     }
56 
57     template <typename T>
58     ErrorBuilder operator<<(const T& t) {
59         mStream << t;
60         return std::move(*this);
61     }
62 
63    private:
64     std::tuple<Ts...> mArgs;
65     std::ostringstream mStream;
66 };
67 
68 }  // namespace detail
69 
70 /**
71  * Creates an error builder for the case where no arguments are provided.
72  */
73 template <typename... Types>
error(Types &&...args)74 inline detail::ErrorBuilder<std::decay_t<Types>...> error(Types&&... args) {
75     return detail::ErrorBuilder<std::decay_t<Types>...>(std::forward<Types>(args)...);
76 }
77 
78 /**
79  * Helper macro that will create an error builder already populated with the file name and line
80  * number.
81  *
82  * This macro uses the following customization points:
83  * * `::android::nn::error` is a set of functions that can be customized to return a specialized
84  *    error builder object. Customization is based on the types of arguments passed and the number
85  *    of arguments passed to `error`.
86  *
87  * Usage at error site:
88  *     if (errorDetected) {
89  *         return NN_ERROR() << "<error_message>";
90  *     }
91  *     return <regular_return_value>;
92  */
93 #define NN_ERROR(...)                                                     \
94     [&] {                                                                 \
95         using ::android::nn::error;                                       \
96         return error(__VA_ARGS__) << __FILE__ << ":" << __LINE__ << ": "; \
97     }()
98 
99 template <typename T, typename E>
nnTryHasValue(const base::expected<T,E> & o)100 bool nnTryHasValue(const base::expected<T, E>& o) {
101     return o.has_value();
102 }
103 
104 template <typename T, typename E>
nnTryGetValue(base::expected<T,E> o)105 T nnTryGetValue(base::expected<T, E> o) {
106     return std::move(o).value();
107 }
108 
109 template <typename T, typename E>
nnTryGetError(base::expected<T,E> o)110 base::unexpected<E> nnTryGetError(base::expected<T, E> o) {
111     return base::unexpected(std::move(o).error());
112 }
113 
114 template <typename T>
nnTryHasValue(const std::optional<T> & o)115 bool nnTryHasValue(const std::optional<T>& o) {
116     return o.has_value();
117 }
118 
119 template <typename T>
nnTryGetValue(std::optional<T> o)120 T nnTryGetValue(std::optional<T> o) {
121     return std::move(o).value();
122 }
123 
124 template <typename T>
nnTryGetError(std::optional<T>)125 std::nullopt_t nnTryGetError(std::optional<T> /*o*/) {
126     return std::nullopt;
127 }
128 
129 /**
130  * A macro that will exit from the current function if `expr` is unexpected or return the expected
131  * value from the macro if `expr` is expected.
132  *
133  * This macro can currently be used on `::android::nn::Result`, `::android::base::expected`, or
134  * `std::optional` values. To enable this macro to be used with other values, implement the
135  * following functions for the type:
136  * * `::android::nn::nnTryHasValue` returns `true` if the `expr` holds a successful value, false if
137  *    the `expr` value holds an error
138  * * `::android::nn::nnTryGetError` returns the successful value of `expr` or crashes
139  * * `::android::nn::nnTryGetValue` returns the error value of `expr` or crashes
140  *
141  * Usage at call site:
142  *     const auto [a, b, c] = NN_TRY(failableFunction(args));
143  */
144 #define NN_TRY(expr)                                               \
145     ({                                                             \
146         using ::android::nn::nnTryHasValue;                        \
147         using ::android::nn::nnTryGetValue;                        \
148         using ::android::nn::nnTryGetError;                        \
149         auto nnTryTemporaryResult = expr;                          \
150         if (!nnTryHasValue(nnTryTemporaryResult)) {                \
151             return nnTryGetError(std::move(nnTryTemporaryResult)); \
152         }                                                          \
153         nnTryGetValue(std::move(nnTryTemporaryResult));            \
154     })
155 
156 }  // namespace android::nn
157 
158 #endif  // ANDROID_FRAMEWORKS_ML_NN_COMMON_NNAPI_RESULT_H
159