Skip to content

Commit 9508653

Browse files
committed
New bitfield syntax.
Bitfield members now accessed via a union instead of accessor functions. Direct assignment/++ instead of get(), set(), add(). Array members support operator[].
1 parent c79dfa4 commit 9508653

File tree

4 files changed

+136
-142
lines changed

4 files changed

+136
-142
lines changed

common/bitfield.h

Lines changed: 86 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -9,152 +9,128 @@
99
#include <cassert>
1010

1111

12-
//---------------------------------------------------------
13-
// BitField<>: Used internally by BEGIN_BITFIELD_TYPE macro.
14-
// T is expected to be an unsigned integral type.
15-
//---------------------------------------------------------
16-
template <class T>
17-
struct BitField
18-
{
19-
typedef T IntType;
20-
T value;
21-
22-
BitField(T v = 0) : value(v) {}
23-
BitField& baseCast() { return *this; }
24-
const BitField& baseCast() const { return *this; }
25-
};
26-
27-
2812
//---------------------------------------------------------
2913
// BitFieldMember<>: Used internally by ADD_BITFIELD_MEMBER macro.
3014
//---------------------------------------------------------
3115
template <class T, int Offset, int Bits>
32-
struct BitFieldMember : BitField<T>
16+
class BitFieldMember
3317
{
18+
private:
3419
static_assert(Offset + Bits <= (int) sizeof(T) * 8, "Member exceeds bitfield boundaries");
3520
static_assert(Bits < (int) sizeof(T) * 8, "Can't fill entire bitfield with one member");
3621

37-
// Compile-time constants.
38-
// Not easy to access since the template instance is wrapped in a macro.
39-
// You can get at them using eg. BitFieldType().member().maximum() instead.
4022
static const T Maximum = (T(1) << Bits) - 1;
4123
static const T Mask = Maximum << Offset;
4224

43-
// Can't instantiate this class directly.
44-
// Must instead cast from BitField<T>.
45-
// That's what ADD_BITFIELD_MEMBER does.
46-
BitFieldMember() = delete;
25+
T value;
4726

27+
public:
4828
T maximum() const { return Maximum; }
4929
T one() const { return T(1) << Offset; }
5030

51-
T get() const
31+
operator T() const
5232
{
53-
return (this->value >> Offset) & Maximum;
33+
return (value >> Offset) & Maximum;
5434
}
5535

56-
void set(T v)
36+
BitFieldMember& operator=(T v)
5737
{
58-
assert(v <= Maximum); // v must fit inside the bitfield member
59-
this->value = (this->value & ~Mask) | (v << Offset);
38+
assert(v <= Maximum); // v must fit inside the bitfield member
39+
value = (value & ~Mask) | (v << Offset);
40+
return *this;
6041
}
6142

62-
void setWrapped(T v)
43+
BitFieldMember& operator+=(T v)
6344
{
64-
this->value = (this->value & ~Mask) | ((v & Maximum) << Offset);
45+
assert(T(*this) + v <= Maximum); // result must fit inside the bitfield member
46+
value += v << Offset;
47+
return *this;
6548
}
6649

67-
void add(T v)
50+
BitFieldMember& operator-=(T v)
6851
{
69-
assert(get() + v <= Maximum); // result must fit inside the bitfield member
70-
this->value += v << Offset;
52+
assert(T(*this) >= v); // result must not underflow
53+
value -= v << Offset;
54+
return *this;
7155
}
7256

73-
void addWrapped(T v)
74-
{
75-
this->value = (this->value & ~Mask) | ((this->value + (v << Offset)) & Mask);
76-
}
77-
78-
void sub(T v)
79-
{
80-
assert(get() >= v); // result must not underflow
81-
this->value -= v << Offset;
82-
}
83-
84-
void subWrapped(T v)
85-
{
86-
this->value = (this->value & ~Mask) | ((this->value - (v << Offset)) & Mask);
87-
}
57+
BitFieldMember& operator++() { return *this += 1; }
58+
BitFieldMember& operator++(int) { return *this += 1; } // postfix form
59+
BitFieldMember& operator--() { return *this -= 1; }
60+
BitFieldMember& operator--(int) { return *this -= 1; } // postfix form
8861
};
8962

