• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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