| // Copyright 2020 The Pigweed Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| // use this file except in compliance with the License. You may obtain a copy of |
| // the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| // License for the specific language governing permissions and limitations under |
| // the License. |
| #pragma once |
| |
| #include <cstddef> |
| |
| #include "pw_span/span.h" |
| #include "pw_status/status.h" |
| |
| namespace pw { |
| namespace ring_buffer { |
| |
| // A circular ring buffer for arbitrary length data entries. Each PushBack() |
| // produces a buffer entry. Each entry consists of a preamble followed by an |
| // arbitrary length data chunk/blob. The preamble is comprised of an optional |
| // user preamble byte and an always present varint. The varint encodes the |
| // number of bytes in the data chunk/blob. |
| // |
| // The ring buffer holds the most recent entries stored in the buffer. Once |
| // filled to capacity, incoming entries bump out the oldest entries to make |
| // room. Entries are internally wrapped around as needed. |
| class PrefixedEntryRingBuffer { |
| public: |
| typedef Status (*ReadOutput)(span<const std::byte>); |
| |
| PrefixedEntryRingBuffer(bool user_preamble = false) |
| : buffer_(nullptr), |
| buffer_bytes_(0), |
| write_idx_(0), |
| read_idx_(0), |
| entry_count_(0), |
| user_preamble_(user_preamble) {} |
| |
| // Set the raw buffer to be used by the ring buffer. |
| // |
| // Return values: |
| // OK - successfully set the raw buffer. |
| // INVALID_ARGUMENT - Argument was nullptr, size zero, or too large. |
| Status SetBuffer(span<std::byte> buffer); |
| |
| // Removes all data from the ring buffer. |
| void Clear(); |
| |
| // Write a chunk/blob of data to the ring buffer. If available space is less |
| // than size of data chunk to be written then silently pop and discard oldest |
| // stored data chunks until space is available. |
| // |
| // Preamble argument is a caller-provided value prepended to the front of the |
| // entry. It is only used if user_preamble was set at class construction |
| // time. |
| // |
| // Return values: |
| // OK - Data successfully written to the ring buffer. |
| // INVALID_ARGUMENT - Size of data to write is zero bytes |
| // FAILED_PRECONDITION - Buffer not initialized. |
| // OUT_OF_RANGE - Size of data is greater than buffer size. |
| Status PushBack(span<const std::byte> data, |
| std::byte user_preamble_data = std::byte(0)); |
| |
| // Read the oldest stored data chunk/blob of data from the ring buffer to |
| // the provided destination span. The number of bytes read is written to |
| // bytes_read |
| // |
| // Return values: |
| // OK - Data successfully read from the ring buffer. |
| // FAILED_PRECONDITION - Buffer not initialized. |
| // OUT_OF_RANGE - No entries in ring buffer to read. |
| // RESOURCE_EXHAUSTED - Destination data span was smaller number of bytes than |
| // the data size of the data chunk being read. Available destination bytes |
| // were filled, remaining bytes of the data chunk were ignored. |
| Status PeekFront(span<std::byte> data, size_t* bytes_read); |
| |
| Status PeekFront(ReadOutput output); |
| |
| // Same as Read but includes the entry's preamble of optional user value and |
| // the varint of the data size |
| Status PeekFrontWithPreamble(span<std::byte> data, size_t* bytes_read); |
| |
| Status PeekFrontWithPreamble(ReadOutput output); |
| |
| // Pop and discard the oldest stored data chunk/blob of data from the ring |
| // buffer. |
| // |
| // Return values: |
| // OK - Data successfully read from the ring buffer. |
| // FAILED_PRECONDITION - Buffer not initialized. |
| // OUT_OF_RANGE - No entries in ring buffer to pop. |
| Status PopFront(); |
| |
| // Dering the buffer by reordering entries internally in the buffer by |
| // rotating to have the oldest entry is at the lowest address/index with |
| // newest entry at the highest address. |
| // |
| // Return values: |
| // OK - Buffer data successfully deringed. |
| // FAILED_PRECONDITION - Buffer not initialized. |
| Status Dering(); |
| |
| // Get the number of variable-length entries currently in the ring buffer. |
| // |
| // Return value: |
| // Entry count. |
| size_t EntryCount() { return entry_count_; } |
| |
| // Get the size in bytes of all the current entries in the ring buffer, |
| // including preamble and data chunk/blob. |
| size_t TotalUsedBytes() { return buffer_bytes_ - RawAvailableBytes(); } |
| |
| // Get the size in bytes of the next data chunk/blob, not including |
| // preamble, to be read. |
| size_t FrontEntryDataSizeBytes(); |
| |
| // Get the size in bytes of the next entry, including preamble and data |
| // chunk/blob, to be read. |
| size_t FrontEntryTotalSizeBytes(); |
| |
| private: |
| struct EntryInfo { |
| size_t preamble_bytes; |
| size_t data_bytes; |
| }; |
| |
| // Internal version of Read used by all the public interface versions. T |
| // should be of type ReadOutput. |
| template <typename T> |
| Status InternalRead(T read_output, bool get_preamble); |
| |
| // Get info struct with the size of the preamble and data chunk/blob for the |
| // next entry to be read. |
| EntryInfo FrontEntryInfo(); |
| |
| // Get the raw number of available bytes free in the ring buffer. This is |
| // not available bytes for data, since there is a variable size preamble for |
| // each entry. |
| size_t RawAvailableBytes(); |
| |
| // Do the basic write of the specified number of bytes starting at the last |
| // write index of the ring buffer to the destination, handing any wrap-around |
| // of the ring buffer. This is basic, raw operation with no safety checks. |
| void RawWrite(span<const std::byte> source); |
| |
| // Do the basic read of the specified number of bytes starting at the given |
| // index of the ring buffer to the destination, handing any wrap-around of |
| // the ring buffer. This is basic, raw operation with no safety checks. |
| void RawRead(std::byte* destination, size_t source_idx, size_t length_bytes); |
| |
| size_t IncrementIndex(size_t index, size_t count); |
| |
| std::byte* buffer_; |
| size_t buffer_bytes_; |
| |
| size_t write_idx_; |
| size_t read_idx_; |
| size_t entry_count_; |
| const bool user_preamble_; |
| |
| // Worst case size for the variable-sized preable that is prepended to |
| // each entry. |
| static constexpr size_t kMaxEntryPreambleBytes = sizeof(size_t) + 1; |
| |
| // Maximum bufer size allowed. Restricted to this to allow index aliasing to |
| // not overflow. |
| static constexpr size_t kMaxBufferBytes = |
| std::numeric_limits<size_t>::max() / 2; |
| }; |
| |
| } // namespace ring_buffer |
| } // namespace pw |