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 <deque>
21 #include <iterator>
22 #include <memory>
23 #include <mutex>
24 #include <vector>
25 
26 namespace bluetooth {
27 namespace common {
28 
29 template <typename T>
30 class CircularBuffer {
31 public:
32   explicit CircularBuffer(size_t size);
33 
34   // Push one item to the circular buffer
35   void Push(T item);
36   // Take a snapshot of the circular buffer and return it as a vector
37   std::vector<T> Pull() const;
38   // Drain everything from the circular buffer and return them as a vector
39   std::vector<T> Drain();
40 
41 private:
42   const size_t size_;
43   std::deque<T> queue_;
44   mutable std::mutex mutex_;
45 };
46 
47 class Timestamper {
48 public:
49   virtual uint64_t GetTimestamp() const = 0;
~Timestamper()50   virtual ~Timestamper() {}
51 };
52 
53 class TimestamperInMilliseconds : public Timestamper {
54 public:
GetTimestamp()55   uint64_t GetTimestamp() const override {
56     return std::chrono::duration_cast<std::chrono::milliseconds>(
57                    std::chrono::system_clock::now().time_since_epoch())
58             .count();
59   }
~TimestamperInMilliseconds()60   virtual ~TimestamperInMilliseconds() {}
61 };
62 
63 template <typename T>
64 struct TimestampedEntry {
65   uint64_t timestamp;
66   T entry;
67 };
68 
69 template <typename T>
70 class TimestampedCircularBuffer : public CircularBuffer<TimestampedEntry<T>> {
71 public:
72   explicit TimestampedCircularBuffer(
73           size_t size,
74           std::unique_ptr<Timestamper> timestamper = std::make_unique<TimestamperInMilliseconds>());
75 
76   void Push(T item);
77   std::vector<TimestampedEntry<T>> Pull() const;
78   std::vector<TimestampedEntry<T>> Drain();
79 
80 private:
81   std::unique_ptr<Timestamper> timestamper_{std::make_unique<TimestamperInMilliseconds>()};
82 };
83 
84 }  // namespace common
85 }  // namespace bluetooth
86 
87 template <typename T>
CircularBuffer(size_t size)88 bluetooth::common::CircularBuffer<T>::CircularBuffer(size_t size) : size_(size) {}
89 
90 template <typename T>
Push(const T item)91 void bluetooth::common::CircularBuffer<T>::Push(const T item) {
92   std::unique_lock<std::mutex> lock(mutex_);
93   queue_.push_back(item);
94   while (queue_.size() > size_) {
95     queue_.pop_front();
96   }
97 }
98 
99 template <typename T>
Pull()100 std::vector<T> bluetooth::common::CircularBuffer<T>::Pull() const {
101   std::unique_lock<std::mutex> lock(mutex_);
102   return std::vector<T>(queue_.cbegin(), queue_.cend());
103 }
104 
105 template <typename T>
Drain()106 std::vector<T> bluetooth::common::CircularBuffer<T>::Drain() {
107   std::unique_lock<std::mutex> lock(mutex_);
108   std::vector<T> items(std::make_move_iterator(queue_.begin()),
109                        std::make_move_iterator(queue_.end()));
110   queue_.clear();
111   return items;
112 }
113 
114 template <typename T>
TimestampedCircularBuffer(size_t size,std::unique_ptr<Timestamper> timestamper)115 bluetooth::common::TimestampedCircularBuffer<T>::TimestampedCircularBuffer(
116         size_t size, std::unique_ptr<Timestamper> timestamper)
117     : CircularBuffer<TimestampedEntry<T>>(size), timestamper_(std::move(timestamper)) {}
118 
119 template <typename T>
Push(const T item)120 void bluetooth::common::TimestampedCircularBuffer<T>::Push(const T item) {
121   TimestampedEntry<T> timestamped_entry{timestamper_->GetTimestamp(), item};
122   bluetooth::common::CircularBuffer<TimestampedEntry<T>>::Push(timestamped_entry);
123 }
124 
125 template <typename T>
126 std::vector<struct bluetooth::common::TimestampedEntry<T>>
Pull()127 bluetooth::common::TimestampedCircularBuffer<T>::Pull() const {
128   return bluetooth::common::CircularBuffer<TimestampedEntry<T>>::Pull();
129 }
130 
131 template <typename T>
132 std::vector<struct bluetooth::common::TimestampedEntry<T>>
Drain()133 bluetooth::common::TimestampedCircularBuffer<T>::Drain() {
134   return bluetooth::common::CircularBuffer<TimestampedEntry<T>>::Drain();
135 }
136