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