| Index: Source/wtf/MathExtras.h
|
| diff --git a/Source/wtf/MathExtras.h b/Source/wtf/MathExtras.h
|
| index 5925ca5e89a1d96dfb6fa34b9908ce9d10ee32f2..808ff9050d0774a024d8510d8e6e3f3cecf335e6 100644
|
| --- a/Source/wtf/MathExtras.h
|
| +++ b/Source/wtf/MathExtras.h
|
| @@ -26,12 +26,13 @@
|
| #ifndef WTF_MathExtras_h
|
| #define WTF_MathExtras_h
|
|
|
| +#include "wtf/Assertions.h"
|
| #include "wtf/CPU.h"
|
| +#include <algorithm>
|
| #include <cmath>
|
| #include <limits>
|
|
|
| #if COMPILER(MSVC)
|
| -#include "wtf/Assertions.h"
|
| #include <stdint.h>
|
| #endif
|
|
|
| @@ -222,54 +223,147 @@ inline float grad2rad(float g) { return g * piFloat / 200.0f; }
|
| inline float turn2grad(float t) { return t * 400; }
|
| inline float grad2turn(float g) { return g / 400; }
|
|
|
| -// std::numeric_limits<T>::min() returns the smallest positive value for floating point types
|
| -template<typename T> inline T defaultMinimumForClamp() { return std::numeric_limits<T>::min(); }
|
| -template<> inline float defaultMinimumForClamp() { return -std::numeric_limits<float>::max(); }
|
| -template<> inline double defaultMinimumForClamp() { return -std::numeric_limits<double>::max(); }
|
| -template<typename T> inline T defaultMaximumForClamp() { return std::numeric_limits<T>::max(); }
|
| +// clampTo() is implemented by templated helper classes (to allow for partial
|
| +// template specialization) as well as several helper functions.
|
|
|
| -template<typename T> inline T clampTo(double value, T min = defaultMinimumForClamp<T>(), T max = defaultMaximumForClamp<T>())
|
| +// This helper function can be called when we know that:
|
| +// (1) The type signednesses match so the compiler will not produce signed vs.
|
| +// unsigned warnings
|
| +// (2) The default type promotions/conversions are sufficient to handle things
|
| +// correctly
|
| +template<typename LimitType, typename ValueType> inline LimitType clampToDirectComparison(ValueType value, LimitType min, LimitType max)
|
| {
|
| - if (value >= static_cast<double>(max))
|
| + if (value >= max)
|
| return max;
|
| - if (value <= static_cast<double>(min))
|
| - return min;
|
| - return static_cast<T>(value);
|
| + return (value <= min) ? min : static_cast<LimitType>(value);
|
| }
|
| -template<> inline long long int clampTo(double, long long int, long long int); // clampTo does not support long long ints.
|
|
|
| -inline int clampToInteger(double value)
|
| -{
|
| - return clampTo<int>(value);
|
| -}
|
| -
|
| -inline unsigned clampToUnsigned(double value)
|
| -{
|
| - return clampTo<unsigned>(value);
|
| -}
|
| -
|
| -inline float clampToFloat(double value)
|
| -{
|
| - return clampTo<float>(value);
|
| -}
|
| -
|
| -inline int clampToPositiveInteger(double value)
|
| -{
|
| - return clampTo<int>(value, 0);
|
| -}
|
| +// For any floating-point limits, or integral limits smaller than long long, we
|
| +// can cast the limits to double without losing precision; then the only cases
|
| +// where |value| can't be represented accurately as a double are the ones where
|
| +// it's outside the limit range anyway. So doing all comparisons as doubles
|
| +// will give correct results.
|
| +//
|
| +// In some cases, we can get better performance by using
|
| +// clampToDirectComparison(). We use a templated class to switch between these
|
| +// two cases (instead of simply using a conditional within one function) in
|
| +// order to only compile the clampToDirectComparison() code for cases where it
|
| +// will actually be used; this prevents the compiler from emitting warnings
|
| +// about unsafe code (even though we wouldn't actually be executing that code).
|
| +template<bool canUseDirectComparison, typename LimitType, typename ValueType> class ClampToNonLongLongHelper;
|
| +template<typename LimitType, typename ValueType> class ClampToNonLongLongHelper<true, LimitType, ValueType> {
|
| +public:
|
| + static inline LimitType clampTo(ValueType value, LimitType min, LimitType max)
|
| + {
|
| + return clampToDirectComparison(value, min, max);
|
| + }
|
| +};
|
| +
|
| +template<typename LimitType, typename ValueType> class ClampToNonLongLongHelper<false, LimitType, ValueType> {
|
| +public:
|
| + static inline LimitType clampTo(ValueType value, LimitType min, LimitType max)
|
| + {
|
| + const double doubleValue = static_cast<double>(value);
|
| + if (doubleValue >= static_cast<double>(max))
|
| + return max;
|
| + if (doubleValue <= static_cast<double>(min))
|
| + return min;
|
| + // If the limit type is integer, we might get better performance by
|
| + // casting |value| (as opposed to |doubleValue|) to the limit type.
|
| + return std::numeric_limits<LimitType>::is_integer ? static_cast<LimitType>(value) : static_cast<LimitType>(doubleValue);
|
| + }
|
| +};
|
| +
|
| +// The unspecialized version of this templated class handles clamping to
|
| +// anything other than [unsigned] long long int limits. It simply uses the
|
| +// class above to toggle between the "fast" and "safe" clamp implementations.
|
| +template<typename LimitType, typename ValueType> class ClampToHelper {
|
| +public:
|
| + static inline LimitType clampTo(ValueType value, LimitType min, LimitType max)
|
| + {
|
| + // We only use clampToDirectComparison() when the integerness and
|
| + // signedness of the two types matches.
|
| + //
|
| + // If the integerness of the types doesn't match, then at best
|
| + // clampToDirectComparison() won't be much more efficient than the
|
| + // cast-everything-to-double method, since we'll need to convert to
|
| + // floating point anyway; at worst, we risk incorrect results when
|
| + // clamping a float to a 32-bit integral type due to potential precision
|
| + // loss.
|
| + //
|
| + // If the signedness doesn't match, clampToDirectComparison() will
|
| + // produce warnings about comparing signed vs. unsigned, which are apt
|
| + // since negative signed values will be converted to large unsigned ones
|
| + // and we'll get incorrect results.
|
| + return ClampToNonLongLongHelper<std::numeric_limits<LimitType>::is_integer == std::numeric_limits<ValueType>::is_integer && std::numeric_limits<LimitType>::is_signed == std::numeric_limits<ValueType>::is_signed, LimitType, ValueType>::clampTo(value, min, max);
|
| + }
|
| +};
|
| +
|
| +// Clamping to [unsigned] long long int limits requires more care. These may
|
| +// not be accurately representable as doubles, so instead we cast |value| to the
|
| +// limit type. But that cast is undefined if |value| is floating point and
|
| +// outside the representable range of the limit type, so we also have to check
|
| +// for that case explicitly.
|
| +template<typename ValueType> class ClampToHelper<long long int, ValueType> {
|
| +public:
|
| + static inline long long int clampTo(ValueType value, long long int min, long long int max)
|
| + {
|
| + if (!std::numeric_limits<ValueType>::is_integer) {
|
| + if (value > 0) {
|
| + if (static_cast<double>(value) >= static_cast<double>(std::numeric_limits<long long int>::max()))
|
| + return max;
|
| + } else if (static_cast<double>(value) <= static_cast<double>(std::numeric_limits<long long int>::min())) {
|
| + return min;
|
| + }
|
| + }
|
| + // Note: If |value| were unsigned long long int, it could be larger than
|
| + // the largest long long int, and this code would be wrong; we handle
|
| + // this case with a separate full specialization below.
|
| + return clampToDirectComparison(static_cast<long long int>(value), min, max);
|
| + }
|
| +};
|
| +
|
| +// This specialization handles the case where the above partial specialization
|
| +// would be potentially incorrect.
|
| +template<> class ClampToHelper<long long int, unsigned long long int> {
|
| +public:
|
| + static inline long long int clampTo(unsigned long long int value, long long int min, long long int max)
|
| + {
|
| + if (max <= 0 || value >= static_cast<unsigned long long int>(max))
|
| + return max;
|
| + const long long int longLongValue = static_cast<long long int>(value);
|
| + return (longLongValue <= min) ? min : longLongValue;
|
| + }
|
| +};
|
| +
|
| +// This is similar to the partial specialization that clamps to long long int,
|
| +// but because the lower-bound check is done for integer value types as well, we
|
| +// don't need a <unsigned long long int, long long int> full specialization.
|
| +template<typename ValueType> class ClampToHelper<unsigned long long int, ValueType> {
|
| +public:
|
| + static inline unsigned long long int clampTo(ValueType value, unsigned long long int min, unsigned long long int max)
|
| + {
|
| + if (value <= 0)
|
| + return min;
|
| + if (!std::numeric_limits<ValueType>::is_integer) {
|
| + if (static_cast<double>(value) >= static_cast<double>(std::numeric_limits<unsigned long long int>::max()))
|
| + return max;
|
| + }
|
| + return clampToDirectComparison(static_cast<unsigned long long int>(value), min, max);
|
| + }
|
| +};
|
|
|
| -inline int clampToInteger(float value)
|
| -{
|
| - return clampTo<int>(value);
|
| -}
|
| +// This basically reimplements C++11's std::numeric_limits<T>::lowest().
|
| +template<typename T> inline T defaultMinimumForClamp() { return std::numeric_limits<T>::min(); }
|
| +template<> inline float defaultMinimumForClamp<float>() { return -std::numeric_limits<float>::max(); }
|
| +template<> inline double defaultMinimumForClamp<double>() { return -std::numeric_limits<double>::max(); }
|
|
|
| -inline int clampToInteger(unsigned x)
|
| +// And, finally, the actual function for people to call.
|
| +template<typename LimitType, typename ValueType> inline LimitType clampTo(ValueType value, LimitType min = defaultMinimumForClamp<LimitType>(), LimitType max = std::numeric_limits<LimitType>::max())
|
| {
|
| - const unsigned intMax = static_cast<unsigned>(std::numeric_limits<int>::max());
|
| -
|
| - if (x >= intMax)
|
| - return std::numeric_limits<int>::max();
|
| - return static_cast<int>(x);
|
| + ASSERT(!std::isnan(static_cast<double>(value)));
|
| + ASSERT(min <= max); // This also ensures |min| and |max| aren't NaN.
|
| + return ClampToHelper<LimitType, ValueType>::clampTo(value, min, max);
|
| }
|
|
|
| inline bool isWithinIntRange(float x)
|
|
|