From: Andrew Krieger Date: Sat, 28 Oct 2017 20:47:17 +0000 (-0700) Subject: Break out BitIterator into its own header X-Git-Tag: v2017.10.30.00~6 X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=commitdiff_plain;h=cbd3e7fb74200100ffadf0fee2a9ab5c490f4051 Break out BitIterator into its own header 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 --- diff --git a/folly/BitIterator.h b/folly/BitIterator.h new file mode 100644 index 00000000..b7545701 --- /dev/null +++ b/folly/BitIterator.h @@ -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 +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +namespace folly { + +/** + * Fast bit iteration facility. + */ + +template +class BitIterator; +template +BitIterator findFirstSet( + BitIterator, + BitIterator); +/** + * 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 BitIterator : public bititerator_detail::BitIteratorBase::type { + public: + /** + * Return the number of bits in an element of the underlying iterator. + */ + static unsigned int bitsPerBlock() { + return std::numeric_limits::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::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::reference, + typename std::iterator_traits::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 +BitIterator makeBitIterator(const BaseIter& iter) { + return BitIterator(iter); +} + +/** + * Find first bit set in a range of bit iterators. + * 4.5x faster than the obvious std::find(begin, end, true); + */ +template +BitIterator findFirstSet( + BitIterator begin, + BitIterator 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 diff --git a/folly/Bits.h b/folly/Bits.h index 4b71c189..942de4dc 100644 --- a/folly/Bits.h +++ b/folly/Bits.h @@ -41,14 +41,6 @@ * 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) */ @@ -65,16 +57,11 @@ #include #include #include -#include #include #include -#include - #include -#include #include -#include #include namespace folly { @@ -332,170 +319,6 @@ class Endian { #undef FB_GEN2 #undef FB_GEN1 -/** - * Fast bit iteration facility. - */ - - -template class BitIterator; -template -BitIterator findFirstSet(BitIterator, - BitIterator); -/** - * 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 BitIterator - : public bititerator_detail::BitIteratorBase::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::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::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::reference, - typename std::iterator_traits::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 -BitIterator makeBitIterator(const BaseIter& iter) { - return BitIterator(iter); -} - - -/** - * Find first bit set in a range of bit iterators. - * 4.5x faster than the obvious std::find(begin, end, true); - */ -template -BitIterator findFirstSet(BitIterator begin, - BitIterator 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 struct Unaligned; diff --git a/folly/io/async/HHWheelTimer.cpp b/folly/io/async/HHWheelTimer.cpp index 96ad8afc..57bb1ce9 100644 --- a/folly/io/async/HHWheelTimer.cpp +++ b/folly/io/async/HHWheelTimer.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include diff --git a/folly/test/BitIteratorTest.cpp b/folly/test/BitIteratorTest.cpp index 01dac747..0fd13a2c 100644 --- a/folly/test/BitIteratorTest.cpp +++ b/folly/test/BitIteratorTest.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include +#include #include #include diff --git a/folly/test/IPAddressTest.cpp b/folly/test/IPAddressTest.cpp index 11ebac5f..5f7c1f62 100644 --- a/folly/test/IPAddressTest.cpp +++ b/folly/test/IPAddressTest.cpp @@ -18,6 +18,7 @@ #include +#include #include #include #include