OLD | NEW |
| (Empty) |
1 // Protocol Buffers - Google's data interchange format | |
2 // Copyright 2008 Google Inc. All rights reserved. | |
3 // https://developers.google.com/protocol-buffers/ | |
4 // | |
5 // Redistribution and use in source and binary forms, with or without | |
6 // modification, are permitted provided that the following conditions are | |
7 // met: | |
8 // | |
9 // * Redistributions of source code must retain the above copyright | |
10 // notice, this list of conditions and the following disclaimer. | |
11 // * Redistributions in binary form must reproduce the above | |
12 // copyright notice, this list of conditions and the following disclaimer | |
13 // in the documentation and/or other materials provided with the | |
14 // distribution. | |
15 // * Neither the name of Google Inc. nor the names of its | |
16 // contributors may be used to endorse or promote products derived from | |
17 // this software without specific prior written permission. | |
18 // | |
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
30 | |
31 #ifndef GOOGLE_PROTOBUF_PYTHON_CPP_SAFE_NUMERICS_H__ | |
32 #define GOOGLE_PROTOBUF_PYTHON_CPP_SAFE_NUMERICS_H__ | |
33 // Copied from chromium with only changes to the namespace. | |
34 | |
35 #include <limits> | |
36 | |
37 #include <google/protobuf/stubs/logging.h> | |
38 #include <google/protobuf/stubs/common.h> | |
39 | |
40 namespace google { | |
41 namespace protobuf { | |
42 namespace python { | |
43 | |
44 template <bool SameSize, bool DestLarger, | |
45 bool DestIsSigned, bool SourceIsSigned> | |
46 struct IsValidNumericCastImpl; | |
47 | |
48 #define BASE_NUMERIC_CAST_CASE_SPECIALIZATION(A, B, C, D, Code) \ | |
49 template <> struct IsValidNumericCastImpl<A, B, C, D> { \ | |
50 template <class Source, class DestBounds> static inline bool Test( \ | |
51 Source source, DestBounds min, DestBounds max) { \ | |
52 return Code; \ | |
53 } \ | |
54 } | |
55 | |
56 #define BASE_NUMERIC_CAST_CASE_SAME_SIZE(DestSigned, SourceSigned, Code) \ | |
57 BASE_NUMERIC_CAST_CASE_SPECIALIZATION( \ | |
58 true, true, DestSigned, SourceSigned, Code); \ | |
59 BASE_NUMERIC_CAST_CASE_SPECIALIZATION( \ | |
60 true, false, DestSigned, SourceSigned, Code) | |
61 | |
62 #define BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(DestSigned, SourceSigned, Code) \ | |
63 BASE_NUMERIC_CAST_CASE_SPECIALIZATION( \ | |
64 false, false, DestSigned, SourceSigned, Code); \ | |
65 | |
66 #define BASE_NUMERIC_CAST_CASE_DEST_LARGER(DestSigned, SourceSigned, Code) \ | |
67 BASE_NUMERIC_CAST_CASE_SPECIALIZATION( \ | |
68 false, true, DestSigned, SourceSigned, Code); \ | |
69 | |
70 // The three top level cases are: | |
71 // - Same size | |
72 // - Source larger | |
73 // - Dest larger | |
74 // And for each of those three cases, we handle the 4 different possibilities | |
75 // of signed and unsigned. This gives 12 cases to handle, which we enumerate | |
76 // below. | |
77 // | |
78 // The last argument in each of the macros is the actual comparison code. It | |
79 // has three arguments available, source (the value), and min/max which are | |
80 // the ranges of the destination. | |
81 | |
82 | |
83 // These are the cases where both types have the same size. | |
84 | |
85 // Both signed. | |
86 BASE_NUMERIC_CAST_CASE_SAME_SIZE(true, true, true); | |
87 // Both unsigned. | |
88 BASE_NUMERIC_CAST_CASE_SAME_SIZE(false, false, true); | |
89 // Dest unsigned, Source signed. | |
90 BASE_NUMERIC_CAST_CASE_SAME_SIZE(false, true, source >= 0); | |
91 // Dest signed, Source unsigned. | |
92 // This cast is OK because Dest's max must be less than Source's. | |
93 BASE_NUMERIC_CAST_CASE_SAME_SIZE(true, false, | |
94 source <= static_cast<Source>(max)); | |
95 | |
96 | |
97 // These are the cases where Source is larger. | |
98 | |
99 // Both unsigned. | |
100 BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(false, false, source <= max); | |
101 // Both signed. | |
102 BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(true, true, | |
103 source >= min && source <= max); | |
104 // Dest is unsigned, Source is signed. | |
105 BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(false, true, | |
106 source >= 0 && source <= max); | |
107 // Dest is signed, Source is unsigned. | |
108 // This cast is OK because Dest's max must be less than Source's. | |
109 BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(true, false, | |
110 source <= static_cast<Source>(max)); | |
111 | |
112 | |
113 // These are the cases where Dest is larger. | |
114 | |
115 // Both unsigned. | |
116 BASE_NUMERIC_CAST_CASE_DEST_LARGER(false, false, true); | |
117 // Both signed. | |
118 BASE_NUMERIC_CAST_CASE_DEST_LARGER(true, true, true); | |
119 // Dest is unsigned, Source is signed. | |
120 BASE_NUMERIC_CAST_CASE_DEST_LARGER(false, true, source >= 0); | |
121 // Dest is signed, Source is unsigned. | |
122 BASE_NUMERIC_CAST_CASE_DEST_LARGER(true, false, true); | |
123 | |
124 #undef BASE_NUMERIC_CAST_CASE_SPECIALIZATION | |
125 #undef BASE_NUMERIC_CAST_CASE_SAME_SIZE | |
126 #undef BASE_NUMERIC_CAST_CASE_SOURCE_LARGER | |
127 #undef BASE_NUMERIC_CAST_CASE_DEST_LARGER | |
128 | |
129 | |
130 // The main test for whether the conversion will under or overflow. | |
131 template <class Dest, class Source> | |
132 inline bool IsValidNumericCast(Source source) { | |
133 typedef std::numeric_limits<Source> SourceLimits; | |
134 typedef std::numeric_limits<Dest> DestLimits; | |
135 GOOGLE_COMPILE_ASSERT(SourceLimits::is_specialized, argument_must_be_numeric); | |
136 GOOGLE_COMPILE_ASSERT(SourceLimits::is_integer, argument_must_be_integral); | |
137 GOOGLE_COMPILE_ASSERT(DestLimits::is_specialized, result_must_be_numeric); | |
138 GOOGLE_COMPILE_ASSERT(DestLimits::is_integer, result_must_be_integral); | |
139 | |
140 return IsValidNumericCastImpl< | |
141 sizeof(Dest) == sizeof(Source), | |
142 (sizeof(Dest) > sizeof(Source)), | |
143 DestLimits::is_signed, | |
144 SourceLimits::is_signed>::Test( | |
145 source, | |
146 DestLimits::min(), | |
147 DestLimits::max()); | |
148 } | |
149 | |
150 // checked_numeric_cast<> is analogous to static_cast<> for numeric types, | |
151 // except that it CHECKs that the specified numeric conversion will not | |
152 // overflow or underflow. Floating point arguments are not currently allowed | |
153 // (this is COMPILE_ASSERTd), though this could be supported if necessary. | |
154 template <class Dest, class Source> | |
155 inline Dest checked_numeric_cast(Source source) { | |
156 GOOGLE_CHECK(IsValidNumericCast<Dest>(source)); | |
157 return static_cast<Dest>(source); | |
158 } | |
159 | |
160 } // namespace python | |
161 } // namespace protobuf | |
162 | |
163 } // namespace google | |
164 #endif // GOOGLE_PROTOBUF_PYTHON_CPP_SAFE_NUMERICS_H__ | |
OLD | NEW |