arm_compute v18.05
[platform/upstream/armcl.git] / support / ToolchainSupport.h
1 /*
2  * Copyright (c) 2017-2018 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_TEST_TOOLCHAINSUPPORT
25 #define ARM_COMPUTE_TEST_TOOLCHAINSUPPORT
26
27 #include <algorithm>
28 #include <cmath>
29 #include <cstddef>
30 #include <limits>
31 #include <memory>
32 #include <numeric>
33 #include <sstream>
34 #include <string>
35 #include <type_traits>
36
37 #include "support/Half.h"
38
39 namespace arm_compute
40 {
41 namespace support
42 {
43 namespace cpp11
44 {
45 #if(__ANDROID__ || BARE_METAL)
46 /** Convert integer and float values to string.
47  *
48  * @note This function implements the same behaviour as std::to_string. The
49  *       latter is missing in some Android toolchains.
50  *
51  * @param[in] value Value to be converted to string.
52  *
53  * @return String representation of @p value.
54  */
55 template <typename T, typename std::enable_if<std::is_arithmetic<typename std::decay<T>::type>::value, int>::type = 0>
56 inline std::string to_string(T && value)
57 {
58     std::stringstream stream;
59     stream << std::forward<T>(value);
60     return stream.str();
61 }
62
63 /** Convert string values to integer.
64  *
65  * @note This function implements the same behaviour as std::stoi. The latter
66  *       is missing in some Android toolchains.
67  *
68  * @param[in] str String to be converted to int.
69  *
70  * @return Integer representation of @p str.
71  */
72 inline int stoi(const std::string &str, std::size_t *pos = 0, int base = 10)
73 {
74     unsigned int      x;
75     std::stringstream ss;
76     if(base == 16)
77     {
78         ss << std::hex;
79     }
80     ss << str;
81     ss >> x;
82     return x;
83 }
84
85 /** Convert string values to unsigned long.
86  *
87  * @note This function implements the same behaviour as std::stoul. The latter
88  *       is missing in some Android toolchains.
89  *
90  * @param[in] str String to be converted to unsigned long.
91  *
92  * @return Unsigned long representation of @p str.
93  */
94 inline unsigned long stoul(const std::string &str, std::size_t *pos = 0, int base = 10)
95 {
96     std::stringstream stream;
97     unsigned long     value = 0;
98     if(base == 16)
99     {
100         stream << std::hex;
101     }
102     stream << str;
103     stream >> value;
104     return value;
105 }
106
107 /** Convert string values to float.
108  *
109  * @note This function implements the same behaviour as std::stof. The latter
110  *       is missing in some Android toolchains.
111  *
112  * @param[in] str String to be converted to float.
113  *
114  * @return Float representation of @p str.
115  */
116 inline float stof(const std::string &str)
117 {
118     std::stringstream stream(str);
119     float             value = 0.f;
120     stream >> value;
121     return value;
122 }
123
124 /** Round floating-point value with half value rounding away from zero.
125  *
126  * @note This function implements the same behaviour as std::round except that it doesn't
127  *       support Integral type. The latter is not in the namespace std in some Android toolchains.
128  *
129  * @param[in] value floating-point value to be rounded.
130  *
131  * @return Floating-point value of rounded @p value.
132  */
133 template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
134 inline T round(T value)
135 {
136     return ::round(value);
137 }
138
139 /** Truncate floating-point value.
140  *
141  * @note This function implements the same behaviour as std::truncate except that it doesn't
142  *       support Integral type. The latter is not in the namespace std in some Android toolchains.
143  *
144  * @param[in] value floating-point value to be truncated.
145  *
146  * @return Floating-point value of truncated @p value.
147  */
148 template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
149 inline T trunc(T value)
150 {
151     return ::trunc(value);
152 }
153
154 /** Composes a floating point value with the magnitude of @p x and the sign of @p y.
155  *
156  * @note This function implements the same behaviour as std::copysign except that it doesn't
157  *       support Integral type. The latter is not in the namespace std in some Android toolchains.
158  *
159  * @param[in] x value that contains the magnitude to be used in constructing the result.
160  * @param[in] y value that contains the sign to be used in construct in the result.
161  *
162  * @return Floating-point value with magnitude of @p x and sign of @p y.
163  */
164 template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
165 inline T copysign(T x, T y)
166 {
167     return ::copysign(x, y);
168 }
169
170 /** Loads the data from the given location, converts them to character string equivalents
171  *  and writes the result to a character string buffer.
172  *
173  * @param[in] s    Pointer to a character string to write to
174  * @param[in] n    Up to buf_size - 1 characters may be written, plus the null terminator
175  * @param[in] fmt  Pointer to a null-terminated multibyte string specifying how to interpret the data.
176  * @param[in] args Arguments forwarded to snprintf.
177  *
178  * @return  Number of characters that would have been written for a sufficiently large buffer
179  *          if successful (not including the terminating null character), or a negative value if an error occurred.
180  */
181 template <typename... Ts>
182 inline int snprintf(char *s, size_t n, const char *fmt, Ts &&... args)
183 {
184     return ::snprintf(s, n, fmt, std::forward<Ts>(args)...);
185 }
186 #else  /* (__ANDROID__ || BARE_METAL) */
187 /** Convert integer and float values to string.
188  *
189  * @note This function acts as a convenience wrapper around std::to_string. The
190  *       latter is missing in some Android toolchains.
191  *
192  * @param[in] value Value to be converted to string.
193  *
194  * @return String representation of @p value.
195  */
196 template <typename T>
197 inline std::string to_string(T &&value)
198 {
199     return ::std::to_string(std::forward<T>(value));
200 }
201
202 /** Convert string values to integer.
203  *
204  * @note This function acts as a convenience wrapper around std::stoi. The
205  *       latter is missing in some Android toolchains.
206  *
207  * @param[in] args Arguments forwarded to std::stoi.
208  *
209  * @return Integer representation of input string.
210  */
211 template <typename... Ts>
212 int stoi(Ts &&... args)
213 {
214     return ::std::stoi(std::forward<Ts>(args)...);
215 }
216
217 /** Convert string values to unsigned long.
218  *
219  * @note This function acts as a convenience wrapper around std::stoul. The
220  *       latter is missing in some Android toolchains.
221  *
222  * @param[in] args Arguments forwarded to std::stoul.
223  *
224  * @return Unsigned long representation of input string.
225  */
226 template <typename... Ts>
227 int stoul(Ts &&... args)
228 {
229     return ::std::stoul(std::forward<Ts>(args)...);
230 }
231
232 /** Convert string values to float.
233  *
234  * @note This function acts as a convenience wrapper around std::stof. The
235  *       latter is missing in some Android toolchains.
236  *
237  * @param[in] args Arguments forwarded to std::stof.
238  *
239  * @return Float representation of input string.
240  */
241 template <typename... Ts>
242 int stof(Ts &&... args)
243 {
244     return ::std::stof(std::forward<Ts>(args)...);
245 }
246
247 /** Round floating-point value with half value rounding away from zero.
248  *
249  * @note This function implements the same behaviour as std::round except that it doesn't
250  *       support Integral type. The latter is not in the namespace std in some Android toolchains.
251  *
252  * @param[in] value floating-point value to be rounded.
253  *
254  * @return Floating-point value of rounded @p value.
255  */
256 template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
257 inline T round(T value)
258 {
259     //Workaround Valgrind's mismatches: when running from Valgrind the call to std::round(-4.500000) == -4.000000 instead of 5.00000
260     return (value < 0.f) ? static_cast<int>(value - 0.5f) : static_cast<int>(value + 0.5f);
261 }
262
263 /** Truncate floating-point value.
264  *
265  * @note This function implements the same behaviour as std::truncate except that it doesn't
266  *       support Integral type. The latter is not in the namespace std in some Android toolchains.
267  *
268  * @param[in] value floating-point value to be truncated.
269  *
270  * @return Floating-point value of truncated @p value.
271  */
272 template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
273 inline T trunc(T value)
274 {
275     return std::trunc(value);
276 }
277
278 /** Composes a floating point value with the magnitude of @p x and the sign of @p y.
279  *
280  * @note This function implements the same behaviour as std::copysign except that it doesn't
281  *       support Integral type. The latter is not in the namespace std in some Android toolchains.
282  *
283  * @param[in] x value that contains the magnitude to be used in constructing the result.
284  * @param[in] y value that contains the sign to be used in construct in the result.
285  *
286  * @return Floating-point value with magnitude of @p x and sign of @p y.
287  */
288 template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
289 inline T copysign(T x, T y)
290 {
291     return std::copysign(x, y);
292 }
293
294 /** Loads the data from the given location, converts them to character string equivalents
295  *  and writes the result to a character string buffer.
296  *
297  * @param[in] s    Pointer to a character string to write to
298  * @param[in] n    Up to buf_size - 1 characters may be written, plus the null terminator
299  * @param[in] fmt  Pointer to a null-terminated multibyte string specifying how to interpret the data.
300  * @param[in] args Arguments forwarded to std::snprintf.
301  *
302  * @return  Number of characters that would have been written for a sufficiently large buffer
303  *          if successful (not including the terminating null character), or a negative value if an error occurred.
304  */
305 template <typename... Ts>
306 inline int snprintf(char *s, std::size_t n, const char *fmt, Ts &&... args)
307 {
308     return std::snprintf(s, n, fmt, std::forward<Ts>(args)...);
309 }
310 #endif /* (__ANDROID__ || BARE_METAL) */
311
312 inline std::string to_string(bool value)
313 {
314     std::stringstream str;
315     str << std::boolalpha << value;
316     return str.str();
317 }
318
319 // std::align is missing in GCC 4.9
320 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57350
321 inline void *align(std::size_t alignment, std::size_t size, void *&ptr, std::size_t &space)
322 {
323     std::uintptr_t pn      = reinterpret_cast<std::uintptr_t>(ptr);
324     std::uintptr_t aligned = (pn + alignment - 1) & -alignment;
325     std::size_t    padding = aligned - pn;
326     if(space < size + padding)
327     {
328         return nullptr;
329     }
330
331     space -= padding;
332
333     return ptr = reinterpret_cast<void *>(aligned);
334 }
335
336 // std::isfinite
337 template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value>::type>
338 inline bool isfinite(T value)
339 {
340     return std::isfinite(value);
341 }
342
343 inline bool isfinite(half_float::half value)
344 {
345     return half_float::isfinite(value);
346 }
347 } // namespace cpp11
348
349 namespace cpp14
350 {
351 /** make_unique is missing in CPP11. Re-implement it according to the standard proposal. */
352
353 /**<Template for single object */
354 template <class T>
355 struct _Unique_if
356 {
357     typedef std::unique_ptr<T> _Single_object; /**< Single object type */
358 };
359
360 /** Template for array */
361 template <class T>
362 struct _Unique_if<T[]>
363 {
364     typedef std::unique_ptr<T[]> _Unknown_bound; /**< Array type */
365 };
366
367 /** Template for array with known bounds (to throw an error).
368  *
369  * @note this is intended to never be hit.
370  */
371 template <class T, size_t N>
372 struct _Unique_if<T[N]>
373 {
374     typedef void _Known_bound; /**< Should never be used */
375 };
376
377 /** Construct a single object and return a unique pointer to it.
378  *
379  * @param[in] args Constructor arguments.
380  *
381  * @return a unique pointer to the new object.
382  */
383 template <class T, class... Args>
384 typename _Unique_if<T>::_Single_object
385 make_unique(Args &&... args)
386 {
387     return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
388 }
389
390 /** Construct an array of objects and return a unique pointer to it.
391  *
392  * @param[in] n Array size
393  *
394  * @return a unique pointer to the new array.
395  */
396 template <class T>
397 typename _Unique_if<T>::_Unknown_bound
398 make_unique(size_t n)
399 {
400     typedef typename std::remove_extent<T>::type U;
401     return std::unique_ptr<T>(new U[n]());
402 }
403
404 /** It is invalid to attempt to make_unique an array with known bounds. */
405 template <class T, class... Args>
406 typename _Unique_if<T>::_Known_bound
407 make_unique(Args &&...) = delete;
408 } // namespace cpp14
409 } // namespace support
410 } // namespace arm_compute
411 #endif /* ARM_COMPUTE_TEST_TOOLCHAINSUPPORT */