From 7ea7f186e66f2b0a51ccb278c7e527204e92e3f6 Mon Sep 17 00:00:00 2001
From: ilor <kailoran@gmail.com>
Date: Thu, 4 Nov 2010 12:30:16 +0100
Subject: [PATCH] Pwrutiuls: add set_bits_iterator with a test, bump version to
 0.0.3

---
 libpwrutils/CMakeLists.txt |  2 +-
 libpwrutils/bitset.h       | 65 +++++++++++++++++++++++++++++++++++++-
 tests/tag_split.cpp        | 12 +++++++
 3 files changed, 77 insertions(+), 2 deletions(-)

diff --git a/libpwrutils/CMakeLists.txt b/libpwrutils/CMakeLists.txt
index b7e1370..84cbcc8 100644
--- a/libpwrutils/CMakeLists.txt
+++ b/libpwrutils/CMakeLists.txt
@@ -4,7 +4,7 @@ PROJECT(pwrutils)
 
 set(pwrutils_ver_major "0")
 set(pwrutils_ver_minor "0")
-set(pwrutils_ver_patch "2")
+set(pwrutils_ver_patch "3")
 
 set(LIBPWRUTILS_VERSION
 	"${pwrutils_ver_major}.${pwrutils_ver_minor}.${pwrutils_ver_patch}")
diff --git a/libpwrutils/bitset.h b/libpwrutils/bitset.h
index a0a2be6..2b5342b 100644
--- a/libpwrutils/bitset.h
+++ b/libpwrutils/bitset.h
@@ -58,6 +58,69 @@ inline size_t lowest_bit(const unsigned long& t)
 	return boost::lowest_bit(t);
 }
 
+/// Helper iterator class for iterating through set bits
+template<typename T>
+struct set_bits_iterator
+{
+	typedef T value_type;
+	typedef std::forward_iterator_tag iterator_category;
+	typedef int difference_type;
+	typedef const T *pointer;
+	typedef const T &reference;
+	set_bits_iterator(const set_bits_iterator &i): i_(i.i_), c_(i.c_) {}
+	set_bits_iterator(const T& i) : i_(i), c_(0) {
+		adv();
+	}
+
+	set_bits_iterator &operator++() {
+		adv(); return *this;
+	}
+	set_bits_iterator operator++(int) {
+		set_bits_iterator c(*this);
+		c.adv();
+		return c;
+	}
+	bool operator==(const set_bits_iterator &i) const {
+		return i_ == i.i_ && c_ == i.c_;
+	}
+	bool operator!=(const set_bits_iterator &i) const {
+		return i_ != i.i_ || c_ != i.c_;
+	}
+	const T &operator*() const { return c_; }
+
+private:
+	void adv() {
+		c_.reset();
+		if (i_.any()) {
+			c_.set(lowest_bit(i_));
+			i_ ^= c_;
+		}
+	}
+
+	T i_;
+	T c_;
+};
+
+/**
+ * Function that returns a foreach-compatible iterator range that allows
+ * iterating through the set bits of a bitset. It only makes sense to read
+ * from the returned range.
+ *
+ * Example usage: \code
+ * foreach (const bitset<32>& b, my_bitset) {
+ *    foo_with(b);
+ * }
+ * \endcode
+ */
+template<size_t S>
+boost::iterator_range< set_bits_iterator< std::bitset<S> > > set_bits(
+		const bitset<S>& bs)
+{
+	return boost::iterator_range< set_bits_iterator< std::bitset<S> > >(
+			bs, bitset<S>()
+		);
+}
+
 } /* end ns PwrNlp */
 
 namespace std {
@@ -106,6 +169,6 @@ bool operator<(bitset<PwrNlp::ulong_bits> left, bitset<PwrNlp::ulong_bits> right
 	return left.to_ulong() < right.to_ulong();
 }
 
-}
+} /* end ns std */
 
 #endif // PWRNLP_BITSET_H
diff --git a/tests/tag_split.cpp b/tests/tag_split.cpp
index 1f4ca44..7197653 100644
--- a/tests/tag_split.cpp
+++ b/tests/tag_split.cpp
@@ -1,6 +1,7 @@
 #include <boost/test/unit_test.hpp>
 #include <set>
 #include <libpwrutils/foreach.h>
+#include <libpwrutils/bitset.h>
 #include <libcorpus2/tagset.h>
 #include <libcorpus2/token.h>
 
@@ -196,3 +197,14 @@ BOOST_FIXTURE_TEST_CASE( tag_size, F )
 }
 
 BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_CASE(bs_split)
+{
+	std::bitset<32> x(0xf6543);
+	std::bitset<32> y(0);
+	foreach (std::bitset<32> b, PwrNlp::set_bits(x)) {
+		BOOST_CHECK_EQUAL(b.count(), 1);
+		y |= b;
+	}
+	BOOST_CHECK_EQUAL(x, y);
+}
-- 
GitLab