/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* mfbt maths algorithms. */ #ifndef mozilla_MathAlgorithms_h_ #define mozilla_MathAlgorithms_h_ #include "mozilla/Assertions.h" #include "mozilla/StandardInteger.h" #include "mozilla/TypeTraits.h" #include #include namespace mozilla { // Greatest Common Divisor template MOZ_ALWAYS_INLINE IntegerType EuclidGCD(IntegerType a, IntegerType b) { // Euclid's algorithm; O(N) in the worst case. (There are better // ways, but we don't need them for the current use of this algo.) MOZ_ASSERT(a > 0); MOZ_ASSERT(b > 0); while (a != b) { if (a > b) { a = a - b; } else { b = b - a; } } return a; } // Least Common Multiple template MOZ_ALWAYS_INLINE IntegerType EuclidLCM(IntegerType a, IntegerType b) { // Divide first to reduce overflow risk. return (a / EuclidGCD(a, b)) * b; } namespace detail { template struct AllowDeprecatedAbsFixed : FalseType {}; template<> struct AllowDeprecatedAbsFixed : TrueType {}; template<> struct AllowDeprecatedAbsFixed : TrueType {}; template struct AllowDeprecatedAbs : AllowDeprecatedAbsFixed {}; template<> struct AllowDeprecatedAbs : TrueType {}; template<> struct AllowDeprecatedAbs : TrueType {}; } // namespace detail // DO NOT USE DeprecatedAbs. It exists only until its callers can be converted // to Abs below, and it will be removed when all callers have been changed. template inline typename mozilla::EnableIf::value, T>::Type DeprecatedAbs(const T t) { // The absolute value of the smallest possible value of a signed-integer type // won't fit in that type (on twos-complement systems -- and we're blithely // assuming we're on such systems, for the non- types listed above), // so assert that the input isn't that value. // // This is the case if: the value is non-negative; or if adding one (giving a // value in the range [-maxvalue, 0]), then negating (giving a value in the // range [0, maxvalue]), doesn't produce maxvalue (because in twos-complement, // (minvalue + 1) == -maxvalue). MOZ_ASSERT(t >= 0 || -(t + 1) != T((1ULL << (CHAR_BIT * sizeof(T) - 1)) - 1), "You can't negate the smallest possible negative integer!"); return t >= 0 ? t : -t; } namespace detail { // For now mozilla::Abs only takes intN_T, the signed natural types, and // float/double/long double. Feel free to add overloads for other standard, // signed types if you need them. template struct AbsReturnTypeFixed; template<> struct AbsReturnTypeFixed { typedef uint8_t Type; }; template<> struct AbsReturnTypeFixed { typedef uint16_t Type; }; template<> struct AbsReturnTypeFixed { typedef uint32_t Type; }; template<> struct AbsReturnTypeFixed { typedef uint64_t Type; }; template struct AbsReturnType : AbsReturnTypeFixed {}; template<> struct AbsReturnType : EnableIf {}; template<> struct AbsReturnType { typedef unsigned char Type; }; template<> struct AbsReturnType { typedef unsigned short Type; }; template<> struct AbsReturnType { typedef unsigned int Type; }; template<> struct AbsReturnType { typedef unsigned long Type; }; template<> struct AbsReturnType { typedef unsigned long long Type; }; template<> struct AbsReturnType { typedef float Type; }; template<> struct AbsReturnType { typedef double Type; }; template<> struct AbsReturnType { typedef long double Type; }; } // namespace detail template inline typename detail::AbsReturnType::Type Abs(const T t) { typedef typename detail::AbsReturnType::Type ReturnType; return t >= 0 ? ReturnType(t) : ~ReturnType(t) + 1; } template<> inline float Abs(const float f) { return std::fabs(f); } template<> inline double Abs(const double d) { return std::fabs(d); } template<> inline long double Abs(const long double d) { return std::fabs(d); } } /* namespace mozilla */ #endif /* mozilla_MathAlgorithms_h_ */