/* * Copyright (C) 2016 The Android Open Source Project * * 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 * * http://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. */ #ifndef MESSAGE_BUFFER_H_ #define MESSAGE_BUFFER_H_ #include <cstdint> #include <memory> #include <tuple> #include "android-base/macros.h" #include "wifilogd/local_utils.h" namespace android { namespace wifilogd { // A fixed-size buffer, which provides FIFO access to read and write // a sequence of messages. class MessageBuffer { public: // A wrapper which guarantees that a MessageBuffer will be rewound, // when the program exits the wrapper's scope. The user must ensure that // |buffer| does not expire before the ScopedRewinder. class ScopedRewinder { public: explicit ScopedRewinder(NONNULL MessageBuffer* buffer) : buffer_(buffer) {} ~ScopedRewinder() { buffer_->Rewind(); } private: MessageBuffer* const buffer_; }; // Constructs the buffer. |size| must be greater than GetHeaderSize(). explicit MessageBuffer(size_t size); // Appends a single message to the buffer. |data_len| must be >=1. Returns // true if the message was added to the buffer. bool Append(NONNULL const uint8_t* data, uint16_t data_len); // Returns true if the buffer is large enough to hold |length| bytes of user // data, when the buffer is empty. bool CanFitEver(uint16_t length) const; // Returns true if the buffer currently has enough free space to hold |length| // bytes of user data. bool CanFitNow(uint16_t length) const; // Clears the buffer. An immediately following read operation will return an // empty message. An immediately following write operation will write to the // head of the buffer. Clearing may be lazy (i.e., underlying storage is not // necessarily zeroed). void Clear(); // Returns the first unread message in the buffer. If there is no such // message, returns {nullptr, 0}. MessageBuffer retains ownership of the // message's storage. std::tuple<const uint8_t*, size_t> ConsumeNextMessage(); // Returns the size of MessageBuffer's per-message header. static constexpr size_t GetHeaderSize() { return sizeof(LengthHeader); } // Returns the total available free space in the buffer. This may be // larger than the usable space, due to overheads. size_t GetFreeSize() const { return capacity_ - write_pos_; } // Resets the read pointer to the start of the buffer. An immediately // following read will return the first message in the buffer. An immediately // following write, however, will be placed at the same position as if // Rewind() had not been called. void Rewind(); private: struct LengthHeader { uint16_t payload_len; }; // Prepares a header, and writes that header into the buffer. void AppendHeader(uint16_t message_len); // Writes arbitrary data into the buffer. void AppendRawBytes(NONNULL const void* data_start, size_t data_len); // Returns the total number of bytes available for reading. This number // includes headers. size_t GetReadableSize() const { return write_pos_ - read_pos_; } const std::unique_ptr<uint8_t[]> data_; const size_t capacity_; size_t read_pos_; size_t write_pos_; // MessageBuffer is a value type, so it would be semantically reasonable to // support copy and assign. Performance-wise, though, we should avoid // copies. Remove the copy constructor and the assignment operator, to // ensure that we don't accidentally make copies. DISALLOW_COPY_AND_ASSIGN(MessageBuffer); }; } // namespace wifilogd } // namespace android #endif // MESSAGE_BUFFER_H_