1 /** 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://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, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef LIBPANDABASE_UTILS_BIT_FIELD_H 17 #define LIBPANDABASE_UTILS_BIT_FIELD_H 18 19 #include <limits> 20 #include "macros.h" 21 22 namespace panda { 23 24 /* 25 * Auxiliary static class that provides access to bits range within an integer value. 26 */ 27 template <typename T, size_t start, size_t bits_num = 1> 28 class BitField { 29 static constexpr unsigned BITS_PER_BYTE = 8; 30 31 static_assert(start < sizeof(uint64_t) * BITS_PER_BYTE, "Invalid position"); 32 static_assert(bits_num != 0U, "Invalid size"); 33 static_assert(bits_num <= sizeof(uint64_t) * BITS_PER_BYTE, "Invalid size"); 34 static_assert(bits_num + start <= sizeof(uint64_t) * BITS_PER_BYTE, "Invalid position + size"); 35 36 public: 37 using ValueType = T; 38 static constexpr unsigned START_BIT = start; 39 static constexpr unsigned END_BIT = start + bits_num; 40 static constexpr unsigned SIZE = bits_num; 41 42 /* 43 * This is static class and should not be instantiated. 44 */ 45 BitField() = delete; 46 47 virtual ~BitField() = delete; 48 49 NO_COPY_SEMANTIC(BitField); 50 NO_MOVE_SEMANTIC(BitField); 51 52 /* 53 * Make BitField type that follows right after current bit range. 54 * 55 * If we have 56 * BitField<T, 0, 9> 57 * then 58 * BitField<T, 0, 9>::NextField<T,3> 59 * will be equal to 60 * BitField<T, 9, 3> 61 * 62 * It is helpful when we need to specify chain of fields. 63 */ 64 template <typename T2, unsigned bits_num2> 65 using NextField = BitField<T2, start + bits_num, bits_num2>; 66 67 /* 68 * Make Flag field that follows right after current bit range. 69 * Same as NextField, but no need to specify number of bits, it is always 1. 70 */ 71 using NextFlag = BitField<bool, start + bits_num, 1>; 72 73 public: 74 /* 75 * Return maximum value that fits bit range [START_BIT : START_BIT+END_BIT] 76 */ MaxValue()77 static constexpr uint64_t MaxValue() 78 { 79 return (1LLU << bits_num) - 1; 80 } 81 82 /* 83 * Return mask of bit range, f.e. 0b1110 for BitField<T, 1, 3> 84 */ Mask()85 static constexpr uint64_t Mask() 86 { 87 return MaxValue() << start; 88 } 89 90 /* 91 * Check if given value fits into the bit field 92 */ IsValid(T value)93 static constexpr bool IsValid(T value) 94 { 95 return (static_cast<uint64_t>(value) & ~MaxValue()) == 0; 96 } 97 98 /* 99 * Set 'value' to current bit range [START_BIT : START_BIT+END_BIT] within the 'stor' parameter. 100 */ 101 template <typename Stor> Set(T value,Stor * stor)102 static constexpr void Set(T value, Stor *stor) 103 { 104 static_assert(END_BIT <= std::numeric_limits<Stor>::digits); 105 *stor = (*stor & ~Mask()) | Encode(value); 106 } 107 108 /* 109 * Return bit range [START_BIT : START_BIT+END_BIT] value from given integer 'value' 110 */ Get(uint64_t value)111 static constexpr T Get(uint64_t value) 112 { 113 return static_cast<T>((value >> start) & MaxValue()); 114 } 115 116 /* 117 * Encode 'value' to current bit range [START_BIT : START_BIT+END_BIT] and return it 118 */ Encode(T value)119 static constexpr uint64_t Encode(T value) 120 { 121 ASSERT(IsValid(value)); 122 return (static_cast<uint64_t>(value) << start); 123 } 124 125 /* 126 * Update 'value' to current bit range [START_BIT : START_BIT+END_BIT] and return it 127 */ Update(uint64_t old_value,T value)128 static constexpr uint64_t Update(uint64_t old_value, T value) 129 { 130 return (old_value & ~Mask()) | Encode(value); 131 } 132 133 /* 134 * Decode from value 135 */ Decode(uint64_t value)136 static constexpr T Decode(uint64_t value) 137 { 138 return Get(value); 139 } 140 }; 141 142 } // namespace panda 143 144 #endif // LIBPANDABASE_UTILS_BIT_FIELD_H 145