9063

9164
//---------------------------------------------------------
9265
// BitFieldArray<>: Used internally by ADD_BITFIELD_ARRAY macro.
9366
//---------------------------------------------------------
9467
template <class T, int BaseOffset, int BitsPerItem, int NumItems>
95-
struct BitFieldArray : BitField<T>
68+
class BitFieldArray
9669
{
70+
private:
9771
static_assert(BaseOffset + BitsPerItem * NumItems <= (int) sizeof(T) * 8, "Array exceeds bitfield boundaries");
9872
static_assert(BitsPerItem < (int) sizeof(T) * 8, "Can't fill entire bitfield with one array element");
9973

100-
// Compile-time constants.
101-
// Not easy to access since the template instance is wrapped in a macro.
102-
// You can get at them using eg. BitFieldType().member().maximum() instead.
10374
static const T Maximum = (T(1) << BitsPerItem) - 1;
10475

105-
// Can't instantiate this class directly.
106-
// Must instead cast from BitField<T>.
107-
// That's what ADD_BITFIELD_ARRAY does.
108-
BitFieldArray() = delete;
109-
110-
T maximum() const { return Maximum; }
111-
int offset(int i) const
112-
{
113-
assert(i >= 0 && i < NumItems); // array index must be in range
114-
return BaseOffset + BitsPerItem * i;
115-
}
116-
T one(int i) const { return T(1) << offset(i); }
117-
T mask(int i) const { return Maximum << offset(i); }
118-
int numItems() const { return NumItems; }
119-
120-
T get(int i) const
121-
{
122-
return (this->value >> offset(i)) & Maximum;
123-
}
124-
125-
void set(int i, T v)
126-
{
127-
assert(v <= Maximum); // v must fit inside the bitfield member
128-
this->value = (this->value & ~mask(i)) | (v << offset(i));
129-
}
130-
131-
void setWrapped(int i, T v)
132-
{
133-
this->value = (this->value & ~mask(i)) | ((v & Maximum) << offset(i));
134-
}
76+
T value;
13577

136-
void add(int i, T v)
78+
class Element
13779
{
138-
assert(get(i) + v <= Maximum); // result must fit inside the bitfield member
139-
this->value += v << offset(i);
140-
}
80+
private:
81+
T& value;
82+
int offset;
83+
84+
public:
85+
Element(T& value, int offset) : value(value), offset(offset) {}
86+
T mask() const { return Maximum << offset; }
87+
88+
operator T() const
89+
{
90+
return (value >> offset) & Maximum;
91+
}
92+
93+
Element& operator=(T v)
94+
{
95+
assert(v <= Maximum); // v must fit inside the bitfield member
96+
value = (value & ~mask()) | (v << offset);
97+
return *this;
98+
}
99+
100+
Element& operator+=(T v)
101+
{
102+
assert(T(*this) + v <= Maximum); // result must fit inside the bitfield member
103+
value += v << offset;
104+
return *this;
105+
}
106+
107+
Element& operator-=(T v)
108+
{
109+
assert(T(*this) >= v); // result must not underflow
110+
value -= v << offset;
111+
return *this;
112+
}
113+
114+
Element& operator++() { return *this += 1; }
115+
Element& operator++(int) { return *this += 1; } // postfix form
116+
Element& operator--() { return *this -= 1; }
117+
Element& operator--(int) { return *this -= 1; } // postfix form
118+
};
141119

142-
void addWrapped(int i, T v)
143-
{
144-
T m = mask(i);
145-
this->value = (this->value & ~m) | ((this->value + (v << offset(i))) & m);
146-
}
120+
public:
121+
T maximum() const { return Maximum; }
122+
int numItems() const { return NumItems; }
147123

148-
void sub(int i, T v)
124+
Element operator[](int i)
149125
{
150-
assert(get(i) >= v); // result must not underflow
151-
this->value -= v << offset(i);
126+
assert(i >= 0 && i < NumItems); // array index must be in range
127+
return Element(value, BaseOffset + BitsPerItem * i);
152128
}
153129

