v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
bit-field.h
Go to the documentation of this file.
1// Copyright 2019 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_BASE_BIT_FIELD_H_
6#define V8_BASE_BIT_FIELD_H_
7
8#include <stdint.h>
9
10#include <algorithm>
11
12#include "src/base/macros.h"
13
14namespace v8 {
15namespace base {
16
17// ----------------------------------------------------------------------------
18// BitField is a help template for encoding and decode bitfield with
19// unsigned content.
20// Instantiate them via 'using', which is cheaper than deriving a new class:
21// using MyBitField = base::BitField<MyEnum, 4, 2>;
22// The BitField class is final to enforce this style over derivation.
23
24template <class T, int shift, int size, class U = uint32_t>
25class BitField final {
26 public:
27 static_assert(std::is_unsigned<U>::value);
28 static_assert(shift < 8 * sizeof(U)); // Otherwise shifts by {shift} are UB.
29 static_assert(size < 8 * sizeof(U)); // Otherwise shifts by {size} are UB.
30 static_assert(shift + size <= 8 * sizeof(U));
31 static_assert(size > 0);
32
33 using FieldType = T;
34 using BaseType = U;
35
36 // A type U mask of bit field. To use all bits of a type U of x bits
37 // in a bitfield without compiler warnings we have to compute 2^x
38 // without using a shift count of x in the computation.
39 static constexpr int kShift = shift;
40 static constexpr int kSize = size;
41 static constexpr U kMask = ((U{1} << kShift) << kSize) - (U{1} << kShift);
42 static constexpr int kLastUsedBit = kShift + kSize - 1;
43 static constexpr U kNumValues = U{1} << kSize;
44 static constexpr U kMax = kNumValues - 1;
45
46 template <class T2, int size2>
48
49 // Tells whether the provided value fits into the bit field.
50 static constexpr bool is_valid(T value) {
51 return (static_cast<U>(value) & ~kMax) == 0;
52 }
53
54 // Returns a type U with the bit field value encoded.
55 static constexpr U encode(T value) {
56 DCHECK(is_valid(value));
57 return static_cast<U>(value) << kShift;
58 }
59
60 // Returns a type U with the bit field value updated.
61 V8_NODISCARD static constexpr U update(U previous, T value) {
62 return (previous & ~kMask) | encode(value);
63 }
64
65 // Extracts the bit field from the value.
66 static constexpr T decode(U value) {
67 return static_cast<T>((value & kMask) >> kShift);
68 }
69};
70
71// ----------------------------------------------------------------------------
72// BitFieldUnion can be used to combine two linear BitFields.
73// So far only the static mask is computed. Encoding and decoding tbd.
74// Can be used for example as a quick combined check:
75// `if (BitFieldUnion<BFA, BFB>::kMask & bitfield) ...`
76
77template <typename A, typename B>
78class BitFieldUnion final {
79 public:
80 static_assert(
81 std::is_same<typename A::BaseType, typename B::BaseType>::value);
82 static_assert((A::kMask & B::kMask) == 0);
83 static constexpr int kShift = std::min(A::kShift, B::kShift);
84 static constexpr int kMask = A::kMask | B::kMask;
85 static constexpr int kSize =
86 A::kSize + B::kSize + (std::max(A::kShift, B::kShift) - kShift);
87};
88
89template <class T, int shift, int size>
91
92template <class T, int shift, int size>
94
95template <class T, int shift, int size>
97
98// Helper macros for defining a contiguous sequence of bit fields. Example:
99// (backslashes at the ends of respective lines of this multi-line macro
100// definition are omitted here to please the compiler)
101//
102// #define MAP_BIT_FIELD1(V, _)
103// V(IsAbcBit, bool, 1, _)
104// V(IsBcdBit, bool, 1, _)
105// V(CdeBits, int, 5, _)
106// V(DefBits, MutableMode, 1, _)
107//
108// DEFINE_BIT_FIELDS(MAP_BIT_FIELD1)
109// or
110// DEFINE_BIT_FIELDS_64(MAP_BIT_FIELD1)
111//
112#define DEFINE_BIT_FIELD_RANGE_TYPE(Name, Type, Size, _) \
113 k##Name##Start, k##Name##End = k##Name##Start + Size - 1,
114
115#define DEFINE_BIT_RANGES(LIST_MACRO) \
116 struct LIST_MACRO##_Ranges { \
117 enum { LIST_MACRO(DEFINE_BIT_FIELD_RANGE_TYPE, _) kBitsCount }; \
118 };
119
120#define DEFINE_BIT_FIELD_TYPE(Name, Type, Size, RangesName) \
121 using Name = base::BitField<Type, RangesName::k##Name##Start, Size>;
122
123#define DEFINE_BIT_FIELD_64_TYPE(Name, Type, Size, RangesName) \
124 using Name = base::BitField64<Type, RangesName::k##Name##Start, Size>;
125
126#define DEFINE_BIT_FIELDS(LIST_MACRO) \
127 DEFINE_BIT_RANGES(LIST_MACRO) \
128 LIST_MACRO(DEFINE_BIT_FIELD_TYPE, LIST_MACRO##_Ranges)
129
130#define DEFINE_BIT_FIELDS_64(LIST_MACRO) \
131 DEFINE_BIT_RANGES(LIST_MACRO) \
132 LIST_MACRO(DEFINE_BIT_FIELD_64_TYPE, LIST_MACRO##_Ranges)
133
134// ----------------------------------------------------------------------------
135// BitSetComputer is a help template for encoding and decoding information for
136// a variable number of items in an array.
137//
138// To encode boolean data in a smi array you would use:
139// using BoolComputer = BitSetComputer<bool, 1, kSmiValueSize, uint32_t>;
140//
141template <class T, int kBitsPerItem, int kBitsPerWord, class U>
143 public:
144 static const int kItemsPerWord = kBitsPerWord / kBitsPerItem;
145 static const int kMask = (1 << kBitsPerItem) - 1;
146
147 // The number of array elements required to embed T information for each item.
148 static int word_count(int items) {
149 if (items == 0) return 0;
150 return (items - 1) / kItemsPerWord + 1;
151 }
152
153 // The array index to look at for item.
154 static int index(int base_index, int item) {
155 return base_index + item / kItemsPerWord;
156 }
157
158 // Extract T data for a given item from data.
159 static T decode(U data, int item) {
160 return static_cast<T>((data >> shift(item)) & kMask);
161 }
162
163 // Return the encoding for a store of value for item in previous.
164 static U encode(U previous, int item, T value) {
165 int shift_value = shift(item);
166 int set_bits = (static_cast<int>(value) << shift_value);
167 return (previous & ~(kMask << shift_value)) | set_bits;
168 }
169
170 static int shift(int item) { return (item % kItemsPerWord) * kBitsPerItem; }
171};
172
173} // namespace base
174} // namespace v8
175
176#endif // V8_BASE_BIT_FIELD_H_
#define T
static constexpr int kMask
Definition bit-field.h:84
static constexpr int kShift
Definition bit-field.h:83
static constexpr int kSize
Definition bit-field.h:85
static constexpr U kMax
Definition bit-field.h:44
static constexpr int kLastUsedBit
Definition bit-field.h:42
static constexpr U kNumValues
Definition bit-field.h:43
static constexpr T decode(U value)
Definition bit-field.h:66
static constexpr bool is_valid(T value)
Definition bit-field.h:50
static constexpr U encode(T value)
Definition bit-field.h:55
static V8_NODISCARD constexpr U update(U previous, T value)
Definition bit-field.h:61
static constexpr int kSize
Definition bit-field.h:40
static constexpr U kMask
Definition bit-field.h:41
static constexpr int kShift
Definition bit-field.h:39
static int index(int base_index, int item)
Definition bit-field.h:154
static U encode(U previous, int item, T value)
Definition bit-field.h:164
static int word_count(int items)
Definition bit-field.h:148
static T decode(U data, int item)
Definition bit-field.h:159
static const int kMask
Definition bit-field.h:145
static int shift(int item)
Definition bit-field.h:170
static const int kItemsPerWord
Definition bit-field.h:144
LineAndColumn previous
#define DCHECK(condition)
Definition logging.h:482
#define V8_NODISCARD
Definition v8config.h:693
std::unique_ptr< ValueMirror > value