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