154-
void subWrapped(int i, T v)
130+
const Element operator[](int i) const
155131
{
156-
T m = mask(i);
157-
this->value = (this->value & ~m) | ((this->value - (v << offset(i))) & m);
132+
assert(i >= 0 && i < NumItems); // array index must be in range
133+
return Element(value, BaseOffset + BitsPerItem * i);
158134
}
159135
};
160136

@@ -164,17 +140,22 @@ struct BitFieldArray : BitField<T>
164140
// For usage examples, see RWLock and LockReducedDiningPhilosophers.
165141
//---------------------------------------------------------
166142
#define BEGIN_BITFIELD_TYPE(typeName, T) \
167-
struct typeName : BitField<T> \
143+
union typeName \
168144
{ \
169-
typeName(T v = 0) : BitField(v) {}
145+
private: \
146+
typedef T _IntType; \
147+
T value; \
148+
public: \
149+
typeName(T v = 0) : value(v) {} \
150+
typeName& operator=(T v) { value = v; return *this; } \
151+
operator T&() { return value; } \
152+
operator T() const { return value; }
170153

171154
#define ADD_BITFIELD_MEMBER(memberName, offset, bits) \
172-
BitFieldMember<IntType, offset, bits>& memberName() { return static_cast<BitFieldMember<IntType, offset, bits>&>(baseCast()); } \
173-
const BitFieldMember<IntType, offset, bits>& memberName() const { return static_cast<const BitFieldMember<IntType, offset, bits>&>(baseCast()); }
155+
BitFieldMember<_IntType, offset, bits> memberName;
174156

175-
#define ADD_BITFIELD_ARRAY(memberName, offset, bitsPerItem, numItems) \
176-
BitFieldArray<IntType, offset, bitsPerItem, numItems>& memberName() { return static_cast<BitFieldArray<IntType, offset, bitsPerItem, numItems>&>(baseCast()); } \
177-
const BitFieldArray<IntType, offset, bitsPerItem, numItems>& memberName() const { return static_cast<const BitFieldArray<IntType, offset, bitsPerItem, numItems>&>(baseCast()); }
157+
#define ADD_BITFIELD_ARRAY(memberName, offset, bits, numItems) \
158+
BitFieldArray<_IntType, offset, bits, numItems> memberName;
178159

179160
#define END_BITFIELD_TYPE() \
180161
};

common/diningphilosophers.h

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ class LockReducedDiningPhilosophers
162162
int m_numPhilos;
163163

