• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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