xref: /aosp_15_r20/external/pigweed/pw_bytes/public/pw_bytes/bit.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2022 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 // Low-level bit operations including std::endian from C++20.
16 #pragma once
17 
18 #include <climits>
19 
20 #include "lib/stdcompat/bit.h"
21 
22 namespace pw {
23 
24 using ::cpp20::endian;
25 
26 namespace bytes {
27 
28 /// Queries size of the object or type in bits.
29 #define SIZE_OF_IN_BIT(...) (sizeof(__VA_ARGS__) * CHAR_BIT)
30 
31 /// Extends the nth bit to the left. Useful for expanding singed values into
32 /// larger integer types.
33 template <std::size_t kBitWidth, typename T>
SignExtend(T nbit_value)34 constexpr T SignExtend(T nbit_value) {
35   static_assert(std::is_integral_v<T>);
36   static_assert(kBitWidth < SIZE_OF_IN_BIT(T));
37 
38   using SignedT = std::make_signed_t<T>;
39 
40   constexpr std::size_t extension_bits = SIZE_OF_IN_BIT(SignedT) - kBitWidth;
41 
42   SignedT nbit_temp = static_cast<SignedT>(nbit_value);
43   return ((nbit_temp << extension_bits) >> extension_bits);
44 }
45 
46 /// Extracts bits between msb and lsb from a value.
47 ///
48 /// @tparam     OutType   The type of output number to be extracted from input
49 /// number.
50 /// @tparam     kMsb      The left bit (included) that extraction starts at.
51 /// @tparam     kLsb      The right bit (included) that extraction ends at.
52 /// @tparam     InType    The type of input number.
53 /// @param[in]  value     The input number.
54 ///
55 /// Example (extrat bits between 10 and 5 from a uint32_t and return as a
56 /// uint8_t):
57 ///
58 /// @code
59 ///   constexpr uint32_t number = 0xA0A0A0A0;
60 ///   constexpr uint8_t extracted_number = ExtractBits<uint8_t, 10, 5>(number);
61 /// @endcode
62 template <typename OutType, std::size_t kMsb, std::size_t kLsb, typename InType>
ExtractBits(InType value)63 constexpr OutType ExtractBits(InType value) {
64   static_assert(kMsb >= kLsb);
65   static_assert(kMsb < SIZE_OF_IN_BIT(InType));
66 
67   constexpr std::size_t kBitWidth = kMsb - kLsb + 1;
68   static_assert(kBitWidth <= SIZE_OF_IN_BIT(OutType));
69 
70   if constexpr (kBitWidth == SIZE_OF_IN_BIT(InType)) {
71     return OutType(value);
72   } else {
73     constexpr OutType mask = OutType((OutType(1) << kBitWidth) - 1);
74     return OutType((value >> kLsb) & mask);
75   }
76 }
77 
78 }  // namespace bytes
79 }  // namespace pw
80