* 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
"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",
#pragma once
-#include <stddef.h>
-
+#include <cstddef>
+#include <iterator>
#include <mutex>
#include <queue>
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_;
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>()};
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;
}
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();
+}
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) {