Merge "trace_processor: add all bits iterator"
diff --git a/Android.bp b/Android.bp
index 679b438..52e65e5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -4514,6 +4514,7 @@
   name: "perfetto_src_trace_processor_db_lib",
   srcs: [
     "src/trace_processor/db/bit_vector.cc",
+    "src/trace_processor/db/bit_vector_iterators.cc",
     "src/trace_processor/db/column.cc",
     "src/trace_processor/db/row_map.cc",
     "src/trace_processor/db/table.cc",
diff --git a/BUILD b/BUILD
index 4063dd8..74e1390 100644
--- a/BUILD
+++ b/BUILD
@@ -516,6 +516,8 @@
     srcs = [
         "src/trace_processor/db/bit_vector.cc",
         "src/trace_processor/db/bit_vector.h",
+        "src/trace_processor/db/bit_vector_iterators.cc",
+        "src/trace_processor/db/bit_vector_iterators.h",
         "src/trace_processor/db/column.cc",
         "src/trace_processor/db/column.h",
         "src/trace_processor/db/row_map.cc",
diff --git a/src/trace_processor/db/BUILD.gn b/src/trace_processor/db/BUILD.gn
index 7360779..57366d2 100644
--- a/src/trace_processor/db/BUILD.gn
+++ b/src/trace_processor/db/BUILD.gn
@@ -18,6 +18,8 @@
   sources = [
     "bit_vector.cc",
     "bit_vector.h",
+    "bit_vector_iterators.cc",
+    "bit_vector_iterators.h",
     "column.cc",
     "column.h",
     "row_map.cc",
diff --git a/src/trace_processor/db/bit_vector.cc b/src/trace_processor/db/bit_vector.cc
index edf1af6..2845a50 100644
--- a/src/trace_processor/db/bit_vector.cc
+++ b/src/trace_processor/db/bit_vector.cc
@@ -16,6 +16,8 @@
 
 #include "src/trace_processor/db/bit_vector.h"
 
+#include "src/trace_processor/db/bit_vector_iterators.h"
+
 namespace perfetto {
 namespace trace_processor {
 
@@ -34,5 +36,25 @@
   return BitVector(blocks_, counts_, size_);
 }
 
+BitVector::AllBitsIterator BitVector::IterateAllBits() const {
+  return AllBitsIterator(this);
+}
+
+void BitVector::UpdateSetBits(const BitVector& other) {
+  PERFETTO_DCHECK(other.size() == GetNumBitsSet());
+
+  // Go through each set bit and if |other| has it unset, then unset the
+  // bit taking care to update the index we consider to take into account
+  // the bits we just unset.
+  // TODO(lalitm): we add a set bits iterator implementation to remove this
+  // inefficient loop.
+  uint32_t removed = 0;
+  for (auto it = other.IterateAllBits(); it; it.Next()) {
+    if (!it.IsSet()) {
+      Clear(IndexOfNthSet(it.index() - removed++));
+    }
+  }
+}
+
 }  // namespace trace_processor
 }  // namespace perfetto
diff --git a/src/trace_processor/db/bit_vector.h b/src/trace_processor/db/bit_vector.h
index df49156..8993b22 100644
--- a/src/trace_processor/db/bit_vector.h
+++ b/src/trace_processor/db/bit_vector.h
@@ -30,10 +30,19 @@
 namespace perfetto {
 namespace trace_processor {
 
+namespace internal {
+
+class BaseIterator;
+class AllBitsIterator;
+
+}  // namespace internal
+
 // A bitvector which compactly stores a vector of bools using a single bit
 // for each bool.
 class BitVector {
  public:
+  using AllBitsIterator = internal::AllBitsIterator;
+
   // Creates an empty bitvector.
   BitVector();
 
@@ -265,23 +274,20 @@
   // This will change this to the following:
   // this:  0 1 0 0 1 0 0
   // TODO(lalitm): investigate whether we should just change this to And.
-  void UpdateSetBits(const BitVector& other) {
-    PERFETTO_DCHECK(other.size() == GetNumBitsSet());
+  void UpdateSetBits(const BitVector& other);
 
-    // Go through each set bit and if |other| has it unset, then unset the
-    // bit taking care to update the index we consider to take into account
-    // the bits we just unset.
-    // TODO(lalitm): we add an iterator implementation to remove this
-    // inefficient loop.
-    uint32_t removed = 0;
-    for (uint32_t i = 0, size = other.size(); i < size; ++i) {
-      if (!other.IsSet(i)) {
-        Clear(IndexOfNthSet(i - removed++));
-      }
-    }
-  }
+  // Iterate all the bits in the BitVector.
+  //
+  // Usage:
+  // for (auto it = bv.IterateAllBits(); it; it.Next()) {
+  //   ...
+  // }
+  AllBitsIterator IterateAllBits() const;
 
  private:
+  friend class internal::BaseIterator;
+  friend class internal::AllBitsIterator;
+
   // Represents the offset of a bit within a block.
   struct BlockOffset {
     uint16_t word_idx;
diff --git a/src/trace_processor/db/bit_vector_iterators.cc b/src/trace_processor/db/bit_vector_iterators.cc
new file mode 100644
index 0000000..29981dd
--- /dev/null
+++ b/src/trace_processor/db/bit_vector_iterators.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include "src/trace_processor/db/bit_vector_iterators.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace internal {
+
+BaseIterator::BaseIterator(BitVector* bv) : bv_(bv) {
+  size_ = bv->size();
+
+  if (size_ > 0) {
+    block_ = bv_->blocks_[0];
+  }
+}
+
+BaseIterator::~BaseIterator() {
+  uint32_t block = index_ / BitVector::Block::kBits;
+  OnBlockChange(block, static_cast<uint32_t>(bv_->blocks_.size()) - 1);
+}
+
+void BaseIterator::OnBlockChange(uint32_t old_block, uint32_t new_block) {
+  // If we touched the current block, flush the block to the bitvector.
+  if (is_block_changed_) {
+    bv_->blocks_[old_block] = block_;
+  }
+
+  if (set_bit_count_diff_ != 0) {
+    // If the count of set bits has changed, go through all the counts between
+    // the old and new blocks and modify them.
+    // We only need to go to new_block and not to the end of the bitvector as
+    // the blocks after new_block will either be updated in a future call to
+    // OnBlockChange or in the destructor.
+    for (uint32_t i = old_block + 1; i <= new_block; ++i) {
+      int32_t new_count =
+          static_cast<int32_t>(bv_->counts_[i]) + set_bit_count_diff_;
+      PERFETTO_DCHECK(new_count >= 0);
+
+      bv_->counts_[i] = static_cast<uint32_t>(new_count);
+    }
+  }
+
+  // Reset the changed flag and cache the new block.
+  is_block_changed_ = false;
+  block_ = bv_->blocks_[new_block];
+}
+
+AllBitsIterator::AllBitsIterator(const BitVector* bv)
+    : BaseIterator(const_cast<BitVector*>(bv)) {}
+
+}  // namespace internal
+}  // namespace trace_processor
+}  // namespace perfetto
diff --git a/src/trace_processor/db/bit_vector_iterators.h b/src/trace_processor/db/bit_vector_iterators.h
new file mode 100644
index 0000000..a1b98d4
--- /dev/null
+++ b/src/trace_processor/db/bit_vector_iterators.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_DB_BIT_VECTOR_ITERATORS_H_
+#define SRC_TRACE_PROCESSOR_DB_BIT_VECTOR_ITERATORS_H_
+
+#include "src/trace_processor/db/bit_vector.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace internal {
+
+// Base iterator class for all iterators on BitVector.
+//
+// This class implements caching of one Block at a time to reduce pointer
+// chasing. It also defers updating counts on Clear calls until the end of each
+// block.
+class BaseIterator {
+ public:
+  BaseIterator(BitVector* bv);
+  ~BaseIterator();
+
+  BaseIterator(BaseIterator&&) noexcept = default;
+  BaseIterator& operator=(BaseIterator&&) = default;
+
+  // Clears the current bit the iterator points to.
+  void Clear() {
+    if (IsSet()) {
+      block_.Clear(block_offset());
+
+      is_block_changed_ = true;
+      --set_bit_count_diff_;
+    }
+  }
+
+  // Returns whether the current bit the iterator points to is set.
+  bool IsSet() { return block_.IsSet(block_offset()); }
+
+  // Returns the index of the current bit the iterator points to.
+  uint32_t index() const { return index_; }
+
+ protected:
+  // Sets the index this iterator points to the given value.
+  //
+  // This method also performs some extra work on block boundaries
+  // as it caches the block to improve performance by reducing pointer
+  // chasing on every IsSet and Clear calls.
+  void SetIndex(uint32_t index) {
+    // We should always move the index forward.
+    PERFETTO_DCHECK(index >= index_);
+
+    uint32_t old_index = index_;
+    index_ = index;
+
+    // If we've reached the end of the iterator, just bail out.
+    if (index >= size_)
+      return;
+
+    uint32_t old_block = old_index / BitVector::Block::kBits;
+    uint32_t new_block = index / BitVector::Block::kBits;
+
+    // Fast path: we're in the same block so we don't need to do
+    // any other work.
+    if (PERFETTO_LIKELY(old_block == new_block))
+      return;
+
+    // Slow path: we have to change block so this will involve flushing the old
+    // block and counts (if necessary) and caching the new block.
+    OnBlockChange(old_block, new_block);
+  }
+
+  // Handles flushing count changes and modified blocks to the bitvector
+  // and caching the new block.
+  void OnBlockChange(uint32_t old_block, uint32_t new_block);
+
+  uint32_t size() const { return size_; }
+
+ private:
+  BaseIterator(const BaseIterator&) = delete;
+  BaseIterator& operator=(const BaseIterator&) = delete;
+
+  BitVector::BlockOffset block_offset() const {
+    uint16_t bit_idx_inside_block = index_ % BitVector::Block::kBits;
+
+    BitVector::BlockOffset bo;
+    bo.word_idx = bit_idx_inside_block / BitVector::BitWord::kBits;
+    bo.bit_idx = bit_idx_inside_block % BitVector::BitWord::kBits;
+    return bo;
+  }
+
+  uint32_t index_ = 0;
+  uint32_t size_ = 0;
+
+  bool is_block_changed_ = false;
+  int32_t set_bit_count_diff_ = 0;
+
+  BitVector* bv_ = nullptr;
+
+  BitVector::Block block_{};
+};
+
+// Iterator over all the bits in a bitvector.
+class AllBitsIterator : public BaseIterator {
+ public:
+  AllBitsIterator(const BitVector*);
+
+  // Increments the iterator to point to the next bit.
+  void Next() { SetIndex(index() + 1); }
+
+  // Returns whether the iterator is valid.
+  operator bool() const { return index() < size(); }
+};
+
+}  // namespace internal
+}  // namespace trace_processor
+}  // namespace perfetto
+
+#endif  // SRC_TRACE_PROCESSOR_DB_BIT_VECTOR_ITERATORS_H_
diff --git a/src/trace_processor/db/bit_vector_unittest.cc b/src/trace_processor/db/bit_vector_unittest.cc
index feb0f6c..c61fba6 100644
--- a/src/trace_processor/db/bit_vector_unittest.cc
+++ b/src/trace_processor/db/bit_vector_unittest.cc
@@ -18,6 +18,7 @@
 
 #include <random>
 
