namespace {
-template <typename TO, typename FROM>
-bool isConversionNarrowing(FROM from) {
- return from == (static_cast<FROM>(static_cast<TO>(from)));
-}
-
-template <typename TO, typename FROM>
-TO saturatedCast(FROM from) {
- FROM max = isConversionNarrowing<FROM>(std::numeric_limits<TO>::max()) ? std::numeric_limits<FROM>::max() :
- static_cast<FROM>(std::numeric_limits<TO>::max());
- FROM min = isConversionNarrowing<FROM>(std::numeric_limits<TO>::min()) ? std::numeric_limits<FROM>::min() :
- static_cast<FROM>(std::numeric_limits<TO>::min());
-
- return static_cast<TO>(std::min(std::max(from, min), max));
-}
-
template <Precision::ePrecision PREC_FROM, Precision::ePrecision PREC_TO>
void convertArrayPrecision(typename PrecisionTrait<PREC_TO>::value_type* dst,
const typename PrecisionTrait<PREC_FROM>::value_type* src, size_t nelem) {
using dst_type = typename PrecisionTrait<PREC_TO>::value_type;
for (size_t i = 0; i < nelem; i++) {
- dst[i] = saturatedCast<dst_type>(src[i]);
+ dst[i] = PrecisionUtils::saturate_cast<dst_type>(src[i]);
}
}
#include <ie_api.h>
#include <cstddef>
+#include <type_traits>
+#include <limits>
+#include <algorithm>
/**
* @brief Inference Engine Plugin API namespace
INFERENCE_ENGINE_API_CPP(void)
f32tof16Arrays(ie_fp16* dst, const float* src, size_t nelem, float scale = 1.f, float bias = 0.f);
+/**
+ * @brief Converts one integral type to another saturating the result if the source value doesn't fit
+ * into destination type range
+ * @ingroup ie_dev_api_precision
+ *
+ * @param value Value to be converted
+ */
+template <class OutT, class InT, typename std::enable_if<
+ std::is_integral<OutT>::value && std::is_integral<InT>::value &&
+ std::is_signed<InT>::value &&
+ !std::is_same<OutT, InT>::value
+ >::type* = nullptr>
+inline OutT saturate_cast(const InT& value) {
+ if (std::numeric_limits<OutT>::max() > std::numeric_limits<InT>::max() &&
+ std::numeric_limits<OutT>::min() < std::numeric_limits<InT>::min()) {
+ return static_cast<OutT>(value);
+ }
+
+ const InT max = std::numeric_limits<OutT>::max() < std::numeric_limits<InT>::max() ? std::numeric_limits<OutT>::max() :
+ std::numeric_limits<InT>::max();
+ const InT min = std::numeric_limits<OutT>::min() > std::numeric_limits<InT>::min() ? std::numeric_limits<OutT>::min() :
+ std::numeric_limits<InT>::min();
+
+ return std::min(std::max(value, min), max);
+}
+
+/**
+ * @brief Converts one integral type to another saturating the result if the source value doesn't fit
+ * into destination type range
+ * @ingroup ie_dev_api_precision
+ *
+ * @param value Value to be converted
+ */
+template <class OutT, class InT, typename std::enable_if<
+ std::is_integral<OutT>::value && std::is_integral<InT>::value &&
+ std::is_unsigned<InT>::value &&
+ !std::is_same<OutT, InT>::value
+ >::type* = nullptr>
+inline OutT saturate_cast(const InT& value) {
+ if (std::numeric_limits<OutT>::max() > std::numeric_limits<InT>::max()) {
+ return static_cast<OutT>(value);
+ }
+
+ const InT max = std::numeric_limits<OutT>::max() < std::numeric_limits<InT>::max() ? std::numeric_limits<OutT>::max() :
+ std::numeric_limits<InT>::max();
+
+ return std::min(value, max);
+}
+
+/**
+ * @brief Converts one integral type to another saturating the result if the source value doesn't fit
+ * into destination type range
+ * @ingroup ie_dev_api_precision
+ *
+ * @param value Value to be converted
+ */
+template <class InT>
+inline InT saturate_cast(const InT& value) {
+ return value;
+}
+
} // namespace PrecisionUtils
} // namespace InferenceEngine
--- /dev/null
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include <gtest/gtest.h>
+#include "common_test_utils/test_common.hpp"
+
+#include "precision_utils.h"
+#include "ie_precision.hpp"
+
+#include <opencv2/core.hpp>
+
+using namespace InferenceEngine;
+
+class SaturateCastTestsI64ToI32 : public CommonTestUtils::TestsCommon {
+public:
+ using fromType = typename PrecisionTrait<Precision::I64>::value_type;
+ using toType = typename PrecisionTrait<Precision::I32>::value_type;
+};
+
+TEST_F(SaturateCastTestsI64ToI32, I64ToI32NonNarrowingPositive) {
+ const auto value = fromType{42};
+ EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
+}
+
+TEST_F(SaturateCastTestsI64ToI32, I64ToI32NonNarrowingNegative) {
+ const auto value = fromType{-42};
+ EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
+}
+
+TEST_F(SaturateCastTestsI64ToI32, I64ToI32NarrowingMaxToMax) {
+ const auto value = std::numeric_limits<fromType>::max();
+ EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
+}
+
+TEST_F(SaturateCastTestsI64ToI32, I64ToI32NarrowingNonMaxToMax) {
+ const auto value = std::numeric_limits<fromType>::max() - 1;
+ EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
+}
+
+TEST_F(SaturateCastTestsI64ToI32, I64ToI32NarrowingMinToMin) {
+ const auto value = std::numeric_limits<fromType>::min();
+ EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
+}
+
+TEST_F(SaturateCastTestsI64ToI32, I64ToI32NarrowingNonMinToMin) {
+ const auto value = std::numeric_limits<fromType>::min() + 1;
+ EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
+}
+
+class SaturateCastTestsU64ToI32 : public CommonTestUtils::TestsCommon {
+public:
+ using fromType = typename PrecisionTrait<Precision::U64>::value_type;
+ using toType = typename PrecisionTrait<Precision::I32>::value_type;
+};
+
+TEST_F(SaturateCastTestsU64ToI32, U64ToI32NonNarrowing) {
+ const auto value = fromType{42};
+ EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
+}
+
+TEST_F(SaturateCastTestsU64ToI32, U64ToI32NarrowingMaxToMax) {
+ const auto value = std::numeric_limits<fromType>::max();
+ EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
+}
+
+TEST_F(SaturateCastTestsU64ToI32, U64ToI32NarrowingNonMaxToMax) {
+ const auto value = std::numeric_limits<fromType>::max() - 1;
+ EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
+}
+
+class SaturateCastTestsBoolToU8 : public CommonTestUtils::TestsCommon {
+public:
+ using fromType = typename PrecisionTrait<Precision::BOOL>::value_type;
+ using toType = typename PrecisionTrait<Precision::U8>::value_type;
+};
+
+TEST_F(SaturateCastTestsBoolToU8, BOOLtoU8MaxToNonMax) {
+ const auto value = std::numeric_limits<fromType>::max();
+ EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
+}
+
+class SaturateCastTestsBoolToI32 : public CommonTestUtils::TestsCommon {
+public:
+ using fromType = typename PrecisionTrait<Precision::BOOL>::value_type;
+ using toType = typename PrecisionTrait<Precision::I32>::value_type;
+};
+
+TEST_F(SaturateCastTestsBoolToI32, BOOLtoI32MaxToNonMax) {
+ const auto value = std::numeric_limits<fromType>::max();
+ EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
+}
+
+class SaturateCastTestsU8ToI32 : public CommonTestUtils::TestsCommon {
+public:
+ using fromType = typename PrecisionTrait<Precision::U8>::value_type;
+ using toType = typename PrecisionTrait<Precision::I32>::value_type;
+};
+
+TEST_F(SaturateCastTestsU8ToI32, U8toI32FMaxToNonMax) {
+ const auto value = std::numeric_limits<fromType>::max();
+ EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
+}
+
+class SaturateCastTestsU16ToI32 : public CommonTestUtils::TestsCommon {
+public:
+ using fromType = typename PrecisionTrait<Precision::U8>::value_type;
+ using toType = typename PrecisionTrait<Precision::I32>::value_type;
+};
+
+TEST_F(SaturateCastTestsU16ToI32, U16toI32FMaxToNonMax) {
+ const auto value = std::numeric_limits<fromType>::max();
+ EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
+}