1 /*
2 * Copyright (c) 2016-2019 Arm Limited.
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24 #ifndef ARM_COMPUTE_VALIDATE_H
25 #define ARM_COMPUTE_VALIDATE_H
26
27 #include "arm_compute/core/Error.h"
28 #include "arm_compute/core/HOGInfo.h"
29 #include "arm_compute/core/IKernel.h"
30 #include "arm_compute/core/IMultiHOG.h"
31 #include "arm_compute/core/IMultiImage.h"
32 #include "arm_compute/core/ITensor.h"
33 #include "arm_compute/core/MultiImageInfo.h"
34 #include "arm_compute/core/Window.h"
35
36 #include <algorithm>
37
38 namespace arm_compute
39 {
40 namespace detail
41 {
42 /* Check whether two dimension objects differ.
43 *
44 * @param[in] dim1 First object to be compared.
45 * @param[in] dim2 Second object to be compared.
46 * @param[in] upper_dim The dimension from which to check.
47 *
48 * @return Return true if the two objects are different.
49 */
50 template <typename T>
have_different_dimensions(const Dimensions<T> & dim1,const Dimensions<T> & dim2,unsigned int upper_dim)51 inline bool have_different_dimensions(const Dimensions<T> &dim1, const Dimensions<T> &dim2, unsigned int upper_dim)
52 {
53 for(unsigned int i = upper_dim; i < arm_compute::Dimensions<T>::num_max_dimensions; ++i)
54 {
55 if(dim1[i] != dim2[i])
56 {
57 return true;
58 }
59 }
60
61 return false;
62 }
63
64 /** Function to compare two @ref Dimensions objects and throw an error on mismatch.
65 *
66 * @param[in] dim Object to compare against.
67 * @param[in] function Function in which the error occurred.
68 * @param[in] file File in which the error occurred.
69 * @param[in] line Line in which the error occurred.
70 */
71 template <typename T>
72 class compare_dimension
73 {
74 public:
75 /** Construct a comparison function.
76 *
77 * @param[in] dim Dimensions to compare.
78 * @param[in] function Source function. Used for error reporting.
79 * @param[in] file Source code file. Used for error reporting.
80 * @param[in] line Source code line. Used for error reporting.
81 */
compare_dimension(const Dimensions<T> & dim,const char * function,const char * file,int line)82 compare_dimension(const Dimensions<T> &dim, const char *function, const char *file, int line)
83 : _dim{ dim }, _function{ function }, _file{ file }, _line{ line }
84 {
85 }
86
87 /** Compare the given object against the stored one.
88 *
89 * @param[in] dim To be compared object.
90 *
91 * @return a status.
92 */
operator()93 arm_compute::Status operator()(const Dimensions<T> &dim)
94 {
95 ARM_COMPUTE_RETURN_ERROR_ON_LOC_MSG(have_different_dimensions(_dim, dim, 0), _function, _file, _line,
96 "Objects have different dimensions");
97 return arm_compute::Status{};
98 }
99
100 private:
101 const Dimensions<T> &_dim;
102 const char *const _function;
103 const char *const _file;
104 const int _line;
105 };
106
107 template <typename F>
for_each_error(F &&)108 inline arm_compute::Status for_each_error(F &&)
109 {
110 return arm_compute::Status{};
111 }
112
113 template <typename F, typename T, typename... Ts>
for_each_error(F && func,T && arg,Ts &&...args)114 inline arm_compute::Status for_each_error(F &&func, T &&arg, Ts &&... args)
115 {
116 ARM_COMPUTE_RETURN_ON_ERROR(func(arg));
117 ARM_COMPUTE_RETURN_ON_ERROR(for_each_error(func, args...));
118 return arm_compute::Status{};
119 }
120
121 /** Get the info for a tensor, dummy struct */
122 template <typename T>
123 struct get_tensor_info_t;
124 /** Get the info for a tensor */
125 template <>
126 struct get_tensor_info_t<ITensorInfo *>
127 {
128 /** Get the info for a tensor.
129 *
130 * @param[in] tensor Tensor.
131 *
132 * @return tensor info.
133 */
134 ITensorInfo *operator()(const ITensor *tensor)
135 {
136 return tensor->info();
137 }
138 };
139 } // namespace detail
140
141 /** Create an error if one of the pointers is a nullptr.
142 *
143 * @param[in] function Function in which the error occurred.
144 * @param[in] file Name of the file where the error occurred.
145 * @param[in] line Line on which the error occurred.
146 * @param[in] pointers Pointers to check against nullptr.
147 *
148 * @return Status
149 */
150 template <typename... Ts>
151 inline arm_compute::Status error_on_nullptr(const char *function, const char *file, const int line, Ts &&... pointers)
152 {
153 const std::array<const void *, sizeof...(Ts)> pointers_array{ { std::forward<Ts>(pointers)... } };
154 bool has_nullptr = std::any_of(pointers_array.begin(), pointers_array.end(), [&](const void *ptr)
155 {
156 return (ptr == nullptr);
157 });
158 ARM_COMPUTE_RETURN_ERROR_ON_LOC_MSG(has_nullptr, function, file, line, "Nullptr object!");
159 return arm_compute::Status{};
160 }
161 #define ARM_COMPUTE_ERROR_ON_NULLPTR(...) \
162 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_nullptr(__func__, __FILE__, __LINE__, __VA_ARGS__))
163 #define ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(...) \
164 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_nullptr(__func__, __FILE__, __LINE__, __VA_ARGS__))
165
166 /** Return an error if the passed window is invalid.
167 *
168 * The subwindow is invalid if:
169 * - It is not a valid window.
170 * - Its dimensions don't match the full window's ones
171 * - The step for each of its dimension is not identical to the corresponding one of the full window.
172 *
173 * @param[in] function Function in which the error occurred.
174 * @param[in] file Name of the file where the error occurred.
175 * @param[in] line Line on which the error occurred.
176 * @param[in] full Full size window
177 * @param[in] win Window to validate.
178 *
179 * @return Status
180 */
181 arm_compute::Status error_on_mismatching_windows(const char *function, const char *file, const int line,
182 const Window &full, const Window &win);
183 #define ARM_COMPUTE_ERROR_ON_MISMATCHING_WINDOWS(f, w) \
184 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_mismatching_windows(__func__, __FILE__, __LINE__, f, w))
185 #define ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_WINDOWS(f, w) \
186 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_mismatching_windows(__func__, __FILE__, __LINE__, f, w))
187
188 /** Return an error if the passed subwindow is invalid.
189 *
190 * The subwindow is invalid if:
191 * - It is not a valid window.
192 * - It is not fully contained inside the full window
193 * - The step for each of its dimension is not identical to the corresponding one of the full window.
194 *
195 * @param[in] function Function in which the error occurred.
196 * @param[in] file Name of the file where the error occurred.
197 * @param[in] line Line on which the error occurred.
198 * @param[in] full Full size window
199 * @param[in] sub Sub-window to validate.
200 *
201 * @return Status
202 */
203 arm_compute::Status error_on_invalid_subwindow(const char *function, const char *file, const int line,
204 const Window &full, const Window &sub);
205 #define ARM_COMPUTE_ERROR_ON_INVALID_SUBWINDOW(f, s) \
206 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_invalid_subwindow(__func__, __FILE__, __LINE__, f, s))
207 #define ARM_COMPUTE_RETURN_ERROR_ON_INVALID_SUBWINDOW(f, s) \
208 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_invalid_subwindow(__func__, __FILE__, __LINE__, f, s))
209
210 /** Return an error if the window can't be collapsed at the given dimension.
211 *
212 * The window cannot be collapsed if the given dimension not equal to the full window's dimension or not start from 0.
213 *
214 * @param[in] function Function in which the error occurred.
215 * @param[in] file Name of the file where the error occurred.
216 * @param[in] line Line on which the error occurred.
217 * @param[in] full Full size window
218 * @param[in] window Window to be collapsed.
219 * @param[in] dim Dimension need to be checked.
220 *
221 * @return Status
222 */
223 arm_compute::Status error_on_window_not_collapsable_at_dimension(const char *function, const char *file, const int line,
224 const Window &full, const Window &window, const int dim);
225 #define ARM_COMPUTE_ERROR_ON_WINDOW_NOT_COLLAPSABLE_AT_DIMENSION(f, w, d) \
226 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_window_not_collapsable_at_dimension(__func__, __FILE__, __LINE__, f, w, d))
227 #define ARM_COMPUTE_RETURN_ERROR_ON_WINDOW_NOT_COLLAPSABLE_AT_DIMENSION(f, w, d) \
228 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_window_not_collapsable_at_dimension(__func__, __FILE__, __LINE__, f, w, d))
229
230 /** Return an error if the passed coordinates have too many dimensions.
231 *
232 * The coordinates have too many dimensions if any of the dimensions greater or equal to max_dim is different from 0.
233 *
234 * @param[in] function Function in which the error occurred.
235 * @param[in] file Name of the file where the error occurred.
236 * @param[in] line Line on which the error occurred.
237 * @param[in] pos Coordinates to validate
238 * @param[in] max_dim Maximum number of dimensions allowed.
239 *
240 * @return Status
241 */
242 arm_compute::Status error_on_coordinates_dimensions_gte(const char *function, const char *file, const int line,
243 const Coordinates &pos, unsigned int max_dim);
244 #define ARM_COMPUTE_ERROR_ON_COORDINATES_DIMENSIONS_GTE(p, md) \
245 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_coordinates_dimensions_gte(__func__, __FILE__, __LINE__, p, md))
246 #define ARM_COMPUTE_RETURN_ERROR_ON_COORDINATES_DIMENSIONS_GTE(p, md) \
247 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_coordinates_dimensions_gte(__func__, __FILE__, __LINE__, p, md))
248
249 /** Return an error if the passed window has too many dimensions.
250 *
251 * The window has too many dimensions if any of the dimension greater or equal to max_dim is different from 0.
252 *
253 * @param[in] function Function in which the error occurred.
254 * @param[in] file Name of the file where the error occurred.
255 * @param[in] line Line on which the error occurred.
256 * @param[in] win Window to validate
257 * @param[in] max_dim Maximum number of dimensions allowed.
258 *
259 * @return Status
260 */
261 arm_compute::Status error_on_window_dimensions_gte(const char *function, const char *file, const int line,
262 const Window &win, unsigned int max_dim);
263 #define ARM_COMPUTE_ERROR_ON_WINDOW_DIMENSIONS_GTE(w, md) \
264 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_window_dimensions_gte(__func__, __FILE__, __LINE__, w, md))
265 #define ARM_COMPUTE_RETURN_ERROR_ON_WINDOW_DIMENSIONS_GTE(w, md) \
266 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_window_dimensions_gte(__func__, __FILE__, __LINE__, w, md))
267
268 /** Return an error if the passed dimension objects differ.
269 *
270 * @param[in] function Function in which the error occurred.
271 * @param[in] file Name of the file where the error occurred.
272 * @param[in] line Line on which the error occurred.
273 * @param[in] dim1 The first object to be compared.
274 * @param[in] dim2 The second object to be compared.
275 * @param[in] dims (Optional) Further allowed objects.
276 *
277 * @return Status
278 */
279 template <typename T, typename... Ts>
280 arm_compute::Status error_on_mismatching_dimensions(const char *function, const char *file, int line,
281 const Dimensions<T> &dim1, const Dimensions<T> &dim2, Ts &&... dims)
282 {
283 ARM_COMPUTE_RETURN_ON_ERROR(detail::for_each_error(detail::compare_dimension<T>(dim1, function, file, line), dim2, std::forward<Ts>(dims)...));
284 return arm_compute::Status{};
285 }
286 #define ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(...) \
287 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_mismatching_dimensions(__func__, __FILE__, __LINE__, __VA_ARGS__))
288 #define ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DIMENSIONS(...) \
289 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_mismatching_dimensions(__func__, __FILE__, __LINE__, __VA_ARGS__))
290
291 /** Return an error if the passed tensor objects are not even.
292 *
293 * @param[in] function Function in which the error occurred.
294 * @param[in] file Name of the file where the error occurred.
295 * @param[in] line Line on which the error occurred.
296 * @param[in] format Format to check if odd shape is allowed
297 * @param[in] tensor1 The first object to be compared for odd shape.
298 * @param[in] tensors (Optional) Further allowed objects.
299 *
300 * @return Status
301 */
302 template <typename... Ts>
303 arm_compute::Status error_on_tensors_not_even(const char *function, const char *file, int line,
304 const Format &format, const ITensor *tensor1, Ts... tensors)
305 {
306 ARM_COMPUTE_RETURN_ERROR_ON_LOC(tensor1 == nullptr, function, file, line);
307 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_nullptr(function, file, line, std::forward<Ts>(tensors)...));
308 const std::array < const ITensor *, 1 + sizeof...(Ts) > tensors_info_array{ { tensor1, std::forward<Ts>(tensors)... } };
309 ARM_COMPUTE_RETURN_ERROR_ON_LOC_MSG(std::any_of(tensors_info_array.cbegin(), tensors_info_array.cend(), [&](const ITensor * tensor)
310 {
311 const TensorShape correct_shape = adjust_odd_shape(tensor->info()->tensor_shape(), format);
312 return detail::have_different_dimensions(tensor->info()->tensor_shape(), correct_shape, 2);
313 }),
314 function, file, line, "Tensor shape has odd dimensions");
315 return arm_compute::Status{};
316 }
317
318 #define ARM_COMPUTE_ERROR_ON_TENSORS_NOT_EVEN(...) \
319 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_tensors_not_even(__func__, __FILE__, __LINE__, __VA_ARGS__))
320 #define ARM_COMPUTE_RETURN_ERROR_ON_TENSORS_NOT_EVEN(...) \
321 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_tensors_not_even(__func__, __FILE__, __LINE__, __VA_ARGS__))
322
323 /** Return an error if the passed tensor objects are not sub-sampled.
324 *
325 * @param[in] function Function in which the error occurred.
326 * @param[in] file Name of the file where the error occurred.
327 * @param[in] line Line on which the error occurred.
328 * @param[in] format Format to check if sub-sampling allowed.
329 * @param[in] shape The tensor shape to calculate sub-sampling from.
330 * @param[in] tensor1 The first object to be compared.
331 * @param[in] tensors (Optional) Further allowed objects.
332 *
333 * @return Status
334 */
335 template <typename... Ts>
336 arm_compute::Status error_on_tensors_not_subsampled(const char *function, const char *file, int line,
337 const Format &format, const TensorShape &shape, const ITensor *tensor1, Ts... tensors)
338 {
339 ARM_COMPUTE_RETURN_ERROR_ON_LOC(tensor1 == nullptr, function, file, line);
340 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_nullptr(function, file, line, std::forward<Ts>(tensors)...));
341 const TensorShape sub2_shape = calculate_subsampled_shape(shape, format);
342 const std::array < const ITensor *, 1 + sizeof...(Ts) > tensors_info_array{ { tensor1, std::forward<Ts>(tensors)... } };
343 ARM_COMPUTE_RETURN_ERROR_ON_LOC_MSG(std::any_of(tensors_info_array.cbegin(), tensors_info_array.cend(), [&](const ITensor * tensor)
344 {
345 return detail::have_different_dimensions(tensor->info()->tensor_shape(), sub2_shape, 2);
346 }),
347 function, file, line, "Tensor shape has mismatch dimensions for sub-sampling");
348 return arm_compute::Status{};
349 }
350
351 #define ARM_COMPUTE_ERROR_ON_TENSORS_NOT_SUBSAMPLED(...) \
352 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_tensors_not_subsampled(__func__, __FILE__, __LINE__, __VA_ARGS__))
353 #define ARM_COMPUTE_RETURN_ERROR_ON_TENSORS_NOT_SUBSAMPLED(...) \
354 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_tensors_not_subsampled(__func__, __FILE__, __LINE__, __VA_ARGS__))
355
356 /** Return an error if the passed two tensor infos have different shapes from the given dimension
357 *
358 * @param[in] function Function in which the error occurred.
359 * @param[in] file Name of the file where the error occurred.
360 * @param[in] line Line on which the error occurred.
361 * @param[in] tensor_info_1 The first tensor info to be compared.
362 * @param[in] tensor_info_2 The second tensor info to be compared.
363 * @param[in] tensor_infos (Optional) Further allowed tensor infos.
364 *
365 * @return Status
366 */
367 template <typename... Ts>
368 inline arm_compute::Status error_on_mismatching_shapes(const char *function, const char *file, const int line,
369 const ITensorInfo *tensor_info_1, const ITensorInfo *tensor_info_2, Ts... tensor_infos)
370 {
371 return error_on_mismatching_shapes(function, file, line, 0U, tensor_info_1, tensor_info_2, std::forward<Ts>(tensor_infos)...);
372 }
373 /** Return an error if the passed two tensors have different shapes from the given dimension
374 *
375 * @param[in] function Function in which the error occurred.
376 * @param[in] file Name of the file where the error occurred.
377 * @param[in] line Line on which the error occurred.
378 * @param[in] tensor_1 The first tensor to be compared.
379 * @param[in] tensor_2 The second tensor to be compared.
380 * @param[in] tensors (Optional) Further allowed tensors.
381 *
382 * @return Status
383 */
384 template <typename... Ts>
385 inline arm_compute::Status error_on_mismatching_shapes(const char *function, const char *file, const int line,
386 const ITensor *tensor_1, const ITensor *tensor_2, Ts... tensors)
387 {
388 return error_on_mismatching_shapes(function, file, line, 0U, tensor_1, tensor_2, std::forward<Ts>(tensors)...);
389 }
390 /** Return an error if the passed two tensors have different shapes from the given dimension
391 *
392 * @param[in] function Function in which the error occurred.
393 * @param[in] file Name of the file where the error occurred.
394 * @param[in] line Line on which the error occurred.
395 * @param[in] upper_dim The dimension from which to check.
396 * @param[in] tensor_info_1 The first tensor info to be compared.
397 * @param[in] tensor_info_2 The second tensor info to be compared.
398 * @param[in] tensor_infos (Optional) Further allowed tensor infos.
399 *
400 * @return Status
401 */
402 template <typename... Ts>
403 inline arm_compute::Status error_on_mismatching_shapes(const char *function, const char *file, const int line,
404 unsigned int upper_dim, const ITensorInfo *tensor_info_1, const ITensorInfo *tensor_info_2, Ts... tensor_infos)
405 {
406 ARM_COMPUTE_RETURN_ERROR_ON_LOC(tensor_info_1 == nullptr, function, file, line);
407 ARM_COMPUTE_RETURN_ERROR_ON_LOC(tensor_info_2 == nullptr, function, file, line);
408 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_nullptr(function, file, line, std::forward<Ts>(tensor_infos)...));
409
410 const std::array < const ITensorInfo *, 2 + sizeof...(Ts) > tensors_info_array{ { tensor_info_1, tensor_info_2, std::forward<Ts>(tensor_infos)... } };
411 ARM_COMPUTE_RETURN_ERROR_ON_LOC_MSG(std::any_of(std::next(tensors_info_array.cbegin()), tensors_info_array.cend(), [&](const ITensorInfo * tensor_info)
412 {
413 return detail::have_different_dimensions((*tensors_info_array.cbegin())->tensor_shape(), tensor_info->tensor_shape(), upper_dim);
414 }),
415 function, file, line, "Tensors have different shapes");
416 return arm_compute::Status{};
417 }
418 /** Return an error if the passed two tensors have different shapes from the given dimension
419 *
420 * @param[in] function Function in which the error occurred.
421 * @param[in] file Name of the file where the error occurred.
422 * @param[in] line Line on which the error occurred.
423 * @param[in] upper_dim The dimension from which to check.
424 * @param[in] tensor_1 The first tensor to be compared.
425 * @param[in] tensor_2 The second tensor to be compared.
426 * @param[in] tensors (Optional) Further allowed tensors.
427 *
428 * @return Status
429 */
430 template <typename... Ts>
431 inline arm_compute::Status error_on_mismatching_shapes(const char *function, const char *file, const int line,
432 unsigned int upper_dim, const ITensor *tensor_1, const ITensor *tensor_2, Ts... tensors)
433 {
434 ARM_COMPUTE_RETURN_ERROR_ON_LOC(tensor_1 == nullptr, function, file, line);
435 ARM_COMPUTE_RETURN_ERROR_ON_LOC(tensor_2 == nullptr, function, file, line);
436 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_nullptr(function, file, line, std::forward<Ts>(tensors)...));
437 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_mismatching_shapes(function, file, line, upper_dim, tensor_1->info(), tensor_2->info(),
438 detail::get_tensor_info_t<ITensorInfo *>()(tensors)...));
439 return arm_compute::Status{};
440 }
441 #define ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(...) \
442 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_mismatching_shapes(__func__, __FILE__, __LINE__, __VA_ARGS__))
443 #define ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_SHAPES(...) \
444 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_mismatching_shapes(__func__, __FILE__, __LINE__, __VA_ARGS__))
445
446 /** Return an error if the passed tensor infos have different data layouts
447 *
448 * @param[in] function Function in which the error occurred.
449 * @param[in] file Name of the file where the error occurred.
450 * @param[in] line Line on which the error occurred.
451 * @param[in] tensor_info The first tensor info to be compared.
452 * @param[in] tensor_infos (Optional) Further allowed tensor infos.
453 *
454 * @return Status
455 */
456 template <typename... Ts>
457 inline arm_compute::Status error_on_mismatching_data_layouts(const char *function, const char *file, const int line,
458 const ITensorInfo *tensor_info, Ts... tensor_infos)
459 {
460 ARM_COMPUTE_RETURN_ERROR_ON_LOC(tensor_info == nullptr, function, file, line);
461 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_nullptr(function, file, line, std::forward<Ts>(tensor_infos)...));
462
463 DataLayout &&tensor_data_layout = tensor_info->data_layout();
464 const std::array<const ITensorInfo *, sizeof...(Ts)> tensors_infos_array{ { std::forward<Ts>(tensor_infos)... } };
465 ARM_COMPUTE_RETURN_ERROR_ON_LOC_MSG(std::any_of(tensors_infos_array.begin(), tensors_infos_array.end(), [&](const ITensorInfo * tensor_info_obj)
466 {
467 return tensor_info_obj->data_layout() != tensor_data_layout;
468 }),
469 function, file, line, "Tensors have different data layouts");
470 return arm_compute::Status{};
471 }
472 /** Return an error if the passed tensors have different data layouts
473 *
474 * @param[in] function Function in which the error occurred.
475 * @param[in] file Name of the file where the error occurred.
476 * @param[in] line Line on which the error occurred.
477 * @param[in] tensor The first tensor to be compared.
478 * @param[in] tensors (Optional) Further allowed tensors.
479 *
480 * @return Status
481 */
482 template <typename... Ts>
483 inline arm_compute::Status error_on_mismatching_data_layouts(const char *function, const char *file, const int line,
484 const ITensor *tensor, Ts... tensors)
485 {
486 ARM_COMPUTE_RETURN_ERROR_ON_LOC(tensor == nullptr, function, file, line);
487 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_nullptr(function, file, line, std::forward<Ts>(tensors)...));
488 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_mismatching_data_layouts(function, file, line, tensor->info(),
489 detail::get_tensor_info_t<ITensorInfo *>()(tensors)...));
490 return arm_compute::Status{};
491 }
492 #define ARM_COMPUTE_ERROR_ON_MISMATCHING_DATA_LAYOUT(...) \
493 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_mismatching_data_layouts(__func__, __FILE__, __LINE__, __VA_ARGS__))
494 #define ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_LAYOUT(...) \
495 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_mismatching_data_layouts(__func__, __FILE__, __LINE__, __VA_ARGS__))
496
497 /** Return an error if the passed two tensor infos have different data types
498 *
499 * @param[in] function Function in which the error occurred.
500 * @param[in] file Name of the file where the error occurred.
501 * @param[in] line Line on which the error occurred.
502 * @param[in] tensor_info The first tensor info to be compared.
503 * @param[in] tensor_infos (Optional) Further allowed tensor infos.
504 *
505 * @return Status
506 */
507 template <typename... Ts>
508 inline arm_compute::Status error_on_mismatching_data_types(const char *function, const char *file, const int line,
509 const ITensorInfo *tensor_info, Ts... tensor_infos)
510 {
511 ARM_COMPUTE_RETURN_ERROR_ON_LOC(tensor_info == nullptr, function, file, line);
512 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_nullptr(function, file, line, std::forward<Ts>(tensor_infos)...));
513
514 DataType &&tensor_data_type = tensor_info->data_type();
515 const std::array<const ITensorInfo *, sizeof...(Ts)> tensors_infos_array{ { std::forward<Ts>(tensor_infos)... } };
516 ARM_COMPUTE_RETURN_ERROR_ON_LOC_MSG(std::any_of(tensors_infos_array.begin(), tensors_infos_array.end(), [&](const ITensorInfo * tensor_info_obj)
517 {
518 return tensor_info_obj->data_type() != tensor_data_type;
519 }),
520 function, file, line, "Tensors have different data types");
521 return arm_compute::Status{};
522 }
523 /** Return an error if the passed two tensors have different data types
524 *
525 * @param[in] function Function in which the error occurred.
526 * @param[in] file Name of the file where the error occurred.
527 * @param[in] line Line on which the error occurred.
528 * @param[in] tensor The first tensor to be compared.
529 * @param[in] tensors (Optional) Further allowed tensors.
530 *
531 * @return Status
532 */
533 template <typename... Ts>
534 inline arm_compute::Status error_on_mismatching_data_types(const char *function, const char *file, const int line,
535 const ITensor *tensor, Ts... tensors)
536 {
537 ARM_COMPUTE_RETURN_ERROR_ON_LOC(tensor == nullptr, function, file, line);
538 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_nullptr(function, file, line, std::forward<Ts>(tensors)...));
539 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_mismatching_data_types(function, file, line, tensor->info(),
540 detail::get_tensor_info_t<ITensorInfo *>()(tensors)...));
541 return arm_compute::Status{};
542 }
543 #define ARM_COMPUTE_ERROR_ON_MISMATCHING_DATA_TYPES(...) \
544 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_mismatching_data_types(__func__, __FILE__, __LINE__, __VA_ARGS__))
545 #define ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(...) \
546 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_mismatching_data_types(__func__, __FILE__, __LINE__, __VA_ARGS__))
547
548 /** Return an error if the passed tensor infos have different asymmetric quantized data types or different quantization info
549 *
550 * @note: If the first tensor info doesn't have asymmetric quantized data type, the function returns without throwing an error
551 *
552 * @param[in] function Function in which the error occurred.
553 * @param[in] file Name of the file where the error occurred.
554 * @param[in] line Line on which the error occurred.
555 * @param[in] tensor_info_1 The first tensor info to be compared.
556 * @param[in] tensor_info_2 The second tensor info to be compared.
557 * @param[in] tensor_infos (Optional) Further allowed tensor infos.
558 *
559 * @return Status
560 */
561 template <typename... Ts>
562 inline arm_compute::Status error_on_mismatching_quantization_info(const char *function, const char *file, const int line,
563 const ITensorInfo *tensor_info_1, const ITensorInfo *tensor_info_2, Ts... tensor_infos)
564 {
565 DataType &&first_data_type = tensor_info_1->data_type();
566 const QuantizationInfo first_quantization_info = tensor_info_1->quantization_info();
567
568 if(!is_data_type_quantized(first_data_type))
569 {
570 return arm_compute::Status{};
571 }
572
573 const std::array < const ITensorInfo *, 1 + sizeof...(Ts) > tensor_infos_array{ { tensor_info_2, std::forward<Ts>(tensor_infos)... } };
574 ARM_COMPUTE_RETURN_ERROR_ON_LOC_MSG(std::any_of(tensor_infos_array.begin(), tensor_infos_array.end(), [&](const ITensorInfo * tensor_info)
575 {
576 return tensor_info->data_type() != first_data_type;
577 }),
578 function, file, line, "Tensors have different asymmetric quantized data types");
579 ARM_COMPUTE_RETURN_ERROR_ON_LOC_MSG(std::any_of(tensor_infos_array.begin(), tensor_infos_array.end(), [&](const ITensorInfo * tensor_info)
580 {
581 return tensor_info->quantization_info() != first_quantization_info;
582 }),
583 function, file, line, "Tensors have different quantization information");
584
585 return arm_compute::Status{};
586 }
587 /** Return an error if the passed tensor have different asymmetric quantized data types or different quantization info
588 *
589 * @note: If the first tensor doesn't have asymmetric quantized data type, the function returns without throwing an error
590 *
591 * @param[in] function Function in which the error occurred.
592 * @param[in] file Name of the file where the error occurred.
593 * @param[in] line Line on which the error occurred.
594 * @param[in] tensor_1 The first tensor to be compared.
595 * @param[in] tensor_2 The second tensor to be compared.
596 * @param[in] tensors (Optional) Further allowed tensors.
597 *
598 * @return Status
599 */
600 template <typename... Ts>
601 inline arm_compute::Status error_on_mismatching_quantization_info(const char *function, const char *file, const int line,
602 const ITensor *tensor_1, const ITensor *tensor_2, Ts... tensors)
603 {
604 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_mismatching_quantization_info(function, file, line, tensor_1->info(), tensor_2->info(),
605 detail::get_tensor_info_t<ITensorInfo *>()(tensors)...));
606 return arm_compute::Status{};
607 }
608 #define ARM_COMPUTE_ERROR_ON_MISMATCHING_QUANTIZATION_INFO(...) \
609 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_mismatching_quantization_info(__func__, __FILE__, __LINE__, __VA_ARGS__))
610 #define ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_QUANTIZATION_INFO(...) \
611 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_mismatching_quantization_info(__func__, __FILE__, __LINE__, __VA_ARGS__))
612
613 /** Throw an error if the format of the passed tensor/multi-image does not match any of the formats provided.
614 *
615 * @param[in] function Function in which the error occurred.
616 * @param[in] file Name of the file where the error occurred.
617 * @param[in] line Line on which the error occurred.
618 * @param[in] object Tensor/multi-image to validate.
619 * @param[in] format First format allowed.
620 * @param[in] formats (Optional) Further allowed formats.
621 */
622 template <typename T, typename F, typename... Fs>
623 void error_on_format_not_in(const char *function, const char *file, const int line,
624 const T *object, F &&format, Fs &&... formats)
625 {
626 ARM_COMPUTE_ERROR_ON_LOC(object == nullptr, function, file, line);
627
628 Format &&object_format = object->info()->format();
629 ARM_COMPUTE_UNUSED(object_format);
630
631 ARM_COMPUTE_ERROR_ON_LOC(object_format == Format::UNKNOWN, function, file, line);
632
633 const std::array<F, sizeof...(Fs)> formats_array{ { std::forward<Fs>(formats)... } };
634 ARM_COMPUTE_UNUSED(formats_array);
635
636 ARM_COMPUTE_ERROR_ON_LOC_MSG(object_format != format && std::none_of(formats_array.begin(), formats_array.end(), [&](const F & f)
637 {
638 return f == object_format;
639 }),
640 function, file, line, "Format %s not supported by this kernel", string_from_format(object_format).c_str());
641 ARM_COMPUTE_UNUSED(function, format, file, line);
642 }
643 #define ARM_COMPUTE_ERROR_ON_FORMAT_NOT_IN(t, ...) ::arm_compute::error_on_format_not_in(__func__, __FILE__, __LINE__, t, __VA_ARGS__)
644
645 /** Return an error if the data type of the passed tensor info does not match any of the data types provided.
646 *
647 * @param[in] function Function in which the error occurred.
648 * @param[in] file Name of the file where the error occurred.
649 * @param[in] line Line on which the error occurred.
650 * @param[in] tensor_info Tensor info to validate.
651 * @param[in] dt First data type allowed.
652 * @param[in] dts (Optional) Further allowed data types.
653 *
654 * @return Status
655 */
656 template <typename T, typename... Ts>
657 inline arm_compute::Status error_on_data_type_not_in(const char *function, const char *file, const int line,
658 const ITensorInfo *tensor_info, T &&dt, Ts &&... dts)
659 {
660 ARM_COMPUTE_RETURN_ERROR_ON_LOC(tensor_info == nullptr, function, file, line);
661
662 const DataType &tensor_dt = tensor_info->data_type(); //NOLINT
663 ARM_COMPUTE_RETURN_ERROR_ON_LOC(tensor_dt == DataType::UNKNOWN, function, file, line);
664
665 const std::array<T, sizeof...(Ts)> dts_array{ { std::forward<Ts>(dts)... } };
666 ARM_COMPUTE_RETURN_ERROR_ON_LOC_MSG_VAR(tensor_dt != dt && std::none_of(dts_array.begin(), dts_array.end(), [&](const T & d)
667 {
668 return d == tensor_dt;
669 }),
670 function, file, line, "ITensor data type %s not supported by this kernel", string_from_data_type(tensor_dt).c_str());
671 return arm_compute::Status{};
672 }
673 /** Return an error if the data type of the passed tensor does not match any of the data types provided.
674 *
675 * @param[in] function Function in which the error occurred.
676 * @param[in] file Name of the file where the error occurred.
677 * @param[in] line Line on which the error occurred.
678 * @param[in] tensor Tensor to validate.
679 * @param[in] dt First data type allowed.
680 * @param[in] dts (Optional) Further allowed data types.
681 *
682 * @return Status
683 */
684 template <typename T, typename... Ts>
685 inline arm_compute::Status error_on_data_type_not_in(const char *function, const char *file, const int line,
686 const ITensor *tensor, T &&dt, Ts &&... dts)
687 {
688 ARM_COMPUTE_RETURN_ERROR_ON_LOC(tensor == nullptr, function, file, line);
689 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_data_type_not_in(function, file, line, tensor->info(), std::forward<T>(dt), std::forward<Ts>(dts)...));
690 return arm_compute::Status{};
691 }
692 #define ARM_COMPUTE_ERROR_ON_DATA_TYPE_NOT_IN(t, ...) \
693 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_data_type_not_in(__func__, __FILE__, __LINE__, t, __VA_ARGS__))
694 #define ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_NOT_IN(t, ...) \
695 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_data_type_not_in(__func__, __FILE__, __LINE__, t, __VA_ARGS__))
696
697 /** Return an error if the data layout of the passed tensor info does not match any of the data layouts provided.
698 *
699 * @param[in] function Function in which the error occurred.
700 * @param[in] file Name of the file where the error occurred.
701 * @param[in] line Line on which the error occurred.
702 * @param[in] tensor_info Tensor info to validate.
703 * @param[in] dl First data layout allowed.
704 * @param[in] dls (Optional) Further allowed data layouts.
705 *
706 * @return Status
707 */
708 template <typename T, typename... Ts>
709 inline arm_compute::Status error_on_data_layout_not_in(const char *function, const char *file, const int line,
710 const ITensorInfo *tensor_info, T &&dl, Ts &&... dls)
711 {
712 ARM_COMPUTE_RETURN_ERROR_ON_LOC(tensor_info == nullptr, function, file, line);
713
714 const DataLayout &tensor_dl = tensor_info->data_layout(); //NOLINT
715 ARM_COMPUTE_RETURN_ERROR_ON_LOC(tensor_dl == DataLayout::UNKNOWN, function, file, line);
716
717 const std::array<T, sizeof...(Ts)> dls_array{ { std::forward<Ts>(dls)... } };
718 ARM_COMPUTE_RETURN_ERROR_ON_LOC_MSG_VAR(tensor_dl != dl && std::none_of(dls_array.begin(), dls_array.end(), [&](const T & l)
719 {
720 return l == tensor_dl;
721 }),
722 function, file, line, "ITensor data layout %s not supported by this kernel", string_from_data_layout(tensor_dl).c_str());
723 return arm_compute::Status{};
724 }
725 /** Return an error if the data layout of the passed tensor does not match any of the data layout provided.
726 *
727 * @param[in] function Function in which the error occurred.
728 * @param[in] file Name of the file where the error occurred.
729 * @param[in] line Line on which the error occurred.
730 * @param[in] tensor Tensor to validate.
731 * @param[in] dl First data layout allowed.
732 * @param[in] dls (Optional) Further allowed data layouts.
733 *
734 * @return Status
735 */
736 template <typename T, typename... Ts>
737 inline arm_compute::Status error_on_data_layout_not_in(const char *function, const char *file, const int line,
738 const ITensor *tensor, T &&dl, Ts &&... dls)
739 {
740 ARM_COMPUTE_RETURN_ERROR_ON_LOC(tensor == nullptr, function, file, line);
741 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_data_layout_not_in(function, file, line, tensor->info(), std::forward<T>(dl), std::forward<Ts>(dls)...));
742 return arm_compute::Status{};
743 }
744 #define ARM_COMPUTE_ERROR_ON_DATA_LAYOUT_NOT_IN(t, ...) \
745 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_data_layout_not_in(__func__, __FILE__, __LINE__, t, __VA_ARGS__))
746 #define ARM_COMPUTE_RETURN_ERROR_ON_DATA_LAYOUT_NOT_IN(t, ...) \
747 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_data_layout_not_in(__func__, __FILE__, __LINE__, t, __VA_ARGS__))
748
749 /** Return an error if the data type or the number of channels of the passed tensor info does not match any of the data types and number of channels provided.
750 *
751 * @param[in] function Function in which the error occurred.
752 * @param[in] file Name of the file where the error occurred.
753 * @param[in] line Line on which the error occurred.
754 * @param[in] tensor_info Tensor info to validate.
755 * @param[in] num_channels Number of channels to check
756 * @param[in] dt First data type allowed.
757 * @param[in] dts (Optional) Further allowed data types.
758 *
759 * @return Status
760 */
761 template <typename T, typename... Ts>
762 inline arm_compute::Status error_on_data_type_channel_not_in(const char *function, const char *file, const int line,
763 const ITensorInfo *tensor_info, size_t num_channels, T &&dt, Ts &&... dts)
764 {
765 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_data_type_not_in(function, file, line, tensor_info, std::forward<T>(dt), std::forward<Ts>(dts)...));
766 const size_t tensor_nc = tensor_info->num_channels();
767 ARM_COMPUTE_RETURN_ERROR_ON_LOC_MSG_VAR(tensor_nc != num_channels, function, file, line, "Number of channels %zu. Required number of channels %zu", tensor_nc, num_channels);
768 return arm_compute::Status{};
769 }
770 /** Return an error if the data type or the number of channels of the passed tensor does not match any of the data types and number of channels provided.
771 *
772 * @param[in] function Function in which the error occurred.
773 * @param[in] file Name of the file where the error occurred.
774 * @param[in] line Line on which the error occurred.
775 * @param[in] tensor Tensor to validate.
776 * @param[in] num_channels Number of channels to check
777 * @param[in] dt First data type allowed.
778 * @param[in] dts (Optional) Further allowed data types.
779 *
780 * @return Status
781 */
782 template <typename T, typename... Ts>
783 inline arm_compute::Status error_on_data_type_channel_not_in(const char *function, const char *file, const int line,
784 const ITensor *tensor, size_t num_channels, T &&dt, Ts &&... dts)
785 {
786 ARM_COMPUTE_RETURN_ERROR_ON_LOC(tensor == nullptr, function, file, line);
787 ARM_COMPUTE_RETURN_ON_ERROR(error_on_data_type_channel_not_in(function, file, line, tensor->info(), num_channels, std::forward<T>(dt), std::forward<Ts>(dts)...));
788 return arm_compute::Status{};
789 }
790 #define ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(t, c, ...) \
791 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_data_type_channel_not_in(__func__, __FILE__, __LINE__, t, c, __VA_ARGS__))
792 #define ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(t, c, ...) \
793 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_data_type_channel_not_in(__func__, __FILE__, __LINE__, t, c, __VA_ARGS__))
794
795 /** Return an error if the data type of the passed tensor info is FP16 and FP16 extension is not supported by the device.
796 *
797 * @param[in] function Function in which the error occurred.
798 * @param[in] file Name of the file where the error occurred.
799 * @param[in] line Line on which the error occurred.
800 * @param[in] tensor_info Tensor info to validate.
801 * @param[in] is_fp16_supported Is fp16 supported by the device.
802 *
803 * @return Status
804 */
805 inline arm_compute::Status error_on_unsupported_fp16(const char *function, const char *file, const int line,
806 const ITensorInfo *tensor_info, bool is_fp16_supported)
807 {
808 ARM_COMPUTE_RETURN_ERROR_ON_LOC(tensor_info == nullptr, function, file, line);
809 ARM_COMPUTE_RETURN_ERROR_ON_LOC_MSG((tensor_info->data_type() == DataType::F16 && !is_fp16_supported),
810 function, file, line, "FP16 not supported by the device");
811 return arm_compute::Status{};
812 }
813
814 /** Return an error if the data type of the passed tensor is FP16 and FP16 extension is not supported by the device.
815 *
816 * @param[in] function Function in which the error occurred.
817 * @param[in] file Name of the file where the error occurred.
818 * @param[in] line Line on which the error occurred.
819 * @param[in] tensor Tensor to validate.
820 * @param[in] is_fp16_supported Is fp16 supported by the device.
821 *
822 * @return Status
823 */
824 inline arm_compute::Status error_on_unsupported_fp16(const char *function, const char *file, const int line,
825 const ITensor *tensor, bool is_fp16_supported)
826 {
827 ARM_COMPUTE_RETURN_ERROR_ON_LOC(tensor == nullptr, function, file, line);
828 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_unsupported_fp16(function, file, line, tensor->info(), is_fp16_supported));
829 return arm_compute::Status{};
830 }
831
832 /** Return an error if the tensor is not 2D.
833 *
834 * @param[in] function Function in which the error occurred.
835 * @param[in] file Name of the file where the error occurred.
836 * @param[in] line Line on which the error occurred.
837 * @param[in] tensor Tensor to validate.
838 *
839 * @return Status
840 */
841 arm_compute::Status error_on_tensor_not_2d(const char *function, const char *file, const int line,
842 const ITensor *tensor);
843
844 /** Return an error if the tensor info is not 2D.
845 *
846 * @param[in] function Function in which the error occurred.
847 * @param[in] file Name of the file where the error occurred.
848 * @param[in] line Line on which the error occurred.
849 * @param[in] tensor Tensor info to validate.
850 *
851 * @return Status
852 */
853 arm_compute::Status error_on_tensor_not_2d(const char *function, const char *file, const int line,
854 const ITensorInfo *tensor);
855
856 #define ARM_COMPUTE_ERROR_ON_TENSOR_NOT_2D(t) \
857 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_tensor_not_2d(__func__, __FILE__, __LINE__, t))
858 #define ARM_COMPUTE_RETURN_ERROR_ON_TENSOR_NOT_2D(t) \
859 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_tensor_not_2d(__func__, __FILE__, __LINE__, t))
860
861 /** Return an error if the channel is not in channels.
862 *
863 * @param[in] function Function in which the error occurred.
864 * @param[in] file Name of the file where the error occurred.
865 * @param[in] line Line on which the error occurred.
866 * @param[in] cn Input channel
867 * @param[in] channel First channel allowed.
868 * @param[in] channels (Optional) Further allowed channels.
869 *
870 * @return Status
871 */
872 template <typename T, typename... Ts>
873 inline arm_compute::Status error_on_channel_not_in(const char *function, const char *file, const int line,
874 T cn, T &&channel, Ts &&... channels)
875 {
876 ARM_COMPUTE_RETURN_ERROR_ON_LOC(cn == Channel::UNKNOWN, function, file, line);
877
878 const std::array<T, sizeof...(Ts)> channels_array{ { std::forward<Ts>(channels)... } };
879 ARM_COMPUTE_RETURN_ERROR_ON_LOC(channel != cn && std::none_of(channels_array.begin(), channels_array.end(), [&](const T & f)
880 {
881 return f == cn;
882 }),
883 function, file, line);
884 return arm_compute::Status{};
885 }
886 #define ARM_COMPUTE_ERROR_ON_CHANNEL_NOT_IN(c, ...) \
887 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_channel_not_in(__func__, __FILE__, __LINE__, c, __VA_ARGS__))
888 #define ARM_COMPUTE_RETURN_ERROR_ON_CHANNEL_NOT_IN(c, ...) \
889 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_channel_not_in(__func__, __FILE__, __LINE__, c, __VA_ARGS__))
890
891 /** Return an error if the channel is not in format.
892 *
893 * @param[in] function Function in which the error occurred.
894 * @param[in] file Name of the file where the error occurred.
895 * @param[in] line Line on which the error occurred.
896 * @param[in] fmt Input channel
897 * @param[in] cn First channel allowed.
898 *
899 * @return Status
900 */
901 arm_compute::Status error_on_channel_not_in_known_format(const char *function, const char *file, const int line,
902 Format fmt, Channel cn);
903 #define ARM_COMPUTE_ERROR_ON_CHANNEL_NOT_IN_KNOWN_FORMAT(f, c) \
904 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_channel_not_in_known_format(__func__, __FILE__, __LINE__, f, c))
905 #define ARM_COMPUTE_RETURN_ERROR_ON_CHANNEL_NOT_IN_KNOWN_FORMAT(f, c) \
906 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_channel_not_in_known_format(__func__, __FILE__, __LINE__, f, c))
907
908 /** Return an error if the @ref IMultiHOG container is invalid
909 *
910 * An @ref IMultiHOG container is invalid if:
911 *
912 * -# it is a nullptr
913 * -# it doesn't contain models
914 * -# it doesn't have the HOG data objects with the same phase_type, normalization_type and l2_hyst_threshold (if normalization_type == L2HYS_NORM)
915 *
916 * @param[in] function Function in which the error occurred.
917 * @param[in] file Name of the file where the error occurred.
918 * @param[in] line Line on which the error occurred.
919 * @param[in] multi_hog IMultiHOG container to validate
920 *
921 * @return Status
922 */
923 arm_compute::Status error_on_invalid_multi_hog(const char *function, const char *file, const int line,
924 const IMultiHOG *multi_hog);
925 #define ARM_COMPUTE_ERROR_ON_INVALID_MULTI_HOG(m) \
926 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_invalid_multi_hog(__func__, __FILE__, __LINE__, m))
927 #define ARM_COMPUTE_RETURN_ERROR_ON_INVALID_MULTI_HOG(m) \
928 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_invalid_multi_hog(__func__, __FILE__, __LINE__, m))
929
930 /** Return an error if the kernel is not configured.
931 *
932 * @param[in] function Function in which the error occurred.
933 * @param[in] file Name of the file where the error occurred.
934 * @param[in] line Line on which the error occurred.
935 * @param[in] kernel Kernel to validate.
936 *
937 * @return Status
938 */
939 arm_compute::Status error_on_unconfigured_kernel(const char *function, const char *file, const int line,
940 const IKernel *kernel);
941 #define ARM_COMPUTE_ERROR_ON_UNCONFIGURED_KERNEL(k) \
942 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_unconfigured_kernel(__func__, __FILE__, __LINE__, k))
943 #define ARM_COMPUTE_RETURN_ERROR_ON_UNCONFIGURED_KERNEL(k) \
944 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_unconfigured_kernel(__func__, __FILE__, __LINE__, k))
945
946 /** Return an error if if the coordinates and shape of the subtensor are within the parent tensor.
947 *
948 * @param[in] function Function in which the error occurred.
949 * @param[in] file Name of the file where the error occurred.
950 * @param[in] line Line on which the error occurred.
951 * @param[in] parent_shape Parent tensor shape
952 * @param[in] coords Coordinates inside the parent tensor where the first element of the subtensor is
953 * @param[in] shape Shape of the subtensor
954 *
955 * @return Status
956 */
957 arm_compute::Status error_on_invalid_subtensor(const char *function, const char *file, const int line,
958 const TensorShape &parent_shape, const Coordinates &coords, const TensorShape &shape);
959 #define ARM_COMPUTE_ERROR_ON_INVALID_SUBTENSOR(p, c, s) \
960 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_invalid_subtensor(__func__, __FILE__, __LINE__, p, c, s))
961 #define ARM_COMPUTE_RETURN_ERROR_ON_INVALID_SUBTENSOR(p, c, s) \
962 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_invalid_subtensor(__func__, __FILE__, __LINE__, p, c, s))
963
964 /** Return an error if the valid region of a subtensor is not inside the valid region of the parent tensor.
965 *
966 * @param[in] function Function in which the error occurred.
967 * @param[in] file Name of the file where the error occurred.
968 * @param[in] line Line on which the error occurred.
969 * @param[in] parent_valid_region Parent valid region.
970 * @param[in] valid_region Valid region of subtensor.
971 *
972 * @return Status
973 */
974 arm_compute::Status error_on_invalid_subtensor_valid_region(const char *function, const char *file, const int line,
975 const ValidRegion &parent_valid_region, const ValidRegion &valid_region);
976 #define ARM_COMPUTE_ERROR_ON_INVALID_SUBTENSOR_VALID_REGION(pv, sv) \
977 ARM_COMPUTE_ERROR_THROW_ON(::arm_compute::error_on_invalid_subtensor_valid_region(__func__, __FILE__, __LINE__, pv, sv))
978 #define ARM_COMPUTE_RETURN_ERROR_ON_INVALID_SUBTENSOR_VALID_REGION(pv, sv) \
979 ARM_COMPUTE_RETURN_ON_ERROR(::arm_compute::error_on_invalid_subtensor_valid_region(__func__, __FILE__, __LINE__, pv, sv))
980 }
981 #endif /* ARM_COMPUTE_VALIDATE_H*/
982