• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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