BitIterator.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /*
  2. * Copyright 2011-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /**
  17. * BitIterator
  18. * Wrapper around an iterator over an integral type that iterates
  19. * over its underlying bits in MSb to LSb order
  20. *
  21. * findFirstSet(BitIterator begin, BitIterator end)
  22. * return a BitIterator pointing to the first 1 bit in [begin, end), or
  23. * end if all bits in [begin, end) are 0
  24. *
  25. * @author Tudor Bosman (tudorb@fb.com)
  26. */
  27. #pragma once
  28. #include <cassert>
  29. #include <cinttypes>
  30. #include <cstdint>
  31. #include <cstring>
  32. #include <iterator>
  33. #include <limits>
  34. #include <type_traits>
  35. #include <boost/iterator/iterator_adaptor.hpp>
  36. #include <folly/Portability.h>
  37. #include <folly/container/detail/BitIteratorDetail.h>
  38. #include <folly/lang/Bits.h>
  39. namespace folly {
  40. /**
  41. * Fast bit iteration facility.
  42. */
  43. template <class BaseIter>
  44. class BitIterator;
  45. template <class BaseIter>
  46. BitIterator<BaseIter> findFirstSet(
  47. BitIterator<BaseIter>,
  48. BitIterator<BaseIter>);
  49. /**
  50. * Wrapper around an iterator over an integer type that iterates
  51. * over its underlying bits in LSb to MSb order.
  52. *
  53. * BitIterator models the same iterator concepts as the base iterator.
  54. */
  55. template <class BaseIter>
  56. class BitIterator : public bititerator_detail::BitIteratorBase<BaseIter>::type {
  57. public:
  58. /**
  59. * Return the number of bits in an element of the underlying iterator.
  60. */
  61. static unsigned int bitsPerBlock() {
  62. return std::numeric_limits<typename std::make_unsigned<
  63. typename std::iterator_traits<BaseIter>::value_type>::type>::digits;
  64. }
  65. /**
  66. * Construct a BitIterator that points at a given bit offset (default 0)
  67. * in iter.
  68. */
  69. explicit BitIterator(const BaseIter& iter, size_t bitOff = 0)
  70. : bititerator_detail::BitIteratorBase<BaseIter>::type(iter),
  71. bitOffset_(bitOff) {
  72. assert(bitOffset_ < bitsPerBlock());
  73. }
  74. size_t bitOffset() const {
  75. return bitOffset_;
  76. }
  77. void advanceToNextBlock() {
  78. bitOffset_ = 0;
  79. ++this->base_reference();
  80. }
  81. BitIterator& operator=(const BaseIter& other) {
  82. this->~BitIterator();
  83. new (this) BitIterator(other);
  84. return *this;
  85. }
  86. private:
  87. friend class boost::iterator_core_access;
  88. friend BitIterator findFirstSet<>(BitIterator, BitIterator);
  89. typedef bititerator_detail::BitReference<
  90. typename std::iterator_traits<BaseIter>::reference,
  91. typename std::iterator_traits<BaseIter>::value_type>
  92. BitRef;
  93. void advanceInBlock(size_t n) {
  94. bitOffset_ += n;
  95. assert(bitOffset_ < bitsPerBlock());
  96. }
  97. BitRef dereference() const {
  98. return BitRef(*this->base_reference(), bitOffset_);
  99. }
  100. void advance(ssize_t n) {
  101. size_t bpb = bitsPerBlock();
  102. ssize_t blocks = n / ssize_t(bpb);
  103. bitOffset_ += n % bpb;
  104. if (bitOffset_ >= bpb) {
  105. bitOffset_ -= bpb;
  106. ++blocks;
  107. }
  108. this->base_reference() += blocks;
  109. }
  110. void increment() {
  111. if (++bitOffset_ == bitsPerBlock()) {
  112. advanceToNextBlock();
  113. }
  114. }
  115. void decrement() {
  116. if (bitOffset_-- == 0) {
  117. bitOffset_ = bitsPerBlock() - 1;
  118. --this->base_reference();
  119. }
  120. }
  121. bool equal(const BitIterator& other) const {
  122. return (
  123. bitOffset_ == other.bitOffset_ &&
  124. this->base_reference() == other.base_reference());
  125. }
  126. ssize_t distance_to(const BitIterator& other) const {
  127. return ssize_t(
  128. (other.base_reference() - this->base_reference()) * bitsPerBlock() +
  129. other.bitOffset_ - bitOffset_);
  130. }
  131. size_t bitOffset_;
  132. };
  133. /**
  134. * Helper function, so you can write
  135. * auto bi = makeBitIterator(container.begin());
  136. */
  137. template <class BaseIter>
  138. BitIterator<BaseIter> makeBitIterator(const BaseIter& iter) {
  139. return BitIterator<BaseIter>(iter);
  140. }
  141. /**
  142. * Find first bit set in a range of bit iterators.
  143. * 4.5x faster than the obvious std::find(begin, end, true);
  144. */
  145. template <class BaseIter>
  146. BitIterator<BaseIter> findFirstSet(
  147. BitIterator<BaseIter> begin,
  148. BitIterator<BaseIter> end) {
  149. // shortcut to avoid ugly static_cast<>
  150. static const typename std::iterator_traits<BaseIter>::value_type one = 1;
  151. while (begin.base() != end.base()) {
  152. typename std::iterator_traits<BaseIter>::value_type v = *begin.base();
  153. // mask out the bits that don't matter (< begin.bitOffset)
  154. v &= ~((one << begin.bitOffset()) - 1);
  155. size_t firstSet = findFirstSet(v);
  156. if (firstSet) {
  157. --firstSet; // now it's 0-based
  158. assert(firstSet >= begin.bitOffset());
  159. begin.advanceInBlock(firstSet - begin.bitOffset());
  160. return begin;
  161. }
  162. begin.advanceToNextBlock();
  163. }
  164. // now begin points to the same block as end
  165. if (end.bitOffset() != 0) { // assume end is dereferenceable
  166. typename std::iterator_traits<BaseIter>::value_type v = *begin.base();
  167. // mask out the bits that don't matter (< begin.bitOffset)
  168. v &= ~((one << begin.bitOffset()) - 1);
  169. // mask out the bits that don't matter (>= end.bitOffset)
  170. v &= (one << end.bitOffset()) - 1;
  171. size_t firstSet = findFirstSet(v);
  172. if (firstSet) {
  173. --firstSet; // now it's 0-based
  174. assert(firstSet >= begin.bitOffset());
  175. begin.advanceInBlock(firstSet - begin.bitOffset());
  176. return begin;
  177. }
  178. }
  179. return end;
  180. }
  181. } // namespace folly