diff options
Diffstat (limited to 'Source/WTF/wtf/MathExtras.h')
-rw-r--r-- | Source/WTF/wtf/MathExtras.h | 184 |
1 files changed, 124 insertions, 60 deletions
diff --git a/Source/WTF/wtf/MathExtras.h b/Source/WTF/wtf/MathExtras.h index 716f512e8..948c48ffa 100644 --- a/Source/WTF/wtf/MathExtras.h +++ b/Source/WTF/wtf/MathExtras.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2013, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -69,17 +69,10 @@ const float piOverFourFloat = static_cast<float>(M_PI_4); #ifndef M_SQRT2 const double sqrtOfTwoDouble = 1.41421356237309504880; +const float sqrtOfTwoFloat = 1.41421356237309504880f; #else const double sqrtOfTwoDouble = M_SQRT2; -#endif - -#if OS(DARWIN) - -// Work around a bug in the Mac OS X libc where ceil(-0.1) return +0. -inline double wtf_ceil(double x) { return copysign(ceil(x), x); } - -#define ceil(x) wtf_ceil(x) - +const float sqrtOfTwoFloat = static_cast<float>(M_SQRT2); #endif #if OS(SOLARIS) @@ -100,21 +93,6 @@ inline bool isinf(double x) { return !finite(x) && !isnand(x); } #endif -#if OS(OPENBSD) - -namespace std { - -#ifndef isfinite -inline bool isfinite(double x) { return finite(x); } -#endif -#ifndef signbit -inline bool signbit(double x) { struct ieee_double *p = (struct ieee_double *)&x; return p->dbl_sign; } -#endif - -} // namespace std - -#endif - #if COMPILER(MSVC) // Work around a bug in Win, where atan2(+-infinity, +-infinity) yields NaN instead of specific values. @@ -140,37 +118,7 @@ extern "C" inline double wtf_atan2(double x, double y) return result; } -// Work around a bug in the Microsoft CRT, where fmod(x, +-infinity) yields NaN instead of x. -extern "C" inline double wtf_fmod(double x, double y) { return (!std::isinf(x) && std::isinf(y)) ? x : fmod(x, y); } - -// Work around a bug in the Microsoft CRT, where pow(NaN, 0) yields NaN instead of 1. -extern "C" inline double wtf_pow(double x, double y) { return y == 0 ? 1 : pow(x, y); } - #define atan2(x, y) wtf_atan2(x, y) -#define fmod(x, y) wtf_fmod(x, y) -#define pow(x, y) wtf_pow(x, y) - -// MSVC's math functions do not bring lrint. -inline long int lrint(double flt) -{ - int64_t intgr; -#if CPU(X86) - __asm { - fld flt - fistp intgr - }; -#else - ASSERT(std::isfinite(flt)); - double rounded = round(flt); - intgr = static_cast<int64_t>(rounded); - // If the fractional part is exactly 0.5, we need to check whether - // the rounded result is even. If it is not we need to add 1 to - // negative values and subtract one from positive values. - if ((fabs(intgr - flt) == 0.5) & intgr) - intgr -= ((intgr >> 62) | 1); // 1 with the sign of result, i.e. -1 or 1. -#endif - return static_cast<long int>(intgr); -} #endif // COMPILER(MSVC) @@ -233,9 +181,12 @@ inline int clampToInteger(float value) return clampTo<int>(value); } -inline int clampToInteger(unsigned x) +template<typename T> +inline int clampToInteger(T x) { - const unsigned intMax = static_cast<unsigned>(std::numeric_limits<int>::max()); + static_assert(std::numeric_limits<T>::is_integer, "T must be an integer."); + + const T intMax = static_cast<unsigned>(std::numeric_limits<int>::max()); if (x >= intMax) return std::numeric_limits<int>::max(); @@ -247,6 +198,15 @@ inline bool isWithinIntRange(float x) return x > static_cast<float>(std::numeric_limits<int>::min()) && x < static_cast<float>(std::numeric_limits<int>::max()); } +inline float normalizedFloat(float value) +{ + if (value > 0 && value < std::numeric_limits<float>::min()) + return std::numeric_limits<float>::min(); + if (value < 0 && value > -std::numeric_limits<float>::min()) + return -std::numeric_limits<float>::min(); + return value; +} + template<typename T> inline bool hasOneBitSet(T value) { return !((value - 1) & value) && value; @@ -264,9 +224,11 @@ template<typename T> inline bool hasTwoOrMoreBitsSet(T value) template <typename T> inline unsigned getLSBSet(T value) { + typedef typename std::make_unsigned<T>::type UnsignedT; unsigned result = 0; - while (value >>= 1) + UnsignedT unsignedValue = static_cast<UnsignedT>(value); + while (unsignedValue >>= 1) ++result; return result; @@ -412,6 +374,108 @@ inline unsigned fastLog2(unsigned i) return log2; } +inline unsigned fastLog2(uint64_t value) +{ + unsigned high = static_cast<unsigned>(value >> 32); + if (high) + return fastLog2(high) + 32; + return fastLog2(static_cast<unsigned>(value)); +} + +template <typename T> +inline typename std::enable_if<std::is_floating_point<T>::value, T>::type safeFPDivision(T u, T v) +{ + // Protect against overflow / underflow. + if (v < 1 && u > v * std::numeric_limits<T>::max()) + return std::numeric_limits<T>::max(); + if (v > 1 && u < v * std::numeric_limits<T>::min()) + return 0; + return u / v; +} + +// Floating point numbers comparison: +// u is "essentially equal" [1][2] to v if: | u - v | / |u| <= e and | u - v | / |v| <= e +// +// [1] Knuth, D. E. "Accuracy of Floating Point Arithmetic." The Art of Computer Programming. 3rd ed. Vol. 2. +// Boston: Addison-Wesley, 1998. 229-45. +// [2] http://www.boost.org/doc/libs/1_34_0/libs/test/doc/components/test_tools/floating_point_comparison.html +template <typename T> +inline typename std::enable_if<std::is_floating_point<T>::value, bool>::type areEssentiallyEqual(T u, T v, T epsilon = std::numeric_limits<T>::epsilon()) +{ + if (u == v) + return true; + + const T delta = std::abs(u - v); + return safeFPDivision(delta, std::abs(u)) <= epsilon && safeFPDivision(delta, std::abs(v)) <= epsilon; +} + +// Match behavior of Math.min, where NaN is returned if either argument is NaN. +template <typename T> +inline typename std::enable_if<std::is_floating_point<T>::value, T>::type nanPropagatingMin(T a, T b) +{ + return std::isnan(a) || std::isnan(b) ? std::numeric_limits<T>::quiet_NaN() : std::min(a, b); +} + +// Match behavior of Math.max, where NaN is returned if either argument is NaN. +template <typename T> +inline typename std::enable_if<std::is_floating_point<T>::value, T>::type nanPropagatingMax(T a, T b) +{ + return std::isnan(a) || std::isnan(b) ? std::numeric_limits<T>::quiet_NaN() : std::max(a, b); +} + +inline bool isIntegral(float value) +{ + return static_cast<int>(value) == value; +} + +template<typename T> +inline void incrementWithSaturation(T& value) +{ + if (value != std::numeric_limits<T>::max()) + value++; +} + +template<typename T> +inline T leftShiftWithSaturation(T value, unsigned shiftAmount, T max = std::numeric_limits<T>::max()) +{ + T result = value << shiftAmount; + // We will have saturated if shifting right doesn't recover the original value. + if (result >> shiftAmount != value) + return max; + if (result > max) + return max; + return result; +} + +// Check if two ranges overlap assuming that neither range is empty. +template<typename T> +inline bool nonEmptyRangesOverlap(T leftMin, T leftMax, T rightMin, T rightMax) +{ + ASSERT(leftMin < leftMax); + ASSERT(rightMin < rightMax); + + return leftMax > rightMin && rightMax > leftMin; +} + +// Pass ranges with the min being inclusive and the max being exclusive. For example, this should +// return false: +// +// rangesOverlap(0, 8, 8, 16) +template<typename T> +inline bool rangesOverlap(T leftMin, T leftMax, T rightMin, T rightMax) +{ + ASSERT(leftMin <= leftMax); + ASSERT(rightMin <= rightMax); + + // Empty ranges interfere with nothing. + if (leftMin == leftMax) + return false; + if (rightMin == rightMax) + return false; + + return nonEmptyRangesOverlap(leftMin, leftMax, rightMin, rightMax); +} + } // namespace WTF #endif // #ifndef WTF_MathExtras_h |