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 |