• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://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, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #pragma once
16 
17 #include <cstdint>
18 #include <optional>
19 
20 #include "pw_assert/assert.h"
21 #include "pw_span/span.h"
22 
23 namespace pw::work_queue::internal {
24 
25 // TODO(hepler): Replace this with a std::deque like container.
26 template <typename T>
27 class CircularBuffer {
28  public:
CircularBuffer(span<T> buffer)29   explicit constexpr CircularBuffer(span<T> buffer)
30       : buffer_(buffer), head_(0), tail_(0), count_(0) {}
31 
empty()32   bool empty() const { return count_ == 0; }
full()33   bool full() const { return count_ == buffer_.size(); }
size()34   size_t size() const { return count_; }
capacity()35   size_t capacity() const { return buffer_.size(); }
36 
37   template <typename Ty>
Push(Ty && value)38   bool Push(Ty&& value) {
39     PW_DASSERT(tail_ < buffer_.size());
40 
41     if (full()) {
42       return false;
43     }
44 
45     buffer_[tail_] = std::forward<Ty>(value);
46     IncrementWithWrap(tail_);
47     ++count_;
48     return true;
49   }
50 
Pop()51   std::optional<T> Pop() {
52     PW_DASSERT(head_ < buffer_.size());
53 
54     if (empty()) {
55       return std::nullopt;
56     }
57 
58     T entry = std::move(buffer_[head_]);
59     IncrementWithWrap(head_);
60     --count_;
61     return entry;
62   }
63 
64  private:
IncrementWithWrap(size_t & index)65   void IncrementWithWrap(size_t& index) const {
66     index++;
67     // Note: branch is faster than mod (%) on common embedded architectures.
68     if (index == buffer_.size()) {
69       index = 0;
70     }
71   }
72 
73   span<T> buffer_;
74 
75   size_t head_;
76   size_t tail_;
77   size_t count_;
78 };
79 
80 }  // namespace pw::work_queue::internal
81