164164
// Lock-free "box office".
165-
// AllStatus::philos() keeps track of the status of each philosopher (thread).
165+
// AllStatus::philos keeps track of the status of each philosopher (thread).
166166
// 0: Philosopher is thinking
167167
// 1: Philosopher is eating
168168
// 2+: Philosopher is waiting and must not eat before his/her direct neighbors if they have a lower status.
@@ -193,19 +193,19 @@ class LockReducedDiningPhilosophers
193193
bool tryAdjustStatus(AllStatus& allStatus, int philoIndex, int target, int step) const
194194
{
195195
// Should not already have the target status.
196-
assert(allStatus.philos().get(philoIndex) != target);
197-
if (allStatus.philos().get(philoIndex) == target + 1)
196+
assert(allStatus.philos[philoIndex] != target);
197+
if (allStatus.philos[philoIndex] == target + 1)
198198
{
199199
// Decrementing this status will bring it to target.
200200
// Make sure the next neighbor doesn't prevent it.
201201
int n = neighbor(philoIndex, step);
202-
assert(allStatus.philos().get(n) != target + 1); // No two neighbors should have equal status > 0.
203-
if (allStatus.philos().get(n) != target)
202+
assert(allStatus.philos[n] != target + 1); // No two neighbors should have equal status > 0.
203+
if (allStatus.philos[n] != target)
204204
{
205205
// Decrement it.
206-
allStatus.philos().set(philoIndex, target);
206+
allStatus.philos[philoIndex] = target;
207207
// If neighbor's status is exactly 1 greater, continue visiting.
208-
if (allStatus.philos().get(n) > IntType(target))
208+
if (allStatus.philos[n] > IntType(target))
209209
tryAdjustStatus(allStatus, n, target + 1, step);
210210
return true;
211211
}
@@ -218,8 +218,8 @@ class LockReducedDiningPhilosophers
218218
: m_numPhilos(numPhilos)
219219
, m_allStatus(0)
220220
{
221-
assert(IntType(numPhilos) <= AllStatus().philos().maximum());
222-
assert(numPhilos < AllStatus().philos().numItems());
221+
assert(IntType(numPhilos) <= AllStatus().philos.maximum());
222+
assert(numPhilos < AllStatus().philos.numItems());
223223
m_sema = std::unique_ptr<DefaultSemaphoreType[]>(new DefaultSemaphoreType[numPhilos]);
224224
}
225225

@@ -230,16 +230,16 @@ class LockReducedDiningPhilosophers
230230
AllStatus oldStatus = m_allStatus.load(std::memory_order_relaxed);
231231
for (;;) // Begin CAS loop
232232
{
233-
assert(oldStatus.philos().get(philoIndex) == 0); // Must have been thinking
233+
assert(oldStatus.philos[philoIndex] == 0); // Must have been thinking
234234
// Establish order relative to direct neighbors.
235-
maxNeighborStatus = std::max(oldStatus.philos().get(left(philoIndex)), oldStatus.philos().get(right(philoIndex)));
235+
maxNeighborStatus = std::max(oldStatus.philos[left(philoIndex)], oldStatus.philos[right(philoIndex)]);
236236
AllStatus newStatus(oldStatus);
237-
newStatus.philos().set(philoIndex, maxNeighborStatus + 1);
237+
newStatus.philos[philoIndex] = maxNeighborStatus + 1;
238238
// Sanity check.
239239
for (int i = 0; i < m_numPhilos; i++)
240-
assert(newStatus.philos().get(i) <= IntType(m_numPhilos));
240+
assert(newStatus.philos[i] <= IntType(m_numPhilos));
241241
// CAS until successful. On failure, oldStatus will be updated with the latest value.
242-
if (m_allStatus.compare_exchange_strong(oldStatus.value, newStatus.value, std::memory_order_relaxed))
242+
if (m_allStatus.compare_exchange_strong(oldStatus, newStatus, std::memory_order_relaxed))
243243
break;
244244
}
245245

@@ -258,11 +258,11 @@ class LockReducedDiningPhilosophers
258258
AllStatus oldStatus = m_allStatus.load(std::memory_order_relaxed);
259259
for (;;) // Begin CAS loop
260260
{
261-
assert(oldStatus.philos().get(philoIndex) == 1); // Must have been eating
261+
assert(oldStatus.philos[philoIndex] == 1); // Must have been eating
262262
AllStatus newStatus(oldStatus);
263-
newStatus.philos().set(philoIndex, 0);
263+
newStatus.philos[philoIndex] = 0;
264264
// Choose which neighbor to visit first based on priority
265-
if (newStatus.philos().get(firstNeighbor) > newStatus.philos().get(secondNeighbor))
265+
if (newStatus.philos[firstNeighbor] > newStatus.philos[secondNeighbor])
266266
{
267267
std::swap(firstNeighbor, secondNeighbor);
268268
stepFirst = m_numPhilos - stepFirst;
@@ -272,9 +272,9 @@ class LockReducedDiningPhilosophers
272272
secondWillEat = tryAdjustStatus(newStatus, secondNeighbor, 1, m_numPhilos - stepFirst);
273273
// Sanity check.
274274
for (int i = 0; i < m_numPhilos; i++)
275-
assert(newStatus.philos().get(i) <= IntType(m_numPhilos));
275+
assert(newStatus.philos[i] <= IntType(m_numPhilos));
276276
// CAS until successful. On failure, oldStatus will be updated with the latest value.
277-
if (m_allStatus.compare_exchange_strong(oldStatus.value, newStatus.value, std::memory_order_relaxed))
277+
if (m_allStatus.compare_exchange_strong(oldStatus, newStatus, std::memory_order_relaxed))
278278
break;
279279
}
280280

0 commit comments

Comments
 (0)