• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 PANDA_LIBPANDABASE_UTILS_BIT_FIELD_H_
17 #define PANDA_LIBPANDABASE_UTILS_BIT_FIELD_H_
18 
19 #include "macros.h"
20 
21 namespace panda {
22 
23 /*
24  * Auxiliary static class that provides access to bits range within an integer value.
25  */
26 template <typename T, size_t start, size_t bits_num = 1>
27 class BitField {
28     static constexpr unsigned BITS_PER_BYTE = 8;
29 
30     static_assert(start < sizeof(uint64_t) * BITS_PER_BYTE, "Invalid position");
31     static_assert(bits_num != 0U, "Invalid size");
32     static_assert(bits_num <= sizeof(uint64_t) * BITS_PER_BYTE, "Invalid size");
33     static_assert(bits_num + start <= sizeof(uint64_t) * BITS_PER_BYTE, "Invalid position + size");
34 
35 public:
36     using ValueType = T;
37     static constexpr unsigned START_BIT = start;
38     static constexpr unsigned END_BIT = start + bits_num;
39     static constexpr unsigned SIZE = bits_num;
40 
41     /*
42      * This is static class and should not be instantiated.
43      */
44     BitField() = delete;
45 
46     virtual ~BitField() = delete;
47 
48     NO_COPY_SEMANTIC(BitField);
49     NO_MOVE_SEMANTIC(BitField);
50 
51     /*
52      * Make BitField type follow right after current bit range.
53      *
54      *  If we have
55      *   BitField<T, 0, 9>
56      * then
57      *   BitField<T, 0, 9>::NextField<T,3>
58      * will be equal to
59      *   BitField<T, 9, 3>
60      *
61      * It is helpful when we need to specify chain of fields.
62      */
63     template <typename T2, unsigned bits_num2>
64     using NextField = BitField<T2, start + bits_num, bits_num2>;
65 
66     /*
67      * Make Flag field follow right after current bit range.
68      * Same as NextField, but no need to specify number of bits. It is always 1.
69      */
70     using NextFlag = BitField<bool, start + bits_num, 1>;
71 
72 public:
73     /*
74      * Return mask of bit range, i.e. 0b1110 for BitField<T, 1, 3>
75      */
Mask()76     static constexpr uint64_t Mask()
77     {
78         return ((1LLU << bits_num) - 1) << start;
79     }
80 
81     /*
82      * Check if given value fits into the bit field
83      */
IsValid(T value)84     static constexpr bool IsValid(T value)
85     {
86         return (static_cast<uint64_t>(value) & ~((1LLU << bits_num) - 1)) == 0;
87     }
88 
89     /*
90      * Set 'value' to current bit range [START_BIT : START_BIT+END_BIT] within the 'stor' parameter.
91      */
92     template <typename Stor>
Set(T value,Stor * stor)93     static constexpr void Set(T value, Stor *stor)
94     {
95         *stor = (*stor & ~Mask()) | (static_cast<uint64_t>(value) << start);
96     }
97 
98     /*
99      * Return bit range [START_BIT : START_BIT+END_BIT] value from given integer 'value'
100      */
Get(uint64_t value)101     constexpr static T Get([[maybe_unused]] uint64_t value)
102     {
103         return static_cast<T>((value >> start) & ((1LLU << bits_num) - 1));
104     }
105 
106     /*
107      * Encode 'value' to current bit range [START_BIT : START_BIT+END_BIT] and return it
108      */
Encode(T value)109     static uint64_t Encode(T value)
110     {
111         ASSERT(IsValid(value));
112         return (static_cast<uint64_t>(value) << start);
113     }
114 
115     /*
116      * Update 'value' to current bit range [START_BIT : START_BIT+END_BIT] and return it
117      */
Update(uint64_t old_value,T value)118     static uint64_t Update(uint64_t old_value, T value)
119     {
120         ASSERT(IsValid(value));
121         return (old_value & ~Mask()) | (static_cast<uint64_t>(value) << start);
122     }
123 
124     /*
125      * Decode from value
126      */
Decode(uint64_t value)127     static T Decode(uint64_t value)
128     {
129         return static_cast<T>((value >> start) & ((1LLU << bits_num) - 1));
130     }
131 };
132 
133 }  // namespace panda
134 
135 #endif  // PANDA_LIBPANDABASE_UTILS_BIT_FIELD_H_
136