rcolyer.net
RC Lib  Version 202403231100
Bitfield.h
Go to the documentation of this file.
1 /////////////////////////////////////////////////////////////////////
2 //
3 // RC Library, (c) 2011-2014, Ryan A. Colyer
4 // Distributed under the Boost Software License, v1.0. (LICENSE.txt)
5 //
6 /// \file Bitfield.h
7 /// Provides a one-dimensional vector-like structure of packed bits.
8 /////////////////////////////////////////////////////////////////////
9 
10 #ifndef RC_BITFIELD_H
11 #define RC_BITFIELD_H
12 
13 
14 #include "Data1D.h"
15 #include "Errors.h"
16 #include <iostream>
17 
18 
19 namespace RC {
20  /// A bounds-safe one-dimensional vector-like structure of efficiently
21  /// packed bits.
22  /** It provides efficient resizing and append operations, and bounds-safe
23  * array access.
24  * @see Bitfield2D
25  * @see Bitfield3D
26  */
27  class Bitfield {
28  friend class Bitfield2D;
29  friend class Bitfield3D;
30 
31  protected:
32  /// @cond UNDOC
33  inline void Initialize(size_t new_b_size) {
34  b_size = new_b_size;
35 
36  size_t u32size;
37 
38  if (b_size > 0) {
39  u32size = b_size >> 5;
40  if (b_size & 31) {
41  u32size++;
42  }
43  data = Data1D<u32>(u32size);
44  }
45  }
46  /// @endcond
47 
48  public:
49  /// Default constructor which initializes to size 0.
50  inline Bitfield() {
51  Initialize(0);
52  }
53 
54  /// Constructor which sets the initial size to b_size bits.
55  /** @param b_size The initial number of bits.
56  */
57  explicit inline Bitfield(size_t b_size) {
58  Initialize(b_size);
59  }
60 
61 
62  /// Deletes the stored data, resets the size to 0, and releases the
63  /// memory.
64  inline void Delete() {
65  data.Delete();
66  b_size = 0;
67  }
68 
69 
70  /// True if the size is 0.
71  inline bool IsEmpty() const {
72  return (b_size == 0);
73  }
74 
75 
76  protected:
77  /// A temporary return-type that serves as an interface to specific
78  /// bit values.
79  class BitfieldBool {
80  friend class Bitfield;
81 
82  public:
83 
84  /// @cond PROTECTED
85  inline BitfieldBool(Bitfield *bf, size_t index)
86  : bf (bf) {
87  bf->Assert(index);
88  index_u32 = index >> 5;
89  index_mask = 1 << (index & 31);
90  }
91  /// @endcond
92 
93  /// Implicit conversion to bool.
94  inline operator bool () const {
95  return (bf->data[index_u32] & index_mask);
96  }
97 
98  /// Set the bit to true / 1.
99  inline void Set() {
100  bf->data[index_u32] |= index_mask;
101  }
102 
103  /// Set the bit to false / 0.
104  inline void Clear() {
105  bf->data[index_u32] &= ~index_mask;
106  }
107 
108  /// Assign the bool value of set to this bit.
109  inline BitfieldBool& operator= (const bool set) {
110  if (set) {
111  Set();
112  }
113  else {
114  Clear();
115  }
116 
117  return *this;
118  }
119 
120 
121  protected:
122  /// @cond PROTECTED
123 
124  Bitfield *bf;
125  size_t index_u32;
126  u32 index_mask;
127  /// @endcond
128  };
129 
130  /// A temporary return-type that serves as a const interface to specific
131  /// bit values.
133  friend class Bitfield;
134 
135  public:
136 
137  /// @cond PROTECTED
138  inline BitfieldBoolConst(const Bitfield *bf, size_t index)
139  : bf (bf) {
140  bf->Assert(index);
141  index_u32 = index >> 5;
142  index_mask = 1 << (index & 31);
143  }
144  /// @endcond
145 
146  /// Implicit conversion to bool.
147  inline operator bool () const {
148  return (bf->data[index_u32] & index_mask);
149  }
150 
151  protected:
152  /// @cond PROTECTED
153 
154  const Bitfield *bf;
155  size_t index_u32;
156  u32 index_mask;
157  /// @endcond
158  };
159  public:
160 
161 
162  /// Bounds-checked access of the element at index x.
163  /** Throws an ErrorMsgBounds exception if x is out of the bounds.
164  * @param x Index of the bit to access.
165  * @return A BitfieldBool structure that casts to a bool or can be
166  * assigned a bool value.
167  */
168  inline BitfieldBool operator[] (size_t x) {
169  return BitfieldBool(this, x);
170  }
171  /// Identical to operator[]
172  inline BitfieldBool operator() (size_t x) {
173  return BitfieldBool(this, x);
174  }
175  /// Const version of operator[]
176  inline BitfieldBoolConst operator[] (size_t x) const {
177  return BitfieldBoolConst(this, x);
178  }
179  /// Const version of operator[]
180  inline BitfieldBoolConst operator() (size_t x) const {
181  return BitfieldBoolConst(this, x);
182  }
183  /// Const version of At()
184  inline BitfieldBool At(size_t x) {
185  return BitfieldBool(this, x);
186  }
187  /// Identical to operator[]
188  inline BitfieldBoolConst At(size_t x) const {
189  return BitfieldBoolConst(this, x);
190  }
191 
192 
193  /// Return the current number of bits.
194  inline size_t size() const { return b_size; }
195  /// Return the number of bits for which space is reserved.
196  inline size_t reserved() const { return (data.reserved() << 5); }
197 
198  /// Set all bits to zero.
199  inline void Zero() {
200  data.Zero();
201  }
202 
203 
204  /// Set all bits to zero between index start and end, inclusive.
205  inline void ZeroRange(const size_t start, const size_t end) {
206  size_t start_u32;
207  size_t start_u32_border;
208  size_t end_u32;
209  size_t end_u32_border;
210  size_t b;
211 
212  start_u32 = (start + 31) >> 5;
213  start_u32_border = start_u32 << 5;
214 
215  if (start_u32_border >= end) {
216  for (b=start; b<end; b++) {
217  (*this)[b].Clear();
218  }
219  }
220 
221  else {
222  end_u32 = (end + 1) >> 5;
223  end_u32_border = end_u32 << 5;
224 
225  if (end_u32 > start_u32) {
226  data.ZeroRange(start_u32, end_u32-1);
227  }
228 
229  for (b=start; b<start_u32_border; b++) {
230  (*this)[b].Clear();
231  }
232 
233  for (b=end_u32_border; b<=end; b++) {
234  (*this)[b].Clear();
235  }
236  }
237  }
238 
239 
240  /// Provides raw access to the Data1D<u32> in which the bits are packed.
241  /** The bits are packed in order, least significant bit first.
242  */
243  inline Data1D<u32>& Raw() { return data; }
244 
245 
246  /// Reserve storage without resizing the Bitfield.
247  /** @param reserve_size The number of bits for which storage should be
248  * reserved.
249  */
250  inline void Reserve(const size_t reserve_size) {
251  size_t u32size;
252 
253  u32size = reserve_size >> 5;
254  if (reserve_size & 31) {
255  u32size++;
256  }
257 
258  data.Resize(u32size);
259  }
260 
261 
262  /// Resize the array, reallocating if necessary.
263  /** See Data1D::Resize for efficiency details.
264  */
265  inline void Resize(const size_t resize_size) {
266  Reserve(resize_size);
267  b_size = resize_size;
268  }
269 
270 
271  /// Reduce memory consumption to only that necessary for size() bits.
272  inline void Crop() {
273  data.Crop();
274  }
275 
276 
277  /// Identical to Delete()
278  inline void Clear() {
279  Delete();
280  }
281 
282 
283  /// Add a bit to the end, expanding if necessary.
284  /** Efficiency note: Expands by doubling for linear efficiency.
285  * @param new_bit The new bit to append to the end.
286  * @see Reserve
287  */
288  inline void Append(const bool new_bit) {
289  size_t last;
290 
291  if (b_size >= reserved()) {
292  data.Append(0);
293  }
294 
295  last = b_size;
296  b_size++;
297  (*this)[last] = new_bit;
298  }
299 
300 
301  /// Append bits from another Bitfield to this Bitfield.
302  /** @param other The Bitfield from which bits should be copied over.
303  */
304  inline void Append(const Bitfield& other) {
305  size_t i;
306  for (i=0; i<other.b_size; i++) {
307  Append(other[i]);
308  }
309  }
310 
311 
312  /// Assign new_bit to index pos, expanding if necessary to reach that
313  /// index.
314  inline void ExpandSet(size_t pos, const bool new_bit) {
315  if (!Check(pos)) {
316  Resize(pos+1);
317  }
318  (*this)[pos] = new_bit;
319  }
320 
321 
322  /// Appends new_bit, expanding as necessary.
323  /** @see Append
324  */
325  inline Bitfield& operator+= (const bool new_bit) {
326  Append(new_bit);
327  return (*this);
328  }
329 
330 
331  /// Appends the bits from other, expanding as necessary.
332  /** @see Append
333  */
334  inline Bitfield& operator+= (const Bitfield& other) {
335  Append(other);
336  return (*this);
337  }
338 
339 
340  /// True if index x is within the Bitfield.
341  inline bool Check(const size_t x) const {
342  if ( ! (x < b_size) ) {
343  return false;
344  }
345  else {
346  return true;
347  }
348  }
349 
350 
351  /// Throws ErrorMsgBounds if index x is out of bounds for this Bitfield.
352  inline void Assert(const size_t x) const {
353  if ( ! Check(x) ) {
354  Throw_RC_Type(Bounds, "Out of bounds");
355  }
356  }
357 
358 
359  /// Efficiently determines the total number of true / 1 values in the
360  /// Bitfield.
361  inline size_t CountOnes() const {
362  size_t count;
363  size_t i;
364  u32 word;
365 
366  count = 0;
367  for (i=0; i<data.size(); i++) {
368  word = data[i];
369  if ((i == data.size()-1) && (b_size & 31)) {
370  word &= (u64(1) << (b_size & 31)) - 1; // trim overflow
371  }
372  // Algorithm from Software Optimization Guide for AMD64, sec. 8.6
373  word = word - ((word >>1) & 0x55555555);
374  word = (word & 0x33333333) + ((word >> 2) & 0x33333333);
375  count += (((word + (word >> 4)) & 0xF0F0F0F) * 0x01010101) >> 24;
376  }
377 
378  return count;
379  }
380 
381  /// Efficiently determines the total number of false / 0 values in the
382  /// Bitfield.
383  inline size_t CountZeroes() const {
384  return b_size - CountOnes();
385  }
386 
387  /// Swap the data in Bitfield a and b.
388  friend void swap(Bitfield &a, Bitfield &b) {
389  std::swap(a.b_size, b.b_size);
390  swap(a.data, b.data);
391  }
392 
393 
394  protected:
395  /// @cond PROTECTED
396 
397  size_t b_size;
398  Data1D<u32> data;
399  /// @endcond
400  };
401 
402  /// Outputs data to a stream as a character series of '1's and '0's.
403  /** Usage like Bitfield bf; std::cout << bf << std::endl;
404  */
405  inline std::ostream& operator<< (std::ostream &out, const Bitfield &b) {
406  size_t i;
407  for (i=0; i<b.size(); i++) {
408  if (b[i]) {
409  out << '1';
410  }
411  else {
412  out << '0';
413  }
414  }
415  return out;
416  }
417 }
418 
419 
420 #endif // RC_BITFIELD_H
421 
Provides a one-dimensional vector-like structure.
Provides informative exception handling.
#define Throw_RC_Type(Type, err)
Use this to throw an RC:ErrorMsg subtype exception.
Definition: Errors.h:282
uint64_t u64
64-bit unsigned integer.
Definition: Types.h:31
uint32_t u32
32-bit unsigned integer.
Definition: Types.h:29
A bounds-safe two-dimensional structure of efficiently packed bits.
Definition: Bitfield2D.h:27
A bounds-safe three-dimensional structure of efficiently packed bits.
Definition: Bitfield3D.h:28
A temporary return-type that serves as a const interface to specific bit values.
Definition: Bitfield.h:132
A temporary return-type that serves as an interface to specific bit values.
Definition: Bitfield.h:79
BitfieldBool & operator=(const bool set)
Assign the bool value of set to this bit.
Definition: Bitfield.h:109
void Set()
Set the bit to true / 1.
Definition: Bitfield.h:99
void Clear()
Set the bit to false / 0.
Definition: Bitfield.h:104
A bounds-safe one-dimensional vector-like structure of efficiently packed bits.
Definition: Bitfield.h:27
void ZeroRange(const size_t start, const size_t end)
Set all bits to zero between index start and end, inclusive.
Definition: Bitfield.h:205
size_t CountZeroes() const
Efficiently determines the total number of false / 0 values in the Bitfield.
Definition: Bitfield.h:383
void Append(const Bitfield &other)
Append bits from another Bitfield to this Bitfield.
Definition: Bitfield.h:304
void Crop()
Reduce memory consumption to only that necessary for size() bits.
Definition: Bitfield.h:272
bool Check(const size_t x) const
True if index x is within the Bitfield.
Definition: Bitfield.h:341
BitfieldBool At(size_t x)
Const version of At()
Definition: Bitfield.h:184
BitfieldBoolConst At(size_t x) const
Identical to operator[].
Definition: Bitfield.h:188
void ExpandSet(size_t pos, const bool new_bit)
Assign new_bit to index pos, expanding if necessary to reach that index.
Definition: Bitfield.h:314
Bitfield(size_t b_size)
Constructor which sets the initial size to b_size bits.
Definition: Bitfield.h:57
friend void swap(Bitfield &a, Bitfield &b)
Swap the data in Bitfield a and b.
Definition: Bitfield.h:388
void Assert(const size_t x) const
Throws ErrorMsgBounds if index x is out of bounds for this Bitfield.
Definition: Bitfield.h:352
Bitfield & operator+=(const bool new_bit)
Appends new_bit, expanding as necessary.
Definition: Bitfield.h:325
Bitfield()
Default constructor which initializes to size 0.
Definition: Bitfield.h:50
void Reserve(const size_t reserve_size)
Reserve storage without resizing the Bitfield.
Definition: Bitfield.h:250
size_t size() const
Return the current number of bits.
Definition: Bitfield.h:194
Data1D< u32 > & Raw()
Provides raw access to the Data1D<u32> in which the bits are packed.
Definition: Bitfield.h:243
bool IsEmpty() const
True if the size is 0.
Definition: Bitfield.h:71
size_t CountOnes() const
Efficiently determines the total number of true / 1 values in the Bitfield.
Definition: Bitfield.h:361
void Zero()
Set all bits to zero.
Definition: Bitfield.h:199
void Delete()
Deletes the stored data, resets the size to 0, and releases the memory.
Definition: Bitfield.h:64
void Resize(const size_t resize_size)
Resize the array, reallocating if necessary.
Definition: Bitfield.h:265
void Clear()
Identical to Delete()
Definition: Bitfield.h:278
void Append(const bool new_bit)
Add a bit to the end, expanding if necessary.
Definition: Bitfield.h:288
BitfieldBool operator[](size_t x)
Bounds-checked access of the element at index x.
Definition: Bitfield.h:168
BitfieldBool operator()(size_t x)
Identical to operator[].
Definition: Bitfield.h:172
size_t reserved() const
Return the number of bits for which space is reserved.
Definition: Bitfield.h:196
Definition: APtr.h:25
std::ostream & operator<<(std::ostream &out, APtr< T > obj)
A convenience stream output for displaying the enclosed object.
Definition: APtr.h:120
void swap(RC::Data1D< T > &a, RC::Data1D< T > &b)
Efficiently swap all the contents of a and b.
Definition: Data1D.h:1184
email address
— (c) 2015