From 53d092d34c1e9924151d8d3a228c04620c1baf5c Mon Sep 17 00:00:00 2001 From: Derek Lamberti Date: Wed, 19 Feb 2020 13:40:56 +0000 Subject: IVGCVSW-4486 Introduce numeric_cast implementation Change-Id: I3e64bca4a1709ac199513676579cf3c9a3090f26 Signed-off-by: Derek Lamberti --- include/armnn/utility/NumericCast.hpp | 124 ++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 include/armnn/utility/NumericCast.hpp (limited to 'include/armnn/utility/NumericCast.hpp') diff --git a/include/armnn/utility/NumericCast.hpp b/include/armnn/utility/NumericCast.hpp new file mode 100644 index 0000000000..62c7d11543 --- /dev/null +++ b/include/armnn/utility/NumericCast.hpp @@ -0,0 +1,124 @@ +// +// Copyright © 2020 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include "Assert.hpp" + +#include +#include + +namespace armnn +{ + +#if !defined(NDEBUG) || defined(ARMNN_NUMERIC_CAST_TESTABLE) +#define ENABLE_NUMERIC_CAST_CHECKS 1 +#else +#define ENABLE_NUMERIC_CAST_CHECKS 0 +#endif + +#if defined(ARMNN_NUMERIC_CAST_TESTABLE) +# define ARMNN_NUMERIC_CAST_CHECK(cond, msg) ConditionalThrow(cond) +#else +# define ARMNN_NUMERIC_CAST_CHECK(cond, msg) ARMNN_ASSERT_MSG(cond, msg) +#endif + +template +typename std::enable_if_t< + std::is_unsigned::value && + std::is_unsigned::value + , Dest> +numeric_cast(Source source) +{ +#if ENABLE_NUMERIC_CAST_CHECKS + if (source > std::numeric_limits::max()) + { + ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting unsigned type to " + "narrower unsigned type. Overflow detected."); + } +#endif // ENABLE_NUMERIC_CAST_CHECKS + + return static_cast(source); +} + +template +typename std::enable_if_t< + std::is_signed::value && + std::is_signed::value + , Dest> +numeric_cast(Source source) +{ + static_assert(!std::is_floating_point::value && !std::is_floating_point::value, + "numeric_cast doesn't cast float."); + +#if ENABLE_NUMERIC_CAST_CHECKS + if (source > std::numeric_limits::max()) + { + ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed type to narrower signed type. " + "Overflow detected."); + } + + if (source < std::numeric_limits::lowest()) + { + ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed type to narrower signed type. " + "Underflow detected."); + } +#endif // ENABLE_NUMERIC_CAST_CHECKS + + return static_cast(source); +} + +// numeric cast from unsigned to signed checked for narrowing overflows +template +typename std::enable_if_t< + std::is_signed::value && + std::is_unsigned::value + , Dest> +numeric_cast(Source sValue) +{ + static_assert(!std::is_floating_point::value, "numeric_cast doesn't cast to float."); + +#if ENABLE_NUMERIC_CAST_CHECKS + if (sValue > static_cast< typename std::make_unsigned::type >(std::numeric_limits::max())) + { + ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting unsigned type to signed type. " + "Overflow detected."); + } +#endif // ENABLE_NUMERIC_CAST_CHECKS + + return static_cast(sValue); +} + +// numeric cast from signed to unsigned checked for underflows and narrowing overflows +template +typename std::enable_if_t< + std::is_unsigned::value && + std::is_signed::value + , Dest> +numeric_cast(Source sValue) +{ + static_assert(!std::is_floating_point::value && !std::is_floating_point::value, + "numeric_cast doesn't cast floats."); + +#if ENABLE_NUMERIC_CAST_CHECKS + if (sValue < 0) + { + ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting negative value to unsigned type. " + "Underflow detected."); + } + + if (static_cast< typename std::make_unsigned::type >(sValue) > std::numeric_limits::max()) + { + ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed type to unsigned type. " + "Overflow detected."); + } + +#endif // ENABLE_NUMERIC_CAST_CHECKS + return static_cast(sValue); +} + +#undef ENABLE_NUMERIC_CAST_CHECKS + +} //namespace armnn \ No newline at end of file -- cgit v1.2.1