#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
const double twoPiDouble = piDouble * 2.0;
const float twoPiFloat = piFloat * 2.0f;
-#if OS(MACOSX)
-
-// 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)
-
-#endif
-
#if OS(OPENBSD)
namespace std {
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);
-}
+template<typename T> inline T defaultMaximumForClamp() { return std::numeric_limits<T>::max(); }
+// 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 = defaultMaximumForClamp<LimitType>())
{
- 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)