This is Unofficial EPICS BASE Doxygen Site
bitSet.cpp
Go to the documentation of this file.
1 /* bitSet.cpp */
2 /*
3  * Copyright information and license terms for this software can be
4  * found in the file LICENSE that is included with the distribution
5  */
9 #include <string.h>
10 #include <stdio.h>
11 #include <iostream>
12 #include <stdexcept>
13 #include <algorithm>
14 
15 #include <epicsMutex.h>
16 
17 #define epicsExportSharedSymbols
18 #include <pv/lock.h>
19 #include <pv/serializeHelper.h>
20 #include <pv/bitSet.h>
21 
22 /*
23  * BitSets are packed into arrays of "words." Currently a word is
24  * a long, which consists of 64 bits, requiring 6 address bits.
25  * The choice of word size is determined purely by performance concerns.
26  */
27 #define ADDRESS_BITS_PER_WORD 6u
28 #define BITS_PER_WORD (1u << ADDRESS_BITS_PER_WORD)
29 #define BYTES_PER_WORD sizeof(uint64)
30 #define BIT_INDEX_MASK (BITS_PER_WORD - 1u)
31 
33 #define WORD_MASK ~((uint64)0)
34 
35 // index of work containing this bit
36 #define WORD_INDEX(bitn) ((bitn)>>ADDRESS_BITS_PER_WORD)
37 // bit offset within word
38 #define WORD_OFFSET(bitn) ((bitn)&BIT_INDEX_MASK)
39 
40 // the words vector should be size()d as small as posible,
41 // so the last word should always have a bit set when the set is not empty
42 #define CHECK_POST() assert(words.empty() || words.back()!=0)
43 
44 namespace epics { namespace pvData {
45 
46  BitSet::shared_pointer BitSet::create(uint32 nbits)
47  {
48  return BitSet::shared_pointer(new BitSet(nbits));
49  }
50 
52 
54  {
55  words.reserve((nbits == 0) ? 1 : WORD_INDEX(nbits-1) + 1);
56  }
57 
58 #if __cplusplus>=201103L
59  BitSet::BitSet(std::initializer_list<uint32> I)
60  {
61  // optimistically guess that highest bit is last (not required)
62  words.reserve((I.size() == 0) ? 1 : WORD_INDEX(*(I.end()-1)) + 1);
63 
64  for(uint32 idx : I)
65  {
66  set(idx);
67  }
68  }
69 #endif
70 
72 
73  void BitSet::recalculateWordsInUse() {
74  // step back from the end to find the first non-zero element
75  size_t nsize = words.size();
76  for(; nsize; nsize--) {
77  if(words[nsize-1])
78  break;
79  }
80  words.resize(nsize);
81  CHECK_POST();
82  }
83 
84  void BitSet::ensureCapacity(uint32 wordsRequired) {
85  words.resize(std::max(words.size(), (size_t)wordsRequired), 0);
86  }
87 
88  void BitSet::expandTo(uint32 wordIndex) {
89  ensureCapacity(wordIndex+1);
90  }
91 
92  BitSet& BitSet::flip(uint32 bitIndex) {
93 
94  uint32 wordIdx = WORD_INDEX(bitIndex);
95  expandTo(wordIdx);
96 
97  words[wordIdx] ^= (((uint64)1) << WORD_OFFSET(bitIndex));
98 
99  recalculateWordsInUse();
100  return *this;
101  }
102 
103  BitSet& BitSet::set(uint32 bitIndex) {
104 
105  uint32 wordIdx = WORD_INDEX(bitIndex);
106  expandTo(wordIdx);
107 
108  words[wordIdx] |= (((uint64)1) << WORD_OFFSET(bitIndex));
109  return *this;
110  }
111 
113 
114  uint32 wordIdx = WORD_INDEX(bitIndex);
115  if (wordIdx < words.size()) {
116  words[wordIdx] &= ~(((uint64)1) << WORD_OFFSET(bitIndex));
117 
118  recalculateWordsInUse();
119  }
120  return *this;
121  }
122 
123  void BitSet::set(uint32 bitIndex, bool value) {
124  if (value)
125  set(bitIndex);
126  else
127  clear(bitIndex);
128  }
129 
130  bool BitSet::get(uint32 bitIndex) const {
131  uint32 wordIdx = WORD_INDEX(bitIndex);
132  return ((wordIdx < words.size())
133  && ((words[wordIdx] & (((uint64)1) << WORD_OFFSET(bitIndex))) != 0));
134  }
135 
136  void BitSet::clear() {
137  words.clear();
138  }
139 
140  uint32 BitSet::numberOfTrailingZeros(uint64 i) {
141  // HD, Figure 5-14
142  uint32 x, y;
143  if (i == 0) return 64;
144  uint32 n = 63;
145  y = (uint32)i; if (y != 0) { n = n -32; x = y; } else x = (uint32)(i>>32);
146  y = x <<16; if (y != 0) { n = n -16; x = y; }
147  y = x << 8; if (y != 0) { n = n - 8; x = y; }
148  y = x << 4; if (y != 0) { n = n - 4; x = y; }
149  y = x << 2; if (y != 0) { n = n - 2; x = y; }
150  return n - ((x << 1) >> 31);
151  }
152 
153  uint32 BitSet::bitCount(uint64 i) {
154  // HD, Figure 5-14
155  i = i - ((i >> 1) & 0x5555555555555555LL);
156  i = (i & 0x3333333333333333LL) + ((i >> 2) & 0x3333333333333333LL);
157  i = (i + (i >> 4)) & 0x0f0f0f0f0f0f0f0fLL;
158  i = i + (i >> 8);
159  i = i + (i >> 16);
160  i = i + (i >> 32);
161  return (uint32)(i & 0x7f);
162  }
163 
164  int32 BitSet::nextSetBit(uint32 fromIndex) const {
165 
166  uint32 u = WORD_INDEX(fromIndex);
167  if (u >= words.size())
168  return -1;
169 
170  uint64 word = words[u] & (WORD_MASK << (fromIndex % BITS_PER_WORD));
171 
172  while (true) {
173  if (word != 0)
174  return (u * BITS_PER_WORD) + numberOfTrailingZeros(word);
175  if (++u == words.size())
176  return -1;
177  word = words[u];
178  }
179  }
180 
181  int32 BitSet::nextClearBit(uint32 fromIndex) const {
182  // Neither spec nor implementation handle bitsets of maximal length.
183 
184  uint32 u = WORD_INDEX(fromIndex);
185  if (u >= words.size())
186  return fromIndex;
187 
188  uint64 word = ~words[u] & (WORD_MASK << (fromIndex % BITS_PER_WORD));
189 
190  while (true) {
191  if (word != 0)
192  return (u * BITS_PER_WORD) + numberOfTrailingZeros(word);
193  if (++u == words.size())
194  return words.size() * BITS_PER_WORD;
195  word = ~words[u];
196  }
197  }
198 
199  bool BitSet::isEmpty() const {
200  return words.empty();
201  }
202 
204  uint32 sum = 0;
205  for (uint32 i = 0; i < words.size(); i++)
206  sum += bitCount(words[i]);
207  return sum;
208  }
209 
211  return words.size() * BITS_PER_WORD;
212  }
213 
214  bool BitSet::logical_and(const BitSet& set) const
215  {
216  size_t nwords = std::min(words.size(), set.words.size());
217  for(size_t i=0; i<nwords; i++) {
218  if(words[i] & set.words[i])
219  return true;
220  }
221  return false;
222  }
223  bool BitSet::logical_or(const BitSet& set) const
224  {
225  return !words.empty() || !set.words.empty();
226  }
227 
229  // Check for self-assignment!
230  if (this == &set) return *this;
231 
232  // the result length will be <= the shorter of the two inputs
233  words.resize(std::min(words.size(), set.words.size()), 0);
234 
235  for(size_t i=0, e=words.size(); i<e; i++)
236  words[i] &= set.words[i];
237 
238  recalculateWordsInUse();
239  return *this;
240  }
241 
243  // Check for self-assignment!
244  if (this == &set) return *this;
245 
246  // result length will be the same as the longer of the two inputs
247  words.resize(std::max(words.size(), set.words.size()), 0);
248 
249  // since we expand w/ zeros, then iterate using the size of the other vector
250  for(size_t i=0, e=set.words.size(); i<e; i++)
251  words[i] |= set.words[i];
252 
253  CHECK_POST();
254  return *this;
255  }
256 
258  // result length will <= the longer of the two inputs
259  words.resize(std::max(words.size(), set.words.size()), 0);
260 
261  for(size_t i=0, e=set.words.size(); i<e; i++)
262  words[i] ^= set.words[i];
263 
264  recalculateWordsInUse();
265  return *this;
266  }
267 
268 
270  // Check for self-assignment!
271  if (this != &set) {
272  words = set.words;
273  }
274  return *this;
275  }
276 
277  void BitSet::swap(BitSet& set)
278  {
279  words.swap(set.words);
280  }
281 
282  void BitSet::or_and(const BitSet& set1, const BitSet& set2) {
283 
284  const size_t andlen = std::min(set1.words.size(), set2.words.size());
285  words.resize(std::max(words.size(), andlen), 0);
286 
287  // Perform logical AND on words in common
288  for (uint32 i = 0; i < andlen; i++)
289  words[i] |= (set1.words[i] & set2.words[i]);
290 
291  recalculateWordsInUse();
292  }
293 
294  bool BitSet::operator==(const BitSet &set) const
295  {
296  if (this == &set)
297  return true;
298 
299  if (words.size() != set.words.size())
300  return false;
301 
302  // Check words in use by both BitSets
303  for (uint32 i = 0; i < words.size(); i++)
304  if (words[i] != set.words[i])
305  return false;
306 
307  return true;
308  }
309 
310  bool BitSet::operator!=(const BitSet &set) const
311  {
312  return !(*this == set);
313  }
314 
315  void BitSet::serialize(ByteBuffer* buffer, SerializableControl* flusher) const {
316 
317  uint32 n = words.size();
318  if (n == 0) {
319  SerializeHelper::writeSize(0, buffer, flusher);
320  return;
321  }
322  uint32 len = BYTES_PER_WORD * (n-1); // length excluding bits in the last word
323  // count non-zero bytes in the last word
324  for (uint64 x = words[n - 1]; x != 0; x >>= 8)
325  len++;
326 
327  SerializeHelper::writeSize(len, buffer, flusher);
328  flusher->ensureBuffer(len);
329 
330  n = len / 8;
331  for (uint32 i = 0; i < n; i++)
332  buffer->putLong(words[i]);
333 
334  if (n < words.size())
335  for (uint64 x = words[words.size() - 1]; x != 0; x >>= 8)
336  buffer->putByte((int8) (x & 0xff));
337  }
338 
340 
341  uint32 bytes = static_cast<uint32>(SerializeHelper::readSize(buffer, control)); // in bytes
342 
343  size_t wordsInUse = (bytes + 7) / BYTES_PER_WORD;
344  words.resize(wordsInUse);
345 
346  if (wordsInUse == 0)
347  return;
348 
349  control->ensureData(bytes);
350 
351  uint32 i = 0;
352  uint32 longs = bytes / 8;
353  while (i < longs)
354  words[i++] = buffer->getLong();
355 
356  for (uint32 j = i; j < wordsInUse; j++)
357  words[j] = 0;
358 
359  for (uint32 remaining = (bytes - longs * 8), j = 0; j < remaining; j++)
360  words[i] |= (buffer->getByte() & 0xffLL) << (8 * j);
361 
362  recalculateWordsInUse(); // Sender shouldn't add extra zero bytes, but don't fail it it does
363  }
364 
365  epicsShareExtern std::ostream& operator<<(std::ostream& o, const BitSet& b)
366  {
367  o << '{';
368  int32 i = b.nextSetBit(0);
369  if (i != -1) {
370  o << i;
371  for (i = b.nextSetBit(i+1); i >= 0; i = b.nextSetBit(i+1)) {
372  int32 endOfRun = b.nextClearBit(i);
373  do { o << ", " << i; } while (++i < endOfRun);
374  }
375  }
376  o << '}';
377  return o;
378  }
379 
380 }};
int8_t int8
Definition: pvType.h:75
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *flusher)
Definition: bitSet.cpp:339
static BitSetPtr create(uint32 nbits)
Definition: bitSet.cpp:46
Definition: link.h:174
#define max(x, y)
Definition: flexdef.h:81
#define BYTES_PER_WORD
Definition: bitSet.cpp:29
EPICS_ALWAYS_INLINE int8 getByte()
Definition: byteBuffer.h:617
bool get(uint32 bitIndex) const
Definition: bitSet.cpp:130
int i
Definition: scan.c:967
#define min(x, y)
Definition: flexdef.h:78
TODO only here because of the Lockable.
Definition: ntaggregate.cpp:16
#define WORD_MASK
Definition: bitSet.cpp:33
A vector of bits.
Definition: bitSet.h:56
static void writeSize(std::size_t s, ByteBuffer *buffer, SerializableControl *flusher)
BitSet & operator=(const BitSet &set)
Definition: bitSet.cpp:269
static std::size_t readSize(ByteBuffer *buffer, DeserializableControl *control)
#define WORD_OFFSET(bitn)
Definition: bitSet.cpp:38
Callback class for deserialization.
Definition: serialize.h:89
bool operator!=(const BitSet &set) const
Definition: bitSet.cpp:310
std::ostream & operator<<(std::ostream &o, const Field &f)
virtual void serialize(ByteBuffer *buffer, SerializableControl *flusher) const
Definition: bitSet.cpp:315
#define WORD_INDEX(bitn)
Definition: bitSet.cpp:36
bool operator==(const BitSet &set) const
Definition: bitSet.cpp:294
#define epicsShareExtern
Definition: shareLib.h:204
uint64_t uint64
Definition: pvType.h:103
int32 nextClearBit(uint32 fromIndex) const
Definition: bitSet.cpp:181
BitSet & flip(uint32 bitIndex)
Definition: bitSet.cpp:92
#define BITS_PER_WORD
Definition: bitSet.cpp:28
APIs for the epicsMutex mutual exclusion semaphore.
EPICS_ALWAYS_INLINE void putByte(int8 value)
Definition: byteBuffer.h:525
This class implements a Bytebuffer that is like the java.nio.ByteBuffer.
Definition: byteBuffer.h:233
int32 nextSetBit(uint32 fromIndex) const
Definition: bitSet.cpp:164
bool logical_and(const BitSet &other) const
Returns true if any bit is set in both *this and other.
Definition: bitSet.cpp:214
bool isEmpty() const
Definition: bitSet.cpp:199
bool logical_or(const BitSet &other) const
Returns true if any bit is set in both *this or other.
Definition: bitSet.cpp:223
BitSet & operator|=(const BitSet &set)
Definition: bitSet.cpp:242
#define CHECK_POST()
Definition: bitSet.cpp:42
void or_and(const BitSet &set1, const BitSet &set2)
Definition: bitSet.cpp:282
virtual ~BitSet()
Definition: bitSet.cpp:71
EPICS_ALWAYS_INLINE int64 getLong()
Definition: byteBuffer.h:635
BitSet & operator^=(const BitSet &set)
Definition: bitSet.cpp:257
void swap(BitSet &set)
Swap contents.
Definition: bitSet.cpp:277
virtual void ensureBuffer(std::size_t size)=0
Callback class for serialization.
Definition: serialize.h:34
uint32 cardinality() const
Definition: bitSet.cpp:203
BitSet & set(uint32 bitIndex)
Definition: bitSet.cpp:103
virtual void ensureData(std::size_t size)=0
EPICS_ALWAYS_INLINE void putLong(int64 value)
Definition: byteBuffer.h:543
int32_t int32
Definition: pvType.h:83
uint32 size() const
Definition: bitSet.cpp:210
uint32_t uint32
Definition: pvType.h:99
BitSet & operator&=(const BitSet &set)
Definition: bitSet.cpp:228