blob: 3939491bb261bbc0fc92e02200c84734f3f43ae2 [file] [log] [blame]
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001/*
Michalis Spyrouf63885b2019-01-16 14:18:09 +00002 * Copyright (c) 2016-2019 ARM Limited.
Anthony Barbier6ff3b192017-09-04 18:44:23 +01003 *
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_UTILS_H__
25#define __ARM_COMPUTE_UTILS_H__
26
27#include "arm_compute/core/Error.h"
Giuseppe Rossinid7647d42018-07-17 18:13:13 +010028#include "arm_compute/core/PixelValue.h"
Michel Iwaniec5dfeae62017-11-29 10:48:23 +000029#include "arm_compute/core/Rounding.h"
Anthony Barbier6ff3b192017-09-04 18:44:23 +010030#include "arm_compute/core/Types.h"
31
32#include <algorithm>
33#include <cstdint>
34#include <cstdlib>
Michalis Spyrou53860dd2019-07-01 14:20:56 +010035#include <iomanip>
Anthony Barbier6ff3b192017-09-04 18:44:23 +010036#include <numeric>
37#include <sstream>
38#include <string>
39#include <type_traits>
40#include <utility>
steniu017ce53c62017-09-29 14:55:00 +010041#include <vector>
Anthony Barbier6ff3b192017-09-04 18:44:23 +010042
43namespace arm_compute
44{
Alex Gildayc357c472018-03-21 13:54:09 +000045/** Calculate the rounded up quotient of val / m.
46 *
47 * @param[in] val Value to divide and round up.
48 * @param[in] m Value to divide by.
49 *
50 * @return the result.
51 */
Diego Lopez Recas35ceeb22017-12-04 18:56:10 +000052template <typename S, typename T>
53constexpr auto DIV_CEIL(S val, T m) -> decltype((val + m - 1) / m)
54{
55 return (val + m - 1) / m;
56}
57
Alex Gildayc357c472018-03-21 13:54:09 +000058/** Computes the smallest number larger or equal to value that is a multiple of divisor.
59 *
60 * @param[in] value Lower bound value
61 * @param[in] divisor Value to compute multiple of.
62 *
63 * @return the result.
64 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +010065template <typename S, typename T>
66inline auto ceil_to_multiple(S value, T divisor) -> decltype(((value + divisor - 1) / divisor) * divisor)
67{
68 ARM_COMPUTE_ERROR_ON(value < 0 || divisor <= 0);
Diego Lopez Recas35ceeb22017-12-04 18:56:10 +000069 return DIV_CEIL(value, divisor) * divisor;
Anthony Barbier6ff3b192017-09-04 18:44:23 +010070}
71
Alex Gildayc357c472018-03-21 13:54:09 +000072/** Computes the largest number smaller or equal to value that is a multiple of divisor.
73 *
74 * @param[in] value Upper bound value
75 * @param[in] divisor Value to compute multiple of.
76 *
77 * @return the result.
78 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +010079template <typename S, typename T>
80inline auto floor_to_multiple(S value, T divisor) -> decltype((value / divisor) * divisor)
81{
82 ARM_COMPUTE_ERROR_ON(value < 0 || divisor <= 0);
83 return (value / divisor) * divisor;
84}
85
Anthony Barbier6ff3b192017-09-04 18:44:23 +010086/** Returns the arm_compute library build information
87 *
88 * Contains the version number and the build options used to build the library
89 *
90 * @return The arm_compute library build information
91 */
92std::string build_information();
93
94/** Load an entire file in memory
95 *
96 * @param[in] filename Name of the file to read.
97 * @param[in] binary Is it a binary file ?
98 *
99 * @return The content of the file.
100 */
101std::string read_file(const std::string &filename, bool binary);
102
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100103/** The size in bytes of the data type
104 *
105 * @param[in] data_type Input data type
106 *
107 * @return The size in bytes of the data type
108 */
109inline size_t data_size_from_type(DataType data_type)
110{
111 switch(data_type)
112 {
113 case DataType::U8:
114 case DataType::S8:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100115 case DataType::QSYMM8:
Michel Iwaniec00633802017-10-12 14:14:15 +0100116 case DataType::QASYMM8:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100117 case DataType::QSYMM8_PER_CHANNEL:
Michalis Spyrouc8530212019-08-22 11:44:04 +0100118 case DataType::QASYMM8_PER_CHANNEL:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100119 return 1;
120 case DataType::U16:
121 case DataType::S16:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100122 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100123 case DataType::QASYMM16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100124 case DataType::F16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100125 return 2;
126 case DataType::F32:
127 case DataType::U32:
128 case DataType::S32:
129 return 4;
130 case DataType::F64:
131 case DataType::U64:
132 case DataType::S64:
133 return 8;
134 case DataType::SIZET:
135 return sizeof(size_t);
136 default:
137 ARM_COMPUTE_ERROR("Invalid data type");
138 return 0;
139 }
140}
141
142/** The size in bytes of the pixel format
143 *
144 * @param[in] format Input format
145 *
146 * @return The size in bytes of the pixel format
147 */
148inline size_t pixel_size_from_format(Format format)
149{
150 switch(format)
151 {
152 case Format::U8:
153 return 1;
154 case Format::U16:
155 case Format::S16:
156 case Format::F16:
157 case Format::UV88:
158 case Format::YUYV422:
159 case Format::UYVY422:
160 return 2;
161 case Format::RGB888:
162 return 3;
163 case Format::RGBA8888:
164 return 4;
165 case Format::U32:
166 case Format::S32:
167 case Format::F32:
168 return 4;
169 //Doesn't make sense for planar formats:
170 case Format::NV12:
171 case Format::NV21:
172 case Format::IYUV:
173 case Format::YUV444:
174 default:
175 ARM_COMPUTE_ERROR("Undefined pixel size for given format");
176 return 0;
177 }
178}
179
180/** The size in bytes of the data type
181 *
182 * @param[in] dt Input data type
183 *
184 * @return The size in bytes of the data type
185 */
186inline size_t element_size_from_data_type(DataType dt)
187{
188 switch(dt)
189 {
190 case DataType::S8:
191 case DataType::U8:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100192 case DataType::QSYMM8:
Michel Iwaniec00633802017-10-12 14:14:15 +0100193 case DataType::QASYMM8:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100194 case DataType::QSYMM8_PER_CHANNEL:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100195 return 1;
196 case DataType::U16:
197 case DataType::S16:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100198 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100199 case DataType::QASYMM16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100200 case DataType::F16:
201 return 2;
202 case DataType::U32:
203 case DataType::S32:
204 case DataType::F32:
205 return 4;
206 default:
207 ARM_COMPUTE_ERROR("Undefined element size for given data type");
208 return 0;
209 }
210}
211
212/** Return the data type used by a given single-planar pixel format
213 *
214 * @param[in] format Input format
215 *
216 * @return The size in bytes of the pixel format
217 */
218inline DataType data_type_from_format(Format format)
219{
220 switch(format)
221 {
222 case Format::U8:
223 case Format::UV88:
224 case Format::RGB888:
225 case Format::RGBA8888:
226 case Format::YUYV422:
227 case Format::UYVY422:
228 return DataType::U8;
229 case Format::U16:
230 return DataType::U16;
231 case Format::S16:
232 return DataType::S16;
233 case Format::U32:
234 return DataType::U32;
235 case Format::S32:
236 return DataType::S32;
237 case Format::F16:
238 return DataType::F16;
239 case Format::F32:
240 return DataType::F32;
241 //Doesn't make sense for planar formats:
242 case Format::NV12:
243 case Format::NV21:
244 case Format::IYUV:
245 case Format::YUV444:
246 default:
247 ARM_COMPUTE_ERROR("Not supported data_type for given format");
248 return DataType::UNKNOWN;
249 }
250}
251
252/** Return the plane index of a given channel given an input format.
253 *
254 * @param[in] format Input format
255 * @param[in] channel Input channel
256 *
257 * @return The plane index of the specific channel of the specific format
258 */
259inline int plane_idx_from_channel(Format format, Channel channel)
260{
261 switch(format)
262 {
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100263 // Single planar formats have a single plane
264 case Format::U8:
265 case Format::U16:
266 case Format::S16:
267 case Format::U32:
268 case Format::S32:
269 case Format::F16:
270 case Format::F32:
271 case Format::UV88:
272 case Format::RGB888:
273 case Format::RGBA8888:
274 case Format::YUYV422:
275 case Format::UYVY422:
276 return 0;
277 // Multi planar formats
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100278 case Format::NV12:
279 case Format::NV21:
280 {
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100281 // Channel U and V share the same plane of format UV88
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100282 switch(channel)
283 {
284 case Channel::Y:
285 return 0;
286 case Channel::U:
287 case Channel::V:
288 return 1;
289 default:
290 ARM_COMPUTE_ERROR("Not supported channel");
291 return 0;
292 }
293 }
294 case Format::IYUV:
295 case Format::YUV444:
296 {
297 switch(channel)
298 {
299 case Channel::Y:
300 return 0;
301 case Channel::U:
302 return 1;
303 case Channel::V:
304 return 2;
305 default:
306 ARM_COMPUTE_ERROR("Not supported channel");
307 return 0;
308 }
309 }
310 default:
311 ARM_COMPUTE_ERROR("Not supported format");
312 return 0;
313 }
314}
315
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100316/** Return the channel index of a given channel given an input format.
317 *
318 * @param[in] format Input format
319 * @param[in] channel Input channel
320 *
321 * @return The channel index of the specific channel of the specific format
322 */
323inline int channel_idx_from_format(Format format, Channel channel)
324{
325 switch(format)
326 {
327 case Format::RGB888:
328 {
329 switch(channel)
330 {
331 case Channel::R:
332 return 0;
333 case Channel::G:
334 return 1;
335 case Channel::B:
336 return 2;
337 default:
338 ARM_COMPUTE_ERROR("Not supported channel");
339 return 0;
340 }
341 }
342 case Format::RGBA8888:
343 {
344 switch(channel)
345 {
346 case Channel::R:
347 return 0;
348 case Channel::G:
349 return 1;
350 case Channel::B:
351 return 2;
352 case Channel::A:
353 return 3;
354 default:
355 ARM_COMPUTE_ERROR("Not supported channel");
356 return 0;
357 }
358 }
359 case Format::YUYV422:
360 {
361 switch(channel)
362 {
363 case Channel::Y:
364 return 0;
365 case Channel::U:
366 return 1;
367 case Channel::V:
368 return 3;
369 default:
370 ARM_COMPUTE_ERROR("Not supported channel");
371 return 0;
372 }
373 }
374 case Format::UYVY422:
375 {
376 switch(channel)
377 {
378 case Channel::Y:
379 return 1;
380 case Channel::U:
381 return 0;
382 case Channel::V:
383 return 2;
384 default:
385 ARM_COMPUTE_ERROR("Not supported channel");
386 return 0;
387 }
388 }
389 case Format::NV12:
390 {
391 switch(channel)
392 {
393 case Channel::Y:
394 return 0;
395 case Channel::U:
396 return 0;
397 case Channel::V:
398 return 1;
399 default:
400 ARM_COMPUTE_ERROR("Not supported channel");
401 return 0;
402 }
403 }
404 case Format::NV21:
405 {
406 switch(channel)
407 {
408 case Channel::Y:
409 return 0;
410 case Channel::U:
411 return 1;
412 case Channel::V:
413 return 0;
414 default:
415 ARM_COMPUTE_ERROR("Not supported channel");
416 return 0;
417 }
418 }
419 case Format::YUV444:
420 case Format::IYUV:
421 {
422 switch(channel)
423 {
424 case Channel::Y:
425 return 0;
426 case Channel::U:
427 return 0;
428 case Channel::V:
429 return 0;
430 default:
431 ARM_COMPUTE_ERROR("Not supported channel");
432 return 0;
433 }
434 }
435 default:
436 ARM_COMPUTE_ERROR("Not supported format");
437 return 0;
438 }
439}
440
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100441/** Return the number of planes for a given format
442 *
443 * @param[in] format Input format
444 *
445 * @return The number of planes for a given image format.
446 */
447inline size_t num_planes_from_format(Format format)
448{
449 switch(format)
450 {
451 case Format::U8:
452 case Format::S16:
453 case Format::U16:
454 case Format::S32:
455 case Format::U32:
456 case Format::F16:
457 case Format::F32:
458 case Format::RGB888:
459 case Format::RGBA8888:
460 case Format::YUYV422:
461 case Format::UYVY422:
462 return 1;
463 case Format::NV12:
464 case Format::NV21:
465 return 2;
466 case Format::IYUV:
467 case Format::YUV444:
468 return 3;
469 default:
470 ARM_COMPUTE_ERROR("Not supported format");
471 return 0;
472 }
473}
474
475/** Return the number of channels for a given single-planar pixel format
476 *
477 * @param[in] format Input format
478 *
479 * @return The number of channels for a given image format.
480 */
481inline size_t num_channels_from_format(Format format)
482{
483 switch(format)
484 {
485 case Format::U8:
486 case Format::U16:
487 case Format::S16:
488 case Format::U32:
489 case Format::S32:
490 case Format::F16:
491 case Format::F32:
492 return 1;
493 // Because the U and V channels are subsampled
494 // these formats appear like having only 2 channels:
495 case Format::YUYV422:
496 case Format::UYVY422:
497 return 2;
498 case Format::UV88:
499 return 2;
500 case Format::RGB888:
501 return 3;
502 case Format::RGBA8888:
503 return 4;
504 //Doesn't make sense for planar formats:
505 case Format::NV12:
506 case Format::NV21:
507 case Format::IYUV:
508 case Format::YUV444:
509 default:
510 return 0;
511 }
512}
513
Chunosovd621bca2017-11-03 17:33:15 +0700514/** Return the promoted data type of a given data type.
515 *
516 * @note If promoted data type is not supported an error will be thrown
517 *
518 * @param[in] dt Data type to get the promoted type of.
519 *
520 * @return Promoted data type
521 */
522inline DataType get_promoted_data_type(DataType dt)
523{
524 switch(dt)
525 {
526 case DataType::U8:
527 return DataType::U16;
528 case DataType::S8:
529 return DataType::S16;
Chunosovd621bca2017-11-03 17:33:15 +0700530 case DataType::U16:
531 return DataType::U32;
532 case DataType::S16:
533 return DataType::S32;
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100534 case DataType::QSYMM8:
Chunosovd621bca2017-11-03 17:33:15 +0700535 case DataType::QASYMM8:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100536 case DataType::QSYMM8_PER_CHANNEL:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100537 case DataType::QASYMM8_PER_CHANNEL:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100538 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100539 case DataType::QASYMM16:
Chunosovd621bca2017-11-03 17:33:15 +0700540 case DataType::F16:
541 case DataType::U32:
542 case DataType::S32:
543 case DataType::F32:
Chunosovd621bca2017-11-03 17:33:15 +0700544 ARM_COMPUTE_ERROR("Unsupported data type promotions!");
545 default:
546 ARM_COMPUTE_ERROR("Undefined data type!");
547 }
548 return DataType::UNKNOWN;
549}
550
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100551/** Return true if the given format has horizontal subsampling.
552 *
553 * @param[in] format Format to determine subsampling.
554 *
555 * @return True if the format can be subsampled horizontaly.
556 */
557inline bool has_format_horizontal_subsampling(Format format)
558{
559 return (format == Format::YUYV422 || format == Format::UYVY422 || format == Format::NV12 || format == Format::NV21 || format == Format::IYUV || format == Format::UV88) ? true : false;
560}
561
562/** Return true if the given format has vertical subsampling.
563 *
564 * @param[in] format Format to determine subsampling.
565 *
566 * @return True if the format can be subsampled verticaly.
567 */
568inline bool has_format_vertical_subsampling(Format format)
569{
570 return (format == Format::NV12 || format == Format::NV21 || format == Format::IYUV || format == Format::UV88) ? true : false;
571}
572
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100573/** Separate a 2D convolution into two 1D convolutions
Anthony Barbierf202e502017-11-23 18:02:04 +0000574 *
575 * @param[in] conv 2D convolution
576 * @param[out] conv_col 1D vertical convolution
577 * @param[out] conv_row 1D horizontal convolution
578 * @param[in] size Size of the 2D convolution
579 *
580 * @return true if the separation was successful
581 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100582inline bool separate_matrix(const int16_t *conv, int16_t *conv_col, int16_t *conv_row, uint8_t size)
583{
584 int32_t min_col = -1;
585 int16_t min_col_val = -1;
586
587 for(int32_t i = 0; i < size; ++i)
588 {
589 if(conv[i] != 0 && (min_col < 0 || abs(min_col_val) > abs(conv[i])))
590 {
591 min_col = i;
592 min_col_val = conv[i];
593 }
594 }
595
596 if(min_col < 0)
597 {
598 return false;
599 }
600
601 for(uint32_t j = 0; j < size; ++j)
602 {
603 conv_col[j] = conv[min_col + j * size];
604 }
605
606 for(uint32_t i = 0; i < size; i++)
607 {
608 if(static_cast<int>(i) == min_col)
609 {
610 conv_row[i] = 1;
611 }
612 else
613 {
614 int16_t coeff = conv[i] / conv[min_col];
615
616 for(uint32_t j = 1; j < size; ++j)
617 {
618 if(conv[i + j * size] != (conv_col[j] * coeff))
619 {
620 return false;
621 }
622 }
623
624 conv_row[i] = coeff;
625 }
626 }
627
628 return true;
629}
630
631/** Calculate the scale of the given square matrix
632 *
633 * The scale is the absolute value of the sum of all the coefficients in the matrix.
634 *
635 * @note If the coefficients add up to 0 then the scale is set to 1.
636 *
637 * @param[in] matrix Matrix coefficients
638 * @param[in] matrix_size Number of elements per side of the square matrix. (Number of coefficients = matrix_size * matrix_size).
639 *
640 * @return The absolute value of the sum of the coefficients if they don't add up to 0, otherwise 1.
641 */
642inline uint32_t calculate_matrix_scale(const int16_t *matrix, unsigned int matrix_size)
643{
644 const size_t size = matrix_size * matrix_size;
645
646 return std::max(1, std::abs(std::accumulate(matrix, matrix + size, 0)));
647}
648
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100649/** Adjust tensor shape size if width or height are odd for a given multi-planar format. No modification is done for other formats.
650 *
651 * @note Adding here a few links discussing the issue of odd size and sharing the same solution:
Manuel Bottini581c8982019-02-07 10:31:57 +0000652 * <a href="https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/graphics/java/android/graphics/YuvImage.java">Android Source</a>
653 * <a href="https://groups.google.com/a/webmproject.org/forum/#!topic/webm-discuss/LaCKpqiDTXM">WebM</a>
654 * <a href="https://bugs.chromium.org/p/libyuv/issues/detail?id=198&amp;can=1&amp;q=odd%20width">libYUV</a>
655 * <a href="https://sourceforge.net/p/raw-yuvplayer/bugs/1/">YUVPlayer</a> *
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100656 *
657 * @param[in, out] shape Tensor shape of 2D size
658 * @param[in] format Format of the tensor
659 *
Alex Gildayc357c472018-03-21 13:54:09 +0000660 * @return The adjusted tensor shape.
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100661 */
662inline TensorShape adjust_odd_shape(const TensorShape &shape, Format format)
663{
664 TensorShape output{ shape };
665
666 // Force width to be even for formats which require subsampling of the U and V channels
667 if(has_format_horizontal_subsampling(format))
668 {
669 output.set(0, output.x() & ~1U);
670 }
671
672 // Force height to be even for formats which require subsampling of the U and V channels
673 if(has_format_vertical_subsampling(format))
674 {
675 output.set(1, output.y() & ~1U);
676 }
677
678 return output;
679}
680
681/** Calculate subsampled shape for a given format and channel
682 *
683 * @param[in] shape Shape of the tensor to calculate the extracted channel.
684 * @param[in] format Format of the tensor.
685 * @param[in] channel Channel to create tensor shape to be extracted.
686 *
687 * @return The subsampled tensor shape.
688 */
689inline TensorShape calculate_subsampled_shape(const TensorShape &shape, Format format, Channel channel = Channel::UNKNOWN)
690{
691 TensorShape output{ shape };
692
693 // Subsample shape only for U or V channel
694 if(Channel::U == channel || Channel::V == channel || Channel::UNKNOWN == channel)
695 {
696 // Subsample width for the tensor shape when channel is U or V
697 if(has_format_horizontal_subsampling(format))
698 {
699 output.set(0, output.x() / 2U);
700 }
701
702 // Subsample height for the tensor shape when channel is U or V
703 if(has_format_vertical_subsampling(format))
704 {
705 output.set(1, output.y() / 2U);
706 }
707 }
708
709 return output;
710}
711
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100712/** Calculate accurary required by the horizontal and vertical convolution computations
713 *
714 * @param[in] conv_col Pointer to the vertical vector of the separated convolution filter
715 * @param[in] conv_row Pointer to the horizontal vector of the convolution filter
716 * @param[in] size Number of elements per vector of the separated matrix
717 *
718 * @return The return type is a pair. The first element of the pair is the biggest data type needed for the first stage. The second
719 * element of the pair is the biggest data type needed for the second stage.
720 */
721inline std::pair<DataType, DataType> data_type_for_convolution(const int16_t *conv_col, const int16_t *conv_row, size_t size)
722{
723 DataType first_stage = DataType::UNKNOWN;
724 DataType second_stage = DataType::UNKNOWN;
725
726 auto gez = [](const int16_t &v)
727 {
728 return v >= 0;
729 };
730
731 auto accu_neg = [](const int &first, const int &second)
732 {
733 return first + (second < 0 ? second : 0);
734 };
735
736 auto accu_pos = [](const int &first, const int &second)
737 {
738 return first + (second > 0 ? second : 0);
739 };
740
741 const bool only_positive_coefficients = std::all_of(conv_row, conv_row + size, gez) && std::all_of(conv_col, conv_col + size, gez);
742
743 if(only_positive_coefficients)
744 {
745 const int max_row_value = std::accumulate(conv_row, conv_row + size, 0) * UINT8_MAX;
746 const int max_value = std::accumulate(conv_col, conv_col + size, 0) * max_row_value;
747
748 first_stage = (max_row_value <= UINT16_MAX) ? DataType::U16 : DataType::S32;
749
750 second_stage = (max_value <= UINT16_MAX) ? DataType::U16 : DataType::S32;
751 }
752 else
753 {
754 const int min_row_value = std::accumulate(conv_row, conv_row + size, 0, accu_neg) * UINT8_MAX;
755 const int max_row_value = std::accumulate(conv_row, conv_row + size, 0, accu_pos) * UINT8_MAX;
756 const int neg_coeffs_sum = std::accumulate(conv_col, conv_col + size, 0, accu_neg);
757 const int pos_coeffs_sum = std::accumulate(conv_col, conv_col + size, 0, accu_pos);
758 const int min_value = neg_coeffs_sum * max_row_value + pos_coeffs_sum * min_row_value;
759 const int max_value = neg_coeffs_sum * min_row_value + pos_coeffs_sum * max_row_value;
760
761 first_stage = ((INT16_MIN <= min_row_value) && (max_row_value <= INT16_MAX)) ? DataType::S16 : DataType::S32;
762
763 second_stage = ((INT16_MIN <= min_value) && (max_value <= INT16_MAX)) ? DataType::S16 : DataType::S32;
764 }
765
766 return std::make_pair(first_stage, second_stage);
767}
768
769/** Calculate the accuracy required by the squared convolution calculation.
770 *
771 *
772 * @param[in] conv Pointer to the squared convolution matrix
773 * @param[in] size The total size of the convolution matrix
774 *
775 * @return The return is the biggest data type needed to do the convolution
776 */
777inline DataType data_type_for_convolution_matrix(const int16_t *conv, size_t size)
778{
779 auto gez = [](const int16_t v)
780 {
781 return v >= 0;
782 };
783
784 const bool only_positive_coefficients = std::all_of(conv, conv + size, gez);
785
786 if(only_positive_coefficients)
787 {
788 const int max_conv_value = std::accumulate(conv, conv + size, 0) * UINT8_MAX;
789 if(max_conv_value <= UINT16_MAX)
790 {
791 return DataType::U16;
792 }
793 else
794 {
795 return DataType::S32;
796 }
797 }
798 else
799 {
800 const int min_value = std::accumulate(conv, conv + size, 0, [](int a, int b)
801 {
802 return b < 0 ? a + b : a;
803 })
804 * UINT8_MAX;
805
806 const int max_value = std::accumulate(conv, conv + size, 0, [](int a, int b)
807 {
808 return b > 0 ? a + b : a;
809 })
810 * UINT8_MAX;
811
812 if((INT16_MIN <= min_value) && (INT16_MAX >= max_value))
813 {
814 return DataType::S16;
815 }
816 else
817 {
818 return DataType::S32;
819 }
820 }
821}
822
Pablo Tello35767bc2018-12-05 17:36:30 +0000823/** Permutes the given dimensions according the permutation vector
824 *
825 * @param[in,out] dimensions Dimensions to be permuted.
826 * @param[in] perm Vector describing the permutation.
827 *
828 */
829template <typename T>
830inline void permute_strides(Dimensions<T> &dimensions, const PermutationVector &perm)
831{
832 const auto old_dim = utility::make_array<Dimensions<T>::num_max_dimensions>(dimensions.begin(), dimensions.end());
833 for(unsigned int i = 0; i < perm.num_dimensions(); ++i)
834 {
835 T dimension_val = old_dim[i];
836 dimensions.set(perm[i], dimension_val);
837 }
838}
839
Georgios Pinitas4074c992018-01-30 18:13:46 +0000840/** Calculate padding requirements in case of SAME padding
841 *
842 * @param[in] input_shape Input shape
843 * @param[in] weights_shape Weights shape
844 * @param[in] conv_info Convolution information (containing strides)
Isabella Gottardi6a914402019-01-30 15:45:42 +0000845 * @param[in] data_layout (Optional) Data layout of the input and weights tensor
Pablo Tello01bbacb2019-04-30 10:32:42 +0100846 * @param[in] dilation (Optional) Dilation factor used in the convolution.
Giorgio Arena17203582019-08-02 16:00:41 +0100847 * @param[in] rounding_type (Optional) Dimension rounding type when down-scaling.
Georgios Pinitas4074c992018-01-30 18:13:46 +0000848 *
849 * @return PadStrideInfo for SAME padding
850 */
Giorgio Arena17203582019-08-02 16:00:41 +0100851PadStrideInfo calculate_same_pad(TensorShape input_shape, TensorShape weights_shape, PadStrideInfo conv_info, DataLayout data_layout = DataLayout::NCHW, const Size2D &dilation = Size2D(1u, 1u),
852 const DimensionRoundingType &rounding_type = DimensionRoundingType::FLOOR);
Georgios Pinitas4074c992018-01-30 18:13:46 +0000853
Pablo Tellof5f34bb2017-08-22 13:34:13 +0100854/** Returns expected width and height of the deconvolution's output tensor.
855 *
Matthew Jacksonb9070a42019-08-22 16:13:27 +0100856 * @param[in] in_width Width of input tensor (Number of columns)
857 * @param[in] in_height Height of input tensor (Number of rows)
858 * @param[in] kernel_width Kernel width.
859 * @param[in] kernel_height Kernel height.
860 * @param[in] pad_stride_info Pad and stride information.
Pablo Tellof5f34bb2017-08-22 13:34:13 +0100861 *
862 * @return A pair with the new width in the first position and the new height in the second.
863 */
Pablo Tello01bbacb2019-04-30 10:32:42 +0100864std::pair<unsigned int, unsigned int> deconvolution_output_dimensions(unsigned int in_width, unsigned int in_height,
865 unsigned int kernel_width, unsigned int kernel_height,
Matthew Jacksonb9070a42019-08-22 16:13:27 +0100866 const PadStrideInfo &pad_stride_info);
Pablo Tellof5f34bb2017-08-22 13:34:13 +0100867
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100868/** Returns expected width and height of output scaled tensor depending on dimensions rounding mode.
869 *
Gian Marco Iodice4e288692017-06-27 11:41:59 +0100870 * @param[in] width Width of input tensor (Number of columns)
871 * @param[in] height Height of input tensor (Number of rows)
872 * @param[in] kernel_width Kernel width.
873 * @param[in] kernel_height Kernel height.
874 * @param[in] pad_stride_info Pad and stride information.
Alex Gilday7da29b62018-03-23 14:16:00 +0000875 * @param[in] dilation (Optional) Dilation, in elements, across x and y. Defaults to (1, 1).
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100876 *
877 * @return A pair with the new width in the first position and the new height in the second.
878 */
Pablo Tello01bbacb2019-04-30 10:32:42 +0100879std::pair<unsigned int, unsigned int> scaled_dimensions(unsigned int width, unsigned int height,
880 unsigned int kernel_width, unsigned int kernel_height,
881 const PadStrideInfo &pad_stride_info,
882 const Size2D &dilation = Size2D(1U, 1U));
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100883
Sang-Hoon Park2697fd82019-10-15 16:49:24 +0100884/** Check if the given reduction operation should be handled in a serial way.
885 *
886 * @param[in] op Reduction operation to perform
887 * @param[in] dt Data type
888 * @param[in] axis Axis along which to reduce
889 *
890 * @return True if the given reduction operation should be handled in a serial way.
891 */
892bool needs_serialized_reduction(ReductionOperation op, DataType dt, unsigned int axis);
893
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100894/** Convert a tensor format into a string.
895 *
896 * @param[in] format @ref Format to be translated to string.
897 *
898 * @return The string describing the format.
899 */
900const std::string &string_from_format(Format format);
901
902/** Convert a channel identity into a string.
903 *
904 * @param[in] channel @ref Channel to be translated to string.
905 *
906 * @return The string describing the channel.
907 */
908const std::string &string_from_channel(Channel channel);
Michele Di Giorgiobf3c6622018-03-08 11:52:27 +0000909/** Convert a data layout identity into a string.
910 *
911 * @param[in] dl @ref DataLayout to be translated to string.
912 *
913 * @return The string describing the data layout.
914 */
915const std::string &string_from_data_layout(DataLayout dl);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100916/** Convert a data type identity into a string.
917 *
918 * @param[in] dt @ref DataType to be translated to string.
919 *
920 * @return The string describing the data type.
921 */
922const std::string &string_from_data_type(DataType dt);
923/** Convert a matrix pattern into a string.
924 *
925 * @param[in] pattern @ref MatrixPattern to be translated to string.
926 *
927 * @return The string describing the matrix pattern.
928 */
929const std::string &string_from_matrix_pattern(MatrixPattern pattern);
930/** Translates a given activation function to a string.
931 *
932 * @param[in] act @ref ActivationLayerInfo::ActivationFunction to be translated to string.
933 *
934 * @return The string describing the activation function.
935 */
936const std::string &string_from_activation_func(ActivationLayerInfo::ActivationFunction act);
937/** Translates a given non linear function to a string.
938 *
939 * @param[in] function @ref NonLinearFilterFunction to be translated to string.
940 *
941 * @return The string describing the non linear function.
942 */
943const std::string &string_from_non_linear_filter_function(NonLinearFilterFunction function);
944/** Translates a given interpolation policy to a string.
945 *
946 * @param[in] policy @ref InterpolationPolicy to be translated to string.
947 *
948 * @return The string describing the interpolation policy.
949 */
950const std::string &string_from_interpolation_policy(InterpolationPolicy policy);
951/** Translates a given border mode policy to a string.
952 *
953 * @param[in] border_mode @ref BorderMode to be translated to string.
954 *
955 * @return The string describing the border mode.
956 */
957const std::string &string_from_border_mode(BorderMode border_mode);
958/** Translates a given normalization type to a string.
959 *
960 * @param[in] type @ref NormType to be translated to string.
961 *
962 * @return The string describing the normalization type.
963 */
964const std::string &string_from_norm_type(NormType type);
Georgios Pinitascdf51452017-08-31 14:21:36 +0100965/** Translates a given pooling type to a string.
966 *
967 * @param[in] type @ref PoolingType to be translated to string.
968 *
969 * @return The string describing the pooling type.
970 */
971const std::string &string_from_pooling_type(PoolingType type);
Gian Marco Iodice4b908652018-10-18 10:21:02 +0100972/** Translates a given GEMMLowp output stage to a string.
973 *
974 * @param[in] output_stage @ref GEMMLowpOutputStageInfo to be translated to string.
975 *
976 * @return The string describing the GEMMLowp output stage
977 */
978const std::string &string_from_gemmlowp_output_stage(GEMMLowpOutputStageType output_stage);
Giuseppe Rossinid7647d42018-07-17 18:13:13 +0100979/** Convert a PixelValue to a string, represented through the specific data type
980 *
981 * @param[in] value The PixelValue to convert
982 * @param[in] data_type The type to be used to convert the @p value
983 *
984 * @return String representation of the PixelValue through the given data type.
985 */
986std::string string_from_pixel_value(const PixelValue &value, const DataType data_type);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100987/** Lower a given string.
988 *
989 * @param[in] val Given string to lower.
990 *
991 * @return The lowered string
992 */
993std::string lower_string(const std::string &val);
994
995/** Check if a given data type is of floating point type
996 *
997 * @param[in] dt Input data type.
998 *
999 * @return True if data type is of floating point type, else false.
1000 */
1001inline bool is_data_type_float(DataType dt)
1002{
1003 switch(dt)
1004 {
1005 case DataType::F16:
1006 case DataType::F32:
1007 return true;
1008 default:
1009 return false;
1010 }
1011}
1012
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001013/** Check if a given data type is of quantized type
1014 *
1015 * @note Quantized is considered a super-set of fixed-point and asymmetric data types.
1016 *
1017 * @param[in] dt Input data type.
1018 *
1019 * @return True if data type is of quantized type, else false.
1020 */
1021inline bool is_data_type_quantized(DataType dt)
1022{
1023 switch(dt)
1024 {
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001025 case DataType::QSYMM8:
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001026 case DataType::QASYMM8:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001027 case DataType::QSYMM8_PER_CHANNEL:
Michalis Spyrouc8530212019-08-22 11:44:04 +01001028 case DataType::QASYMM8_PER_CHANNEL:
Manuel Bottini3689fcd2019-06-14 17:18:12 +01001029 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +01001030 case DataType::QASYMM16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001031 return true;
1032 default:
1033 return false;
1034 }
1035}
1036
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001037/** Check if a given data type is of asymmetric quantized type
1038 *
1039 * @param[in] dt Input data type.
1040 *
Michele Di Giorgio6997fc92019-06-18 10:23:22 +01001041 * @return True if data type is of asymmetric quantized type, else false.
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001042 */
Anton Lokhmotovaf6204c2017-11-08 09:34:19 +00001043inline bool is_data_type_quantized_asymmetric(DataType dt)
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001044{
1045 switch(dt)
1046 {
1047 case DataType::QASYMM8:
Michalis Spyrouc8530212019-08-22 11:44:04 +01001048 case DataType::QASYMM8_PER_CHANNEL:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +01001049 case DataType::QASYMM16:
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001050 return true;
1051 default:
1052 return false;
1053 }
1054}
1055
Michele Di Giorgio6997fc92019-06-18 10:23:22 +01001056/** Check if a given data type is of symmetric quantized type
1057 *
1058 * @param[in] dt Input data type.
1059 *
1060 * @return True if data type is of symmetric quantized type, else false.
1061 */
1062inline bool is_data_type_quantized_symmetric(DataType dt)
1063{
1064 switch(dt)
1065 {
1066 case DataType::QSYMM8:
1067 case DataType::QSYMM8_PER_CHANNEL:
1068 case DataType::QSYMM16:
1069 return true;
1070 default:
1071 return false;
1072 }
1073}
1074
Michalis Spyrouc8530212019-08-22 11:44:04 +01001075/** Check if a given data type is of per channel type
1076 *
1077 * @param[in] dt Input data type.
1078 *
1079 * @return True if data type is of per channel type, else false.
1080 */
1081inline bool is_data_type_quantized_per_channel(DataType dt)
1082{
1083 switch(dt)
1084 {
1085 case DataType::QSYMM8_PER_CHANNEL:
1086 case DataType::QASYMM8_PER_CHANNEL:
1087 return true;
1088 default:
1089 return false;
1090 }
1091}
1092
Georgios Pinitas89010962017-08-04 14:58:27 +01001093/** Create a string with the float in full precision.
1094 *
1095 * @param val Floating point value
1096 *
1097 * @return String with the floating point value.
1098 */
1099inline std::string float_to_string_with_full_precision(float val)
1100{
1101 std::stringstream ss;
Georgios Pinitas7900a9e2018-11-23 11:44:58 +00001102 ss.precision(std::numeric_limits<float>::max_digits10);
Georgios Pinitas89010962017-08-04 14:58:27 +01001103 ss << val;
Giorgio Arena73023022018-09-04 14:55:55 +01001104
1105 if(val != static_cast<int>(val))
1106 {
1107 ss << "f";
1108 }
1109
Georgios Pinitas89010962017-08-04 14:58:27 +01001110 return ss.str();
1111}
1112
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001113/** Returns the number of elements required to go from start to end with the wanted step
1114 *
1115 * @param[in] start start value
1116 * @param[in] end end value
1117 * @param[in] step step value between each number in the wanted sequence
1118 *
1119 * @return number of elements to go from start value to end value using the wanted step
1120 */
1121inline size_t num_of_elements_in_range(const float start, const float end, const float step)
1122{
1123 ARM_COMPUTE_ERROR_ON_MSG(step == 0, "Range Step cannot be 0");
1124 return size_t(std::ceil((end - start) / step));
1125}
1126
1127/** Returns true if the value can be represented by the given data type
1128 *
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001129 * @param[in] val value to be checked
1130 * @param[in] dt data type that is checked
1131 * @param[in] qinfo (Optional) quantization info if the data type is QASYMM8
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001132 *
1133 * @return true if the data type can hold the value.
1134 */
1135template <typename T>
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001136bool check_value_range(T val, DataType dt, QuantizationInfo qinfo = QuantizationInfo())
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001137{
1138 switch(dt)
1139 {
1140 case DataType::U8:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001141 {
1142 const auto val_u8 = static_cast<uint8_t>(val);
1143 return ((val_u8 == val) && val_u8 >= std::numeric_limits<uint8_t>::lowest() && val_u8 <= std::numeric_limits<uint8_t>::max());
1144 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001145 case DataType::QASYMM8:
1146 {
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001147 double min = static_cast<double>(dequantize_qasymm8(0, qinfo));
1148 double max = static_cast<double>(dequantize_qasymm8(std::numeric_limits<uint8_t>::max(), qinfo));
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001149 return ((double)val >= min && (double)val <= max);
1150 }
1151 case DataType::S8:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001152 {
1153 const auto val_s8 = static_cast<int8_t>(val);
1154 return ((val_s8 == val) && val_s8 >= std::numeric_limits<int8_t>::lowest() && val_s8 <= std::numeric_limits<int8_t>::max());
1155 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001156 case DataType::U16:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001157 {
1158 const auto val_u16 = static_cast<uint16_t>(val);
1159 return ((val_u16 == val) && val_u16 >= std::numeric_limits<uint16_t>::lowest() && val_u16 <= std::numeric_limits<uint16_t>::max());
1160 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001161 case DataType::S16:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001162 {
1163 const auto val_s16 = static_cast<int16_t>(val);
1164 return ((val_s16 == val) && val_s16 >= std::numeric_limits<int16_t>::lowest() && val_s16 <= std::numeric_limits<int16_t>::max());
1165 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001166 case DataType::U32:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001167 {
1168 const auto val_u32 = static_cast<uint32_t>(val);
1169 return ((val_u32 == val) && val_u32 >= std::numeric_limits<uint32_t>::lowest() && val_u32 <= std::numeric_limits<uint32_t>::max());
1170 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001171 case DataType::S32:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001172 {
1173 const auto val_s32 = static_cast<int32_t>(val);
1174 return ((val_s32 == val) && val_s32 >= std::numeric_limits<int32_t>::lowest() && val_s32 <= std::numeric_limits<int32_t>::max());
1175 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001176 case DataType::F16:
1177 return (val >= std::numeric_limits<half>::lowest() && val <= std::numeric_limits<half>::max());
1178 case DataType::F32:
1179 return (val >= std::numeric_limits<float>::lowest() && val <= std::numeric_limits<float>::max());
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001180 default:
1181 ARM_COMPUTE_ERROR("Data type not supported");
1182 return false;
1183 }
1184}
1185
giuros01edc21e42018-11-16 14:45:31 +00001186#ifdef ARM_COMPUTE_ASSERTS_ENABLED
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001187/** Print consecutive elements to an output stream.
1188 *
1189 * @param[out] s Output stream to print the elements to.
1190 * @param[in] ptr Pointer to print the elements from.
1191 * @param[in] n Number of elements to print.
1192 * @param[in] stream_width (Optional) Width of the stream. If set to 0 the element's width is used. Defaults to 0.
1193 * @param[in] element_delim (Optional) Delimeter among the consecutive elements. Defaults to space delimeter
1194 */
1195template <typename T>
1196void print_consecutive_elements_impl(std::ostream &s, const T *ptr, unsigned int n, int stream_width = 0, const std::string &element_delim = " ")
1197{
1198 using print_type = typename std::conditional<std::is_floating_point<T>::value, T, int>::type;
Michalis Spyrou53860dd2019-07-01 14:20:56 +01001199 std::ios stream_status(nullptr);
1200 stream_status.copyfmt(s);
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001201
1202 for(unsigned int i = 0; i < n; ++i)
1203 {
1204 // Set stream width as it is not a "sticky" stream manipulator
1205 if(stream_width != 0)
1206 {
1207 s.width(stream_width);
1208 }
Anthony Barbier7068f992017-10-26 15:23:08 +01001209
1210 if(std::is_same<typename std::decay<T>::type, half>::value)
1211 {
1212 // We use T instead of print_type here is because the std::is_floating_point<half> returns false and then the print_type becomes int.
1213 s << std::right << static_cast<T>(ptr[i]) << element_delim;
1214 }
1215 else
1216 {
1217 s << std::right << static_cast<print_type>(ptr[i]) << element_delim;
1218 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001219 }
Michalis Spyrou53860dd2019-07-01 14:20:56 +01001220
1221 // Restore output stream flags
1222 s.copyfmt(stream_status);
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001223}
1224
1225/** Identify the maximum width of n consecutive elements.
1226 *
1227 * @param[in] s The output stream which will be used to print the elements. Used to extract the stream format.
1228 * @param[in] ptr Pointer to the elements.
1229 * @param[in] n Number of elements.
1230 *
1231 * @return The maximum width of the elements.
1232 */
1233template <typename T>
1234int max_consecutive_elements_display_width_impl(std::ostream &s, const T *ptr, unsigned int n)
1235{
1236 using print_type = typename std::conditional<std::is_floating_point<T>::value, T, int>::type;
1237
1238 int max_width = -1;
1239 for(unsigned int i = 0; i < n; ++i)
1240 {
1241 std::stringstream ss;
1242 ss.copyfmt(s);
Anthony Barbier7068f992017-10-26 15:23:08 +01001243
1244 if(std::is_same<typename std::decay<T>::type, half>::value)
1245 {
1246 // We use T instead of print_type here is because the std::is_floating_point<half> returns false and then the print_type becomes int.
1247 ss << static_cast<T>(ptr[i]);
1248 }
1249 else
1250 {
1251 ss << static_cast<print_type>(ptr[i]);
1252 }
1253
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001254 max_width = std::max<int>(max_width, ss.str().size());
1255 }
1256 return max_width;
1257}
1258
1259/** Print consecutive elements to an output stream.
1260 *
1261 * @param[out] s Output stream to print the elements to.
1262 * @param[in] dt Data type of the elements
1263 * @param[in] ptr Pointer to print the elements from.
1264 * @param[in] n Number of elements to print.
1265 * @param[in] stream_width (Optional) Width of the stream. If set to 0 the element's width is used. Defaults to 0.
1266 * @param[in] element_delim (Optional) Delimeter among the consecutive elements. Defaults to space delimeter
1267 */
1268void print_consecutive_elements(std::ostream &s, DataType dt, const uint8_t *ptr, unsigned int n, int stream_width, const std::string &element_delim = " ");
1269
1270/** Identify the maximum width of n consecutive elements.
1271 *
1272 * @param[in] s Output stream to print the elements to.
1273 * @param[in] dt Data type of the elements
1274 * @param[in] ptr Pointer to print the elements from.
1275 * @param[in] n Number of elements to print.
1276 *
1277 * @return The maximum width of the elements.
1278 */
1279int max_consecutive_elements_display_width(std::ostream &s, DataType dt, const uint8_t *ptr, unsigned int n);
giuros01edc21e42018-11-16 14:45:31 +00001280#endif /* ARM_COMPUTE_ASSERTS_ENABLED */
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001281}
1282#endif /*__ARM_COMPUTE_UTILS_H__ */