| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2014 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2014 The WebRTC Project Authors. All rights reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 // Borrowed from Chromium's src/base/numerics/safe_conversions_impl.h. | 11 // Borrowed from Chromium's src/base/numerics/safe_conversions_impl.h. |
| 12 | 12 |
| 13 #ifndef WEBRTC_BASE_SAFE_CONVERSIONS_IMPL_H_ | 13 #ifndef WEBRTC_BASE_SAFE_CONVERSIONS_IMPL_H_ |
| 14 #define WEBRTC_BASE_SAFE_CONVERSIONS_IMPL_H_ | 14 #define WEBRTC_BASE_SAFE_CONVERSIONS_IMPL_H_ |
| 15 | 15 |
| 16 #include <limits> | |
| 17 | 16 |
| 18 namespace rtc { | 17 // This header is deprecated and is just left here temporarily during |
| 19 namespace internal { | 18 // refactoring. See https://bugs.webrtc.org/7634 for more details. |
| 20 | 19 #include "webrtc/rtc_base/safe_conversions_impl.h" |
| 21 enum DstSign { | |
| 22 DST_UNSIGNED, | |
| 23 DST_SIGNED | |
| 24 }; | |
| 25 | |
| 26 enum SrcSign { | |
| 27 SRC_UNSIGNED, | |
| 28 SRC_SIGNED | |
| 29 }; | |
| 30 | |
| 31 enum DstRange { | |
| 32 OVERLAPS_RANGE, | |
| 33 CONTAINS_RANGE | |
| 34 }; | |
| 35 | |
| 36 // Helper templates to statically determine if our destination type can contain | |
| 37 // all values represented by the source type. | |
| 38 | |
| 39 template <typename Dst, typename Src, | |
| 40 DstSign IsDstSigned = std::numeric_limits<Dst>::is_signed ? | |
| 41 DST_SIGNED : DST_UNSIGNED, | |
| 42 SrcSign IsSrcSigned = std::numeric_limits<Src>::is_signed ? | |
| 43 SRC_SIGNED : SRC_UNSIGNED> | |
| 44 struct StaticRangeCheck {}; | |
| 45 | |
| 46 template <typename Dst, typename Src> | |
| 47 struct StaticRangeCheck<Dst, Src, DST_SIGNED, SRC_SIGNED> { | |
| 48 typedef std::numeric_limits<Dst> DstLimits; | |
| 49 typedef std::numeric_limits<Src> SrcLimits; | |
| 50 // Compare based on max_exponent, which we must compute for integrals. | |
| 51 static const size_t kDstMaxExponent = DstLimits::is_iec559 ? | |
| 52 DstLimits::max_exponent : | |
| 53 (sizeof(Dst) * 8 - 1); | |
| 54 static const size_t kSrcMaxExponent = SrcLimits::is_iec559 ? | |
| 55 SrcLimits::max_exponent : | |
| 56 (sizeof(Src) * 8 - 1); | |
| 57 static const DstRange value = kDstMaxExponent >= kSrcMaxExponent ? | |
| 58 CONTAINS_RANGE : OVERLAPS_RANGE; | |
| 59 }; | |
| 60 | |
| 61 template <typename Dst, typename Src> | |
| 62 struct StaticRangeCheck<Dst, Src, DST_UNSIGNED, SRC_UNSIGNED> { | |
| 63 static const DstRange value = sizeof(Dst) >= sizeof(Src) ? | |
| 64 CONTAINS_RANGE : OVERLAPS_RANGE; | |
| 65 }; | |
| 66 | |
| 67 template <typename Dst, typename Src> | |
| 68 struct StaticRangeCheck<Dst, Src, DST_SIGNED, SRC_UNSIGNED> { | |
| 69 typedef std::numeric_limits<Dst> DstLimits; | |
| 70 typedef std::numeric_limits<Src> SrcLimits; | |
| 71 // Compare based on max_exponent, which we must compute for integrals. | |
| 72 static const size_t kDstMaxExponent = DstLimits::is_iec559 ? | |
| 73 DstLimits::max_exponent : | |
| 74 (sizeof(Dst) * 8 - 1); | |
| 75 static const size_t kSrcMaxExponent = sizeof(Src) * 8; | |
| 76 static const DstRange value = kDstMaxExponent >= kSrcMaxExponent ? | |
| 77 CONTAINS_RANGE : OVERLAPS_RANGE; | |
| 78 }; | |
| 79 | |
| 80 template <typename Dst, typename Src> | |
| 81 struct StaticRangeCheck<Dst, Src, DST_UNSIGNED, SRC_SIGNED> { | |
| 82 static const DstRange value = OVERLAPS_RANGE; | |
| 83 }; | |
| 84 | |
| 85 | |
| 86 enum RangeCheckResult { | |
| 87 TYPE_VALID = 0, // Value can be represented by the destination type. | |
| 88 TYPE_UNDERFLOW = 1, // Value would overflow. | |
| 89 TYPE_OVERFLOW = 2, // Value would underflow. | |
| 90 TYPE_INVALID = 3 // Source value is invalid (i.e. NaN). | |
| 91 }; | |
| 92 | |
| 93 // This macro creates a RangeCheckResult from an upper and lower bound | |
| 94 // check by taking advantage of the fact that only NaN can be out of range in | |
| 95 // both directions at once. | |
| 96 #define BASE_NUMERIC_RANGE_CHECK_RESULT(is_in_upper_bound, is_in_lower_bound) \ | |
| 97 RangeCheckResult(((is_in_upper_bound) ? 0 : TYPE_OVERFLOW) | \ | |
| 98 ((is_in_lower_bound) ? 0 : TYPE_UNDERFLOW)) | |
| 99 | |
| 100 template <typename Dst, | |
| 101 typename Src, | |
| 102 DstSign IsDstSigned = std::numeric_limits<Dst>::is_signed ? | |
| 103 DST_SIGNED : DST_UNSIGNED, | |
| 104 SrcSign IsSrcSigned = std::numeric_limits<Src>::is_signed ? | |
| 105 SRC_SIGNED : SRC_UNSIGNED, | |
| 106 DstRange IsSrcRangeContained = StaticRangeCheck<Dst, Src>::value> | |
| 107 struct RangeCheckImpl {}; | |
| 108 | |
| 109 // The following templates are for ranges that must be verified at runtime. We | |
| 110 // split it into checks based on signedness to avoid confusing casts and | |
| 111 // compiler warnings on signed an unsigned comparisons. | |
| 112 | |
| 113 // Dst range always contains the result: nothing to check. | |
| 114 template <typename Dst, typename Src, DstSign IsDstSigned, SrcSign IsSrcSigned> | |
| 115 struct RangeCheckImpl<Dst, Src, IsDstSigned, IsSrcSigned, CONTAINS_RANGE> { | |
| 116 static RangeCheckResult Check(Src value) { | |
| 117 return TYPE_VALID; | |
| 118 } | |
| 119 }; | |
| 120 | |
| 121 // Signed to signed narrowing. | |
| 122 template <typename Dst, typename Src> | |
| 123 struct RangeCheckImpl<Dst, Src, DST_SIGNED, SRC_SIGNED, OVERLAPS_RANGE> { | |
| 124 static RangeCheckResult Check(Src value) { | |
| 125 typedef std::numeric_limits<Dst> DstLimits; | |
| 126 return DstLimits::is_iec559 ? | |
| 127 BASE_NUMERIC_RANGE_CHECK_RESULT( | |
| 128 value <= static_cast<Src>(DstLimits::max()), | |
| 129 value >= static_cast<Src>(DstLimits::max() * -1)) : | |
| 130 BASE_NUMERIC_RANGE_CHECK_RESULT( | |
| 131 value <= static_cast<Src>(DstLimits::max()), | |
| 132 value >= static_cast<Src>(DstLimits::min())); | |
| 133 } | |
| 134 }; | |
| 135 | |
| 136 // Unsigned to unsigned narrowing. | |
| 137 template <typename Dst, typename Src> | |
| 138 struct RangeCheckImpl<Dst, Src, DST_UNSIGNED, SRC_UNSIGNED, OVERLAPS_RANGE> { | |
| 139 static RangeCheckResult Check(Src value) { | |
| 140 typedef std::numeric_limits<Dst> DstLimits; | |
| 141 return BASE_NUMERIC_RANGE_CHECK_RESULT( | |
| 142 value <= static_cast<Src>(DstLimits::max()), true); | |
| 143 } | |
| 144 }; | |
| 145 | |
| 146 // Unsigned to signed. | |
| 147 template <typename Dst, typename Src> | |
| 148 struct RangeCheckImpl<Dst, Src, DST_SIGNED, SRC_UNSIGNED, OVERLAPS_RANGE> { | |
| 149 static RangeCheckResult Check(Src value) { | |
| 150 typedef std::numeric_limits<Dst> DstLimits; | |
| 151 return sizeof(Dst) > sizeof(Src) ? TYPE_VALID : | |
| 152 BASE_NUMERIC_RANGE_CHECK_RESULT( | |
| 153 value <= static_cast<Src>(DstLimits::max()), true); | |
| 154 } | |
| 155 }; | |
| 156 | |
| 157 // Signed to unsigned. | |
| 158 template <typename Dst, typename Src> | |
| 159 struct RangeCheckImpl<Dst, Src, DST_UNSIGNED, SRC_SIGNED, OVERLAPS_RANGE> { | |
| 160 static RangeCheckResult Check(Src value) { | |
| 161 typedef std::numeric_limits<Dst> DstLimits; | |
| 162 typedef std::numeric_limits<Src> SrcLimits; | |
| 163 // Compare based on max_exponent, which we must compute for integrals. | |
| 164 static const size_t kDstMaxExponent = sizeof(Dst) * 8; | |
| 165 static const size_t kSrcMaxExponent = SrcLimits::is_iec559 ? | |
| 166 SrcLimits::max_exponent : | |
| 167 (sizeof(Src) * 8 - 1); | |
| 168 return (kDstMaxExponent >= kSrcMaxExponent) ? | |
| 169 BASE_NUMERIC_RANGE_CHECK_RESULT(true, value >= static_cast<Src>(0)) : | |
| 170 BASE_NUMERIC_RANGE_CHECK_RESULT( | |
| 171 value <= static_cast<Src>(DstLimits::max()), | |
| 172 value >= static_cast<Src>(0)); | |
| 173 } | |
| 174 }; | |
| 175 | |
| 176 template <typename Dst, typename Src> | |
| 177 inline RangeCheckResult RangeCheck(Src value) { | |
| 178 static_assert(std::numeric_limits<Src>::is_specialized, | |
| 179 "argument must be numeric"); | |
| 180 static_assert(std::numeric_limits<Dst>::is_specialized, | |
| 181 "result must be numeric"); | |
| 182 return RangeCheckImpl<Dst, Src>::Check(value); | |
| 183 } | |
| 184 | |
| 185 } // namespace internal | |
| 186 } // namespace rtc | |
| 187 | 20 |
| 188 #endif // WEBRTC_BASE_SAFE_CONVERSIONS_IMPL_H_ | 21 #endif // WEBRTC_BASE_SAFE_CONVERSIONS_IMPL_H_ |
| OLD | NEW |