mukesh agrawal | fd65102 | 2016-09-21 13:27:07 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2016 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | // Local utilities (macros and free-standing functions). |
| 18 | |
| 19 | #ifndef LOCAL_UTILS_H_ |
| 20 | #define LOCAL_UTILS_H_ |
| 21 | |
mukesh agrawal | 53b465f | 2016-09-23 18:22:13 -0700 | [diff] [blame] | 22 | #include <limits> |
| 23 | #include <type_traits> |
| 24 | |
mukesh agrawal | 0da0547 | 2016-09-29 14:59:27 -0700 | [diff] [blame] | 25 | #include "android-base/logging.h" |
| 26 | |
mukesh agrawal | 53b465f | 2016-09-23 18:22:13 -0700 | [diff] [blame] | 27 | // Converts the value SRC to a value of DST_TYPE, in the range of [MIN, MAX]. |
| 28 | // Values less than MIN are clamped to MIN, and values greater than MAX are |
| 29 | // clamped to MAX. Conversions are safe in the sense that the range is checked |
| 30 | // to be valid for both SRC and DST_TYPE, at compile-time. |
| 31 | // |
| 32 | // As compared to static_cast<>, SAFELY_CLAMP is a) more explicit, b) more |
| 33 | // flexible, and c) less prone to surprising conversions (e.g. -1 becoming |
| 34 | // UINT_MAX). |
| 35 | #define SAFELY_CLAMP(SRC, DST_TYPE, MIN, MAX) \ |
| 36 | local_utils::internal::SafelyClamp<decltype(SRC), DST_TYPE, MIN, MAX, MIN, \ |
| 37 | MAX>(SRC) |
| 38 | |
mukesh agrawal | 3d8db08 | 2016-09-30 18:47:12 -0700 | [diff] [blame] | 39 | // While attributes are standard in C++11, these attributes are not part of |
| 40 | // the standard. We use macros to abstract these attributes, to allow |
| 41 | // the code to compile with compilers that don't recognize these attributes. |
mukesh agrawal | fd65102 | 2016-09-21 13:27:07 -0700 | [diff] [blame] | 42 | #if defined(__clang__) |
mukesh agrawal | 3d8db08 | 2016-09-30 18:47:12 -0700 | [diff] [blame] | 43 | #define NONNULL [[gnu::nonnull]] /* NOLINT(whitespace/braces) */ |
| 44 | #define RETURNS_NONNULL [[gnu::returns_nonnull]] /* NOLINT ... */ |
mukesh agrawal | fd65102 | 2016-09-21 13:27:07 -0700 | [diff] [blame] | 45 | #else |
| 46 | #define NONNULL |
mukesh agrawal | 3d8db08 | 2016-09-30 18:47:12 -0700 | [diff] [blame] | 47 | #define RETURNS_NONNULL |
mukesh agrawal | fd65102 | 2016-09-21 13:27:07 -0700 | [diff] [blame] | 48 | #endif |
| 49 | |
mukesh agrawal | 53b465f | 2016-09-23 18:22:13 -0700 | [diff] [blame] | 50 | namespace android { |
| 51 | namespace wifilogd { |
| 52 | namespace local_utils { |
| 53 | |
mukesh agrawal | 9cfc037 | 2016-10-20 13:54:10 -0700 | [diff] [blame] | 54 | // Returns the value in |enum_value|, as the integral type underlying the |
| 55 | // enum. (E.g. uint8_t, int32_t, etc.) |
| 56 | template <typename T> |
| 57 | constexpr auto CastEnumToInteger(T enum_value) { |
| 58 | static_assert(std::is_enum<T>::value, "argument must be of an enum type"); |
| 59 | return static_cast<typename std::underlying_type<T>::type>(enum_value); |
| 60 | } |
| 61 | |
mukesh agrawal | 0da0547 | 2016-09-29 14:59:27 -0700 | [diff] [blame] | 62 | // Copies a |T| out of |buf|, aborting if |buf| is too short to hold a |T|. |
| 63 | // |
| 64 | // As compared to accessing the underlying data using reinterpret_cast<>, |
| 65 | // CopyFromBufferOrDie() provides three benefits: |
| 66 | // 1. Guarantees that the returned header is properly aligned. While |
| 67 | // many processors support some unaligned reads, there are some |
| 68 | // exceptions. E.g, a 64-bit unaligned read on 32-bit ARM may cause |
| 69 | // a program to abort. |
| 70 | // 2. Removes the potential for bugs due to compiler optimizations based |
| 71 | // on type-based alias analysis. (These are the kinds of bugs that |
| 72 | // "strict-aliasing" warnings try to call out.) |
| 73 | // 3. Verifies that the source buffer is large enough to contain the |
| 74 | // data we're trying to read out. |
| 75 | template <typename T> |
| 76 | T CopyFromBufferOrDie(NONNULL const void* buf, size_t buf_len) { |
| 77 | static_assert(std::is_trivially_copyable<T>::value, |
| 78 | "CopyFromBufferOrDie can only copy trivially copyable types"); |
| 79 | T out; |
| 80 | CHECK(buf_len >= sizeof(out)); |
| 81 | std::memcpy(&out, buf, sizeof(out)); |
| 82 | return out; |
| 83 | } |
| 84 | |
mukesh agrawal | 53b465f | 2016-09-23 18:22:13 -0700 | [diff] [blame] | 85 | // Returns the maximal value representable by T. Generates a compile-time |
| 86 | // error if T is not an integral type. |
| 87 | template <typename T> |
| 88 | constexpr T GetMaxVal() { |
| 89 | // Give a useful error for non-numeric types, and avoid returning zero for |
| 90 | // pointers and C-style enums (http://stackoverflow.com/a/9201960). |
| 91 | static_assert(std::is_integral<T>::value, |
| 92 | "GetMaxVal requires an integral type"); |
| 93 | return std::numeric_limits<T>::max(); |
| 94 | } |
| 95 | |
| 96 | // Returns the maximal value representable by |t_instance|. Generates a |
| 97 | // compile-time error if |t_instance| is not an instance of an integral type. |
| 98 | template <typename T> |
| 99 | constexpr T GetMaxVal(const T& /* t_instance */) { |
| 100 | return GetMaxVal<T>(); |
| 101 | } |
| 102 | |
mukesh agrawal | fde5bda | 2016-10-05 17:37:10 -0700 | [diff] [blame] | 103 | // Returns true if |c| is a printable character, for ASCII data. |
| 104 | inline bool IsAsciiPrintable(uint8_t c) { |
| 105 | return (c == '\t' || c == '\n' || (c >= ' ' && c <= '~')); |
| 106 | } |
| 107 | |
mukesh agrawal | 53b465f | 2016-09-23 18:22:13 -0700 | [diff] [blame] | 108 | namespace internal { |
| 109 | |
| 110 | // Implements the functionality documented for the SAFELY_CLAMP macro. |
| 111 | // This function should be used via the SAFELY_CLAMP macro. |
| 112 | template <typename SrcType, typename DstType, SrcType MinAsSrcType, |
| 113 | SrcType MaxAsSrcType, DstType MinAsDstType, DstType MaxAsDstType> |
| 114 | DstType SafelyClamp(SrcType input) { |
| 115 | static_assert(std::is_integral<SrcType>::value, |
| 116 | "source type must be integral"); |
| 117 | static_assert(std::is_integral<DstType>::value, |
| 118 | "destination type must be integral"); |
| 119 | static_assert(MinAsSrcType < MaxAsSrcType, "invalid source range"); |
| 120 | static_assert(MinAsDstType < MaxAsDstType, "invalid destination range"); |
| 121 | // Clients should use the SAFELY_CLAMP macro, in which case this should never |
| 122 | // happen. (When the SAFELY_CLAMP macro is used, the values can only be |
| 123 | // unequal if there was a narrowing conversion. But, in that case, the value |
| 124 | // should have failed to match the template, since narrowing-conversions are |
| 125 | // not allowed for non-type template arguments. |
| 126 | // http://stackoverflow.com/a/24346350) |
| 127 | // |
| 128 | // Anyway, these checks provide a fail-safe, in case clients use the template |
| 129 | // function directly, and pass in inconsistent values for the range |
| 130 | // definition. |
| 131 | static_assert(MinAsSrcType == MinAsDstType, "inconsistent range min"); |
| 132 | static_assert(MaxAsSrcType == MaxAsDstType, "inconsistent range max"); |
| 133 | |
| 134 | if (input < MinAsSrcType) { |
| 135 | return MinAsDstType; |
| 136 | } else if (input > MaxAsSrcType) { |
| 137 | return MaxAsDstType; |
| 138 | } else { |
| 139 | // - Given that the template has matched, we know that MinAsSrcType, |
| 140 | // MaxAsSrcType, MinAsDstType, and MaxAsDstType are valid for their |
| 141 | // respective types. (See narrowing-conversion comment above.) |
| 142 | // - Given the static_assert()s above, we know that a) the ranges are |
| 143 | // well-formed, and that the b) source range is identical to the |
| 144 | // destination range. |
| 145 | // - Given the range checks above, we know that |input| is within the range. |
| 146 | // |
| 147 | // Hence, the value to be returned must be valid for DstType, and the |
| 148 | // expression below has the same value as |input|. |
| 149 | return static_cast<DstType>(input); |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | } // namespace internal |
| 154 | |
| 155 | } // namespace local_utils |
| 156 | } // namespace wifilogd |
| 157 | } // namespace android |
| 158 | |
mukesh agrawal | fd65102 | 2016-09-21 13:27:07 -0700 | [diff] [blame] | 159 | #endif // LOCAL_UTILS_H_ |