/* * Copyright 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include namespace android::test { using ftl::cast_safety; using ftl::CastSafety; template constexpr T min = std::numeric_limits::lowest(); template constexpr T max = std::numeric_limits::max(); template constexpr T inf = std::numeric_limits::infinity(); template constexpr T NaN = std::numeric_limits::quiet_NaN(); // Keep in sync with example usage in header file. static_assert(cast_safety(-1) == CastSafety::kUnderflow); static_assert(cast_safety(128u) == CastSafety::kOverflow); static_assert(cast_safety(-.1f) == CastSafety::kUnderflow); static_assert(cast_safety(static_cast(INT32_MAX)) == CastSafety::kOverflow); static_assert(cast_safety(-DBL_MAX) == CastSafety::kUnderflow); // Unsigned to unsigned. static_assert(cast_safety(0u) == CastSafety::kSafe); static_assert(cast_safety(max) == CastSafety::kSafe); static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); static_assert(cast_safety(max) == CastSafety::kOverflow); static_assert(cast_safety(static_cast(max) + 1) == CastSafety::kOverflow); // Unsigned to signed. static_assert(cast_safety(0u) == CastSafety::kSafe); static_assert(cast_safety(max) == CastSafety::kSafe); static_assert(cast_safety(max) == CastSafety::kOverflow); static_assert(cast_safety(static_cast(max) - 1) == CastSafety::kSafe); static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); static_assert(cast_safety(static_cast(max) + 1) == CastSafety::kOverflow); // Signed to unsigned. static_assert(cast_safety(0) == CastSafety::kSafe); static_assert(cast_safety(max) == CastSafety::kSafe); static_assert(cast_safety(max) == CastSafety::kSafe); static_assert(cast_safety(-1) == CastSafety::kUnderflow); static_assert(cast_safety(max) == CastSafety::kOverflow); static_assert(cast_safety(static_cast(max) - 1) == CastSafety::kSafe); static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); static_assert(cast_safety(static_cast(max) + 1) == CastSafety::kOverflow); // Signed to signed. static_assert(cast_safety(-129) == CastSafety::kUnderflow); static_assert(cast_safety(-128) == CastSafety::kSafe); static_assert(cast_safety(127) == CastSafety::kSafe); static_assert(cast_safety(128) == CastSafety::kOverflow); static_assert(cast_safety(static_cast(min)) == CastSafety::kSafe); static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); static_assert(cast_safety(min) == CastSafety::kUnderflow); static_assert(cast_safety(max) == CastSafety::kOverflow); // Float to float. static_assert(cast_safety(max) == CastSafety::kSafe); static_assert(cast_safety(min) == CastSafety::kSafe); static_assert(cast_safety(min) == CastSafety::kUnderflow); static_assert(cast_safety(max) == CastSafety::kOverflow); TEST(CastSafety, FloatToFloat) { EXPECT_EQ(cast_safety(std::nexttoward(static_cast(min), min)), CastSafety::kUnderflow); EXPECT_EQ(cast_safety(std::nexttoward(static_cast(max), max)), CastSafety::kOverflow); } // Unsigned to float. static_assert(cast_safety(0u) == CastSafety::kSafe); static_assert(cast_safety(max) == CastSafety::kSafe); static_assert(cast_safety(0u) == CastSafety::kSafe); static_assert(cast_safety(max) == CastSafety::kSafe); // Signed to float. static_assert(cast_safety(min) == CastSafety::kSafe); static_assert(cast_safety(max) == CastSafety::kSafe); static_assert(cast_safety(min) == CastSafety::kSafe); static_assert(cast_safety(max) == CastSafety::kSafe); // Float to unsigned. static_assert(cast_safety(0.f) == CastSafety::kSafe); static_assert(cast_safety(min) == CastSafety::kUnderflow); static_assert(cast_safety(max) == CastSafety::kOverflow); static_assert(cast_safety(-.1f) == CastSafety::kUnderflow); static_assert(cast_safety(-inf) == CastSafety::kUnderflow); static_assert(cast_safety(inf) == CastSafety::kOverflow); static_assert(cast_safety(NaN) == CastSafety::kOverflow); static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); static_assert(cast_safety(static_cast(max)) == CastSafety::kOverflow); static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); static_assert(cast_safety(0.0) == CastSafety::kSafe); static_assert(cast_safety(min) == CastSafety::kUnderflow); static_assert(cast_safety(max) == CastSafety::kOverflow); static_assert(cast_safety(-.1) == CastSafety::kUnderflow); static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); static_assert(cast_safety(static_cast(max)) == CastSafety::kOverflow); static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); static_assert(cast_safety(static_cast(max)) == CastSafety::kOverflow); // Float to signed. static_assert(cast_safety(0.f) == CastSafety::kSafe); static_assert(cast_safety(min) == CastSafety::kUnderflow); static_assert(cast_safety(max) == CastSafety::kOverflow); static_assert(cast_safety(-inf) == CastSafety::kUnderflow); static_assert(cast_safety(inf) == CastSafety::kOverflow); static_assert(cast_safety(NaN) == CastSafety::kOverflow); static_assert(cast_safety(static_cast(min)) == CastSafety::kSafe); static_assert(cast_safety(static_cast(max)) == CastSafety::kOverflow); static_assert(cast_safety(static_cast(min)) == CastSafety::kSafe); static_assert(cast_safety(static_cast(max)) == CastSafety::kSafe); static_assert(cast_safety(0.0) == CastSafety::kSafe); static_assert(cast_safety(min) == CastSafety::kUnderflow); static_assert(cast_safety(max) == CastSafety::kOverflow); static_assert(cast_safety(static_cast(min)) == CastSafety::kSafe); static_assert(cast_safety(static_cast(max)) == CastSafety::kOverflow); static_assert(cast_safety(static_cast(min)) == CastSafety::kSafe); static_assert(cast_safety(static_cast(max)) == CastSafety::kOverflow); TEST(CastSafety, FloatToSigned) { constexpr int32_t kMax = ftl::details::safe_limits::max(); static_assert(kMax == 2'147'483'520); EXPECT_EQ(kMax, static_cast(std::nexttowardf(max, 0))); EXPECT_EQ(cast_safety(std::nexttowardf(min, 0)), CastSafety::kSafe); EXPECT_EQ(cast_safety(std::nexttowardf(max, 0)), CastSafety::kSafe); EXPECT_EQ(cast_safety(std::nexttoward(min, 0)), CastSafety::kSafe); EXPECT_EQ(cast_safety(std::nexttoward(max, 0)), CastSafety::kSafe); EXPECT_EQ(cast_safety(std::nexttowardf(min, min)), CastSafety::kUnderflow); EXPECT_EQ(cast_safety(std::nexttowardf(max, max)), CastSafety::kOverflow); EXPECT_EQ(cast_safety(std::nexttoward(min, min)), CastSafety::kUnderflow); EXPECT_EQ(cast_safety(std::nexttoward(max, max)), CastSafety::kOverflow); } } // namespace android::test