/src/brpc/src/butil/numerics/safe_conversions.h
Line | Count | Source |
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 |
3 | | // found in the LICENSE file. |
4 | | |
5 | | #ifndef BUTIL_SAFE_CONVERSIONS_H_ |
6 | | #define BUTIL_SAFE_CONVERSIONS_H_ |
7 | | |
8 | | #include <limits> |
9 | | |
10 | | #include "butil/logging.h" |
11 | | #include "butil/numerics/safe_conversions_impl.h" |
12 | | |
13 | | namespace butil { |
14 | | |
15 | | // Convenience function that returns true if the supplied value is in range |
16 | | // for the destination type. |
17 | | template <typename Dst, typename Src> |
18 | | inline bool IsValueInRangeForNumericType(Src value) { |
19 | | return internal::DstRangeRelationToSrcRange<Dst>(value) == |
20 | | internal::RANGE_VALID; |
21 | | } |
22 | | |
23 | | // checked_cast<> is analogous to static_cast<> for numeric types, |
24 | | // except that it CHECKs that the specified numeric conversion will not |
25 | | // overflow or underflow. NaN source will always trigger a CHECK. |
26 | | template <typename Dst, typename Src> |
27 | | inline Dst checked_cast(Src value) { |
28 | | CHECK(IsValueInRangeForNumericType<Dst>(value)); |
29 | | return static_cast<Dst>(value); |
30 | | } |
31 | | |
32 | | // saturated_cast<> is analogous to static_cast<> for numeric types, except |
33 | | // that the specified numeric conversion will saturate rather than overflow or |
34 | | // underflow. NaN assignment to an integral will trigger a CHECK condition. |
35 | | template <typename Dst, typename Src> |
36 | 285 | inline Dst saturated_cast(Src value) { |
37 | | // Optimization for floating point values, which already saturate. |
38 | 285 | if (std::numeric_limits<Dst>::is_iec559) |
39 | 0 | return static_cast<Dst>(value); |
40 | | |
41 | 285 | switch (internal::DstRangeRelationToSrcRange<Dst>(value)) { |
42 | 285 | case internal::RANGE_VALID: |
43 | 285 | return static_cast<Dst>(value); |
44 | | |
45 | 0 | case internal::RANGE_UNDERFLOW: |
46 | 0 | return std::numeric_limits<Dst>::min(); |
47 | | |
48 | 0 | case internal::RANGE_OVERFLOW: |
49 | 0 | return std::numeric_limits<Dst>::max(); |
50 | | |
51 | | // Should fail only on attempting to assign NaN to a saturated integer. |
52 | 0 | case internal::RANGE_INVALID: |
53 | 0 | CHECK(false); |
54 | 0 | return std::numeric_limits<Dst>::max(); |
55 | 285 | } |
56 | | |
57 | 0 | NOTREACHED(); |
58 | 0 | return static_cast<Dst>(value); |
59 | 285 | } |
60 | | |
61 | 0 | inline uint64_t safe_abs(uint64_t x) { |
62 | 0 | return x; |
63 | 0 | } |
64 | | |
65 | 0 | inline uint64_t safe_abs(int64_t x) { |
66 | 0 | return (x >= 0) ? (uint64_t)x : ((~(uint64_t)(x)) + 1); |
67 | 0 | } |
68 | | |
69 | 0 | inline uint32_t safe_abs(uint32_t x) { |
70 | 0 | return x; |
71 | 0 | } |
72 | | |
73 | 0 | inline uint32_t safe_abs(int32_t x) { |
74 | 0 | return (uint32_t)safe_abs((int64_t)x); |
75 | 0 | } |
76 | | |
77 | | #if defined(__APPLE__) |
78 | | inline unsigned long safe_abs(unsigned long x) { |
79 | | return x; |
80 | | } |
81 | | inline unsigned long safe_abs(long x) { |
82 | | return (x >= 0) ? (unsigned long)x : ((~(unsigned long)(x)) + 1); |
83 | | } |
84 | | #endif |
85 | | |
86 | | } // namespace butil |
87 | | |
88 | | #endif // BUTIL_SAFE_CONVERSIONS_H_ |