Chromium Code Reviews| Index: base/safe_numerics_impl.h |
| =================================================================== |
| --- base/safe_numerics_impl.h (revision 0) |
| +++ base/safe_numerics_impl.h (revision 0) |
| @@ -0,0 +1,134 @@ |
| +// Copyright 2014 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_SAFE_NUMERICS_IMPL_H_ |
| +#define BASE_SAFE_NUMERICS_IMPL_H_ |
| + |
| +#include <limits> |
| + |
| +#include "base/macros.h" |
| + |
| +namespace base { |
| +namespace internal { |
| + |
| +// Helper templates to determine if our destination type can contain all values |
| +// represented by the source type. |
| + |
| +template<typename Dest, |
|
akalin
2014/01/14 00:49:19
nit: space before <
jschuh
2014/01/14 05:24:33
Done.
|
| + typename Source, |
| + bool IsDestSigned = std::numeric_limits<Dest>::is_signed, |
|
akalin
2014/01/14 00:49:19
perhaps define enums for DestSigned and SourceSign
jschuh
2014/01/14 05:24:33
Done.
|
| + bool IsSourceSigned = std::numeric_limits<Source>::is_signed> |
| +struct DoesRangeContainRange {}; |
| + |
| +template<typename Dest, typename Source, bool IsSigned> |
|
akalin
2014/01/14 00:49:19
doesn't look like this overload is used. remove?
jschuh
2014/01/14 05:24:33
It caught the case where the signs matched, but I
|
| +struct DoesRangeContainRange<Dest, Source, IsSigned, IsSigned> { |
| + // We always treat float to integral as narrowing. |
| + static const bool value = std::numeric_limits<Dest>::is_integer && |
|
akalin
2014/01/14 00:49:19
maybe use an enum for this, too? e.g. CONTAINS_RAN
jschuh
2014/01/14 05:24:33
Done.
|
| + sizeof(Dest) >= sizeof(Source); |
| +}; |
| + |
| +template<typename Dest, typename Source> |
| +struct DoesRangeContainRange<Dest, Source, true, false> { |
| + // We always treat float to integral as narrowing. |
| + static const bool value = std::numeric_limits<Dest>::is_integer && |
| + sizeof(Dest) > sizeof(Source); |
| +}; |
| + |
| +template<typename Dest, typename Source> |
| +struct DoesRangeContainRange<Dest, Source, false, true> { |
| + static const bool value = false; |
| +}; |
| + |
| + |
| +// The following templates are for ranges that must be verified at runtime. We |
| +// split it into checks based on signedness to avoid confusing casts and |
| +// compiler warnings on signed an unsigned comparisons. |
| + |
| +enum NumericRangeCheckResult { |
| + TYPE_VALID = 0, // Value can be represented by the destination type. |
| + TYPE_UNDERFLOW = 1, // Value would overflow. |
| + TYPE_OVERFLOW = 2, // Value would underflow. |
| + TYPE_INVALID = 3 // Source value is invalid (i.e. NaN). |
| +}; |
| + |
| +// This macro creates a NumericRangeCheckResult from an upper and lower bound |
| +// check by taking advantage of the fact that only NaN can be out of range in |
| +// both directions at once. |
| +#define BASE_NUMERIC_RANGE_CHECK_RESULT(is_in_upper_bound, is_in_lower_bound) \ |
| + NumericRangeCheckResult(((is_in_upper_bound) ? 0 : TYPE_OVERFLOW) | \ |
| + ((is_in_lower_bound) ? 0 : TYPE_UNDERFLOW)) |
| + |
| +template<typename Dest, |
| + typename Source, |
| + bool IsDestSigned = std::numeric_limits<Dest>::is_signed, |
| + bool IsSourceSigned = std::numeric_limits<Source>::is_signed, |
| + bool DoesDestRangeContainSourceRange = DoesRangeContainRange<Dest, |
| + Source>::value> |
| +struct NumericRangeCheckImpl {}; |
| + |
| +// Dest range always contains the result: nothing to check. |
| +template<typename Dest, typename Source, bool IsDestSigned, bool IsSourceSigned> |
| +struct NumericRangeCheckImpl<Dest, Source, IsDestSigned, IsSourceSigned, true> { |
| + static NumericRangeCheckResult run(Source) { |
|
akalin
2014/01/14 00:49:19
would name this Check() myself
akalin
2014/01/14 00:49:19
I'd prefer (Source x), even though you don't use x
|
| + return BASE_NUMERIC_RANGE_CHECK_RESULT(true, true); |
| + } |
| +}; |
| + |
| +// Signed to signed narrowing. |
| +template<typename Dest, typename Source> |
| +struct NumericRangeCheckImpl<Dest, Source, true, true, false> { |
| + static NumericRangeCheckResult run(Source x) { |
| + typedef std::numeric_limits<Dest> DestLimits; |
| + return BASE_NUMERIC_RANGE_CHECK_RESULT(x <= DestLimits::max(), |
| + x >= DestLimits::min()); |
| + } |
| +}; |
| + |
| +// Unsigned to unsigned narrowing. |
| +template<typename Dest, typename Source> |
| +struct NumericRangeCheckImpl<Dest, Source, false, false, false> { |
| + static NumericRangeCheckResult run(Source x) { |
| + typedef std::numeric_limits<Dest> DestLimits; |
| + return BASE_NUMERIC_RANGE_CHECK_RESULT(x <= DestLimits::max(), true); |
| + } |
| +}; |
| + |
| +// Unsigned to signed. |
| +template<typename Dest, typename Source> |
| +struct NumericRangeCheckImpl<Dest, Source, true, false, false> { |
| + static NumericRangeCheckResult run(Source x) { |
| + typedef std::numeric_limits<Dest> DestLimits; |
| + return sizeof(Dest) >= sizeof(Source) ? |
| + BASE_NUMERIC_RANGE_CHECK_RESULT(true, true) : |
| + BASE_NUMERIC_RANGE_CHECK_RESULT(x <= Source(DestLimits::max()), true); |
| + } |
| +}; |
| + |
| +// Signed to unsigned. |
| +template<typename Dest, typename Source> |
| +struct NumericRangeCheckImpl<Dest, Source, false, true, false> { |
| + static NumericRangeCheckResult run(Source x) { |
| + typedef std::numeric_limits<Dest> DestLimits; |
| + return sizeof(Dest) >= sizeof(Source) ? |
| + BASE_NUMERIC_RANGE_CHECK_RESULT(true, x >= 0) : |
| + BASE_NUMERIC_RANGE_CHECK_RESULT(x <= Source(DestLimits::max()), x >= 0); |
| + } |
| +}; |
| + |
| +template<typename Dest, typename Source> |
| +inline NumericRangeCheckResult NumericRangeCheck(Source x) { |
| + COMPILE_ASSERT(std::numeric_limits<Source>::is_specialized, |
| + argument_must_be_numeric); |
| + COMPILE_ASSERT(std::numeric_limits<Dest>::is_specialized, |
| + argument_must_be_numeric); |
| + COMPILE_ASSERT(std::numeric_limits<Dest>::is_integer, |
| + result_must_be_integral); |
| + return NumericRangeCheckImpl<Dest, Source>::run(x); |
| +} |
| + |
| +} // namespace internal |
| +} // namespace base |
| + |
| +#endif // BASE_SAFE_NUMERICS_IMPL_H_ |
| + |
| Property changes on: base\safe_numerics_impl.h |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| + LF |