blob: 424df25ea6eee48569f838de675123bc22a5e308 [file] [log] [blame]
mukesh agrawalfd651022016-09-21 13:27:07 -07001/*
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 agrawal53b465f2016-09-23 18:22:13 -070022#include <limits>
23#include <type_traits>
24
mukesh agrawal0da05472016-09-29 14:59:27 -070025#include "android-base/logging.h"
26
mukesh agrawal53b465f2016-09-23 18:22:13 -070027// 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 agrawal3d8db082016-09-30 18:47:12 -070039// 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 agrawalfd651022016-09-21 13:27:07 -070042#if defined(__clang__)
mukesh agrawal3d8db082016-09-30 18:47:12 -070043#define NONNULL [[gnu::nonnull]] /* NOLINT(whitespace/braces) */
44#define RETURNS_NONNULL [[gnu::returns_nonnull]] /* NOLINT ... */
mukesh agrawalfd651022016-09-21 13:27:07 -070045#else
46#define NONNULL
mukesh agrawal3d8db082016-09-30 18:47:12 -070047#define RETURNS_NONNULL
mukesh agrawalfd651022016-09-21 13:27:07 -070048#endif
49
mukesh agrawal53b465f2016-09-23 18:22:13 -070050namespace android {
51namespace wifilogd {
52namespace local_utils {
53
mukesh agrawal9cfc0372016-10-20 13:54:10 -070054// Returns the value in |enum_value|, as the integral type underlying the
55// enum. (E.g. uint8_t, int32_t, etc.)
56template <typename T>
57constexpr 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 agrawal0da05472016-09-29 14:59:27 -070062// 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.
75template <typename T>
76T 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 agrawal53b465f2016-09-23 18:22:13 -070085// Returns the maximal value representable by T. Generates a compile-time
86// error if T is not an integral type.
87template <typename T>
88constexpr 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.
98template <typename T>
99constexpr T GetMaxVal(const T& /* t_instance */) {
100 return GetMaxVal<T>();
101}
102
mukesh agrawalfde5bda2016-10-05 17:37:10 -0700103// Returns true if |c| is a printable character, for ASCII data.
104inline bool IsAsciiPrintable(uint8_t c) {
105 return (c == '\t' || c == '\n' || (c >= ' ' && c <= '~'));
106}
107
mukesh agrawal53b465f2016-09-23 18:22:13 -0700108namespace internal {
109
110// Implements the functionality documented for the SAFELY_CLAMP macro.
111// This function should be used via the SAFELY_CLAMP macro.
112template <typename SrcType, typename DstType, SrcType MinAsSrcType,
113 SrcType MaxAsSrcType, DstType MinAsDstType, DstType MaxAsDstType>
114DstType 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 agrawalfd651022016-09-21 13:27:07 -0700159#endif // LOCAL_UTILS_H_