+#include "src/trace_processor/db/bit_vector_iterators.h"
 #include "test/gtest_and_gmock.h"
 
 namespace perfetto {
@@ -236,6 +237,55 @@
   ASSERT_TRUE(bv.IsSet(4));
 }
 
+TEST(BitVectorUnittest, IterateAllBitsConst) {
+  BitVector bv;
+  for (uint32_t i = 0; i < 12345; ++i) {
+    if (i % 7 == 0 || i % 13 == 0) {
+      bv.AppendTrue();
+    } else {
+      bv.AppendFalse();
+    }
+  }
+
+  uint32_t i = 0;
+  for (auto it = bv.IterateAllBits(); it; it.Next(), ++i) {
+    ASSERT_EQ(it.IsSet(), i % 7 == 0 || i % 13 == 0);
+    ASSERT_EQ(it.index(), i);
+  }
+}
+
+TEST(BitVectorUnittest, IterateAllBitsClear) {
+  BitVector bv;
+  for (uint32_t i = 0; i < 12345; ++i) {
+    if (i % 7 == 0 || i % 13 == 0) {
+      bv.AppendTrue();
+    } else {
+      bv.AppendFalse();
+    }
+  }
+
+  // Unset every 15th bit.
+  for (auto it = bv.IterateAllBits(); it; it.Next()) {
+    if (it.index() % 15 == 0) {
+      it.Clear();
+    }
+  }
+
+  // Go through the iterator manually and check it has updated
+  // to not have every 15th bit set.
+  uint32_t count = 0;
+  for (uint32_t i = 0; i < 12345; ++i) {
+    bool is_set = i % 15 != 0 && (i % 7 == 0 || i % 13 == 0);
+
+    ASSERT_EQ(bv.IsSet(i), is_set);
+    ASSERT_EQ(bv.GetNumBitsSet(i), count);
+
+    if (is_set) {
+      ASSERT_EQ(bv.IndexOfNthSet(count++), i);
+    }
+  }
+}
+
 TEST(BitVectorUnittest, QueryStressTest) {
   BitVector bv;
   std::vector<bool> bool_vec;
@@ -255,12 +305,19 @@
       int_vec.emplace_back(i);
   }
 
+  auto it = bv.IterateAllBits();
   for (uint32_t i = 0; i < kCount; ++i) {
     uint32_t count = static_cast<uint32_t>(std::count(
         bool_vec.begin(), bool_vec.begin() + static_cast<int32_t>(i), true));
     ASSERT_EQ(bv.IsSet(i), bool_vec[i]);
     ASSERT_EQ(bv.GetNumBitsSet(i), count);
+
+    ASSERT_TRUE(it);
+    ASSERT_EQ(it.IsSet(), bool_vec[i]);
+    ASSERT_EQ(it.index(), i);
+    it.Next();
   }
+  ASSERT_FALSE(it);
 
   for (uint32_t i = 0; i < int_vec.size(); ++i) {
     ASSERT_EQ(bv.IndexOfNthSet(i), int_vec[i]);