2 * Copyright 2014 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.
17 #ifndef FOLLY_CURSOR_H
18 #define FOLLY_CURSOR_H
24 #include <type_traits>
27 #include <folly/Bits.h>
28 #include <folly/io/IOBuf.h>
29 #include <folly/io/IOBufQueue.h>
30 #include <folly/Likely.h>
31 #include <folly/Memory.h>
32 #include <folly/Portability.h>
33 #include <folly/Range.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 {
54 template <class Derived, typename BufType>
57 const uint8_t* data() const {
58 return crtBuf_->data() + offset_;
62 * Return the remaining space available in the current IOBuf.
64 * May return 0 if the cursor is at the end of an IOBuf. Use peek() instead
65 * if you want to avoid this. peek() will advance to the next non-empty
66 * IOBuf (up to the end of the chain) if the cursor is currently pointing at
67 * the end of a buffer.
69 size_t length() const {
70 return crtBuf_->length() - offset_;
74 * Return the space available until the end of the entire IOBuf chain.
76 size_t totalLength() const {
77 if (crtBuf_ == buffer_) {
78 return crtBuf_->computeChainDataLength() - offset_;
80 CursorBase end(buffer_->prev());
81 end.offset_ = end.buffer_->length();
85 Derived& operator+=(size_t offset) {
86 Derived* p = static_cast<Derived*>(this);
90 Derived operator+(size_t offset) const {
97 * Compare cursors for equality/inequality.
99 * Two cursors are equal if they are pointing to the same location in the
102 bool operator==(const Derived& other) const {
103 return (offset_ == other.offset_) && (crtBuf_ == other.crtBuf_);
105 bool operator!=(const Derived& other) const {
106 return !operator==(other);
110 typename std::enable_if<std::is_arithmetic<T>::value, T>::type
113 pull(&val, sizeof(T));
119 return Endian::big(read<T>());
124 return Endian::little(read<T>());
128 * Read a fixed-length string.
130 * The std::string-based APIs should probably be avoided unless you
131 * ultimately want the data to live in an std::string. You're better off
132 * using the pull() APIs to copy into a raw buffer otherwise.
134 std::string readFixedString(size_t len) {
139 // Fast path: it all fits in one buffer.
140 size_t available = length();
141 if (LIKELY(available >= len)) {
142 str.append(reinterpret_cast<const char*>(data()), len);
147 str.append(reinterpret_cast<const char*>(data()), available);
148 if (UNLIKELY(!tryAdvanceBuffer())) {
149 throw std::out_of_range("string underflow");
156 * Read a string consisting of bytes until the given terminator character is
157 * seen. Raises an std::length_error if maxLength bytes have been processed
158 * before the terminator is seen.
160 * See comments in readFixedString() about when it's appropriate to use this
163 std::string readTerminatedString(
164 char termChar = '\0',
165 size_t maxLength = std::numeric_limits<size_t>::max()) {
169 const uint8_t* buf = data();
170 size_t buflen = length();
173 while (i < buflen && buf[i] != termChar) {
176 // Do this check after incrementing 'i', as even though we start at the
177 // 0 byte, it still represents a single character
178 if (str.length() + i >= maxLength) {
179 throw std::length_error("string overflow");
183 str.append(reinterpret_cast<const char*>(buf), i);
191 if (UNLIKELY(!tryAdvanceBuffer())) {
192 throw std::out_of_range("string underflow");
197 explicit CursorBase(BufType* buf)
202 // Make all the templated classes friends for copy constructor.
203 template <class D, typename B> friend class CursorBase;
208 * This also allows constructing a CursorBase from other derived types.
209 * For instance, this allows constructing a Cursor from an RWPrivateCursor.
211 template <class OtherDerived, class OtherBuf>
212 explicit CursorBase(const CursorBase<OtherDerived, OtherBuf>& cursor)
213 : crtBuf_(cursor.crtBuf_),
214 offset_(cursor.offset_),
215 buffer_(cursor.buffer_) {}
217 // reset cursor to point to a new buffer.
218 void reset(BufType* buf) {
225 * Return the available data in the current buffer.
226 * If you want to gather more data from the chain into a contiguous region
227 * (for hopefully zero-copy access), use gather() before peek().
229 std::pair<const uint8_t*, size_t> peek() {
230 // Ensure that we're pointing to valid data
231 size_t available = length();
232 while (UNLIKELY(available == 0 && tryAdvanceBuffer())) {
233 available = length();
236 return std::make_pair(data(), available);
240 * Read one byte. Equivalent to pull(&byte, 1) but faster.
244 if (LIKELY(length() >= 1)) {
245 uint8_t byte = *data();
252 if (UNLIKELY(pullAtMost(&byte, 1) != 1)) {
253 throw std::out_of_range("underflow");
258 void pull(void* buf, size_t len) {
259 if (UNLIKELY(pullAtMost(buf, len) != len)) {
260 throw std::out_of_range("underflow");
264 void clone(std::unique_ptr<folly::IOBuf>& buf, size_t len) {
265 if (UNLIKELY(cloneAtMost(buf, len) != len)) {
266 throw std::out_of_range("underflow");
270 void clone(folly::IOBuf& buf, size_t len) {
271 if (UNLIKELY(cloneAtMost(buf, len) != len)) {
272 throw std::out_of_range("underflow");
276 void skip(size_t len) {
277 if (UNLIKELY(skipAtMost(len) != len)) {
278 throw std::out_of_range("underflow");
282 size_t pullAtMost(void* buf, size_t len) {
283 uint8_t* p = reinterpret_cast<uint8_t*>(buf);
286 // Fast path: it all fits in one buffer.
287 size_t available = length();
288 if (LIKELY(available >= len)) {
289 memcpy(p, data(), len);
294 memcpy(p, data(), available);
296 if (UNLIKELY(!tryAdvanceBuffer())) {
304 size_t cloneAtMost(folly::IOBuf& buf, size_t len) {
305 buf = folly::IOBuf();
307 std::unique_ptr<folly::IOBuf> tmp;
309 for (int loopCount = 0; true; ++loopCount) {
310 // Fast path: it all fits in one buffer.
311 size_t available = length();
312 if (LIKELY(available >= len)) {
313 if (loopCount == 0) {
314 crtBuf_->cloneOneInto(buf);
315 buf.trimStart(offset_);
316 buf.trimEnd(buf.length() - len);
318 tmp = crtBuf_->cloneOne();
319 tmp->trimStart(offset_);
320 tmp->trimEnd(tmp->length() - len);
321 buf.prependChain(std::move(tmp));
329 if (loopCount == 0) {
330 crtBuf_->cloneOneInto(buf);
331 buf.trimStart(offset_);
333 tmp = crtBuf_->cloneOne();
334 tmp->trimStart(offset_);
335 buf.prependChain(std::move(tmp));
339 if (UNLIKELY(!tryAdvanceBuffer())) {
346 size_t cloneAtMost(std::unique_ptr<folly::IOBuf>& buf, size_t len) {
348 buf = make_unique<folly::IOBuf>();
351 return cloneAtMost(*buf, len);
354 size_t skipAtMost(size_t len) {
357 // Fast path: it all fits in one buffer.
358 size_t available = length();
359 if (LIKELY(available >= len)) {
361 return skipped + len;
364 skipped += available;
365 if (UNLIKELY(!tryAdvanceBuffer())) {
373 * Return the distance between two cursors.
375 size_t operator-(const CursorBase& other) const {
376 BufType *otherBuf = other.crtBuf_;
379 if (otherBuf != crtBuf_) {
380 len += otherBuf->length() - other.offset_;
382 for (otherBuf = otherBuf->next();
383 otherBuf != crtBuf_ && otherBuf != other.buffer_;
384 otherBuf = otherBuf->next()) {
385 len += otherBuf->length();
388 if (otherBuf == other.buffer_) {
389 throw std::out_of_range("wrap-around");
394 if (offset_ < other.offset_) {
395 throw std::out_of_range("underflow");
398 len += offset_ - other.offset_;
405 * Return the distance from the given IOBuf to the this cursor.
407 size_t operator-(const BufType* buf) const {
410 BufType *curBuf = buf;
411 while (curBuf != crtBuf_) {
412 len += curBuf->length();
413 curBuf = curBuf->next();
414 if (curBuf == buf || curBuf == buffer_) {
415 throw std::out_of_range("wrap-around");
433 bool tryAdvanceBuffer() {
434 BufType* nextBuf = crtBuf_->next();
435 if (UNLIKELY(nextBuf == buffer_)) {
436 offset_ = crtBuf_->length();
442 static_cast<Derived*>(this)->advanceDone();
455 class Cursor : public detail::CursorBase<Cursor, const IOBuf> {
457 explicit Cursor(const IOBuf* buf)
458 : detail::CursorBase<Cursor, const IOBuf>(buf) {}
460 template <class OtherDerived, class OtherBuf>
461 explicit Cursor(const detail::CursorBase<OtherDerived, OtherBuf>& cursor)
462 : detail::CursorBase<Cursor, const IOBuf>(cursor) {}
467 template <class Derived>
471 typename std::enable_if<std::is_arithmetic<T>::value>::type
473 const uint8_t* u8 = reinterpret_cast<const uint8_t*>(&value);
474 Derived* d = static_cast<Derived*>(this);
475 d->push(u8, sizeof(T));
479 void writeBE(T value) {
480 Derived* d = static_cast<Derived*>(this);
481 d->write(Endian::big(value));
485 void writeLE(T value) {
486 Derived* d = static_cast<Derived*>(this);
487 d->write(Endian::little(value));
490 void push(const uint8_t* buf, size_t len) {
491 Derived* d = static_cast<Derived*>(this);
492 if (d->pushAtMost(buf, len) != len) {
493 throw std::out_of_range("overflow");
497 void push(ByteRange buf) {
498 if (this->pushAtMost(buf) != buf.size()) {
499 throw std::out_of_range("overflow");
503 size_t pushAtMost(ByteRange buf) {
504 Derived* d = static_cast<Derived*>(this);
505 return d->pushAtMost(buf.data(), buf.size());
509 * push len bytes of data from input cursor, data could be in an IOBuf chain.
510 * If input cursor contains less than len bytes, or this cursor has less than
511 * len bytes writable space, an out_of_range exception will be thrown.
513 void push(Cursor cursor, size_t len) {
514 if (this->pushAtMost(cursor, len) != len) {
515 throw std::out_of_range("overflow");
519 size_t pushAtMost(Cursor cursor, size_t len) {
522 auto currentBuffer = cursor.peek();
523 const uint8_t* crtData = currentBuffer.first;
524 size_t available = currentBuffer.second;
525 if (available == 0) {
526 // end of buffer chain
529 // all data is in current buffer
530 if (available >= len) {
531 this->push(crtData, len);
533 return written + len;
536 // write the whole current IOBuf
537 this->push(crtData, available);
538 cursor.skip(available);
539 written += available;
545 } // namespace detail
547 enum class CursorAccess {
552 template <CursorAccess access>
554 : public detail::CursorBase<RWCursor<access>, IOBuf>,
555 public detail::Writable<RWCursor<access>> {
556 friend class detail::CursorBase<RWCursor<access>, IOBuf>;
558 explicit RWCursor(IOBuf* buf)
559 : detail::CursorBase<RWCursor<access>, IOBuf>(buf),
560 maybeShared_(true) {}
562 template <class OtherDerived, class OtherBuf>
563 explicit RWCursor(const detail::CursorBase<OtherDerived, OtherBuf>& cursor)
564 : detail::CursorBase<RWCursor<access>, IOBuf>(cursor),
565 maybeShared_(true) {}
567 * Gather at least n bytes contiguously into the current buffer,
568 * by coalescing subsequent buffers from the chain as necessary.
570 void gather(size_t n) {
571 // Forbid attempts to gather beyond the end of this IOBuf chain.
572 // Otherwise we could try to coalesce the head of the chain and end up
573 // accidentally freeing it, invalidating the pointer owned by external
576 // If crtBuf_ == head() then IOBuf::gather() will perform all necessary
577 // checking. We only have to perform an explicit check here when calling
578 // gather() on a non-head element.
579 if (this->crtBuf_ != this->head() && this->totalLength() < n) {
580 throw std::overflow_error("cannot gather() past the end of the chain");
582 this->crtBuf_->gather(this->offset_ + n);
584 void gatherAtMost(size_t n) {
585 size_t size = std::min(n, this->totalLength());
586 return this->crtBuf_->gather(this->offset_ + size);
589 using detail::Writable<RWCursor<access>>::pushAtMost;
590 size_t pushAtMost(const uint8_t* buf, size_t len) {
593 // Fast path: the current buffer is big enough.
594 size_t available = this->length();
595 if (LIKELY(available >= len)) {
596 if (access == CursorAccess::UNSHARE) {
599 memcpy(writableData(), buf, len);
600 this->offset_ += len;
604 if (access == CursorAccess::UNSHARE) {
607 memcpy(writableData(), buf, available);
609 if (UNLIKELY(!this->tryAdvanceBuffer())) {
617 void insert(std::unique_ptr<folly::IOBuf> buf) {
618 folly::IOBuf* nextBuf;
619 if (this->offset_ == 0) {
621 nextBuf = this->crtBuf_;
622 this->crtBuf_->prependChain(std::move(buf));
624 std::unique_ptr<folly::IOBuf> remaining;
625 if (this->crtBuf_->length() - this->offset_ > 0) {
626 // Need to split current IOBuf in two.
627 remaining = this->crtBuf_->cloneOne();
628 remaining->trimStart(this->offset_);
629 nextBuf = remaining.get();
630 buf->prependChain(std::move(remaining));
633 nextBuf = this->crtBuf_->next();
635 this->crtBuf_->trimEnd(this->length());
636 this->crtBuf_->appendChain(std::move(buf));
638 // Jump past the new links
640 this->crtBuf_ = nextBuf;
643 uint8_t* writableData() {
644 return this->crtBuf_->writableData() + this->offset_;
648 void maybeUnshare() {
649 if (UNLIKELY(maybeShared_)) {
650 this->crtBuf_->unshareOne();
651 maybeShared_ = false;
662 typedef RWCursor<CursorAccess::PRIVATE> RWPrivateCursor;
663 typedef RWCursor<CursorAccess::UNSHARE> RWUnshareCursor;
666 * Append to the end of a buffer chain, growing the chain (by allocating new
667 * buffers) in increments of at least growth bytes every time. Won't grow
668 * (and push() and ensure() will throw) if growth == 0.
670 * TODO(tudorb): add a flavor of Appender that reallocates one IOBuf instead
673 class Appender : public detail::Writable<Appender> {
675 Appender(IOBuf* buf, uint64_t growth)
677 crtBuf_(buf->prev()),
681 uint8_t* writableData() {
682 return crtBuf_->writableTail();
685 size_t length() const {
686 return crtBuf_->tailroom();
690 * Mark n bytes (must be <= length()) as appended, as per the
691 * IOBuf::append() method.
693 void append(size_t n) {
698 * Ensure at least n contiguous bytes available to write.
699 * Postcondition: length() >= n.
701 void ensure(uint64_t n) {
702 if (LIKELY(length() >= n)) {
706 // Waste the rest of the current buffer and allocate a new one.
707 // Don't make it too small, either.
709 throw std::out_of_range("can't grow buffer chain");
712 n = std::max(n, growth_);
713 buffer_->prependChain(IOBuf::create(n));
714 crtBuf_ = buffer_->prev();
717 using detail::Writable<Appender>::pushAtMost;
718 size_t pushAtMost(const uint8_t* buf, size_t len) {
721 // Fast path: it all fits in one buffer.
722 size_t available = length();
723 if (LIKELY(available >= len)) {
724 memcpy(writableData(), buf, len);
729 memcpy(writableData(), buf, available);
732 if (UNLIKELY(!tryGrowChain())) {
741 * Append to the end of this buffer, using a printf() style
744 * Note that folly/Format.h provides nicer and more type-safe mechanisms
745 * for formatting strings, which should generally be preferred over
746 * printf-style formatting. Appender objects can be used directly as an
747 * output argument for Formatter objects. For example:
749 * Appender app(&iobuf);
750 * format("{} {}", "hello", "world")(app);
752 * However, printf-style strings are still needed when dealing with existing
753 * third-party code in some cases.
755 * This will always add a nul-terminating character after the end
756 * of the output. However, the buffer data length will only be updated to
757 * include the data itself. The nul terminator will be the first byte in the
760 * This method may throw exceptions on error.
762 void printf(FOLLY_PRINTF_FORMAT const char* fmt, ...)
763 FOLLY_PRINTF_FORMAT_ATTR(2, 3);
765 void vprintf(const char* fmt, va_list ap);
768 * Calling an Appender object with a StringPiece will append the string
769 * piece. This allows Appender objects to be used directly with
772 void operator()(StringPiece sp) {
777 bool tryGrowChain() {
778 assert(crtBuf_->next() == buffer_);
783 buffer_->prependChain(IOBuf::create(growth_));
784 crtBuf_ = buffer_->prev();
793 class QueueAppender : public detail::Writable<QueueAppender> {
796 * Create an Appender that writes to a IOBufQueue. When we allocate
797 * space in the queue, we grow no more than growth bytes at once
798 * (unless you call ensure() with a bigger value yourself).
800 QueueAppender(IOBufQueue* queue, uint64_t growth) {
801 reset(queue, growth);
804 void reset(IOBufQueue* queue, uint64_t growth) {
809 uint8_t* writableData() {
810 return static_cast<uint8_t*>(queue_->writableTail());
813 size_t length() const { return queue_->tailroom(); }
815 void append(size_t n) { queue_->postallocate(n); }
817 // Ensure at least n contiguous; can go above growth_, throws if
819 void ensure(uint64_t n) { queue_->preallocate(n, growth_); }
822 typename std::enable_if<std::is_arithmetic<T>::value>::type
825 auto p = queue_->preallocate(sizeof(T), growth_);
826 storeUnaligned(p.first, value);
827 queue_->postallocate(sizeof(T));
830 using detail::Writable<QueueAppender>::pushAtMost;
831 size_t pushAtMost(const uint8_t* buf, size_t len) {
832 size_t remaining = len;
833 while (remaining != 0) {
834 auto p = queue_->preallocate(std::min(remaining, growth_),
837 memcpy(p.first, buf, p.second);
838 queue_->postallocate(p.second);
840 remaining -= p.second;
846 void insert(std::unique_ptr<folly::IOBuf> buf) {
848 queue_->append(std::move(buf), true);
853 folly::IOBufQueue* queue_;
859 #endif // FOLLY_CURSOR_H