2 * Copyright 2016 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
23 #include <type_traits>
26 #include <folly/Bits.h>
27 #include <folly/io/IOBuf.h>
28 #include <folly/io/IOBufQueue.h>
29 #include <folly/Likely.h>
30 #include <folly/Memory.h>
31 #include <folly/Portability.h>
32 #include <folly/Range.h>
35 * Cursor class for fast iteration over IOBuf chains.
37 * Cursor - Read-only access
39 * RWPrivateCursor - Read-write access, assumes private access to IOBuf chain
40 * RWUnshareCursor - Read-write access, calls unshare on write (COW)
41 * Appender - Write access, assumes private access to IOBuf chian
43 * Note that RW cursors write in the preallocated part of buffers (that is,
44 * between the buffer's data() and tail()), while Appenders append to the end
45 * of the buffer (between the buffer's tail() and bufferEnd()). Appenders
46 * automatically adjust the buffer pointers, so you may only use one
47 * Appender with a buffer chain; for this reason, Appenders assume private
48 * access to the buffer (you need to call unshare() yourself if necessary).
50 namespace folly { namespace io {
54 template <class Derived, class BufType>
56 // Make all the templated classes friends for copy constructor.
57 template <class D, typename B> friend class CursorBase;
59 explicit CursorBase(BufType* buf) : crtBuf_(buf), buffer_(buf) { }
64 * This also allows constructing a CursorBase from other derived types.
65 * For instance, this allows constructing a Cursor from an RWPrivateCursor.
67 template <class OtherDerived, class OtherBuf>
68 explicit CursorBase(const CursorBase<OtherDerived, OtherBuf>& cursor)
69 : crtBuf_(cursor.crtBuf_),
70 offset_(cursor.offset_),
71 buffer_(cursor.buffer_) { }
74 * Reset cursor to point to a new buffer.
76 void reset(BufType* buf) {
82 const uint8_t* data() const {
83 return crtBuf_->data() + offset_;
87 * Return the remaining space available in the current IOBuf.
89 * May return 0 if the cursor is at the end of an IOBuf. Use peekBytes()
90 * instead if you want to avoid this. peekBytes() will advance to the next
91 * non-empty IOBuf (up to the end of the chain) if the cursor is currently
92 * pointing at the end of a buffer.
94 size_t length() const {
95 return crtBuf_->length() - offset_;
99 * Return the space available until the end of the entire IOBuf chain.
101 size_t totalLength() const {
102 if (crtBuf_ == buffer_) {
103 return crtBuf_->computeChainDataLength() - offset_;
105 CursorBase end(buffer_->prev());
106 end.offset_ = end.buffer_->length();
111 * Return true if the cursor could advance the specified number of bytes
112 * from its current position.
113 * This is useful for applications that want to do checked reads instead of
114 * catching exceptions and is more efficient than using totalLength as it
115 * walks the minimal set of buffers in the chain to determine the result.
117 bool canAdvance(size_t amount) const {
118 const IOBuf* nextBuf = crtBuf_;
119 size_t available = length();
121 if (available >= amount) {
125 nextBuf = nextBuf->next();
126 available = nextBuf->length();
127 } while (nextBuf != buffer_);
132 * Return true if the cursor is at the end of the entire IOBuf chain.
134 bool isAtEnd() const {
135 // Check for the simple cases first.
136 if (offset_ != crtBuf_->length()) {
139 if (crtBuf_ == buffer_->prev()) {
142 // We are at the end of a buffer, but it isn't the last buffer.
143 // We might still be at the end if the remaining buffers in the chain are
145 const IOBuf* buf = crtBuf_->next();;
146 while (buf != buffer_) {
147 if (buf->length() > 0) {
155 Derived& operator+=(size_t offset) {
156 Derived* p = static_cast<Derived*>(this);
160 Derived operator+(size_t offset) const {
161 Derived other(*this);
167 * Compare cursors for equality/inequality.
169 * Two cursors are equal if they are pointing to the same location in the
172 bool operator==(const Derived& other) const {
173 return (offset_ == other.offset_) && (crtBuf_ == other.crtBuf_);
175 bool operator!=(const Derived& other) const {
176 return !operator==(other);
180 typename std::enable_if<std::is_arithmetic<T>::value, T>::type read() {
182 if (LIKELY(length() >= sizeof(T))) {
183 val = loadUnaligned<T>(data());
184 offset_ += sizeof(T);
185 advanceBufferIfEmpty();
187 pullSlow(&val, sizeof(T));
194 return Endian::big(read<T>());
199 return Endian::little(read<T>());
203 * Read a fixed-length string.
205 * The std::string-based APIs should probably be avoided unless you
206 * ultimately want the data to live in an std::string. You're better off
207 * using the pull() APIs to copy into a raw buffer otherwise.
209 std::string readFixedString(size_t len) {
212 if (LIKELY(length() >= len)) {
213 str.append(reinterpret_cast<const char*>(data()), len);
215 advanceBufferIfEmpty();
217 readFixedStringSlow(&str, len);
223 * Read a string consisting of bytes until the given terminator character is
224 * seen. Raises an std::length_error if maxLength bytes have been processed
225 * before the terminator is seen.
227 * See comments in readFixedString() about when it's appropriate to use this
230 std::string readTerminatedString(
231 char termChar = '\0',
232 size_t maxLength = std::numeric_limits<size_t>::max()) {
236 const uint8_t* buf = data();
237 size_t buflen = length();
240 while (i < buflen && buf[i] != termChar) {
243 // Do this check after incrementing 'i', as even though we start at the
244 // 0 byte, it still represents a single character
245 if (str.length() + i >= maxLength) {
246 throw std::length_error("string overflow");
250 str.append(reinterpret_cast<const char*>(buf), i);
258 throw std::out_of_range("terminator not found");
261 size_t skipAtMost(size_t len) {
262 if (LIKELY(length() >= len)) {
264 advanceBufferIfEmpty();
267 return skipAtMostSlow(len);
270 void skip(size_t len) {
271 if (LIKELY(length() >= len)) {
273 advanceBufferIfEmpty();
279 size_t pullAtMost(void* buf, size_t len) {
280 // Fast path: it all fits in one buffer.
281 if (LIKELY(length() >= len)) {
282 memcpy(buf, data(), len);
284 advanceBufferIfEmpty();
287 return pullAtMostSlow(buf, len);
290 void pull(void* buf, size_t len) {
291 if (LIKELY(length() >= len)) {
292 memcpy(buf, data(), len);
294 advanceBufferIfEmpty();
301 * Return the available data in the current buffer.
302 * If you want to gather more data from the chain into a contiguous region
303 * (for hopefully zero-copy access), use gather() before peekBytes().
305 ByteRange peekBytes() {
306 // Ensure that we're pointing to valid data
307 size_t available = length();
308 while (UNLIKELY(available == 0 && tryAdvanceBuffer())) {
309 available = length();
311 return ByteRange{data(), available};
315 * Alternate version of peekBytes() that returns a std::pair
316 * instead of a ByteRange. (This method pre-dates ByteRange.)
318 * This function will eventually be deprecated.
320 std::pair<const uint8_t*, size_t> peek() {
321 auto bytes = peekBytes();
322 return std::make_pair(bytes.data(), bytes.size());
325 void clone(std::unique_ptr<folly::IOBuf>& buf, size_t len) {
326 if (UNLIKELY(cloneAtMost(buf, len) != len)) {
327 throw std::out_of_range("underflow");
331 void clone(folly::IOBuf& buf, size_t len) {
332 if (UNLIKELY(cloneAtMost(buf, len) != len)) {
333 throw std::out_of_range("underflow");
337 size_t cloneAtMost(folly::IOBuf& buf, size_t len) {
338 std::unique_ptr<folly::IOBuf> tmp;
340 for (int loopCount = 0; true; ++loopCount) {
341 // Fast path: it all fits in one buffer.
342 size_t available = length();
343 if (LIKELY(available >= len)) {
344 if (loopCount == 0) {
345 crtBuf_->cloneOneInto(buf);
346 buf.trimStart(offset_);
347 buf.trimEnd(buf.length() - len);
349 tmp = crtBuf_->cloneOne();
350 tmp->trimStart(offset_);
351 tmp->trimEnd(tmp->length() - len);
352 buf.prependChain(std::move(tmp));
356 advanceBufferIfEmpty();
360 if (loopCount == 0) {
361 crtBuf_->cloneOneInto(buf);
362 buf.trimStart(offset_);
364 tmp = crtBuf_->cloneOne();
365 tmp->trimStart(offset_);
366 buf.prependChain(std::move(tmp));
370 if (UNLIKELY(!tryAdvanceBuffer())) {
377 size_t cloneAtMost(std::unique_ptr<folly::IOBuf>& buf, size_t len) {
379 buf = make_unique<folly::IOBuf>();
381 return cloneAtMost(*buf, len);
385 * Return the distance between two cursors.
387 size_t operator-(const CursorBase& other) const {
388 BufType *otherBuf = other.crtBuf_;
391 if (otherBuf != crtBuf_) {
392 len += otherBuf->length() - other.offset_;
394 for (otherBuf = otherBuf->next();
395 otherBuf != crtBuf_ && otherBuf != other.buffer_;
396 otherBuf = otherBuf->next()) {
397 len += otherBuf->length();
400 if (otherBuf == other.buffer_) {
401 throw std::out_of_range("wrap-around");
406 if (offset_ < other.offset_) {
407 throw std::out_of_range("underflow");
410 len += offset_ - other.offset_;
417 * Return the distance from the given IOBuf to the this cursor.
419 size_t operator-(const BufType* buf) const {
422 BufType *curBuf = buf;
423 while (curBuf != crtBuf_) {
424 len += curBuf->length();
425 curBuf = curBuf->next();
426 if (curBuf == buf || curBuf == buffer_) {
427 throw std::out_of_range("wrap-around");
442 bool tryAdvanceBuffer() {
443 BufType* nextBuf = crtBuf_->next();
444 if (UNLIKELY(nextBuf == buffer_)) {
445 offset_ = crtBuf_->length();
451 static_cast<Derived*>(this)->advanceDone();
455 void advanceBufferIfEmpty() {
465 void readFixedStringSlow(std::string* str, size_t len) {
466 for (size_t available; (available = length()) < len; ) {
467 str->append(reinterpret_cast<const char*>(data()), available);
468 if (UNLIKELY(!tryAdvanceBuffer())) {
469 throw std::out_of_range("string underflow");
473 str->append(reinterpret_cast<const char*>(data()), len);
475 advanceBufferIfEmpty();
478 size_t pullAtMostSlow(void* buf, size_t len) {
479 uint8_t* p = reinterpret_cast<uint8_t*>(buf);
481 for (size_t available; (available = length()) < len; ) {
482 memcpy(p, data(), available);
484 if (UNLIKELY(!tryAdvanceBuffer())) {
490 memcpy(p, data(), len);
492 advanceBufferIfEmpty();
496 void pullSlow(void* buf, size_t len) {
497 if (UNLIKELY(pullAtMostSlow(buf, len) != len)) {
498 throw std::out_of_range("underflow");
502 size_t skipAtMostSlow(size_t len) {
504 for (size_t available; (available = length()) < len; ) {
505 skipped += available;
506 if (UNLIKELY(!tryAdvanceBuffer())) {
512 advanceBufferIfEmpty();
513 return skipped + len;
516 void skipSlow(size_t len) {
517 if (UNLIKELY(skipAtMostSlow(len) != len)) {
518 throw std::out_of_range("underflow");
528 } // namespace detail
530 class Cursor : public detail::CursorBase<Cursor, const IOBuf> {
532 explicit Cursor(const IOBuf* buf)
533 : detail::CursorBase<Cursor, const IOBuf>(buf) {}
535 template <class OtherDerived, class OtherBuf>
536 explicit Cursor(const detail::CursorBase<OtherDerived, OtherBuf>& cursor)
537 : detail::CursorBase<Cursor, const IOBuf>(cursor) {}
542 template <class Derived>
546 typename std::enable_if<std::is_arithmetic<T>::value>::type
548 const uint8_t* u8 = reinterpret_cast<const uint8_t*>(&value);
549 Derived* d = static_cast<Derived*>(this);
550 d->push(u8, sizeof(T));
554 void writeBE(T value) {
555 Derived* d = static_cast<Derived*>(this);
556 d->write(Endian::big(value));
560 void writeLE(T value) {
561 Derived* d = static_cast<Derived*>(this);
562 d->write(Endian::little(value));
565 void push(const uint8_t* buf, size_t len) {
566 Derived* d = static_cast<Derived*>(this);
567 if (d->pushAtMost(buf, len) != len) {
568 throw std::out_of_range("overflow");
572 void push(ByteRange buf) {
573 if (this->pushAtMost(buf) != buf.size()) {
574 throw std::out_of_range("overflow");
578 size_t pushAtMost(ByteRange buf) {
579 Derived* d = static_cast<Derived*>(this);
580 return d->pushAtMost(buf.data(), buf.size());
584 * push len bytes of data from input cursor, data could be in an IOBuf chain.
585 * If input cursor contains less than len bytes, or this cursor has less than
586 * len bytes writable space, an out_of_range exception will be thrown.
588 void push(Cursor cursor, size_t len) {
589 if (this->pushAtMost(cursor, len) != len) {
590 throw std::out_of_range("overflow");
594 size_t pushAtMost(Cursor cursor, size_t len) {
597 auto currentBuffer = cursor.peekBytes();
598 const uint8_t* crtData = currentBuffer.data();
599 size_t available = currentBuffer.size();
600 if (available == 0) {
601 // end of buffer chain
604 // all data is in current buffer
605 if (available >= len) {
606 this->push(crtData, len);
608 return written + len;
611 // write the whole current IOBuf
612 this->push(crtData, available);
613 cursor.skip(available);
614 written += available;
620 } // namespace detail
622 enum class CursorAccess {
627 template <CursorAccess access>
629 : public detail::CursorBase<RWCursor<access>, IOBuf>,
630 public detail::Writable<RWCursor<access>> {
631 friend class detail::CursorBase<RWCursor<access>, IOBuf>;
633 explicit RWCursor(IOBuf* buf)
634 : detail::CursorBase<RWCursor<access>, IOBuf>(buf),
635 maybeShared_(true) {}
637 template <class OtherDerived, class OtherBuf>
638 explicit RWCursor(const detail::CursorBase<OtherDerived, OtherBuf>& cursor)
639 : detail::CursorBase<RWCursor<access>, IOBuf>(cursor),
640 maybeShared_(true) {}
642 * Gather at least n bytes contiguously into the current buffer,
643 * by coalescing subsequent buffers from the chain as necessary.
645 void gather(size_t n) {
646 // Forbid attempts to gather beyond the end of this IOBuf chain.
647 // Otherwise we could try to coalesce the head of the chain and end up
648 // accidentally freeing it, invalidating the pointer owned by external
651 // If crtBuf_ == head() then IOBuf::gather() will perform all necessary
652 // checking. We only have to perform an explicit check here when calling
653 // gather() on a non-head element.
654 if (this->crtBuf_ != this->head() && this->totalLength() < n) {
655 throw std::overflow_error("cannot gather() past the end of the chain");
657 this->crtBuf_->gather(this->offset_ + n);
659 void gatherAtMost(size_t n) {
660 size_t size = std::min(n, this->totalLength());
661 return this->crtBuf_->gather(this->offset_ + size);
664 using detail::Writable<RWCursor<access>>::pushAtMost;
665 size_t pushAtMost(const uint8_t* buf, size_t len) {
668 // Fast path: the current buffer is big enough.
669 size_t available = this->length();
670 if (LIKELY(available >= len)) {
671 if (access == CursorAccess::UNSHARE) {
674 memcpy(writableData(), buf, len);
675 this->offset_ += len;
679 if (access == CursorAccess::UNSHARE) {
682 memcpy(writableData(), buf, available);
684 if (UNLIKELY(!this->tryAdvanceBuffer())) {
692 void insert(std::unique_ptr<folly::IOBuf> buf) {
693 folly::IOBuf* nextBuf;
694 if (this->offset_ == 0) {
696 nextBuf = this->crtBuf_;
697 this->crtBuf_->prependChain(std::move(buf));
699 std::unique_ptr<folly::IOBuf> remaining;
700 if (this->crtBuf_->length() - this->offset_ > 0) {
701 // Need to split current IOBuf in two.
702 remaining = this->crtBuf_->cloneOne();
703 remaining->trimStart(this->offset_);
704 nextBuf = remaining.get();
705 buf->prependChain(std::move(remaining));
708 nextBuf = this->crtBuf_->next();
710 this->crtBuf_->trimEnd(this->length());
711 this->crtBuf_->appendChain(std::move(buf));
713 // Jump past the new links
715 this->crtBuf_ = nextBuf;
718 uint8_t* writableData() {
719 return this->crtBuf_->writableData() + this->offset_;
723 void maybeUnshare() {
724 if (UNLIKELY(maybeShared_)) {
725 this->crtBuf_->unshareOne();
726 maybeShared_ = false;
737 typedef RWCursor<CursorAccess::PRIVATE> RWPrivateCursor;
738 typedef RWCursor<CursorAccess::UNSHARE> RWUnshareCursor;
741 * Append to the end of a buffer chain, growing the chain (by allocating new
742 * buffers) in increments of at least growth bytes every time. Won't grow
743 * (and push() and ensure() will throw) if growth == 0.
745 * TODO(tudorb): add a flavor of Appender that reallocates one IOBuf instead
748 class Appender : public detail::Writable<Appender> {
750 Appender(IOBuf* buf, uint64_t growth)
752 crtBuf_(buf->prev()),
756 uint8_t* writableData() {
757 return crtBuf_->writableTail();
760 size_t length() const {
761 return crtBuf_->tailroom();
765 * Mark n bytes (must be <= length()) as appended, as per the
766 * IOBuf::append() method.
768 void append(size_t n) {
773 * Ensure at least n contiguous bytes available to write.
774 * Postcondition: length() >= n.
776 void ensure(uint64_t n) {
777 if (LIKELY(length() >= n)) {
781 // Waste the rest of the current buffer and allocate a new one.
782 // Don't make it too small, either.
784 throw std::out_of_range("can't grow buffer chain");
787 n = std::max(n, growth_);
788 buffer_->prependChain(IOBuf::create(n));
789 crtBuf_ = buffer_->prev();
792 using detail::Writable<Appender>::pushAtMost;
793 size_t pushAtMost(const uint8_t* buf, size_t len) {
796 // Fast path: it all fits in one buffer.
797 size_t available = length();
798 if (LIKELY(available >= len)) {
799 memcpy(writableData(), buf, len);
804 memcpy(writableData(), buf, available);
807 if (UNLIKELY(!tryGrowChain())) {
816 * Append to the end of this buffer, using a printf() style
819 * Note that folly/Format.h provides nicer and more type-safe mechanisms
820 * for formatting strings, which should generally be preferred over
821 * printf-style formatting. Appender objects can be used directly as an
822 * output argument for Formatter objects. For example:
824 * Appender app(&iobuf);
825 * format("{} {}", "hello", "world")(app);
827 * However, printf-style strings are still needed when dealing with existing
828 * third-party code in some cases.
830 * This will always add a nul-terminating character after the end
831 * of the output. However, the buffer data length will only be updated to
832 * include the data itself. The nul terminator will be the first byte in the
835 * This method may throw exceptions on error.
837 void printf(FOLLY_PRINTF_FORMAT const char* fmt, ...)
838 FOLLY_PRINTF_FORMAT_ATTR(2, 3);
840 void vprintf(const char* fmt, va_list ap);
843 * Calling an Appender object with a StringPiece will append the string
844 * piece. This allows Appender objects to be used directly with
847 void operator()(StringPiece sp) {
852 bool tryGrowChain() {
853 assert(crtBuf_->next() == buffer_);
858 buffer_->prependChain(IOBuf::create(growth_));
859 crtBuf_ = buffer_->prev();
868 class QueueAppender : public detail::Writable<QueueAppender> {
871 * Create an Appender that writes to a IOBufQueue. When we allocate
872 * space in the queue, we grow no more than growth bytes at once
873 * (unless you call ensure() with a bigger value yourself).
875 QueueAppender(IOBufQueue* queue, uint64_t growth) {
876 reset(queue, growth);
879 void reset(IOBufQueue* queue, uint64_t growth) {
884 uint8_t* writableData() {
885 return static_cast<uint8_t*>(queue_->writableTail());
888 size_t length() const { return queue_->tailroom(); }
890 void append(size_t n) { queue_->postallocate(n); }
892 // Ensure at least n contiguous; can go above growth_, throws if
894 void ensure(uint64_t n) { queue_->preallocate(n, growth_); }
897 typename std::enable_if<std::is_arithmetic<T>::value>::type
900 auto p = queue_->preallocate(sizeof(T), growth_);
901 storeUnaligned(p.first, value);
902 queue_->postallocate(sizeof(T));
905 using detail::Writable<QueueAppender>::pushAtMost;
906 size_t pushAtMost(const uint8_t* buf, size_t len) {
907 size_t remaining = len;
908 while (remaining != 0) {
909 auto p = queue_->preallocate(std::min(remaining, growth_),
912 memcpy(p.first, buf, p.second);
913 queue_->postallocate(p.second);
915 remaining -= p.second;
921 void insert(std::unique_ptr<folly::IOBuf> buf) {
923 queue_->append(std::move(buf), true);
927 void insert(const folly::IOBuf& buf) {
932 folly::IOBufQueue* queue_;