1 // Copyright 2024 gRPC authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef GRPC_SRC_CORE_UTIL_RING_BUFFER_H 16 #define GRPC_SRC_CORE_UTIL_RING_BUFFER_H 17 18 #include <grpc/support/port_platform.h> 19 20 #include <array> 21 #include <cstddef> 22 #include <iterator> 23 24 #include "absl/types/optional.h" 25 26 namespace grpc_core { 27 28 template <typename T, int kCapacity> 29 class RingBuffer { 30 public: 31 class RingBufferIterator { 32 public: 33 using iterator_category = std::forward_iterator_tag; 34 using value_type = const T; 35 using pointer = void; 36 using reference = void; 37 using difference_type = std::ptrdiff_t; 38 39 RingBufferIterator& operator++() { 40 if (--size_ <= 0) { 41 head_ = 0; 42 size_ = 0; 43 buffer_ = nullptr; 44 } else { 45 head_ = (head_ + 1) % kCapacity; 46 } 47 return *this; 48 } 49 50 RingBufferIterator operator++(int) { 51 RingBufferIterator tmp(*this); 52 operator++(); 53 return tmp; 54 } 55 56 bool operator==(const RingBufferIterator& rhs) const { 57 return (buffer_ == rhs.buffer_ && head_ == rhs.head_ && 58 size_ == rhs.size_); 59 } 60 61 bool operator!=(const RingBufferIterator& rhs) const { 62 return !operator==(rhs); 63 } 64 65 T operator*() { return buffer_->data_[head_]; } 66 RingBufferIterator()67 RingBufferIterator() : buffer_(nullptr), head_(0), size_(0) {}; 68 RingBufferIterator(const RingBufferIterator& other) = default; RingBufferIterator(const RingBuffer<T,kCapacity> * buffer)69 explicit RingBufferIterator(const RingBuffer<T, kCapacity>* buffer) 70 : buffer_(buffer), head_(buffer->head_), size_(buffer->size_) { 71 if (!size_) { 72 buffer_ = nullptr; 73 } 74 } 75 76 private: 77 friend class RingBuffer<T, kCapacity>; 78 const RingBuffer<T, kCapacity>* buffer_; 79 int head_ = 0; 80 int size_ = 0; 81 }; 82 83 RingBuffer() = default; 84 Append(T data)85 void Append(T data) { 86 if (size_ < kCapacity) { 87 data_[size_] = std::move(data); 88 size_++; 89 } else { 90 data_[head_] = std::move(data); 91 head_ = (head_ + 1) % kCapacity; 92 } 93 } 94 95 // Returns the data of the first element in the buffer and removes it from 96 // the buffer. If the buffer is empty, returns absl::nullopt. PopIfNotEmpty()97 absl::optional<T> PopIfNotEmpty() { 98 if (!size_) return absl::nullopt; 99 T data = std::move(data_[head_]); 100 --size_; 101 head_ = (head_ + 1) % kCapacity; 102 return data; 103 } 104 Clear()105 void Clear() { 106 head_ = 0; 107 size_ = 0; 108 } 109 begin()110 RingBufferIterator begin() const { return RingBufferIterator(this); } 111 end()112 RingBufferIterator end() const { return RingBufferIterator(); } 113 114 private: 115 friend class RingBufferIterator; 116 std::array<T, kCapacity> data_; 117 int head_ = 0; 118 int size_ = 0; 119 }; 120 121 } // namespace grpc_core 122 123 #endif // GRPC_SRC_CORE_UTIL_RING_BUFFER_H 124