int Buffer::pushBytes(const uint8_t* bytes, int cnt) { if (writeAvailable() < cnt) cnt = writeAvailable(); memcpy(_tail, bytes, cnt); _tail += cnt; return cnt; }
std::vector<iovec> Buffer::writeBuffers(size_t length) { if (length == (size_t)~0) length = writeAvailable(); reserve(length); std::vector<iovec> result; result.reserve(m_segments.size()); size_t remaining = length; std::list<Segment>::iterator it = m_writeIt; while (remaining > 0) { Segment& segment = *it; size_t toProduce = (std::min)(segment.writeAvailable(), remaining); SegmentData data = segment.writeBuffer().slice(0, toProduce); #ifdef WINDOWS while (data.length() > 0) { iovec wsabuf; wsabuf.iov_base = (void *)data.start(); wsabuf.iov_len = iovLength(data.length()); result.push_back(wsabuf); data = data.slice(wsabuf.iov_len); } #else iovec iov; iov.iov_base = (void *)data.start(); iov.iov_len = data.length(); result.push_back(iov); #endif remaining -= toProduce; ++it; } MORDOR_ASSERT(remaining == 0); invariant(); return result; }
void Buffer::Segment::produce(size_t length) { MORDOR_ASSERT(length <= writeAvailable()); m_writeIndex += length; invariant(); }
int Buffer::pushBytesFromStream(std::basic_istream<char>& istr, int cnt) { if (writeAvailable() < cnt) cnt = writeAvailable(); istr.read((char*)_tail, cnt); if (istr.eof()) { cnt = istr.gcount(); } else if (istr.fail()) { return -1; } _tail += cnt; return cnt; }
iovec Buffer::writeBuffer(size_t length, bool coalesce) { iovec result; result.iov_base = NULL; result.iov_len = 0; if (length == 0u) return result; // Must allocate just the write segment if (writeAvailable() == 0) { reserve(length); MORDOR_ASSERT(m_writeIt != m_segments.end()); MORDOR_ASSERT(m_writeIt->writeAvailable() >= length); SegmentData data = m_writeIt->writeBuffer().slice(0, length); result.iov_base = data.start(); result.iov_len = iovLength(data.length()); return result; } // Can use an existing write segment if (writeAvailable() > 0 && m_writeIt->writeAvailable() >= length) { SegmentData data = m_writeIt->writeBuffer().slice(0, length); result.iov_base = data.start(); result.iov_len = iovLength(data.length()); return result; } // If they don't want us to coalesce, just return as much as we can from // the first segment if (!coalesce) { SegmentData data = m_writeIt->writeBuffer(); result.iov_base = data.start(); result.iov_len = iovLength(data.length()); return result; } // Existing bufs are insufficient... remove them and reserve anew compact(); reserve(length); MORDOR_ASSERT(m_writeIt != m_segments.end()); MORDOR_ASSERT(m_writeIt->writeAvailable() >= length); SegmentData data = m_writeIt->writeBuffer().slice(0, length); result.iov_base = data.start(); result.iov_len = iovLength(data.length()); return result; }
void Buffer::reserve(size_t length) { if (writeAvailable() < length) { // over-reserve to avoid fragmentation Segment newSegment(length * 2 - writeAvailable()); if (readAvailable() == 0) { // put the new buffer at the front if possible to avoid // fragmentation m_segments.push_front(newSegment); m_writeIt = m_segments.begin(); } else { m_segments.push_back(newSegment); if (m_writeAvailable == 0) { m_writeIt = m_segments.end(); --m_writeIt; } } m_writeAvailable += newSegment.length(); invariant(); } }
void Buffer::compact() { invariant(); if (m_writeIt != m_segments.end()) { if (m_writeIt->readAvailable() > 0) { Segment newSegment = Segment(m_writeIt->readBuffer()); m_segments.insert(m_writeIt, newSegment); } m_writeIt = m_segments.erase(m_writeIt, m_segments.end()); m_writeAvailable = 0; } MORDOR_ASSERT(writeAvailable() == 0); }
void Buffer::produce(size_t length) { MORDOR_ASSERT(length <= writeAvailable()); m_readAvailable += length; m_writeAvailable -= length; while (length > 0) { Segment &segment = *m_writeIt; size_t toProduce = (std::min)(segment.writeAvailable(), length); segment.produce(toProduce); length -= toProduce; if (segment.writeAvailable() == 0) ++m_writeIt; } MORDOR_ASSERT(length == 0); invariant(); }