Break out BitIterator into its own header
authorAndrew Krieger <andrew.krieger@oculus.com>
Sat, 28 Oct 2017 20:47:17 +0000 (13:47 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Sat, 28 Oct 2017 20:51:36 +0000 (13:51 -0700)
Summary:
BitIterator is a standalone construct that has a heavy boost
dependency, but not common usage. Breaking it out into its own header
will help a lot of transitive dependendencies, because it is included
in Hash.h which is included in a variety of other common headers.

This reduces the number of transitively included headers by 248 (!)

Reviewed By: yfeldblum, ot, luciang

Differential Revision: D6178564

fbshipit-source-id: 1380154b012615b7b8c73bc15ab0ac62f6b990d3

folly/BitIterator.h [new file with mode: 0644]
folly/Bits.h
folly/io/async/HHWheelTimer.cpp
folly/test/BitIteratorTest.cpp
folly/test/IPAddressTest.cpp

diff --git a/folly/BitIterator.h b/folly/BitIterator.h
new file mode 100644 (file)
index 0000000..b754570
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * BitIterator
+ *    Wrapper around an iterator over an integral type that iterates
+ *    over its underlying bits in MSb to LSb order
+ *
+ * findFirstSet(BitIterator begin, BitIterator end)
+ *    return a BitIterator pointing to the first 1 bit in [begin, end), or
+ *    end if all bits in [begin, end) are 0
+ *
+ * @author Tudor Bosman (tudorb@fb.com)
+ */
+
+#pragma once
+
+#include <cassert>
+#include <cinttypes>
+#include <cstdint>
+#include <cstring>
+#include <iterator>
+#include <limits>
+#include <type_traits>
+
+#include <boost/iterator/iterator_adaptor.hpp>
+
+#include <folly/Bits.h>
+#include <folly/Portability.h>
+#include <folly/detail/BitIteratorDetail.h>
+
+namespace folly {
+
+/**
+ * Fast bit iteration facility.
+ */
+
+template <class BaseIter>
+class BitIterator;
+template <class BaseIter>
+BitIterator<BaseIter> findFirstSet(
+    BitIterator<BaseIter>,
+    BitIterator<BaseIter>);
+/**
+ * Wrapper around an iterator over an integer type that iterates
+ * over its underlying bits in LSb to MSb order.
+ *
+ * BitIterator models the same iterator concepts as the base iterator.
+ */
+template <class BaseIter>
+class BitIterator : public bititerator_detail::BitIteratorBase<BaseIter>::type {
+ public:
+  /**
+   * Return the number of bits in an element of the underlying iterator.
+   */
+  static unsigned int bitsPerBlock() {
+    return std::numeric_limits<typename std::make_unsigned<
+        typename std::iterator_traits<BaseIter>::value_type>::type>::digits;
+  }
+
+  /**
+   * Construct a BitIterator that points at a given bit offset (default 0)
+   * in iter.
+   */
+  explicit BitIterator(const BaseIter& iter, size_t bitOff = 0)
+      : bititerator_detail::BitIteratorBase<BaseIter>::type(iter),
+        bitOffset_(bitOff) {
+    assert(bitOffset_ < bitsPerBlock());
+  }
+
+  size_t bitOffset() const {
+    return bitOffset_;
+  }
+
+  void advanceToNextBlock() {
+    bitOffset_ = 0;
+    ++this->base_reference();
+  }
+
+  BitIterator& operator=(const BaseIter& other) {
+    this->~BitIterator();
+    new (this) BitIterator(other);
+    return *this;
+  }
+
+ private:
+  friend class boost::iterator_core_access;
+  friend BitIterator findFirstSet<>(BitIterator, BitIterator);
+
+  typedef bititerator_detail::BitReference<
+      typename std::iterator_traits<BaseIter>::reference,
+      typename std::iterator_traits<BaseIter>::value_type>
+      BitRef;
+
+  void advanceInBlock(size_t n) {
+    bitOffset_ += n;
+    assert(bitOffset_ < bitsPerBlock());
+  }
+
+  BitRef dereference() const {
+    return BitRef(*this->base_reference(), bitOffset_);
+  }
+
+  void advance(ssize_t n) {
+    size_t bpb = bitsPerBlock();
+    ssize_t blocks = n / ssize_t(bpb);
+    bitOffset_ += n % bpb;
+    if (bitOffset_ >= bpb) {
+      bitOffset_ -= bpb;
+      ++blocks;
+    }
+    this->base_reference() += blocks;
+  }
+
+  void increment() {
+    if (++bitOffset_ == bitsPerBlock()) {
+      advanceToNextBlock();
+    }
+  }
+
+  void decrement() {
+    if (bitOffset_-- == 0) {
+      bitOffset_ = bitsPerBlock() - 1;
+      --this->base_reference();
+    }
+  }
+
+  bool equal(const BitIterator& other) const {
+    return (
+        bitOffset_ == other.bitOffset_ &&
+        this->base_reference() == other.base_reference());
+  }
+
+  ssize_t distance_to(const BitIterator& other) const {
+    return ssize_t(
+        (other.base_reference() - this->base_reference()) * bitsPerBlock() +
+        other.bitOffset_ - bitOffset_);
+  }
+
+  size_t bitOffset_;
+};
+
+/**
+ * Helper function, so you can write
+ * auto bi = makeBitIterator(container.begin());
+ */
+template <class BaseIter>
+BitIterator<BaseIter> makeBitIterator(const BaseIter& iter) {
+  return BitIterator<BaseIter>(iter);
+}
+
+/**
+ * Find first bit set in a range of bit iterators.
+ * 4.5x faster than the obvious std::find(begin, end, true);
+ */
+template <class BaseIter>
+BitIterator<BaseIter> findFirstSet(
+    BitIterator<BaseIter> begin,
+    BitIterator<BaseIter> end) {
+  // shortcut to avoid ugly static_cast<>
+  static const typename BaseIter::value_type one = 1;
+
+  while (begin.base() != end.base()) {
+    typename BaseIter::value_type v = *begin.base();
+    // mask out the bits that don't matter (< begin.bitOffset)
+    v &= ~((one << begin.bitOffset()) - 1);
+    size_t firstSet = findFirstSet(v);
+    if (firstSet) {
+      --firstSet; // now it's 0-based
+      assert(firstSet >= begin.bitOffset());
+      begin.advanceInBlock(firstSet - begin.bitOffset());
+      return begin;
+    }
+    begin.advanceToNextBlock();
+  }
+
+  // now begin points to the same block as end
+  if (end.bitOffset() != 0) { // assume end is dereferenceable
+    typename BaseIter::value_type v = *begin.base();
+    // mask out the bits that don't matter (< begin.bitOffset)
+    v &= ~((one << begin.bitOffset()) - 1);
+    // mask out the bits that don't matter (>= end.bitOffset)
+    v &= (one << end.bitOffset()) - 1;
+    size_t firstSet = findFirstSet(v);
+    if (firstSet) {
+      --firstSet; // now it's 0-based
+      assert(firstSet >= begin.bitOffset());
+      begin.advanceInBlock(firstSet - begin.bitOffset());
+      return begin;
+    }
+  }
+
+  return end;
+}
+
+} // namespace folly
index 4b71c18963600ebdd74b4eadc076d98cbf5fbb96..942de4dc95633e358ee1f386daa86787c1b22194 100644 (file)
  *    Endian::little(x)   little <-> native
  *    Endian::swap(x)     big <-> little
  *
- * BitIterator
- *    Wrapper around an iterator over an integral type that iterates
- *    over its underlying bits in MSb to LSb order
- *
- * findFirstSet(BitIterator begin, BitIterator end)
- *    return a BitIterator pointing to the first 1 bit in [begin, end), or
- *    end if all bits in [begin, end) are 0
- *
  * @author Tudor Bosman (tudorb@fb.com)
  */
 
 #include <cinttypes>
 #include <cstdint>
 #include <cstring>
-#include <iterator>
 #include <limits>
 #include <type_traits>
 
-#include <boost/iterator/iterator_adaptor.hpp>
-
 #include <folly/Assume.h>
-#include <folly/Likely.h>
 #include <folly/Portability.h>
-#include <folly/detail/BitIteratorDetail.h>
 #include <folly/portability/Builtins.h>
 
 namespace folly {
@@ -332,170 +319,6 @@ class Endian {
 #undef FB_GEN2
 #undef FB_GEN1
 
-/**
- * Fast bit iteration facility.
- */
-
-
-template <class BaseIter> class BitIterator;
-template <class BaseIter>
-BitIterator<BaseIter> findFirstSet(BitIterator<BaseIter>,
-                                   BitIterator<BaseIter>);
-/**
- * Wrapper around an iterator over an integer type that iterates
- * over its underlying bits in LSb to MSb order.
- *
- * BitIterator models the same iterator concepts as the base iterator.
- */
-template <class BaseIter>
-class BitIterator
-  : public bititerator_detail::BitIteratorBase<BaseIter>::type {
- public:
-  /**
-   * Return the number of bits in an element of the underlying iterator.
-   */
-  static unsigned int bitsPerBlock() {
-    return std::numeric_limits<
-      typename std::make_unsigned<
-        typename std::iterator_traits<BaseIter>::value_type
-      >::type
-    >::digits;
-  }
-
-  /**
-   * Construct a BitIterator that points at a given bit offset (default 0)
-   * in iter.
-   */
-  explicit BitIterator(const BaseIter& iter, size_t bitOff=0)
-    : bititerator_detail::BitIteratorBase<BaseIter>::type(iter),
-      bitOffset_(bitOff) {
-    assert(bitOffset_ < bitsPerBlock());
-  }
-
-  size_t bitOffset() const {
-    return bitOffset_;
-  }
-
-  void advanceToNextBlock() {
-    bitOffset_ = 0;
-    ++this->base_reference();
-  }
-
-  BitIterator& operator=(const BaseIter& other) {
-    this->~BitIterator();
-    new (this) BitIterator(other);
-    return *this;
-  }
-
- private:
-  friend class boost::iterator_core_access;
-  friend BitIterator findFirstSet<>(BitIterator, BitIterator);
-
-  typedef bititerator_detail::BitReference<
-      typename std::iterator_traits<BaseIter>::reference,
-      typename std::iterator_traits<BaseIter>::value_type
-    > BitRef;
-
-  void advanceInBlock(size_t n) {
-    bitOffset_ += n;
-    assert(bitOffset_ < bitsPerBlock());
-  }
-
-  BitRef dereference() const {
-    return BitRef(*this->base_reference(), bitOffset_);
-  }
-
-  void advance(ssize_t n) {
-    size_t bpb = bitsPerBlock();
-    ssize_t blocks = n / ssize_t(bpb);
-    bitOffset_ += n % bpb;
-    if (bitOffset_ >= bpb) {
-      bitOffset_ -= bpb;
-      ++blocks;
-    }
-    this->base_reference() += blocks;
-  }
-
-  void increment() {
-    if (++bitOffset_ == bitsPerBlock()) {
-      advanceToNextBlock();
-    }
-  }
-
-  void decrement() {
-    if (bitOffset_-- == 0) {
-      bitOffset_ = bitsPerBlock() - 1;
-      --this->base_reference();
-    }
-  }
-
-  bool equal(const BitIterator& other) const {
-    return (bitOffset_ == other.bitOffset_ &&
-            this->base_reference() == other.base_reference());
-  }
-
-  ssize_t distance_to(const BitIterator& other) const {
-    return ssize_t(
-        (other.base_reference() - this->base_reference()) * bitsPerBlock() +
-        other.bitOffset_ - bitOffset_);
-  }
-
-  size_t bitOffset_;
-};
-
-/**
- * Helper function, so you can write
- * auto bi = makeBitIterator(container.begin());
- */
-template <class BaseIter>
-BitIterator<BaseIter> makeBitIterator(const BaseIter& iter) {
-  return BitIterator<BaseIter>(iter);
-}
-
-
-/**
- * Find first bit set in a range of bit iterators.
- * 4.5x faster than the obvious std::find(begin, end, true);
- */
-template <class BaseIter>
-BitIterator<BaseIter> findFirstSet(BitIterator<BaseIter> begin,
-                                   BitIterator<BaseIter> end) {
-  // shortcut to avoid ugly static_cast<>
-  static const typename BaseIter::value_type one = 1;
-
-  while (begin.base() != end.base()) {
-    typename BaseIter::value_type v = *begin.base();
-    // mask out the bits that don't matter (< begin.bitOffset)
-    v &= ~((one << begin.bitOffset()) - 1);
-    size_t firstSet = findFirstSet(v);
-    if (firstSet) {
-      --firstSet;  // now it's 0-based
-      assert(firstSet >= begin.bitOffset());
-      begin.advanceInBlock(firstSet - begin.bitOffset());
-      return begin;
-    }
-    begin.advanceToNextBlock();
-  }
-
-  // now begin points to the same block as end
-  if (end.bitOffset() != 0) {  // assume end is dereferenceable
-    typename BaseIter::value_type v = *begin.base();
-    // mask out the bits that don't matter (< begin.bitOffset)
-    v &= ~((one << begin.bitOffset()) - 1);
-    // mask out the bits that don't matter (>= end.bitOffset)
-    v &= (one << end.bitOffset()) - 1;
-    size_t firstSet = findFirstSet(v);
-    if (firstSet) {
-      --firstSet;  // now it's 0-based
-      assert(firstSet >= begin.bitOffset());
-      begin.advanceInBlock(firstSet - begin.bitOffset());
-      return begin;
-    }
-  }
-
-  return end;
-}
-
 
 template <class T, class Enable=void> struct Unaligned;
 
index 96ad8afc4a627bca3fc07e6b3984817fc929d302..57bb1ce97d7f3fca69355fbd853c1cd0976923c8 100644 (file)
@@ -17,6 +17,7 @@
 #include <folly/io/async/HHWheelTimer.h>
 #include <folly/io/async/Request.h>
 
+#include <folly/BitIterator.h>
 #include <folly/Memory.h>
 #include <folly/Optional.h>
 #include <folly/ScopeGuard.h>
index 01dac7471045a4c4438b4a4c8f0484d959ac54a0..0fd13a2c0bc3d9032cddef171fa6b2990477dbdd 100644 (file)
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <folly/Bits.h>
+#include <folly/BitIterator.h>
 
 #include <algorithm>
 #include <limits>
index 11ebac5f4f523def6423d5448d12f1ffc1442306..5f7c1f62e16af286d35ef95bc96c0d3f1749b981 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <string>
 
+#include <folly/BitIterator.h>
 #include <folly/Bits.h>
 #include <folly/Format.h>
 #include <folly/IPAddress.h>