1 /*
2 * Copyright 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #pragma once
18
19 #include <cstddef>
20 #include <iterator>
21 #include <memory>
22 #include <mutex>
23 #include <queue>
24
25 namespace bluetooth {
26 namespace common {
27
28 template <typename T>
29 class CircularBuffer {
30 public:
31 explicit CircularBuffer(size_t size);
32
33 // Push one item to the circular buffer
34 void Push(T item);
35 // Take a snapshot of the circular buffer and return it as a vector
36 std::vector<T> Pull() const;
37 // Drain everything from the circular buffer and return them as a vector
38 std::vector<T> Drain();
39
40 private:
41 const size_t size_;
42 std::deque<T> queue_;
43 mutable std::mutex mutex_;
44 };
45
46 class Timestamper {
47 public:
48 virtual long long GetTimestamp() const = 0;
~Timestamper()49 virtual ~Timestamper() {}
50 };
51
52 class TimestamperInMilliseconds : public Timestamper {
53 public:
GetTimestamp()54 long long GetTimestamp() const override {
55 return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch())
56 .count();
57 }
~TimestamperInMilliseconds()58 virtual ~TimestamperInMilliseconds() {}
59 };
60
61 template <typename T>
62 struct TimestampedEntry {
63 long long timestamp;
64 T entry;
65 };
66
67 template <typename T>
68 class TimestampedCircularBuffer : public CircularBuffer<TimestampedEntry<T>> {
69 public:
70 explicit TimestampedCircularBuffer(
71 size_t size, std::unique_ptr<Timestamper> timestamper = std::make_unique<TimestamperInMilliseconds>());
72
73 void Push(T item);
74 std::vector<TimestampedEntry<T>> Pull() const;
75 std::vector<TimestampedEntry<T>> Drain();
76
77 private:
78 std::unique_ptr<Timestamper> timestamper_{std::make_unique<TimestamperInMilliseconds>()};
79 };
80
81 } // namespace common
82 } // namespace bluetooth
83
84 template <typename T>
CircularBuffer(size_t size)85 bluetooth::common::CircularBuffer<T>::CircularBuffer(size_t size) : size_(size) {}
86
87 template <typename T>
Push(const T item)88 void bluetooth::common::CircularBuffer<T>::Push(const T item) {
89 std::unique_lock<std::mutex> lock(mutex_);
90 queue_.push_back(item);
91 while (queue_.size() > size_) {
92 queue_.pop_front();
93 }
94 }
95
96 template <typename T>
Pull()97 std::vector<T> bluetooth::common::CircularBuffer<T>::Pull() const {
98 std::unique_lock<std::mutex> lock(mutex_);
99 return std::vector<T>(queue_.cbegin(), queue_.cend());
100 }
101
102 template <typename T>
Drain()103 std::vector<T> bluetooth::common::CircularBuffer<T>::Drain() {
104 std::unique_lock<std::mutex> lock(mutex_);
105 std::vector<T> items(std::make_move_iterator(queue_.begin()), std::make_move_iterator(queue_.end()));
106 queue_.clear();
107 return items;
108 }
109
110 template <typename T>
TimestampedCircularBuffer(size_t size,std::unique_ptr<Timestamper> timestamper)111 bluetooth::common::TimestampedCircularBuffer<T>::TimestampedCircularBuffer(
112 size_t size, std::unique_ptr<Timestamper> timestamper)
113 : CircularBuffer<TimestampedEntry<T>>(size), timestamper_(std::move(timestamper)) {}
114
115 template <typename T>
Push(const T item)116 void bluetooth::common::TimestampedCircularBuffer<T>::Push(const T item) {
117 TimestampedEntry<T> timestamped_entry{timestamper_->GetTimestamp(), item};
118 bluetooth::common::CircularBuffer<TimestampedEntry<T>>::Push(timestamped_entry);
119 }
120
121 template <typename T>
Pull()122 std::vector<struct bluetooth::common::TimestampedEntry<T>> bluetooth::common::TimestampedCircularBuffer<T>::Pull()
123 const {
124 return bluetooth::common::CircularBuffer<TimestampedEntry<T>>::Pull();
125 }
126
127 template <typename T>
Drain()128 std::vector<struct bluetooth::common::TimestampedEntry<T>> bluetooth::common::TimestampedCircularBuffer<T>::Drain() {
129 return bluetooth::common::CircularBuffer<TimestampedEntry<T>>::Drain();
130 }
131