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..f62a0200765fc702dbc6bf85a8b20ea121dd4366 |
| --- /dev/null |
| +++ b/base/numerics/saturated_arithmetic.h |
| @@ -0,0 +1,98 @@ |
| +// 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 <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 FractionalShift> |
|
danakj
2016/11/12 02:03:19
nit: should be kFractionalShift? or fractional_shi
|
| +inline int SaturatedSet(int value) { |
| + const int kIntMaxForLayoutUnit = |
| + std::numeric_limits<int>::max() >> FractionalShift; |
| + |
| + const int kIntMinForLayoutUnit = |
| + std::numeric_limits<int>::min() >> FractionalShift; |
| + |
| + if (value > kIntMaxForLayoutUnit) |
| + return std::numeric_limits<int>::max(); |
| + |
| + if (value < kIntMinForLayoutUnit) |
| + return std::numeric_limits<int>::min(); |
| + |
| + return value << FractionalShift; |
| +} |
| + |
| +template <int FractionalShift> |
| +inline int SaturatedSet(unsigned value) { |
| + const unsigned kIntMaxForLayoutUnit = |
| + std::numeric_limits<int>::max() >> FractionalShift; |
| + |
| + if (value >= kIntMaxForLayoutUnit) |
| + return std::numeric_limits<int>::max(); |
| + |
| + return value << FractionalShift; |
| +} |
| + |
| +} // namespace base |
| + |
| +#endif // CPU(ARM) && COMPILER(GCC) |
| +#endif // BASE_NUMERICS_SATURATED_ARITHMETIC_H_ |