//------------------------------------------------------------------------------ /* This file is part of rippled: https://github.com/ripple/rippled Copyright (c) 2012, 2013 Ripple Labs Inc. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== #ifndef RIPPLE_OVERLAY_ZEROCOPYSTREAM_H_INCLUDED #define RIPPLE_OVERLAY_ZEROCOPYSTREAM_H_INCLUDED #include #include #include namespace ripple { /** Implements ZeroCopyInputStream around a buffer sequence. @tparam Buffers A type meeting the requirements of ConstBufferSequence. @see https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.io.zero_copy_stream */ template class ZeroCopyInputStream : public ::google::protobuf::io::ZeroCopyInputStream { private: using iterator = typename Buffers::const_iterator; using const_buffer = boost::asio::const_buffer; std::int64_t count_ = 0; iterator last_; iterator first_; // Where pos_ comes from const_buffer pos_; // What Next() will return public: explicit ZeroCopyInputStream (Buffers const& buffers); bool Next (const void** data, int* size) override; void BackUp (int count) override; bool Skip (int count) override; std::int64_t ByteCount() const override { return count_; } }; //------------------------------------------------------------------------------ template ZeroCopyInputStream::ZeroCopyInputStream ( Buffers const& buffers) : last_ (buffers.end()) , first_ (buffers.begin()) , pos_ ((first_ != last_) ? *first_ : const_buffer(nullptr, 0)) { } template bool ZeroCopyInputStream::Next ( const void** data, int* size) { *data = boost::asio::buffer_cast(pos_); *size = boost::asio::buffer_size(pos_); if (first_ == last_) return false; count_ += *size; pos_ = (++first_ != last_) ? *first_ : const_buffer(nullptr, 0); return true; } template void ZeroCopyInputStream::BackUp (int count) { --first_; pos_ = *first_ + (boost::asio::buffer_size(*first_) - count); count_ -= count; } template bool ZeroCopyInputStream::Skip (int count) { if (first_ == last_) return false; while (count > 0) { auto const size = boost::asio::buffer_size(pos_); if (count < size) { pos_ = pos_ + count; count_ += count; return true; } count_ += size; if (++first_ == last_) return false; count -= size; pos_ = *first_; } return true; } //------------------------------------------------------------------------------ /** Implements ZeroCopyOutputStream around a Streambuf. Streambuf matches the public interface defined by boost::asio::streambuf. @tparam Streambuf A type meeting the requirements of Streambuf. */ template class ZeroCopyOutputStream : public ::google::protobuf::io::ZeroCopyOutputStream { private: using buffers_type = typename Streambuf::mutable_buffers_type; using iterator = typename buffers_type::const_iterator; using mutable_buffer = boost::asio::mutable_buffer; Streambuf& streambuf_; std::size_t blockSize_; std::size_t count_ = 0; std::size_t commit_ = 0; buffers_type buffers_; iterator pos_; public: explicit ZeroCopyOutputStream (Streambuf& streambuf, std::size_t blockSize); bool Next (void** data, int* size) override; void BackUp (int count) override; std::int64_t ByteCount() const override { return count_; } }; //------------------------------------------------------------------------------ template ZeroCopyOutputStream::ZeroCopyOutputStream( Streambuf& streambuf, std::size_t blockSize) : streambuf_ (streambuf) , blockSize_ (blockSize) , buffers_ (streambuf_.prepare(blockSize_)) , pos_ (buffers_.begin()) { } template bool ZeroCopyOutputStream::Next( void** data, int* size) { if (commit_ != 0) { streambuf_.commit(commit_); count_ += commit_; } if (pos_ == buffers_.end()) { buffers_ = streambuf_.prepare (blockSize_); pos_ = buffers_.begin(); } *data = boost::asio::buffer_cast(*pos_); *size = boost::asio::buffer_size(*pos_); commit_ = *size; ++pos_; return true; } template void ZeroCopyOutputStream::BackUp (int count) { assert(count <= commit_); auto const n = commit_ - count; streambuf_.commit(n); count_ += n; commit_ = 0; } } // ripple #endif