/* * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE * * This file was based on * https://embeddedartistry.com/blog/2017/05/17/creating-a-circular-buffer-in-c-and-c/ * https://github.com/embeddedartistry/embedded-resources/blob/master/examples/cpp/circular_buffer.cpp */ #ifndef AZEROTHCORE_CIRCULAR_BUFFER_H #define AZEROTHCORE_CIRCULAR_BUFFER_H #include #include #include template class CircularBuffer { public: explicit CircularBuffer(std::size_t size) : buf_(std::unique_ptr(new T[size])), max_size_(size) { } void put(T item) { std::lock_guard lock(mutex_); buf_[head_] = item; if (full_) { tail_ = (tail_ + 1) % max_size_; } head_ = (head_ + 1) % max_size_; full_ = head_ == tail_; } [[nodiscard]] bool empty() const { //if head and tail are equal, we are empty return (!full_ && (head_ == tail_)); } [[nodiscard]] bool full() const { //If tail is ahead the head by 1, we are full return full_; } [[nodiscard]] std::size_t capacity() const { return max_size_; } [[nodiscard]] std::size_t size() const { std::size_t size = max_size_; if (!full_) { if (head_ >= tail_) { size = head_ - tail_; } else { size += head_ - tail_; } } return size; } // the implementation of this function is simplified by the fact that head_ will never be lower than tail_ // when compared to the original implementation of this class std::vector content() { std::lock_guard lock(mutex_); return std::vector(buf_.get(), buf_.get() + size()); } T peak_back() { std::lock_guard lock(mutex_); return empty() ? T() : buf_[tail_]; } private: std::mutex mutex_; std::unique_ptr buf_; std::size_t head_ = 0; std::size_t tail_ = 0; const std::size_t max_size_; bool full_ = false; }; #endif