OSDN Git Service

GD-Common: Add CircularBuffer::Drain() method
authorJack He <siyuanh@google.com>
Thu, 18 Feb 2021 07:44:57 +0000 (23:44 -0800)
committerJack He <siyuanh@google.com>
Thu, 18 Feb 2021 07:52:13 +0000 (23:52 -0800)
* Drain() allows a circular buffer to return and clear
  its content so that one can clear a circular buffer
  in-place
* Moreover, Drain() uses move semantic to avoid copying
  its content and hence is more efficient
* Modify Pull() to use range-based initialization to do
  blocked copy that tends to be more efficient
* Add circular buffer unit test to compilation target
  and presubmit

Bug: 180569201
Test: gd/cert/run
Test: bluetooth_test_gd
Tag: #gd-refactor
Change-Id: Ic94f70fc862f244dcdc6b9d5f2526c45d0b8eb52

gd/common/Android.bp
gd/common/circular_buffer.h
gd/common/circular_buffer_test.cc

index c176992..0911138 100644 (file)
@@ -13,6 +13,7 @@ filegroup {
         "blocking_queue_unittest.cc",
         "bidi_queue_unittest.cc",
         "byte_array_test.cc",
+        "circular_buffer_test.cc",
         "observer_registry_test.cc",
         "init_flags_test.cc",
         "list_map_test.cc",
index 7347fce..1914fa0 100644 (file)
@@ -16,8 +16,8 @@
 
 #pragma once
 
-#include <stddef.h>
-
+#include <cstddef>
+#include <iterator>
 #include <mutex>
 #include <queue>
 
@@ -29,8 +29,12 @@ class CircularBuffer {
  public:
   explicit CircularBuffer(size_t size);
 
+  // Push one item to the circular buffer
   void Push(T item);
+  // Take a snapshot of the circular buffer and return it as a vector
   std::vector<T> Pull() const;
+  // Drain everything from the circular buffer and return them as a vector
+  std::vector<T> Drain();
 
  private:
   const size_t size_;
@@ -67,6 +71,7 @@ class TimestampedCircularBuffer : public CircularBuffer<TimestampedEntry<T>> {
 
   void Push(T item);
   std::vector<TimestampedEntry<T>> Pull() const;
+  std::vector<TimestampedEntry<T>> Drain();
 
  private:
   std::unique_ptr<Timestamper> timestamper_{std::make_unique<TimestamperInMilliseconds>()};
@@ -90,10 +95,14 @@ void bluetooth::common::CircularBuffer<T>::Push(const T item) {
 template <typename T>
 std::vector<T> bluetooth::common::CircularBuffer<T>::Pull() const {
   std::unique_lock<std::mutex> lock(mutex_);
-  std::vector<T> items;
-  for (auto it = queue_.cbegin(); it != queue_.cend(); ++it) {
-    items.push_back(*it);
-  }
+  return std::vector<T>(queue_.cbegin(), queue_.cend());
+}
+
+template <typename T>
+std::vector<T> bluetooth::common::CircularBuffer<T>::Drain() {
+  std::unique_lock<std::mutex> lock(mutex_);
+  std::vector<T> items(std::make_move_iterator(queue_.begin()), std::make_move_iterator(queue_.end()));
+  queue_.clear();
   return items;
 }
 
@@ -113,3 +122,8 @@ std::vector<struct bluetooth::common::TimestampedEntry<T>> bluetooth::common::Ti
     const {
   return bluetooth::common::CircularBuffer<TimestampedEntry<T>>::Pull();
 }
+
+template <typename T>
+std::vector<struct bluetooth::common::TimestampedEntry<T>> bluetooth::common::TimestampedCircularBuffer<T>::Drain() {
+  return bluetooth::common::CircularBuffer<TimestampedEntry<T>>::Drain();
+}
index 04c2995..bc67207 100644 (file)
@@ -43,6 +43,28 @@ TEST(CircularBufferTest, simple) {
   ASSERT_STREQ("One", vec[0].entry.c_str());
   ASSERT_STREQ("Two", vec[1].entry.c_str());
   ASSERT_STREQ("Three", vec[2].entry.c_str());
+
+  auto vec2 = buffer.Pull();
+
+  ASSERT_FALSE(vec2.empty());
+}
+
+TEST(CircularBufferTest, simple_drain) {
+  bluetooth::common::TimestampedCircularBuffer<std::string> buffer(10);
+
+  buffer.Push(std::string("One"));
+  buffer.Push(std::string("Two"));
+  buffer.Push(std::string("Three"));
+
+  auto vec = buffer.Drain();
+
+  ASSERT_STREQ("One", vec[0].entry.c_str());
+  ASSERT_STREQ("Two", vec[1].entry.c_str());
+  ASSERT_STREQ("Three", vec[2].entry.c_str());
+
+  auto vec2 = buffer.Pull();
+
+  ASSERT_TRUE(vec2.empty());
 }
 
 TEST(CircularBufferTest, test_timestamps) {