Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(693)

Side by Side Diff: base/safe_numerics.h

Issue 131063002: Expand support in safe_numeric.h (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Ready for review Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | base/safe_numerics_impl.h » ('j') | base/safe_numerics_impl.h » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef BASE_SAFE_NUMERICS_H_ 5 #ifndef BASE_SAFE_NUMERICS_H_
6 #define BASE_SAFE_NUMERICS_H_ 6 #define BASE_SAFE_NUMERICS_H_
7 7
8 #include <limits> 8 #include <limits>
9 9
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/safe_numerics_impl.h"
11 12
12 namespace base { 13 namespace base {
13 namespace internal {
14 14
15 template <bool SameSize, bool DestLarger, 15 // Convenience function that returns true if the supplied value is in range
16 bool DestIsSigned, bool SourceIsSigned> 16 // for the destination type.
17 struct IsValidNumericCastImpl; 17 template <typename Dst, typename Src>
18 18 inline bool IsValueInRangeForNumericType(Src value) {
19 #define BASE_NUMERIC_CAST_CASE_SPECIALIZATION(A, B, C, D, Code) \ 19 return internal::RangeCheck<Dst>(value) == internal::TYPE_VALID;
20 template <> struct IsValidNumericCastImpl<A, B, C, D> { \
21 template <class Source, class DestBounds> static inline bool Test( \
22 Source source, DestBounds min, DestBounds max) { \
23 return Code; \
24 } \
25 } 20 }
26 21
27 #define BASE_NUMERIC_CAST_CASE_SAME_SIZE(DestSigned, SourceSigned, Code) \
28 BASE_NUMERIC_CAST_CASE_SPECIALIZATION( \
29 true, true, DestSigned, SourceSigned, Code); \
30 BASE_NUMERIC_CAST_CASE_SPECIALIZATION( \
31 true, false, DestSigned, SourceSigned, Code)
32
33 #define BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(DestSigned, SourceSigned, Code) \
34 BASE_NUMERIC_CAST_CASE_SPECIALIZATION( \
35 false, false, DestSigned, SourceSigned, Code); \
36
37 #define BASE_NUMERIC_CAST_CASE_DEST_LARGER(DestSigned, SourceSigned, Code) \
38 BASE_NUMERIC_CAST_CASE_SPECIALIZATION( \
39 false, true, DestSigned, SourceSigned, Code); \
40
41 // The three top level cases are:
42 // - Same size
43 // - Source larger
44 // - Dest larger
45 // And for each of those three cases, we handle the 4 different possibilities
46 // of signed and unsigned. This gives 12 cases to handle, which we enumerate
47 // below.
48 //
49 // The last argument in each of the macros is the actual comparison code. It
50 // has three arguments available, source (the value), and min/max which are
51 // the ranges of the destination.
52
53
54 // These are the cases where both types have the same size.
55
56 // Both signed.
57 BASE_NUMERIC_CAST_CASE_SAME_SIZE(true, true, true);
58 // Both unsigned.
59 BASE_NUMERIC_CAST_CASE_SAME_SIZE(false, false, true);
60 // Dest unsigned, Source signed.
61 BASE_NUMERIC_CAST_CASE_SAME_SIZE(false, true, source >= 0);
62 // Dest signed, Source unsigned.
63 // This cast is OK because Dest's max must be less than Source's.
64 BASE_NUMERIC_CAST_CASE_SAME_SIZE(true, false,
65 source <= static_cast<Source>(max));
66
67
68 // These are the cases where Source is larger.
69
70 // Both unsigned.
71 BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(false, false, source <= max);
72 // Both signed.
73 BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(true, true,
74 source >= min && source <= max);
75 // Dest is unsigned, Source is signed.
76 BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(false, true,
77 source >= 0 && source <= max);
78 // Dest is signed, Source is unsigned.
79 // This cast is OK because Dest's max must be less than Source's.
80 BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(true, false,
81 source <= static_cast<Source>(max));
82
83
84 // These are the cases where Dest is larger.
85
86 // Both unsigned.
87 BASE_NUMERIC_CAST_CASE_DEST_LARGER(false, false, true);
88 // Both signed.
89 BASE_NUMERIC_CAST_CASE_DEST_LARGER(true, true, true);
90 // Dest is unsigned, Source is signed.
91 BASE_NUMERIC_CAST_CASE_DEST_LARGER(false, true, source >= 0);
92 // Dest is signed, Source is unsigned.
93 BASE_NUMERIC_CAST_CASE_DEST_LARGER(true, false, true);
94
95 #undef BASE_NUMERIC_CAST_CASE_SPECIALIZATION
96 #undef BASE_NUMERIC_CAST_CASE_SAME_SIZE
97 #undef BASE_NUMERIC_CAST_CASE_SOURCE_LARGER
98 #undef BASE_NUMERIC_CAST_CASE_DEST_LARGER
99
100
101 // The main test for whether the conversion will under or overflow.
102 template <class Dest, class Source>
103 inline bool IsValidNumericCast(Source source) {
104 typedef std::numeric_limits<Source> SourceLimits;
105 typedef std::numeric_limits<Dest> DestLimits;
106 COMPILE_ASSERT(SourceLimits::is_specialized, argument_must_be_numeric);
107 COMPILE_ASSERT(SourceLimits::is_integer, argument_must_be_integral);
108 COMPILE_ASSERT(DestLimits::is_specialized, result_must_be_numeric);
109 COMPILE_ASSERT(DestLimits::is_integer, result_must_be_integral);
110
111 return IsValidNumericCastImpl<
112 sizeof(Dest) == sizeof(Source),
113 (sizeof(Dest) > sizeof(Source)),
114 DestLimits::is_signed,
115 SourceLimits::is_signed>::Test(
116 source,
117 DestLimits::min(),
118 DestLimits::max());
119 }
120
121 } // namespace internal
122
123 // checked_numeric_cast<> is analogous to static_cast<> for numeric types, 22 // checked_numeric_cast<> is analogous to static_cast<> for numeric types,
124 // except that it CHECKs that the specified numeric conversion will not 23 // except that it CHECKs that the specified numeric conversion will not
125 // overflow or underflow. Floating point arguments are not currently allowed 24 // overflow or underflow. NaN source will always trigger a CHECK.
126 // (this is COMPILE_ASSERTd), though this could be supported if necessary. 25 template <typename Dst, typename Src>
127 template <class Dest, class Source> 26 inline Dst checked_numeric_cast(Src value) {
128 inline Dest checked_numeric_cast(Source source) { 27 CHECK(IsValueInRangeForNumericType<Dst>(value));
129 CHECK(internal::IsValidNumericCast<Dest>(source)); 28 return static_cast<Dst>(value);
130 return static_cast<Dest>(source); 29 }
30
31 // saturated_cast<> is analogous to static_cast<> for numeric types, except
32 // that the specified numeric conversion will saturate rather than overflow or
33 // underflow. NaN assignment to an integral will trigger a CHECK condition.
34 template <typename Dst, typename Src>
35 inline Dst saturated_cast(Src value) {
36 // Optimization for floating point values, which already saturate.
akalin 2014/01/16 00:21:55 saturate -> saturates
jschuh 2014/01/16 01:26:31 The antecedent is values, which is plural. :)
akalin 2014/01/16 02:28:12 d'oh!
37 if (std::numeric_limits<Dst>::is_iec559)
38 return static_cast<Dst>(value);
39
40 switch (internal::RangeCheck<Dst>(value)) {
41 case internal::TYPE_UNDERFLOW:
42 return std::numeric_limits<Dst>::min();
43
44 case internal::TYPE_OVERFLOW:
45 return std::numeric_limits<Dst>::max();
46
47 // Should fail only on attempting to assign NaN to a saturated integer.
48 case internal::TYPE_INVALID:
49 CHECK(false);
50 return std::numeric_limits<Dst>::max();
51
52 default:
53 return static_cast<Dst>(value);
akalin 2014/01/16 00:21:55 i think you should explicitly list the TYPE_VALID
jschuh 2014/01/16 01:26:31 Done.
54 }
131 } 55 }
132 56
133 } // namespace base 57 } // namespace base
134 58
135 #endif // BASE_SAFE_NUMERICS_H_ 59 #endif // BASE_SAFE_NUMERICS_H_
OLDNEW
« no previous file with comments | « no previous file | base/safe_numerics_impl.h » ('j') | base/safe_numerics_impl.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698