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