Chromium Code Reviews| Index: base/numerics/saturated_arithmetic.h |
| diff --git a/base/numerics/saturated_arithmetic.h b/base/numerics/saturated_arithmetic.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..e8f118bbee2b3247704d07fdd98e7596a2e592dc |
| --- /dev/null |
| +++ b/base/numerics/saturated_arithmetic.h |
| @@ -0,0 +1,100 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#ifndef BASE_NUMERICS_SATURATED_ARITHMETIC_H_ |
| +#define BASE_NUMERICS_SATURATED_ARITHMETIC_H_ |
| + |
| +#include <stdint.h> |
| + |
| +#include <limits> |
| + |
| +#include "base/compiler_specific.h" |
| + |
| +#if defined(ARCH_CPU_ARM_FAMILY) && defined(COMPILER_GCC) && __OPTIMIZE__ |
| + |
| +// If we're building ARM on GCC we replace the C++ versions with some |
| +// native ARM assembly for speed. |
| +#include "base/numerics/saturated_arithmetic_arm.h" |
| + |
| +#else |
| + |
| +namespace base { |
| + |
| +inline int32_t SaturatedAddition(int32_t a, int32_t b) { |
| + uint32_t ua = a; |
| + uint32_t ub = b; |
| + uint32_t result = ua + ub; |
| + |
| + // Can only overflow if the signed bit of the two values match. If the |
| + // signed bit of the result and one of the values differ it overflowed. |
| + // The branch compiles to a CMOVNS instruction on x86. |
| + if (~(ua ^ ub) & (result ^ ua) & (1 << 31)) |
| + return std::numeric_limits<int>::max() + (ua >> 31); |
| + |
| + return result; |
| +} |
| + |
| +inline int32_t SaturatedSubtraction(int32_t a, int32_t b) { |
| + uint32_t ua = a; |
| + uint32_t ub = b; |
| + uint32_t result = ua - ub; |
| + |
| + // Can only overflow if the signed bit of the two input values differ. If |
| + // the signed bit of the result and the first value differ it overflowed. |
| + // The branch compiles to a CMOVNS instruction on x86. |
| + if ((ua ^ ub) & (result ^ ua) & (1 << 31)) |
| + return std::numeric_limits<int>::max() + (ua >> 31); |
| + |
| + return result; |
| +} |
| + |
| +inline int32_t SaturatedNegative(int32_t a) { |
| + if (UNLIKELY(a == std::numeric_limits<int>::min())) |
| + return std::numeric_limits<int>::max(); |
| + return -a; |
| +} |
| + |
| +inline int GetMaxSaturatedSetResultForTesting(int fractional_shift) { |
| + // For C version the set function maxes out to max int, this differs from |
| + // the ARM asm version, see saturated_arithmetic_arm.h for the equivalent asm |
| + // version. |
| + return std::numeric_limits<int>::max(); |
| +} |
| + |
| +inline int GetMinSaturatedSetResultForTesting(int fractional_shift) { |
| + return std::numeric_limits<int>::min(); |
| +} |
| + |
| +template <int fractional_shift> |
| +inline int SaturatedSet(int value) { |
| + const int kIntMaxForLayoutUnit = |
|
esprehn
2016/11/14 22:26:06
Should probably give these better names not specif
|
| + std::numeric_limits<int>::max() >> fractional_shift; |
| + |
| + const int kIntMinForLayoutUnit = |
| + std::numeric_limits<int>::min() >> fractional_shift; |
| + |
| + if (value > kIntMaxForLayoutUnit) |
| + return std::numeric_limits<int>::max(); |
| + |
| + if (value < kIntMinForLayoutUnit) |
| + return std::numeric_limits<int>::min(); |
| + |
| + return value << fractional_shift; |
| +} |
| + |
| +template <int fractional_shift> |
| +inline int SaturatedSet(unsigned value) { |
| + const unsigned kIntMaxForLayoutUnit = |
| + std::numeric_limits<int>::max() >> fractional_shift; |
| + |
| + if (value >= kIntMaxForLayoutUnit) |
| + return std::numeric_limits<int>::max(); |
| + |
| + return value << fractional_shift; |
| +} |
| + |
| +} // namespace base |
| + |
| +#endif // CPU(ARM) && COMPILER(GCC) |
| +#endif // BASE_NUMERICS_SATURATED_ARITHMETIC_H_ |