diff --git a/include/lucene++/BitSet.h b/include/lucene++/BitSet.h
index e06e6c7..0d42a40 100644
--- a/include/lucene++/BitSet.h
+++ b/include/lucene++/BitSet.h
@@ -8,6 +8,7 @@
 #define BITSET_H
 
 #include <boost/dynamic_bitset.hpp>
+#include <boost/version.hpp>
 #include "LuceneObject.h"
 
 namespace Lucene {
@@ -24,7 +25,9 @@ protected:
     bitset_type bitSet;
 
 public:
+#if BOOST_VERSION < 109000
     const uint64_t* getBits();
+#endif
     void clear();
     void clear(uint32_t bitIndex);
     void fastClear(uint32_t bitIndex);
diff --git a/src/core/util/BitSet.cpp b/src/core/util/BitSet.cpp
index 6eb9d94..8c09bbe 100644
--- a/src/core/util/BitSet.cpp
+++ b/src/core/util/BitSet.cpp
@@ -7,6 +7,8 @@
 #include "LuceneInc.h"
 #include "BitSet.h"
 #include "BitUtil.h"
+#include <boost/version.hpp>
+#include <boost/iterator/function_output_iterator.hpp>
 
 namespace Lucene {
 
@@ -16,9 +18,11 @@ BitSet::BitSet(uint32_t size) : bitSet(size) {
 BitSet::~BitSet() {
 }
 
+#if BOOST_VERSION < 109000
 const uint64_t* BitSet::getBits() {
     return bitSet.empty() ? NULL : static_cast<const uint64_t*>(&bitSet.m_bits[0]);
 }
+#endif
 
 void BitSet::clear() {
     bitSet.clear();
@@ -35,16 +39,20 @@ void BitSet::fastClear(uint32_t bitIndex) {
 }
 
 void BitSet::clear(uint32_t fromIndex, uint32_t toIndex) {
+#if BOOST_VERSION >= 106900
+    fromIndex = std::min<bitset_type::size_type>(fromIndex, bitSet.size());
+    toIndex = std::min<bitset_type::size_type>(toIndex, bitSet.size());
+    bitSet.reset(fromIndex, toIndex - fromIndex);
+#else
     toIndex = std::min(toIndex, (uint32_t)bitSet.size());
     for (bitset_type::size_type i = std::min(fromIndex, (uint32_t)bitSet.size()); i < toIndex; ++i) {
         bitSet.set(i, false);
     }
+#endif
 }
 
 void BitSet::fastClear(uint32_t fromIndex, uint32_t toIndex) {
-    for (bitset_type::size_type i = fromIndex; i < toIndex; ++i) {
-        bitSet.set(i, false);
-    }
+    fastSet(fromIndex, toIndex, false);
 }
 
 void BitSet::set(uint32_t bitIndex) {
@@ -70,33 +78,28 @@ void BitSet::fastSet(uint32_t bitIndex, bool value) {
 }
 
 void BitSet::set(uint32_t fromIndex, uint32_t toIndex) {
-    if (toIndex >= bitSet.size()) {
-        resize(toIndex + 1);
-    }
-    for (bitset_type::size_type i = fromIndex; i < toIndex; ++i) {
-        bitSet.set(i, true);
-    }
+    set(fromIndex, toIndex, true);
 }
 
 void BitSet::fastSet(uint32_t fromIndex, uint32_t toIndex) {
-    for (bitset_type::size_type i = fromIndex; i < toIndex; ++i) {
-        bitSet.set(i, true);
-    }
+    fastSet(fromIndex, toIndex, true);
 }
 
 void BitSet::set(uint32_t fromIndex, uint32_t toIndex, bool value) {
     if (toIndex >= bitSet.size()) {
         resize(toIndex + 1);
     }
-    for (bitset_type::size_type i = fromIndex; i < toIndex; ++i) {
-        bitSet.set(i, value);
-    }
+    fastSet(fromIndex, toIndex, value);
 }
 
 void BitSet::fastSet(uint32_t fromIndex, uint32_t toIndex, bool value) {
+#if BOOST_VERSION >= 106900
+    bitSet.set(fromIndex, toIndex - fromIndex, value);
+#else
     for (bitset_type::size_type i = fromIndex; i < toIndex; ++i) {
         bitSet.set(i, value);
     }
+#endif
 }
 
 void BitSet::flip(uint32_t bitIndex) {
@@ -114,15 +117,17 @@ void BitSet::flip(uint32_t fromIndex, uint32_t toIndex) {
     if (toIndex >= bitSet.size()) {
         resize(toIndex + 1);
     }
-    for (bitset_type::size_type i = fromIndex; i < toIndex; ++i) {
-        bitSet.flip(i);
-    }
+    fastFlip(fromIndex, toIndex);
 }
 
 void BitSet::fastFlip(uint32_t fromIndex, uint32_t toIndex) {
+#if BOOST_VERSION >= 106900
+    bitSet.flip(fromIndex, toIndex - fromIndex);
+#else
     for (bitset_type::size_type i = fromIndex; i < toIndex; ++i) {
         bitSet.flip(i);
     }
+#endif
 }
 
 uint32_t BitSet::size() const {
@@ -146,51 +151,46 @@ bool BitSet::fastGet(uint32_t bitIndex) const {
 }
 
 int32_t BitSet::nextSetBit(uint32_t fromIndex) const {
+#if BOOST_VERSION >= 108800
+    return bitSet.find_first(fromIndex);
+#else
     bitset_type::size_type next = fromIndex == 0 ? bitSet.find_first() : bitSet.find_next(fromIndex - 1);
     return next == bitset_type::npos ? -1 : next;
+#endif
 }
 
 void BitSet::_and(const BitSetPtr& set) {
-    bitset_type::size_type minBlocks = std::min(bitSet.num_blocks(), set->bitSet.num_blocks());
-    for (bitset_type::size_type i = 0; i < minBlocks; ++i) {
-        bitSet.m_bits[i] &= set->bitSet.m_bits[i];
-    }
-    if (bitSet.num_blocks() > minBlocks) {
-        std::fill(bitSet.m_bits.begin() + minBlocks, bitSet.m_bits.end(), bitset_type::block_type(0));
-    }
+    bitset_type other = set->bitSet;
+    other.resize(bitSet.size());
+    bitSet &= other;
 }
 
 void BitSet::_or(const BitSetPtr& set) {
-    bitset_type::size_type minBlocks = std::min(bitSet.num_blocks(), set->bitSet.num_blocks());
     if (set->bitSet.size() > bitSet.size()) {
         resize(set->bitSet.size());
-    }
-    for (bitset_type::size_type i = 0; i < minBlocks; ++i) {
-        bitSet.m_bits[i] |= set->bitSet.m_bits[i];
-    }
-    if (bitSet.num_blocks() > minBlocks) {
-        std::copy(set->bitSet.m_bits.begin() + minBlocks, set->bitSet.m_bits.end(), bitSet.m_bits.begin() + minBlocks);
+        bitSet |= set->bitSet;
+    } else {
+        bitset_type other = set->bitSet;
+        other.resize(bitSet.size());
+        bitSet |= other;
     }
 }
 
 void BitSet::_xor(const BitSetPtr& set) {
-    bitset_type::size_type minBlocks = std::min(bitSet.num_blocks(), set->bitSet.num_blocks());
     if (set->bitSet.size() > bitSet.size()) {
         resize(set->bitSet.size());
-    }
-    for (bitset_type::size_type i = 0; i < minBlocks; ++i) {
-        bitSet.m_bits[i] ^= set->bitSet.m_bits[i];
-    }
-    if (bitSet.num_blocks() > minBlocks) {
-        std::copy(set->bitSet.m_bits.begin() + minBlocks, set->bitSet.m_bits.end(), bitSet.m_bits.begin() + minBlocks);
+        bitSet ^= set->bitSet;
+    } else {
+        bitset_type other = set->bitSet;
+        other.resize(bitSet.size());
+        bitSet ^= other;
     }
 }
 
 void BitSet::andNot(const BitSetPtr& set) {
-    bitset_type::size_type minBlocks = std::min(bitSet.num_blocks(), set->bitSet.num_blocks());
-    for (bitset_type::size_type i = 0; i < minBlocks; ++i) {
-        bitSet.m_bits[i] &= ~set->bitSet.m_bits[i];
-    }
+    bitset_type other = set->bitSet;
+    other.resize(bitSet.size());
+    bitSet &= other.flip();
 }
 
 bool BitSet::intersectsBitSet(const BitSetPtr& set) const {
@@ -198,20 +198,11 @@ bool BitSet::intersectsBitSet(const BitSetPtr& set) const {
 }
 
 uint32_t BitSet::cardinality() {
-    return bitSet.num_blocks() == 0 ? 0 : (uint32_t)BitUtil::pop_array((int64_t*)getBits(), 0, bitSet.num_blocks());
+    return bitSet.count();
 }
 
 void BitSet::resize(uint32_t size) {
-    bitset_type::size_type old_num_blocks = bitSet.num_blocks();
-    bitset_type::size_type required_blocks = bitSet.calc_num_blocks(size);
-    if (required_blocks != old_num_blocks) {
-        bitSet.m_bits.resize(required_blocks, bitset_type::block_type(0));
-    }
-    bitSet.m_num_bits = size;
-    uint64_t extra_bits = static_cast<uint64_t>(bitSet.size() % bitSet.bits_per_block);
-    if (extra_bits != 0) {
-        bitSet.m_bits.back() &= ~(~static_cast<bitset_type::block_type>(0) << extra_bits);
-    }
+    bitSet.resize(size);
 }
 
 bool BitSet::equals(const LuceneObjectPtr& other) {
@@ -224,31 +215,28 @@ bool BitSet::equals(const LuceneObjectPtr& other) {
     }
     BitSetPtr first = bitSet.num_blocks() < otherBitSet->bitSet.num_blocks() ? otherBitSet : shared_from_this();
     BitSetPtr second = bitSet.num_blocks() < otherBitSet->bitSet.num_blocks() ? shared_from_this() : otherBitSet;
-    bitset_type::size_type firstLength = first->bitSet.num_blocks();
-    bitset_type::size_type secondLength = second->bitSet.num_blocks();
-    for (bitset_type::size_type i = secondLength; i < firstLength; ++i) {
-        if (first->bitSet.m_bits[i] != 0) {
-            return false;
+    bitset_type::size_type f = first->bitSet.find_first();
+    bitset_type::size_type s = second->bitSet.find_first();
+    while (f == s) {
+        if (f == bitset_type::npos) {
+            return true;
         }
+        f = first->bitSet.find_next(f);
+        s = second->bitSet.find_next(s);
     }
-    for (bitset_type::size_type i = 0; i < secondLength; ++i) {
-        if (first->bitSet.m_bits[i] != second->bitSet.m_bits[i]) {
-            return false;
-        }
-    }
-    return true;
+    return false;
 }
 
 int32_t BitSet::hashCode() {
     // Start with a zero hash and use a mix that results in zero if the input is zero.
     // This effectively truncates trailing zeros without an explicit check.
     int64_t hash = 0;
-    uint32_t maxSize = bitSet.num_blocks();
-    const uint64_t* bits = getBits();
-    for (uint32_t bit = 0; bit < maxSize; ++bit) {
-        hash ^= bits[bit];
-        hash = (hash << 1) | (hash >> 63); // rotate left
-    }
+    to_block_range(bitSet, boost::make_function_output_iterator(
+        [&hash](bitset_type::block_type block) {
+            hash ^= block;
+            hash = (hash << 1) | (hash >> 63); // rotate left
+        }
+    ));
     // Fold leftmost bits into right and add a constant to prevent empty sets from
     // returning 0, which is too common.
     return (int32_t)((hash >> 32) ^ hash) + 0x98761234;
