DO NOT MERGE: [libc++] Add __truncating_cast for safely casting float types to integers
This is needed anytime we need to clamp an arbitrary floating point value to an integer type. Thanks to Eric Fiselier for the patch. Differential Revision: https://reviews.llvm.org/D66836 git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@370891 91177308-0d34-0410-b5e6-96231b3b80d8 (cherry picked from commit c9ac8d533010d8915bcfdecab891fb451f71ce74) (cherry picked from commit 4561f55204960c0b3bc4594089ddcf56e5655cad) (cherry picked from commit f4471784fdb5799b9862febc385a26becfbe53b3) Bug: https://bugs.chromium.org/p/chromium/issues/detail?id=994957 Bug: http://b/139690488 Change-Id: I3d402ed0237a2f5f934a5d368ca91304bfcd9ed0
This commit is contained in:
90
test/libcxx/numerics/clamp_to_integral.pass.cpp
Normal file
90
test/libcxx/numerics/clamp_to_integral.pass.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// __clamp_to_integral<IntT>(RealT)
|
||||
|
||||
// Test the conversion function that truncates floating point types to the
|
||||
// closest representable value for the specified integer type, or
|
||||
// numeric_limits<IntT>::max()/min() if the value isn't representable.
|
||||
|
||||
#include <limits>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
template <class IntT>
|
||||
void test() {
|
||||
typedef std::numeric_limits<IntT> Lim;
|
||||
const bool MaxIsRepresentable = sizeof(IntT) < 8;
|
||||
const bool IsSigned = std::is_signed<IntT>::value;
|
||||
struct TestCase {
|
||||
double Input;
|
||||
IntT Expect;
|
||||
bool IsRepresentable;
|
||||
} TestCases[] = {
|
||||
{0, 0, true},
|
||||
{1, 1, true},
|
||||
{IsSigned ? static_cast<IntT>(-1) : 0,
|
||||
IsSigned ? static_cast<IntT>(-1) : 0, true},
|
||||
{Lim::lowest(), Lim::lowest(), true},
|
||||
{static_cast<double>(Lim::max()), Lim::max(), MaxIsRepresentable},
|
||||
{static_cast<double>(Lim::max()) + 1, Lim::max(), false},
|
||||
{static_cast<double>(Lim::max()) + 1024, Lim::max(), false},
|
||||
{nextafter(static_cast<double>(Lim::max()), INFINITY), Lim::max(), false},
|
||||
};
|
||||
for (TestCase TC : TestCases) {
|
||||
auto res = std::__clamp_to_integral<IntT>(TC.Input);
|
||||
assert(res == TC.Expect);
|
||||
if (TC.IsRepresentable) {
|
||||
auto other = static_cast<IntT>(std::trunc(TC.Input));
|
||||
assert(res == other);
|
||||
} else
|
||||
assert(res == Lim::min() || res == Lim::max());
|
||||
}
|
||||
}
|
||||
|
||||
template <class IntT>
|
||||
void test_float() {
|
||||
typedef std::numeric_limits<IntT> Lim;
|
||||
const bool MaxIsRepresentable = sizeof(IntT) < 4;
|
||||
((void)MaxIsRepresentable);
|
||||
const bool IsSigned = std::is_signed<IntT>::value;
|
||||
struct TestCase {
|
||||
float Input;
|
||||
IntT Expect;
|
||||
bool IsRepresentable;
|
||||
} TestCases[] = {
|
||||
{0, 0, true},
|
||||
{1, 1, true},
|
||||
{IsSigned ? static_cast<IntT>(-1) : 0,
|
||||
IsSigned ? static_cast<IntT>(-1) : 0, true},
|
||||
{Lim::lowest(), Lim::lowest(), true},
|
||||
{static_cast<float>(Lim::max()), Lim::max(), MaxIsRepresentable },
|
||||
{nextafter(static_cast<float>(Lim::max()), INFINITY), Lim::max(), false},
|
||||
};
|
||||
for (TestCase TC : TestCases) {
|
||||
auto res = std::__clamp_to_integral<IntT>(TC.Input);
|
||||
assert(res == TC.Expect);
|
||||
if (TC.IsRepresentable) {
|
||||
auto other = static_cast<IntT>(std::trunc(TC.Input));
|
||||
assert(res == other);
|
||||
} else
|
||||
assert(res == Lim::min() || res == Lim::max());
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
test<short>();
|
||||
test<unsigned short>();
|
||||
test<int>();
|
||||
test<unsigned>();
|
||||
test<long long>();
|
||||
test<unsigned long long>();
|
||||
test_float<short>();
|
||||
test_float<int>();
|
||||
test_float<long long>();
|
||||
}
|
||||
Reference in New Issue
Block a user