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 22 #include <limits> 23 #include <type_traits> 24 25 #include "android-base/logging.h" 26 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 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. 42 #if defined(__clang__) 43 #define NONNULL [[gnu::nonnull]] /* NOLINT(whitespace/braces) */ 44 #define RETURNS_NONNULL [[gnu::returns_nonnull]] /* NOLINT ... */ 45 #else 46 #define NONNULL 47 #define RETURNS_NONNULL 48 #endif 49 50 namespace android { 51 namespace wifilogd { 52 namespace local_utils { 53 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 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 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 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 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 159 #endif // LOCAL_UTILS_H_ 160