bitset.h
Go to the documentation of this file.
1 /*
2  * This file is a part of TiledArray.
3  * Copyright (C) 2013 Virginia Tech
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #ifndef TILEDARRAY_BITSET_H__INCLUDED
21 #define TILEDARRAY_BITSET_H__INCLUDED
22 
23 #include <TiledArray/error.h>
25 #include <climits>
26 #include <iomanip>
27 #include <iosfwd>
28 
29 namespace TiledArray {
30 namespace detail {
31 
33 
40 template <typename Block = unsigned long>
41 class Bitset {
42  private:
43  static_assert((std::is_integral<Block>::value ||
44  std::is_same<Block, char>::value),
45  "Bitset template type Block must be an integral or char type");
46 
47  static const std::size_t block_bits;
48  static const Block zero;
49  static const Block one;
50  static const Block xffff;
51 
52  public:
53  class reference {
54  friend class Bitset<Block>;
55 
56  reference(Block& block, Block mask) : block_(block), mask_(mask) {}
57 
58  // Not allowed
59  void operator&();
60 
61  public:
62  reference& operator=(bool value) {
63  assign(value);
64  return *this;
65  }
66 
67  reference& operator=(const reference& other) {
68  assign(other);
69  return *this;
70  }
71 
72  reference& operator|=(bool value) {
73  if (value) set();
74  return *this;
75  }
76 
77  reference& operator&=(bool value) {
78  if (!value) reset();
79  return *this;
80  }
81 
82  reference& operator^=(bool value) {
83  if (value) flip();
84  return *this;
85  }
86 
87  reference& operator-=(bool value) {
88  if (value) reset();
89  return *this;
90  }
91 
92  operator bool() const { return block_ & mask_; }
93 
94  bool operator~() const { return !(block_ & mask_); }
95 
97  block_ ^= mask_;
98  return *this;
99  }
100 
101  private:
102  void assign(bool value) {
103  if (value)
104  set();
105  else
106  reset();
107  }
108 
109  void set() { block_ |= mask_; }
110 
111  void reset() { block_ &= ~mask_; }
112 
113  Block& block_;
114  const Block mask_;
115  }; // class reference
116 
117  private:
119  class ConstTransformOp {
120  public:
121  typedef std::size_t argument_type;
122  typedef Block result_type;
123 
124  ConstTransformOp(const Bitset<Block>& bitset) : bitset_(&bitset) {}
125 
126  ConstTransformOp(const ConstTransformOp& other) : bitset_(other.bitset_) {}
127 
128  ConstTransformOp& operator=(const ConstTransformOp& other) {
129  bitset_ = other.bitset_;
130 
131  return *this;
132  }
133 
134  Block operator()(std::size_t i) const { return (*bitset_)[i]; }
135 
136  private:
137  const Bitset<Block>* bitset_;
138  }; // class ConstTransformOp
139 
141  class TransformOp {
142  public:
143  typedef std::size_t argument_type;
144  typedef reference result_type;
145 
146  TransformOp(const Bitset<Block>& bitset) : bitset_(bitset) {}
147  reference operator()(std::size_t i) const {
148  return const_cast<Bitset<Block>&>(bitset_)[i];
149  }
150 
151  private:
152  const Bitset<Block>& bitset_;
153  }; // class TransformOp
154 
155  public:
157  typedef Block block_type;
158  typedef Block value_type;
159  typedef Block const_reference;
160  typedef std::size_t size_type;
165 
167 
171  : size_(s),
172  blocks_((size_ / block_bits) + (size_ % block_bits ? 1 : 0)),
173  set_((size_ ? new block_type[blocks_] : NULL)) {
174  std::fill_n(set_, blocks_, zero);
175  }
176 
178 
183  template <typename InIter>
184  Bitset(InIter first, InIter last)
185  : size_(std::distance(first, last)),
186  blocks_((size_ / block_bits) + (size_ % block_bits ? 1 : 0)),
187  set_((size_ ? new block_type[blocks_] : NULL)) {
188  // Initialize to zero
189  std::fill_n(set_, blocks_, zero);
190 
191  for (size_type i = 0; first != last; ++i, ++first)
192  if (*first) set(i);
193  }
194 
196 
199  Bitset(const Bitset<Block>& other)
200  : size_(other.size_),
201  blocks_(other.blocks_),
202  set_((size_ ? new block_type[blocks_] : NULL)) {
203  std::copy(other.set_, other.set_ + blocks_, set_);
204  }
205 
207  ~Bitset() { delete[] set_; }
208 
210 
216  if (blocks_ == other.blocks_) {
217  if (this != &other) {
218  size_ = other.size_;
219  std::copy(other.set_, other.set_ + blocks_, set_);
220  }
221  } else {
222  Bitset<Block>(other).swap(*this);
223  }
224 
225  return *this;
226  }
227 
229 
234  TA_ASSERT(size_ == other.size_);
235  for (size_type i = 0; i < blocks_; ++i) set_[i] |= other.set_[i];
236 
237  return *this;
238  }
239 
241 
246  TA_ASSERT(size_ == other.size_);
247  for (size_type i = 0; i < blocks_; ++i) set_[i] &= other.set_[i];
248 
249  return *this;
250  }
251 
253 
258  TA_ASSERT(size_ == other.size_);
259  for (size_type i = 0; i < blocks_; ++i) set_[i] ^= other.set_[i];
260 
261  return *this;
262  }
263 
264  private:
265  static void left_shift(Bitset<Block>& dest, const Bitset<Block>& source,
266  size_type n) {
267  // Compute shifts
268  const size_type block_shift = dest.block_index(n);
269  const size_type bit_shift = dest.bit_index(n);
270 
271  // Compute iteration ranges
272  block_type* last = dest.set_ + dest.blocks_ - 1;
273  const block_type* const first = dest.set_ + block_shift;
274  const block_type* base = source.set_ + source.blocks_ - 1 - block_shift;
275 
276  if (bit_shift == 0) {
277  // Shift by unit strides
278  while (last >= first) *last-- = *base--;
279  } else {
280  // Shift by non-unit strides
281  const block_type* base1 = base - 1;
282  const size_type reverse_bit_shift = block_bits - bit_shift;
283  while (last > first) {
284  *last-- = (*base << bit_shift) | (*base1 >> reverse_bit_shift);
285  base = base1--;
286  }
287  *last-- = (*base << bit_shift);
288  }
289 
290  // Zero the head
291  while (last >= dest.set_) *last-- = zero;
292 
293  // Zero the tail
294  const size_type extra_bits = dest.size_ % block_bits;
295  if (extra_bits != 0) dest.set_[dest.blocks_ - 1] &= ~(xffff << extra_bits);
296  }
297 
298  static void right_shift(Bitset<Block>& dest, const Bitset<Block>& source,
299  size_type n) {
300  // Compute shifts
301  size_type const block_shift = block_index(n);
302  size_type const bit_shift = bit_index(n);
303 
304  // Compute iterator ranges
305  const block_type* base = source.set_ + block_shift;
306  block_type* first = dest.set_;
307  const block_type* const end = dest.set_ + dest.blocks_;
308  const block_type* const last = end - 1 - block_shift;
309 
310  if (bit_shift == 0) {
311  // Shift by unit strides
312  while (first <= last) *first++ = *base++;
313  } else {
314  // Shift by non-unit strides
315  size_type const reverse_bit_shift = block_bits - bit_shift;
316  const block_type* base1 = base + 1;
317 
318  while (first < last) {
319  *first++ = (*base >> bit_shift) | (*base1 << reverse_bit_shift);
320  base = base1++;
321  }
322  *first++ = *base >> bit_shift;
323  }
324 
325  // Zero the tail
326  while (first < end) *first++ = zero;
327  }
328 
329  public:
331  if (n >= size_)
332  reset();
333  else if (n > 0ul)
334  left_shift(*this, *this, n);
335  return *this;
336  }
337 
338  Bitset<Block> operator<<(size_type n) {
339  Bitset<Block> temp = Bitset<Block>(size_);
340  if (n < size_) left_shift(temp, *this, n);
341  return temp;
342  }
343 
345  if (n >= size_)
346  reset();
347  else if (n > 0ul)
348  right_shift(*this, *this, n);
349  return *this;
350  }
351 
353  Bitset<Block> temp = Bitset<Block>(size_);
354  if (n < size_) right_shift(temp, *this, n);
355  return temp;
356  }
357 
359 
364  TA_ASSERT(i < size_);
365  return mask(i) & set_[block_index(i)];
366  }
367 
369  TA_ASSERT(i < size_);
370  return reference(set_[block_index(i)], mask(i));
371  }
372 
373  operator bool() const {
374  const block_type* const end = set_ + blocks_;
375  for (const block_type* first = set_; first != end; ++first)
376  if (*first) return true;
377 
378  return false;
379  }
380 
381  bool operator!() const {
382  const block_type* const end = set_ + blocks_;
383  for (const block_type* first = set_; first != end; ++first)
384  if (*first) return false;
385 
386  return true;
387  }
388 
390  return const_iterator(0, ConstTransformOp(*this));
391  }
392 
393  iterator begin() { return iterator(0, TransformOp(*this)); }
394 
395  const_iterator end() const {
396  return const_iterator(size_, ConstTransformOp(*this));
397  }
398 
399  iterator end() { return iterator(size_, TransformOp(*this)); }
400 
402 
406  void set(size_type i, bool value = true) {
407  TA_ASSERT(i < size_);
408  if (value)
409  set_[block_index(i)] |= mask(i);
410  else
411  reset(i);
412  }
413 
415 
417  void set() {
418  std::fill_n(set_, blocks_, xffff);
419 
420  // Zero the tail
421  const size_type extra_bits = bit_index(size_);
422  if (extra_bits != 0) set_[blocks_ - 1] &= ~(xffff << extra_bits);
423  }
424 
426 
429  void set_range(size_type first, size_type last) {
430  if (last >= size_) last = size_ - 1;
431  TA_ASSERT(first < last);
432 
433  // Get iterator and shift values
434  block_type* first_block = set_ + block_index(first);
435  const size_type first_shift = bit_index(first);
436  block_type* const last_block = set_ + block_index(last);
437  const size_type last_shift = block_bits - bit_index(last) - 1;
438 
439  // Set the first and last bits
440  if (first_block == last_block) {
441  *first_block |= (xffff << first_shift) & (xffff >> last_shift);
442  } else {
443  *first_block++ |= (xffff << first_shift);
444  *last_block |= (xffff >> last_shift);
445  }
446 
447  // Set all blocks between the first and last blocks.
448  while (first_block < last_block) *first_block++ = xffff;
449  }
450 
452 
455  void set_stride(size_type first, size_type stride) {
456  for (; first < size_; first += stride)
457  set_[block_index(first)] |= mask(first);
458  }
459 
461 
464  void reset(size_type i) {
465  TA_ASSERT(i < size_);
466  set_[block_index(i)] &= ~mask(i);
467  }
468 
470 
472  void reset() { std::fill_n(set_, blocks_, zero); }
473 
475 
478  void flip(size_type i) {
479  TA_ASSERT(i < size_);
480  set_[block_index(i)] ^= mask(i);
481  }
482 
484 
486  void flip() {
487  for (size_type i = 0; i < blocks_; ++i) set_[i] = ~set_[i];
488  }
489 
491 
493  size_type count() const {
494  size_type c = 0ul;
495  for (size_type i = 0ul; i < blocks_; ++i) {
496  block_type v = set_[i]; // temp
497  v = v - ((v >> 1) & xffff / 3);
498  v = (v & xffff / 15 * 3) + ((v >> 2) & xffff / 15 * 3);
499  v = (v + (v >> 4)) & xffff / 255 * 15;
500  c += block_type(v * (xffff / 255)) >>
501  (sizeof(block_type) - 1) * CHAR_BIT; // count
502  }
503  return c;
504  }
505 
507 
512  const block_type* get() const { return set_; }
513 
515 
520  block_type* get() { return set_; }
521 
523 
526  size_type size() const { return size_; }
527 
529 
532  size_type num_blocks() const { return blocks_; }
533 
534  void swap(Bitset_& other) {
535  std::swap(size_, other.size_);
536  std::swap(blocks_, other.blocks_);
537  std::swap(set_, other.set_);
538  }
539 
540  private:
542 
545  static size_type block_index(size_type i) { return i / block_bits; }
546 
548 
551  static size_type bit_index(size_type i) { return i % block_bits; }
552 
554 
557  static block_type mask(size_type i) { return one << bit_index(i); }
558 
559  size_type size_;
560  size_type blocks_;
561  block_type* set_;
562 }; // class Bitset
563 
564 template <typename B>
565 inline void swap(Bitset<B>& b0, Bitset<B>& b1) {
566  b0.swap(b1);
567 }
568 
569 // Bitset static constant data
570 template <typename Block>
571 const std::size_t Bitset<Block>::block_bits =
572  8ul * sizeof(typename Bitset<Block>::block_type);
573 template <typename Block>
574 const Block Bitset<Block>::zero = Block(0);
575 template <typename Block>
576 const Block Bitset<Block>::one = Block(1);
577 template <typename Block>
578 const Block Bitset<Block>::xffff = ~Block(0);
579 
581 
586 template <typename Block>
588  left &= right;
589  return left;
590 }
591 
593 
598 template <typename Block>
600  left |= right;
601  return left;
602 }
603 
605 
610 template <typename Block>
612  left ^= right;
613  return left;
614 }
615 
616 template <typename Block>
617 std::ostream& operator<<(std::ostream& os, const Bitset<Block>& bitset) {
618  os << std::hex;
619  for (long i = bitset.num_blocks() - 1l; i >= 0l; --i)
620  os << std::setfill('0') << std::setw(sizeof(Block) * 2) << bitset.get()[i]
621  << " ";
622 
623  os << std::setbase(10) << std::setw(0);
624  return os;
625 }
626 
627 } // namespace detail
628 } // namespace TiledArray
629 
630 #endif // TILEDARRAY_BITSET_H__INCLUDED
Bitset(size_type s)
Construct a bitset that contains s bits.
Definition: bitset.h:170
const_iterator end() const
Definition: bitset.h:395
Block block_type
The type used to store the data.
Definition: bitset.h:157
reference operator[](size_type i)
Definition: bitset.h:368
Bitset(const Bitset< Block > &other)
Copy constructor for bitset.
Definition: bitset.h:199
std::size_t size_type
indexing size type
Definition: bitset.h:160
void reset(size_type i)
Reset a bit.
Definition: bitset.h:464
void swap(Bitset< B > &b0, Bitset< B > &b1)
Definition: bitset.h:565
bool operator!() const
Definition: bitset.h:381
Bitset< Block > operator>>(size_type n)
Definition: bitset.h:352
reference & operator^=(bool value)
Definition: bitset.h:82
reference & operator|=(bool value)
Definition: bitset.h:72
Bitset< Block > & operator=(const Bitset< Block > &other)
Assignment operator.
Definition: bitset.h:215
Bitset< Block > & operator>>=(size_type n)
Definition: bitset.h:344
std::ostream & operator<<(std::ostream &os, const TileReference< Impl > &a)
redirect operator to std::ostream for TileReference objects
Definition: array_impl.h:132
Bitset< Block > operator|(Bitset< Block > left, const Bitset< Block > &right)
Bitwise or operator of bitset.
Definition: bitset.h:599
Bitset< Block > & operator|=(const Bitset< Block > &other)
Or-assignment operator.
Definition: bitset.h:233
reference & operator=(bool value)
Definition: bitset.h:62
UnaryTransformIterator< Block, TransformOp > iterator
Iterator type.
Definition: bitset.h:164
reference & operator&=(bool value)
Definition: bitset.h:77
size_type count() const
Count the number of non-zero bits.
Definition: bitset.h:493
size_type size() const
Bitset size.
Definition: bitset.h:526
void flip()
Flip all bits.
Definition: bitset.h:486
Bitset< Block > & operator<<=(size_type n)
Definition: bitset.h:330
Block const_reference
Constant reference to a bit.
Definition: bitset.h:159
size_type num_blocks() const
Bitset block size.
Definition: bitset.h:532
Block value_type
The value type.
Definition: bitset.h:158
Bitset< Block > & operator&=(const Bitset< Block > &other)
And-assignment operator.
Definition: bitset.h:245
UnaryTransformIterator< Block, ConstTransformOp > const_iterator
Const iterator type.
Definition: bitset.h:162
#define TA_ASSERT(EXPR,...)
Definition: error.h:39
Bitset< Block > operator<<(size_type n)
Definition: bitset.h:338
reference & operator=(const reference &other)
Definition: bitset.h:67
void set_range(size_type first, size_type last)
Set all bits from first to last.
Definition: bitset.h:429
void flip(size_type i)
Flip a bit.
Definition: bitset.h:478
const_reference operator[](size_type i) const
Bit accessor operator.
Definition: bitset.h:363
void set()
Set all bits.
Definition: bitset.h:417
Bitset< Block > operator&(Bitset< Block > left, const Bitset< Block > &right)
Bitwise and operator of bitset.
Definition: bitset.h:587
const_iterator begin() const
Definition: bitset.h:389
Bitset< Block > Bitset_
This object type.
Definition: bitset.h:156
block_type * get()
Data pointer accessor.
Definition: bitset.h:520
const block_type * get() const
Data pointer accessor.
Definition: bitset.h:512
~Bitset()
Destructor.
Definition: bitset.h:207
Fixed size bitset.
Definition: bitset.h:41
reference & operator-=(bool value)
Definition: bitset.h:87
void zero(DistArray< Tile, Policy > &a)
Definition: basic.h:51
void reset()
Set all bits.
Definition: bitset.h:472
Bitset< Block > & operator^=(const Bitset< Block > &other)
And-assignment operator.
Definition: bitset.h:257
Bitset< Block > operator^(Bitset< Block > left, const Bitset< Block > &right)
Bitwise xor operator of bitset.
Definition: bitset.h:611
void set(size_type i, bool value=true)
Set a bit value.
Definition: bitset.h:406
void set_stride(size_type first, size_type stride)
Set elements separated by stride.
Definition: bitset.h:455
Bitset(InIter first, InIter last)
Construct a bitset that contains s bits.
Definition: bitset.h:184
void swap(Bitset_ &other)
Definition: bitset.h:534