local_utils.h 6.4 KB

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