123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492 |
- /*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.
- */
- #ifndef avro_Buffer_hh__
- #define avro_Buffer_hh__
- #ifndef _WIN32
- #include <sys/uio.h>
- #endif
- #include <utility>
- #include <vector>
- #include "../Config.hh"
- #include "detail/BufferDetail.hh"
- #include "detail/BufferDetailIterator.hh"
- /**
- * \file Buffer.hh
- *
- * \brief Definitions for InputBuffer and OutputBuffer classes
- *
- **/
- namespace avro {
- class OutputBuffer;
- class InputBuffer;
- /**
- * The OutputBuffer (write-only buffer)
- *
- * Use cases for OutputBuffer
- *
- * - write message to buffer using ostream class or directly
- * - append messages to headers
- * - building up streams of messages via append
- * - converting to read-only buffers for sending
- * - extracting parts of the messages into read-only buffers
- *
- * -# ASIO access:
- * - write to a buffer(s) by asio using iterator
- * - convert to read buffer for deserializing
- *
- * OutputBuffer is assignable and copy-constructable. On copy or assignment,
- * only a pointer is copied, so the two resulting copies are identical, so
- * modifying one will modify both.
- **/
- class AVRO_DECL OutputBuffer {
- public:
- typedef detail::size_type size_type;
- typedef detail::data_type data_type;
- /**
- * The asio library expects a const_iterator (the const-ness refers to the
- * fact that the underlying avro of buffers will not be modified, even
- * though the data in those buffers is being modified). The iterator
- * provides the list of addresses an operation can write to.
- **/
- typedef detail::OutputBufferIterator const_iterator;
- /**
- * Default constructor. Will pre-allocate at least the requested size, but
- * can grow larger on demand.
- *
- * Destructor uses the default, which resets a shared pointer, deleting the
- * underlying data if no other copies of exist.
- *
- * Copy and assignment operators are not explicitly provided because the
- * default ones work fine. The default makes only a shallow copy, so the
- * copies will refer to the same memory. This is required by asio
- * functions, which will implicitly make copies for asynchronous
- * operations. Therefore, the user must be careful that if they create
- * multiple copies of the same OutputBuffer, only one is being modified
- * otherwise undefined behavior may occur.
- *
- **/
- explicit OutputBuffer(size_type reserveSize = 0) : pimpl_(new detail::BufferImpl) {
- if (reserveSize) {
- reserve(reserveSize);
- }
- }
- /**
- * Reserve enough space for a wroteTo() operation. When using writeTo(),
- * the buffer will grow dynamically as needed. But when using the iterator
- * to write (followed by wroteTo()), data may only be written to the space
- * available, so this ensures there is enough room in the buffer before
- * the write operation.
- **/
- void reserve(size_type reserveSize) {
- pimpl_->reserveFreeSpace(reserveSize);
- }
- /**
- * Write a block of data to the buffer. The buffer size will automatically
- * grow if the size is larger than what is currently free.
- **/
- size_type writeTo(const data_type *data, size_type size) {
- return pimpl_->writeTo(data, size);
- }
- /**
- * Write a single value to the buffer. The buffer size will automatically
- * grow if there is not room for the byte. The value must be a
- * "fundamental" type, e.g. int, float, etc. (otherwise use the other
- * writeTo tests).
- **/
- template<typename T>
- void writeTo(T val) {
- pimpl_->writeTo(val, std::is_fundamental<T>());
- }
- /**
- * Update the state of the buffer after writing through the iterator
- * interface. This function exists primarily for the boost:asio which
- * writes directly to the buffer using its iterator. In this case, the
- * internal state of the buffer does not reflect that the data was written
- * This informs the buffer how much data was written.
- *
- * The buffer does not automatically resize in this case, the bytes written
- * cannot exceed the amount of free space. Attempting to write more will
- * throw a std::length_error exception.
- **/
- size_type wroteTo(size_type size) {
- size_type wrote = 0;
- if (size) {
- if (size > freeSpace()) {
- throw std::length_error("Impossible to write more data than free space");
- }
- wrote = pimpl_->wroteTo(size);
- }
- return wrote;
- }
- /**
- * Does the buffer have any data?
- **/
- bool empty() const {
- return (pimpl_->size() == 0);
- }
- /**
- * Returns the size of the buffer, in bytes.
- */
- size_type size() const {
- return pimpl_->size();
- }
- /**
- * Returns the current free space that is available to write to in the
- * buffer, in bytes. This is not a strict limit in size, as writeTo() can
- * automatically increase capacity if necessary.
- **/
- size_type freeSpace() const {
- return pimpl_->freeSpace();
- }
- /**
- * Appends the data in the argument to the end of this buffer. The
- * argument can be either an InputBuffer or OutputBuffer.
- *
- **/
- template<class BufferType>
- void append(const BufferType &buf) {
- // don't append an empty buffer
- if (buf.size()) {
- pimpl_->append(*(buf.pimpl_.get()));
- }
- }
- /**
- * Return an iterator pointing to the first data chunk of this buffer
- * that may be written to.
- **/
- const_iterator begin() const {
- return const_iterator(pimpl_->beginWrite());
- }
- /**
- * Return the end iterator for writing.
- **/
- const_iterator end() const {
- return const_iterator(pimpl_->endWrite());
- }
- /**
- * Discard any data in this buffer.
- **/
- void discardData() {
- pimpl_->discardData();
- }
- /**
- * Discard the specified number of bytes from this data, starting at the beginning.
- * Throws if the size is greater than the number of bytes.
- **/
- void discardData(size_t bytes) {
- if (bytes > 0) {
- if (bytes < pimpl_->size()) {
- pimpl_->discardData(bytes);
- } else if (bytes == pimpl_->size()) {
- pimpl_->discardData();
- } else {
- throw std::out_of_range("trying to discard more data than exists");
- }
- }
- }
- /**
- * Remove bytes from this buffer, starting from the beginning, and place
- * them into a new buffer. Throws if the number of requested bytes exceeds
- * the size of the buffer. Data and freeSpace in the buffer after bytes
- * remains in this buffer.
- **/
- InputBuffer extractData(size_type bytes);
- /**
- * Remove all bytes from this buffer, returning them in a new buffer.
- * After removing data, some freeSpace may remain in this buffer.
- **/
- InputBuffer extractData();
- /**
- * Clone this buffer, creating a copy that contains the same data.
- **/
- OutputBuffer clone() const {
- detail::BufferImpl::SharedPtr newImpl(new detail::BufferImpl(*pimpl_));
- return OutputBuffer(newImpl);
- }
- /**
- * Add unmanaged data to the buffer. The buffer will not automatically
- * free the data, but it will call the supplied function when the data is
- * no longer referenced by the buffer (or copies of the buffer).
- **/
- void appendForeignData(const data_type *data, size_type size, const detail::free_func &func) {
- pimpl_->appendForeignData(data, size, func);
- }
- /**
- * Returns the number of chunks that contain free space.
- **/
- int numChunks() const {
- return pimpl_->numFreeChunks();
- }
- /**
- * Returns the number of chunks that contain data
- **/
- int numDataChunks() const {
- return pimpl_->numDataChunks();
- }
- private:
- friend class InputBuffer;
- friend class BufferReader;
- explicit OutputBuffer(detail::BufferImpl::SharedPtr pimpl) : pimpl_(std::move(pimpl)) {}
- detail::BufferImpl::SharedPtr pimpl_; ///< Must never be null.
- };
- /**
- * The InputBuffer (read-only buffer)
- *
- * InputBuffer is an immutable buffer which that may be constructed from an
- * OutputBuffer, or several of OutputBuffer's methods. Once the data is
- * transfered to an InputBuffer it cannot be modified, only read (via
- * BufferReader, istream, or its iterator).
- *
- * Assignments and copies are shallow copies.
- *
- * -# ASIO access: - iterate using const_iterator for sending messages
- *
- **/
- class AVRO_DECL InputBuffer {
- public:
- typedef detail::size_type size_type;
- typedef detail::data_type data_type;
- // needed for asio
- typedef detail::InputBufferIterator const_iterator;
- /**
- * Default InputBuffer creates an empty buffer.
- *
- * Copy/assignment functions use the default ones. They will do a shallow
- * copy, and because InputBuffer is immutable, the copies will be
- * identical.
- *
- * Destructor also uses the default, which resets a shared pointer,
- * deleting the underlying data if no other copies of exist.
- **/
- InputBuffer() : pimpl_(new detail::BufferImpl) {}
- /**
- * Construct an InputBuffer that contains the contents of an OutputBuffer.
- * The two buffers will have the same contents, but this copy will be
- * immutable, while the the OutputBuffer may still be written to.
- *
- * If you wish to move the data from the OutputBuffer to a new InputBuffer
- * (leaving only free space in the OutputBuffer),
- * OutputBuffer::extractData() will do this more efficiently.
- *
- * Implicit conversion is allowed.
- **/
- // NOLINTNEXTLINE(google-explicit-constructor)
- InputBuffer(const OutputBuffer &src) : pimpl_(new detail::BufferImpl(*src.pimpl_)) {}
- /**
- * Does the buffer have any data?
- **/
- bool empty() const {
- return (pimpl_->size() == 0);
- }
- /**
- * Returns the size of the buffer, in bytes.
- **/
- size_type size() const {
- return pimpl_->size();
- }
- /**
- * Return an iterator pointing to the first data chunk of this buffer
- * that contains data.
- **/
- const_iterator begin() const {
- return const_iterator(pimpl_->beginRead());
- }
- /**
- * Return the end iterator.
- **/
- const_iterator end() const {
- return const_iterator(pimpl_->endRead());
- }
- /**
- * Returns the number of chunks containing data.
- **/
- int numChunks() const {
- return pimpl_->numDataChunks();
- }
- private:
- friend class OutputBuffer; // for append function
- friend class istreambuf;
- friend class BufferReader;
- explicit InputBuffer(const detail::BufferImpl::SharedPtr &pimpl) : pimpl_(pimpl) {}
- /**
- * Class to indicate that a copy of a OutputBuffer to InputBuffer should be
- * a shallow copy, used to enable reading of the contents of an
- * OutputBuffer without need to convert it to InputBuffer using a deep
- * copy. It is private and only used by BufferReader and istreambuf
- * classes.
- *
- * Writing to an OutputBuffer while it is being read may lead to undefined
- * behavior.
- **/
- class ShallowCopy {};
- /**
- * Make a shallow copy of an OutputBuffer in order to read it without
- * causing conversion overhead.
- **/
- InputBuffer(const OutputBuffer &src, const ShallowCopy &) : pimpl_(src.pimpl_) {}
- /**
- * Make a shallow copy of an InputBuffer. The default copy constructor
- * already provides shallow copy, this is just provided for generic
- * algorithms that wish to treat InputBuffer and OutputBuffer in the same
- * manner.
- **/
- InputBuffer(const InputBuffer &src, const ShallowCopy &) : pimpl_(src.pimpl_) {}
- detail::BufferImpl::ConstSharedPtr pimpl_; ///< Must never be null.
- };
- /*
- * Implementations of some OutputBuffer functions are inlined here
- * because InputBuffer definition was required before.
- */
- inline InputBuffer OutputBuffer::extractData() {
- detail::BufferImpl::SharedPtr newImpl(new detail::BufferImpl);
- if (pimpl_->size()) {
- pimpl_->extractData(*newImpl);
- }
- return InputBuffer(newImpl);
- }
- inline InputBuffer OutputBuffer::extractData(size_type bytes) {
- if (bytes > pimpl_->size()) {
- throw std::out_of_range("trying to extract more data than exists");
- }
- detail::BufferImpl::SharedPtr newImpl(new detail::BufferImpl);
- if (bytes > 0) {
- if (bytes < pimpl_->size()) {
- pimpl_->extractData(*newImpl, bytes);
- } else {
- pimpl_->extractData(*newImpl);
- }
- }
- return InputBuffer(newImpl);
- }
- #ifndef _WIN32
- /**
- * Create an array of iovec structures from the buffer. This utility is used
- * to support writev and readv function calls. The caller should ensure the
- * buffer object is not deleted while using the iovec vector.
- *
- * If the BufferType is an InputBuffer, the iovec will point to the data that
- * already exists in the buffer, for reading.
- *
- * If the BufferType is an OutputBuffer, the iovec will point to the free
- * space, which may be written to. Before writing, the caller should call
- * OutputBuffer::reserve() to create enough room for the desired write (which
- * can be verified by calling OutputBuffer::freeSpace()), and after writing,
- * they MUST call OutputBuffer::wroteTo(), otherwise the buffer will not know
- * the space is not free anymore.
- *
- **/
- template<class BufferType>
- inline void toIovec(BufferType &buf, std::vector<struct iovec> &iov) {
- const int chunks = buf.numChunks();
- iov.resize(chunks);
- typename BufferType::const_iterator iter = buf.begin();
- for (int i = 0; i < chunks; ++i) {
- iov[i].iov_base = const_cast<typename BufferType::data_type *>(iter->data());
- iov[i].iov_len = iter->size();
- ++iter;
- }
- }
- #endif
- } // namespace avro
- #endif
|