Line data Source code
1 : /*
2 : * Copyright (c) 2021 Project CHIP Authors
3 : * All rights reserved.
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #pragma once
19 :
20 : #include <cstddef>
21 :
22 : #include <lib/core/CHIPError.h>
23 : #include <lib/support/CodeUtils.h>
24 : #include <lib/support/Span.h>
25 :
26 : namespace chip {
27 :
28 : /**
29 : * @brief A circular buffer to store byte sequences.
30 : *
31 : * This circular buffer provides a queue like interface to push/pop byte sequences
32 : * from the buffer. When there is no space to push a new byte sequence, the oldest
33 : * byte sequences will be discarded silently to free up space until there is enough
34 : * for the new byte sequence.
35 : */
36 : class BytesCircularBuffer
37 : {
38 : public:
39 : /**
40 : * @brief Create a byte sequence circular buffer.
41 : *
42 : * @param storage The underlying storage. This class doesn't take the ownership of the storage.
43 : * @param capacity The length of the storage.
44 : */
45 8 : BytesCircularBuffer(uint8_t * storage, size_t capacity) : mStorage(storage), mCapacity(capacity)
46 : {
47 8 : VerifyOrDie(mCapacity > sizeof(SizeType) + 1);
48 8 : }
49 :
50 : /**
51 : * @brief Push a byte sequence into the circular buffer. When there is no
52 : * space to push a new byte sequence, the oldest byte sequences will be
53 : * discarded silently to free up space until there is enough for the new
54 : * byte sequence.
55 : *
56 : * @returns CHIP_NO_ERROR if successful
57 : * CHIP_ERROR_INVALID_ARGUMENT if the payload is too large to fit into the buffer
58 : */
59 : CHIP_ERROR Push(const ByteSpan & payload);
60 :
61 : /// @brief Same as previous Push, but payload can be spread into 2 spans.
62 : CHIP_ERROR Push(const ByteSpan & payload1, const ByteSpan & payload2);
63 :
64 : /** @brief discard the oldest byte sequence in the buffer.
65 : *
66 : * @returns CHIP_NO_ERROR if successful
67 : * CHIP_ERROR_INCORRECT_STATE if the buffer is empty
68 : */
69 : CHIP_ERROR Pop();
70 :
71 : bool IsEmpty() const;
72 :
73 : /** @brief get the length of the front element. */
74 : size_t GetFrontSize() const;
75 :
76 : /** @brief read the front element into dest.
77 : *
78 : * @returns CHIP_NO_ERROR if successful
79 : * CHIP_ERROR_INCORRECT_STATE if the buffer is empty
80 : * CHIP_ERROR_INVALID_ARGUMENT if the length of dest is less than GetFrontSize */
81 : CHIP_ERROR ReadFront(MutableByteSpan & dest) const;
82 :
83 : private:
84 : void Read(uint8_t * dest, size_t length, size_t offset) const; // read length bytes into dest
85 : void Write(const uint8_t * source, size_t length);
86 : void Drop(size_t length);
87 : size_t StorageAvailable() const; // returns number of bytes available
88 : size_t StorageUsed() const; // returns number of bytes stored
89 :
90 : /** @brief advance dataLocation by amount, wrap around on mCapacity
91 : *
92 : * @pre amount must be less than mCapacity
93 : */
94 : size_t Advance(size_t dataLocation, size_t amount) const;
95 :
96 : // Internal storage. Arranged by packets with following structure:
97 : // | Size (2 bytes) | Byte sequence (size bytes) |
98 : uint8_t * const mStorage;
99 : const size_t mCapacity;
100 :
101 : using SizeType = uint16_t;
102 :
103 : // Both mDataStart and mDataEnd range from [0, mCapacity). mDataEnd is pointing past the last element.
104 : // When mDataStart == mDataEnd, the buffer is empty
105 : // When mDataStart < mDataEnd, the actual data is stored in [mDataStart, mDataEnd)
106 : // When mDataStart > mDataEnd, the actual data is stored in [mDataStart, mCapacity) ++ [0, mDataEnd)
107 : size_t mDataStart = 0;
108 : size_t mDataEnd = 0;
109 : };
110 :
111 : } // namespace chip
|