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; 49 virtual ~Timestamper() {} 50 }; 51 52 class TimestamperInMilliseconds : public Timestamper { 53 public: 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 } 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> 85 bluetooth::common::CircularBuffer<T>::CircularBuffer(size_t size) : size_(size) {} 86 87 template <typename T> 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> 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> 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> 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> 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> 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> 128 std::vector<struct bluetooth::common::TimestampedEntry<T>> bluetooth::common::TimestampedCircularBuffer<T>::Drain() { 129 return bluetooth::common::CircularBuffer<TimestampedEntry<T>>::Drain(); 130 } 131