/****************************************************************************** * * Copyright 2016 Google, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #pragma once #include #include #include namespace bluetooth { namespace common { /* * LeakyBondedQueue * * - LeakyLondedQueue is a fixed size queue that leaks oldest item when * reaching its capacity. This is useful in creating memory bonded data * structure where freshness is more important than full coverage. * - The queue is protected by a simple mutex and is thread-safe, although * improvements could be made to lock enqueue and dequeue separately, it * is not implemented at this moment due to lack of demand * - The queue uses unique_ptr to automatically free its content when it is * destructed. It is the user's responsibility to implement T's destructor * correctly. * */ template class LeakyBondedQueue { public: LeakyBondedQueue(size_t capacity); /* Default destructor * * Call Clear() and free the queue structure itself */ ~LeakyBondedQueue(); /* * Add item NEW_ITEM to the underlining queue. If the queue is full, pop * the oldest item */ void Enqueue(T* new_item); /* * Add item NEW_ITEM to the underlining queue. If the queue is full, dequeue * the oldest item and returns it to the caller. Return nullptr otherwise. */ T* EnqueueWithPop(T* new_item); /* * Dequeues the oldest item from the queue. Return nullptr if queue is empty */ T* Dequeue(); /* * Returns the length of queue */ size_t Length(); /* * Returns the defined capacity of the queue */ size_t Capacity(); /* * Returns whether the queue is empty */ bool Empty(); /* * Pops all items from the queue */ void Clear(); private: // Put item in unique_ptr so that they get freed automatically when poped or // when queue_ is freed std::queue> queue_; std::mutex lock_; size_t capacity_; }; /* * Definitions must be in the header for template classes */ template LeakyBondedQueue::LeakyBondedQueue(size_t capacity) { capacity_ = capacity; } template LeakyBondedQueue::~LeakyBondedQueue() {} template void LeakyBondedQueue::Enqueue(T* new_item) { std::lock_guard lock(lock_); if ((queue_.size() + 1) > capacity_) { queue_.pop(); } std::unique_ptr item_ptr(new_item); queue_.push(std::move(item_ptr)); } template T* LeakyBondedQueue::EnqueueWithPop(T* new_item) { std::lock_guard lock(lock_); T* old_item = nullptr; if ((queue_.size() + 1) > capacity_) { std::unique_ptr item = std::move(queue_.front()); queue_.pop(); old_item = item.release(); } std::unique_ptr item_ptr(new_item); queue_.push(std::move(item_ptr)); return old_item; } template T* LeakyBondedQueue::Dequeue() { std::lock_guard lock(lock_); std::unique_ptr item = std::move(queue_.front()); queue_.pop(); return item.release(); } template void LeakyBondedQueue::Clear() { std::lock_guard lock(lock_); while (!queue_.empty()) { // unique_ptr does not need to be freed queue_.pop(); } } template size_t LeakyBondedQueue::Length() { std::lock_guard lock(lock_); return queue_.size(); } template size_t LeakyBondedQueue::Capacity() { return capacity_; } template bool LeakyBondedQueue::Empty() { std::lock_guard lock(lock_); return queue_.empty(); } } // namespace common } // namespace bluetooth