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/Likely.h>
28 #include <folly/Memory.h>
29 #include <folly/Portability.h>
30 #include <folly/Range.h>
31 #include <folly/io/IOBuf.h>
32 #include <folly/io/IOBufQueue.h>
33 #include <folly/portability/BitsFunctexcept.h>
36 * Cursor class for fast iteration over IOBuf chains.
38 * Cursor - Read-only access
40 * RWPrivateCursor - Read-write access, assumes private access to IOBuf chain
41 * RWUnshareCursor - Read-write access, calls unshare on write (COW)
42 * Appender - Write access, assumes private access to IOBuf chian
44 * Note that RW cursors write in the preallocated part of buffers (that is,
45 * between the buffer's data() and tail()), while Appenders append to the end
46 * of the buffer (between the buffer's tail() and bufferEnd()). Appenders
47 * automatically adjust the buffer pointers, so you may only use one
48 * Appender with a buffer chain; for this reason, Appenders assume private
49 * access to the buffer (you need to call unshare() yourself if necessary).
51 namespace folly { namespace io {
55 template <class Derived, class BufType>
57 // Make all the templated classes friends for copy constructor.
58 template <class D, typename B> friend class CursorBase;
60 explicit CursorBase(BufType* buf) : crtBuf_(buf), buffer_(buf) { }
65 * This also allows constructing a CursorBase from other derived types.
66 * For instance, this allows constructing a Cursor from an RWPrivateCursor.
68 template <class OtherDerived, class OtherBuf>
69 explicit CursorBase(const CursorBase<OtherDerived, OtherBuf>& cursor)
70 : crtBuf_(cursor.crtBuf_),
71 offset_(cursor.offset_),
72 buffer_(cursor.buffer_) { }
75 * Reset cursor to point to a new buffer.
77 void reset(BufType* buf) {
83 const uint8_t* data() const {
84 return crtBuf_->data() + offset_;
88 * Return the remaining space available in the current IOBuf.
90 * May return 0 if the cursor is at the end of an IOBuf. Use peekBytes()
91 * instead if you want to avoid this. peekBytes() will advance to the next
92 * non-empty IOBuf (up to the end of the chain) if the cursor is currently
93 * pointing at the end of a buffer.
95 size_t length() const {
96 return crtBuf_->length() - offset_;
100 * Return the space available until the end of the entire IOBuf chain.
102 size_t totalLength() const {
103 if (crtBuf_ == buffer_) {
104 return crtBuf_->computeChainDataLength() - offset_;
106 CursorBase end(buffer_->prev());
107 end.offset_ = end.buffer_->length();
112 * Return true if the cursor could advance the specified number of bytes
113 * from its current position.
114 * This is useful for applications that want to do checked reads instead of
115 * catching exceptions and is more efficient than using totalLength as it
116 * walks the minimal set of buffers in the chain to determine the result.
118 bool canAdvance(size_t amount) const {
119 const IOBuf* nextBuf = crtBuf_;
120 size_t available = length();
122 if (available >= amount) {
126 nextBuf = nextBuf->next();
127 available = nextBuf->length();
128 } while (nextBuf != buffer_);
133 * Return true if the cursor is at the end of the entire IOBuf chain.
135 bool isAtEnd() const {
136 // Check for the simple cases first.
137 if (offset_ != crtBuf_->length()) {
140 if (crtBuf_ == buffer_->prev()) {
143 // We are at the end of a buffer, but it isn't the last buffer.
144 // We might still be at the end if the remaining buffers in the chain are
146 const IOBuf* buf = crtBuf_->next();;
147 while (buf != buffer_) {
148 if (buf->length() > 0) {
156 Derived& operator+=(size_t offset) {
157 Derived* p = static_cast<Derived*>(this);
161 Derived operator+(size_t offset) const {
162 Derived other(*this);
168 * Compare cursors for equality/inequality.
170 * Two cursors are equal if they are pointing to the same location in the
173 bool operator==(const Derived& other) const {
174 return (offset_ == other.offset_) && (crtBuf_ == other.crtBuf_);
176 bool operator!=(const Derived& other) const {
177 return !operator==(other);
181 typename std::enable_if<std::is_arithmetic<T>::value, T>::type read() {
183 if (LIKELY(length() >= sizeof(T))) {
184 val = loadUnaligned<T>(data());
185 offset_ += sizeof(T);
186 advanceBufferIfEmpty();
188 pullSlow(&val, sizeof(T));
195 return Endian::big(read<T>());
200 return Endian::little(read<T>());
204 * Read a fixed-length string.
206 * The std::string-based APIs should probably be avoided unless you
207 * ultimately want the data to live in an std::string. You're better off
208 * using the pull() APIs to copy into a raw buffer otherwise.
210 std::string readFixedString(size_t len) {
213 if (LIKELY(length() >= len)) {
214 str.append(reinterpret_cast<const char*>(data()), len);
216 advanceBufferIfEmpty();
218 readFixedStringSlow(&str, len);
224 * Read a string consisting of bytes until the given terminator character is
225 * seen. Raises an std::length_error if maxLength bytes have been processed
226 * before the terminator is seen.
228 * See comments in readFixedString() about when it's appropriate to use this
231 std::string readTerminatedString(
232 char termChar = '\0',
233 size_t maxLength = std::numeric_limits<size_t>::max());
236 * Read all bytes until the specified predicate returns true.
238 * The predicate will be called on each byte in turn, until it returns false
239 * or until the end of the IOBuf chain is reached.
241 * Returns the result as a string.
243 template <typename Predicate>
244 std::string readWhile(const Predicate& predicate);
247 * Read all bytes until the specified predicate returns true.
249 * This is a more generic version of readWhile() takes an arbitrary Output
250 * object, and calls Output::append() with each chunk of matching data.
252 template <typename Predicate, typename Output>
253 void readWhile(const Predicate& predicate, Output& out);
256 * Skip all bytes until the specified predicate returns true.
258 * The predicate will be called on each byte in turn, until it returns false
259 * or until the end of the IOBuf chain is reached.
261 template <typename Predicate>
262 void skipWhile(const Predicate& predicate);
264 size_t skipAtMost(size_t len) {
265 if (LIKELY(length() >= len)) {
267 advanceBufferIfEmpty();
270 return skipAtMostSlow(len);
273 void skip(size_t len) {
274 if (LIKELY(length() >= len)) {
276 advanceBufferIfEmpty();
282 size_t pullAtMost(void* buf, size_t len) {
283 // Fast path: it all fits in one buffer.
284 if (LIKELY(length() >= len)) {
285 memcpy(buf, data(), len);
287 advanceBufferIfEmpty();
290 return pullAtMostSlow(buf, len);
293 void pull(void* buf, size_t len) {
294 if (LIKELY(length() >= len)) {
295 memcpy(buf, data(), len);
297 advanceBufferIfEmpty();
304 * Return the available data in the current buffer.
305 * If you want to gather more data from the chain into a contiguous region
306 * (for hopefully zero-copy access), use gather() before peekBytes().
308 ByteRange peekBytes() {
309 // Ensure that we're pointing to valid data
310 size_t available = length();
311 while (UNLIKELY(available == 0 && tryAdvanceBuffer())) {
312 available = length();
314 return ByteRange{data(), available};
318 * Alternate version of peekBytes() that returns a std::pair
319 * instead of a ByteRange. (This method pre-dates ByteRange.)
321 * This function will eventually be deprecated.
323 std::pair<const uint8_t*, size_t> peek() {
324 auto bytes = peekBytes();
325 return std::make_pair(bytes.data(), bytes.size());
328 void clone(std::unique_ptr<folly::IOBuf>& buf, size_t len) {
329 if (UNLIKELY(cloneAtMost(buf, len) != len)) {
330 std::__throw_out_of_range("underflow");
334 void clone(folly::IOBuf& buf, size_t len) {
335 if (UNLIKELY(cloneAtMost(buf, len) != len)) {
336 std::__throw_out_of_range("underflow");
340 size_t cloneAtMost(folly::IOBuf& buf, size_t len) {
341 std::unique_ptr<folly::IOBuf> tmp;
343 for (int loopCount = 0; true; ++loopCount) {
344 // Fast path: it all fits in one buffer.
345 size_t available = length();
346 if (LIKELY(available >= len)) {
347 if (loopCount == 0) {
348 crtBuf_->cloneOneInto(buf);
349 buf.trimStart(offset_);
350 buf.trimEnd(buf.length() - len);
352 tmp = crtBuf_->cloneOne();
353 tmp->trimStart(offset_);
354 tmp->trimEnd(tmp->length() - len);
355 buf.prependChain(std::move(tmp));
359 advanceBufferIfEmpty();
363 if (loopCount == 0) {
364 crtBuf_->cloneOneInto(buf);
365 buf.trimStart(offset_);
367 tmp = crtBuf_->cloneOne();
368 tmp->trimStart(offset_);
369 buf.prependChain(std::move(tmp));
373 if (UNLIKELY(!tryAdvanceBuffer())) {
380 size_t cloneAtMost(std::unique_ptr<folly::IOBuf>& buf, size_t len) {
382 buf = make_unique<folly::IOBuf>();
384 return cloneAtMost(*buf, len);
388 * Return the distance between two cursors.
390 size_t operator-(const CursorBase& other) const {
391 BufType *otherBuf = other.crtBuf_;
394 if (otherBuf != crtBuf_) {
395 len += otherBuf->length() - other.offset_;
397 for (otherBuf = otherBuf->next();
398 otherBuf != crtBuf_ && otherBuf != other.buffer_;
399 otherBuf = otherBuf->next()) {
400 len += otherBuf->length();
403 if (otherBuf == other.buffer_) {
404 std::__throw_out_of_range("wrap-around");
409 if (offset_ < other.offset_) {
410 std::__throw_out_of_range("underflow");
413 len += offset_ - other.offset_;
420 * Return the distance from the given IOBuf to the this cursor.
422 size_t operator-(const BufType* buf) const {
425 const BufType* curBuf = buf;
426 while (curBuf != crtBuf_) {
427 len += curBuf->length();
428 curBuf = curBuf->next();
429 if (curBuf == buf || curBuf == buffer_) {
430 std::__throw_out_of_range("wrap-around");
445 bool tryAdvanceBuffer() {
446 BufType* nextBuf = crtBuf_->next();
447 if (UNLIKELY(nextBuf == buffer_)) {
448 offset_ = crtBuf_->length();
454 static_cast<Derived*>(this)->advanceDone();
458 void advanceBufferIfEmpty() {
468 void readFixedStringSlow(std::string* str, size_t len) {
469 for (size_t available; (available = length()) < len; ) {
470 str->append(reinterpret_cast<const char*>(data()), available);
471 if (UNLIKELY(!tryAdvanceBuffer())) {
472 std::__throw_out_of_range("string underflow");
476 str->append(reinterpret_cast<const char*>(data()), len);
478 advanceBufferIfEmpty();
481 size_t pullAtMostSlow(void* buf, size_t len) {
482 uint8_t* p = reinterpret_cast<uint8_t*>(buf);
484 for (size_t available; (available = length()) < len; ) {
485 memcpy(p, data(), available);
487 if (UNLIKELY(!tryAdvanceBuffer())) {
493 memcpy(p, data(), len);
495 advanceBufferIfEmpty();
499 void pullSlow(void* buf, size_t len) {
500 if (UNLIKELY(pullAtMostSlow(buf, len) != len)) {
501 std::__throw_out_of_range("underflow");
505 size_t skipAtMostSlow(size_t len) {
507 for (size_t available; (available = length()) < len; ) {
508 skipped += available;
509 if (UNLIKELY(!tryAdvanceBuffer())) {
515 advanceBufferIfEmpty();
516 return skipped + len;
519 void skipSlow(size_t len) {
520 if (UNLIKELY(skipAtMostSlow(len) != len)) {
521 std::__throw_out_of_range("underflow");
531 } // namespace detail
533 class Cursor : public detail::CursorBase<Cursor, const IOBuf> {
535 explicit Cursor(const IOBuf* buf)
536 : detail::CursorBase<Cursor, const IOBuf>(buf) {}
538 template <class OtherDerived, class OtherBuf>
539 explicit Cursor(const detail::CursorBase<OtherDerived, OtherBuf>& cursor)
540 : detail::CursorBase<Cursor, const IOBuf>(cursor) {}
545 template <class Derived>
549 typename std::enable_if<std::is_arithmetic<T>::value>::type
551 const uint8_t* u8 = reinterpret_cast<const uint8_t*>(&value);
552 Derived* d = static_cast<Derived*>(this);
553 d->push(u8, sizeof(T));
557 void writeBE(T value) {
558 Derived* d = static_cast<Derived*>(this);
559 d->write(Endian::big(value));
563 void writeLE(T value) {
564 Derived* d = static_cast<Derived*>(this);
565 d->write(Endian::little(value));
568 void push(const uint8_t* buf, size_t len) {
569 Derived* d = static_cast<Derived*>(this);
570 if (d->pushAtMost(buf, len) != len) {
571 std::__throw_out_of_range("overflow");
575 void push(ByteRange buf) {
576 if (this->pushAtMost(buf) != buf.size()) {
577 std::__throw_out_of_range("overflow");
581 size_t pushAtMost(ByteRange buf) {
582 Derived* d = static_cast<Derived*>(this);
583 return d->pushAtMost(buf.data(), buf.size());
587 * push len bytes of data from input cursor, data could be in an IOBuf chain.
588 * If input cursor contains less than len bytes, or this cursor has less than
589 * len bytes writable space, an out_of_range exception will be thrown.
591 void push(Cursor cursor, size_t len) {
592 if (this->pushAtMost(cursor, len) != len) {
593 std::__throw_out_of_range("overflow");
597 size_t pushAtMost(Cursor cursor, size_t len) {
600 auto currentBuffer = cursor.peekBytes();
601 const uint8_t* crtData = currentBuffer.data();
602 size_t available = currentBuffer.size();
603 if (available == 0) {
604 // end of buffer chain
607 // all data is in current buffer
608 if (available >= len) {
609 this->push(crtData, len);
611 return written + len;
614 // write the whole current IOBuf
615 this->push(crtData, available);
616 cursor.skip(available);
617 written += available;
623 } // namespace detail
625 enum class CursorAccess {
630 template <CursorAccess access>
632 : public detail::CursorBase<RWCursor<access>, IOBuf>,
633 public detail::Writable<RWCursor<access>> {
634 friend class detail::CursorBase<RWCursor<access>, IOBuf>;
636 explicit RWCursor(IOBuf* buf)
637 : detail::CursorBase<RWCursor<access>, IOBuf>(buf),
638 maybeShared_(true) {}
640 template <class OtherDerived, class OtherBuf>
641 explicit RWCursor(const detail::CursorBase<OtherDerived, OtherBuf>& cursor)
642 : detail::CursorBase<RWCursor<access>, IOBuf>(cursor),
643 maybeShared_(true) {}
645 * Gather at least n bytes contiguously into the current buffer,
646 * by coalescing subsequent buffers from the chain as necessary.
648 void gather(size_t n) {
649 // Forbid attempts to gather beyond the end of this IOBuf chain.
650 // Otherwise we could try to coalesce the head of the chain and end up
651 // accidentally freeing it, invalidating the pointer owned by external
654 // If crtBuf_ == head() then IOBuf::gather() will perform all necessary
655 // checking. We only have to perform an explicit check here when calling
656 // gather() on a non-head element.
657 if (this->crtBuf_ != this->head() && this->totalLength() < n) {
658 throw std::overflow_error("cannot gather() past the end of the chain");
660 this->crtBuf_->gather(this->offset_ + n);
662 void gatherAtMost(size_t n) {
663 size_t size = std::min(n, this->totalLength());
664 return this->crtBuf_->gather(this->offset_ + size);
667 using detail::Writable<RWCursor<access>>::pushAtMost;
668 size_t pushAtMost(const uint8_t* buf, size_t len) {
671 // Fast path: the current buffer is big enough.
672 size_t available = this->length();
673 if (LIKELY(available >= len)) {
674 if (access == CursorAccess::UNSHARE) {
677 memcpy(writableData(), buf, len);
678 this->offset_ += len;
682 if (access == CursorAccess::UNSHARE) {
685 memcpy(writableData(), buf, available);
687 if (UNLIKELY(!this->tryAdvanceBuffer())) {
695 void insert(std::unique_ptr<folly::IOBuf> buf) {
696 folly::IOBuf* nextBuf;
697 if (this->offset_ == 0) {
699 nextBuf = this->crtBuf_;
700 this->crtBuf_->prependChain(std::move(buf));
702 std::unique_ptr<folly::IOBuf> remaining;
703 if (this->crtBuf_->length() - this->offset_ > 0) {
704 // Need to split current IOBuf in two.
705 remaining = this->crtBuf_->cloneOne();
706 remaining->trimStart(this->offset_);
707 nextBuf = remaining.get();
708 buf->prependChain(std::move(remaining));
711 nextBuf = this->crtBuf_->next();
713 this->crtBuf_->trimEnd(this->length());
714 this->crtBuf_->appendChain(std::move(buf));
716 // Jump past the new links
718 this->crtBuf_ = nextBuf;
721 uint8_t* writableData() {
722 return this->crtBuf_->writableData() + this->offset_;
726 void maybeUnshare() {
727 if (UNLIKELY(maybeShared_)) {
728 this->crtBuf_->unshareOne();
729 maybeShared_ = false;
740 typedef RWCursor<CursorAccess::PRIVATE> RWPrivateCursor;
741 typedef RWCursor<CursorAccess::UNSHARE> RWUnshareCursor;
744 * Append to the end of a buffer chain, growing the chain (by allocating new
745 * buffers) in increments of at least growth bytes every time. Won't grow
746 * (and push() and ensure() will throw) if growth == 0.
748 * TODO(tudorb): add a flavor of Appender that reallocates one IOBuf instead
751 class Appender : public detail::Writable<Appender> {
753 Appender(IOBuf* buf, uint64_t growth)
755 crtBuf_(buf->prev()),
759 uint8_t* writableData() {
760 return crtBuf_->writableTail();
763 size_t length() const {
764 return crtBuf_->tailroom();
768 * Mark n bytes (must be <= length()) as appended, as per the
769 * IOBuf::append() method.
771 void append(size_t n) {
776 * Ensure at least n contiguous bytes available to write.
777 * Postcondition: length() >= n.
779 void ensure(uint64_t n) {
780 if (LIKELY(length() >= n)) {
784 // Waste the rest of the current buffer and allocate a new one.
785 // Don't make it too small, either.
787 std::__throw_out_of_range("can't grow buffer chain");
790 n = std::max(n, growth_);
791 buffer_->prependChain(IOBuf::create(n));
792 crtBuf_ = buffer_->prev();
795 using detail::Writable<Appender>::pushAtMost;
796 size_t pushAtMost(const uint8_t* buf, size_t len) {
799 // Fast path: it all fits in one buffer.
800 size_t available = length();
801 if (LIKELY(available >= len)) {
802 memcpy(writableData(), buf, len);
807 memcpy(writableData(), buf, available);
810 if (UNLIKELY(!tryGrowChain())) {
819 * Append to the end of this buffer, using a printf() style
822 * Note that folly/Format.h provides nicer and more type-safe mechanisms
823 * for formatting strings, which should generally be preferred over
824 * printf-style formatting. Appender objects can be used directly as an
825 * output argument for Formatter objects. For example:
827 * Appender app(&iobuf);
828 * format("{} {}", "hello", "world")(app);
830 * However, printf-style strings are still needed when dealing with existing
831 * third-party code in some cases.
833 * This will always add a nul-terminating character after the end
834 * of the output. However, the buffer data length will only be updated to
835 * include the data itself. The nul terminator will be the first byte in the
838 * This method may throw exceptions on error.
840 void printf(FOLLY_PRINTF_FORMAT const char* fmt, ...)
841 FOLLY_PRINTF_FORMAT_ATTR(2, 3);
843 void vprintf(const char* fmt, va_list ap);
846 * Calling an Appender object with a StringPiece will append the string
847 * piece. This allows Appender objects to be used directly with
850 void operator()(StringPiece sp) {
855 bool tryGrowChain() {
856 assert(crtBuf_->next() == buffer_);
861 buffer_->prependChain(IOBuf::create(growth_));
862 crtBuf_ = buffer_->prev();
871 class QueueAppender : public detail::Writable<QueueAppender> {
874 * Create an Appender that writes to a IOBufQueue. When we allocate
875 * space in the queue, we grow no more than growth bytes at once
876 * (unless you call ensure() with a bigger value yourself).
878 QueueAppender(IOBufQueue* queue, uint64_t growth) {
879 reset(queue, growth);
882 void reset(IOBufQueue* queue, uint64_t growth) {
887 uint8_t* writableData() {
888 return static_cast<uint8_t*>(queue_->writableTail());
891 size_t length() const { return queue_->tailroom(); }
893 void append(size_t n) { queue_->postallocate(n); }
895 // Ensure at least n contiguous; can go above growth_, throws if
897 void ensure(uint64_t n) { queue_->preallocate(n, growth_); }
900 typename std::enable_if<std::is_arithmetic<T>::value>::type
903 auto p = queue_->preallocate(sizeof(T), growth_);
904 storeUnaligned(p.first, value);
905 queue_->postallocate(sizeof(T));
908 using detail::Writable<QueueAppender>::pushAtMost;
909 size_t pushAtMost(const uint8_t* buf, size_t len) {
910 size_t remaining = len;
911 while (remaining != 0) {
912 auto p = queue_->preallocate(std::min(remaining, growth_),
915 memcpy(p.first, buf, p.second);
916 queue_->postallocate(p.second);
918 remaining -= p.second;
924 void insert(std::unique_ptr<folly::IOBuf> buf) {
926 queue_->append(std::move(buf), true);
930 void insert(const folly::IOBuf& buf) {
935 folly::IOBufQueue* queue_;
941 #include <folly/io/Cursor-inl.h>