2 * Copyright 2013-present 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>
25 #include <folly/Likely.h>
26 #include <folly/Memory.h>
27 #include <folly/Portability.h>
28 #include <folly/Range.h>
29 #include <folly/io/IOBuf.h>
30 #include <folly/io/IOBufQueue.h>
31 #include <folly/lang/Bits.h>
32 #include <folly/portability/BitsFunctexcept.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 chain
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).
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) {
62 crtPos_ = crtBegin_ = crtBuf_->data();
63 crtEnd_ = crtBuf_->tail();
70 * This also allows constructing a CursorBase from other derived types.
71 * For instance, this allows constructing a Cursor from an RWPrivateCursor.
73 template <class OtherDerived, class OtherBuf>
74 explicit CursorBase(const CursorBase<OtherDerived, OtherBuf>& cursor)
75 : crtBuf_(cursor.crtBuf_),
76 buffer_(cursor.buffer_),
77 crtBegin_(cursor.crtBegin_),
78 crtEnd_(cursor.crtEnd_),
79 crtPos_(cursor.crtPos_),
80 absolutePos_(cursor.absolutePos_) {}
83 * Reset cursor to point to a new buffer.
85 void reset(BufType* buf) {
90 crtPos_ = crtBegin_ = crtBuf_->data();
91 crtEnd_ = crtBuf_->tail();
96 * Get the current Cursor position relative to the head of IOBuf chain.
98 size_t getCurrentPosition() const {
99 return (crtPos_ - crtBegin_) + absolutePos_;
102 const uint8_t* data() const {
107 * Return the remaining space available in the current IOBuf.
109 * May return 0 if the cursor is at the end of an IOBuf. Use peekBytes()
110 * instead if you want to avoid this. peekBytes() will advance to the next
111 * non-empty IOBuf (up to the end of the chain) if the cursor is currently
112 * pointing at the end of a buffer.
114 size_t length() const {
115 return crtEnd_ - crtPos_;
119 * Return the space available until the end of the entire IOBuf chain.
121 size_t totalLength() const {
122 if (crtBuf_ == buffer_) {
123 return crtBuf_->computeChainDataLength() - (crtPos_ - crtBegin_);
125 CursorBase end(buffer_->prev());
126 end.crtPos_ = end.crtEnd_;
131 * Return true if the cursor could advance the specified number of bytes
132 * from its current position.
133 * This is useful for applications that want to do checked reads instead of
134 * catching exceptions and is more efficient than using totalLength as it
135 * walks the minimal set of buffers in the chain to determine the result.
137 bool canAdvance(size_t amount) const {
138 const IOBuf* nextBuf = crtBuf_;
139 size_t available = length();
141 if (available >= amount) {
145 nextBuf = nextBuf->next();
146 available = nextBuf->length();
147 } while (nextBuf != buffer_);
152 * Return true if the cursor is at the end of the entire IOBuf chain.
154 bool isAtEnd() const {
155 // Check for the simple cases first.
156 if (crtPos_ != crtEnd_) {
159 if (crtBuf_ == buffer_->prev()) {
162 // We are at the end of a buffer, but it isn't the last buffer.
163 // We might still be at the end if the remaining buffers in the chain are
165 const IOBuf* buf = crtBuf_->next();;
166 while (buf != buffer_) {
167 if (buf->length() > 0) {
176 * Advances the cursor to the end of the entire IOBuf chain.
178 void advanceToEnd() {
179 // Simple case, we're already in the last IOBuf.
180 if (crtBuf_ == buffer_->prev()) {
185 auto* nextBuf = crtBuf_->next();
186 while (nextBuf != buffer_) {
187 absolutePos_ += crtEnd_ - crtBegin_;
190 nextBuf = crtBuf_->next();
191 crtBegin_ = crtBuf_->data();
192 crtPos_ = crtEnd_ = crtBuf_->tail();
194 static_cast<Derived*>(this)->advanceDone();
198 Derived& operator+=(size_t offset) {
199 Derived* p = static_cast<Derived*>(this);
203 Derived operator+(size_t offset) const {
204 Derived other(*this);
209 Derived& operator-=(size_t offset) {
210 Derived* p = static_cast<Derived*>(this);
214 Derived operator-(size_t offset) const {
215 Derived other(*this);
216 other.retreat(offset);
221 * Compare cursors for equality/inequality.
223 * Two cursors are equal if they are pointing to the same location in the
226 bool operator==(const Derived& other) const {
227 const IOBuf* crtBuf = crtBuf_;
228 auto crtPos = crtPos_;
229 // We can be pointing to the end of a buffer chunk, find first non-empty.
230 while (crtPos == crtBuf->tail() && crtBuf != buffer_->prev()) {
231 crtBuf = crtBuf->next();
232 crtPos = crtBuf->data();
235 const IOBuf* crtBufOther = other.crtBuf_;
236 auto crtPosOther = other.crtPos_;
237 // We can be pointing to the end of a buffer chunk, find first non-empty.
238 while (crtPosOther == crtBufOther->tail() &&
239 crtBufOther != other.buffer_->prev()) {
240 crtBufOther = crtBufOther->next();
241 crtPosOther = crtBufOther->data();
243 return (crtPos == crtPosOther) && (crtBuf == crtBufOther);
245 bool operator!=(const Derived& other) const {
246 return !operator==(other);
250 typename std::enable_if<std::is_arithmetic<T>::value, bool>::type tryRead(
252 if (LIKELY(crtPos_ + sizeof(T) <= crtEnd_)) {
253 val = loadUnaligned<T>(data());
254 crtPos_ += sizeof(T);
257 return pullAtMostSlow(&val, sizeof(T)) == sizeof(T);
261 bool tryReadBE(T& val) {
262 const bool result = tryRead(val);
263 val = Endian::big(val);
268 bool tryReadLE(T& val) {
269 const bool result = tryRead(val);
270 val = Endian::little(val);
276 if (LIKELY(crtPos_ + sizeof(T) <= crtEnd_)) {
277 T val = loadUnaligned<T>(data());
278 crtPos_ += sizeof(T);
281 return readSlow<T>();
287 return Endian::big(read<T>());
292 return Endian::little(read<T>());
296 * Read a fixed-length string.
298 * The std::string-based APIs should probably be avoided unless you
299 * ultimately want the data to live in an std::string. You're better off
300 * using the pull() APIs to copy into a raw buffer otherwise.
302 std::string readFixedString(size_t len) {
305 if (LIKELY(length() >= len)) {
306 str.append(reinterpret_cast<const char*>(data()), len);
309 readFixedStringSlow(&str, len);
315 * Read a string consisting of bytes until the given terminator character is
316 * seen. Raises an std::length_error if maxLength bytes have been processed
317 * before the terminator is seen.
319 * See comments in readFixedString() about when it's appropriate to use this
322 std::string readTerminatedString(
323 char termChar = '\0',
324 size_t maxLength = std::numeric_limits<size_t>::max());
327 * Read all bytes until the specified predicate returns true.
329 * The predicate will be called on each byte in turn, until it returns false
330 * or until the end of the IOBuf chain is reached.
332 * Returns the result as a string.
334 template <typename Predicate>
335 std::string readWhile(const Predicate& predicate);
338 * Read all bytes until the specified predicate returns true.
340 * This is a more generic version of readWhile() takes an arbitrary Output
341 * object, and calls Output::append() with each chunk of matching data.
343 template <typename Predicate, typename Output>
344 void readWhile(const Predicate& predicate, Output& out);
347 * Skip all bytes until the specified predicate returns true.
349 * The predicate will be called on each byte in turn, until it returns false
350 * or until the end of the IOBuf chain is reached.
352 template <typename Predicate>
353 void skipWhile(const Predicate& predicate);
355 size_t skipAtMost(size_t len) {
356 if (LIKELY(crtPos_ + len < crtEnd_)) {
360 return skipAtMostSlow(len);
363 void skip(size_t len) {
364 if (LIKELY(crtPos_ + len < crtEnd_)) {
372 * Skip bytes in the current IOBuf without advancing to the next one.
373 * Precondition: length() >= len
375 void skipNoAdvance(size_t len) {
376 DCHECK_LE(len, length());
380 size_t retreatAtMost(size_t len) {
381 if (len <= static_cast<size_t>(crtPos_ - crtBegin_)) {
385 return retreatAtMostSlow(len);
388 void retreat(size_t len) {
389 if (len <= static_cast<size_t>(crtPos_ - crtBegin_)) {
396 size_t pullAtMost(void* buf, size_t len) {
397 // Fast path: it all fits in one buffer.
398 if (LIKELY(crtPos_ + len <= crtEnd_)) {
399 memcpy(buf, data(), len);
403 return pullAtMostSlow(buf, len);
406 void pull(void* buf, size_t len) {
407 if (LIKELY(crtPos_ + len <= crtEnd_)) {
408 memcpy(buf, data(), len);
416 * Return the available data in the current buffer.
417 * If you want to gather more data from the chain into a contiguous region
418 * (for hopefully zero-copy access), use gather() before peekBytes().
420 ByteRange peekBytes() {
421 // Ensure that we're pointing to valid data
422 size_t available = length();
423 while (UNLIKELY(available == 0 && tryAdvanceBuffer())) {
424 available = length();
426 return ByteRange{data(), available};
430 * Alternate version of peekBytes() that returns a std::pair
431 * instead of a ByteRange. (This method pre-dates ByteRange.)
433 * This function will eventually be deprecated.
435 std::pair<const uint8_t*, size_t> peek() {
436 auto bytes = peekBytes();
437 return std::make_pair(bytes.data(), bytes.size());
440 void clone(std::unique_ptr<folly::IOBuf>& buf, size_t len) {
441 if (UNLIKELY(cloneAtMost(buf, len) != len)) {
442 std::__throw_out_of_range("underflow");
446 void clone(folly::IOBuf& buf, size_t len) {
447 if (UNLIKELY(cloneAtMost(buf, len) != len)) {
448 std::__throw_out_of_range("underflow");
452 size_t cloneAtMost(folly::IOBuf& buf, size_t len) {
453 // We might be at the end of buffer.
454 advanceBufferIfEmpty();
456 std::unique_ptr<folly::IOBuf> tmp;
458 for (int loopCount = 0; true; ++loopCount) {
459 // Fast path: it all fits in one buffer.
460 size_t available = length();
461 if (LIKELY(available >= len)) {
462 if (loopCount == 0) {
463 crtBuf_->cloneOneInto(buf);
464 buf.trimStart(crtPos_ - crtBegin_);
465 buf.trimEnd(buf.length() - len);
467 tmp = crtBuf_->cloneOne();
468 tmp->trimStart(crtPos_ - crtBegin_);
469 tmp->trimEnd(tmp->length() - len);
470 buf.prependChain(std::move(tmp));
474 advanceBufferIfEmpty();
478 if (loopCount == 0) {
479 crtBuf_->cloneOneInto(buf);
480 buf.trimStart(crtPos_ - crtBegin_);
482 tmp = crtBuf_->cloneOne();
483 tmp->trimStart(crtPos_ - crtBegin_);
484 buf.prependChain(std::move(tmp));
488 if (UNLIKELY(!tryAdvanceBuffer())) {
495 size_t cloneAtMost(std::unique_ptr<folly::IOBuf>& buf, size_t len) {
497 buf = std::make_unique<folly::IOBuf>();
499 return cloneAtMost(*buf, len);
503 * Return the distance between two cursors.
505 size_t operator-(const CursorBase& other) const {
506 BufType *otherBuf = other.crtBuf_;
509 if (otherBuf != crtBuf_) {
510 len += other.crtEnd_ - other.crtPos_;
512 for (otherBuf = otherBuf->next();
513 otherBuf != crtBuf_ && otherBuf != other.buffer_;
514 otherBuf = otherBuf->next()) {
515 len += otherBuf->length();
518 if (otherBuf == other.buffer_) {
519 std::__throw_out_of_range("wrap-around");
522 len += crtPos_ - crtBegin_;
524 if (crtPos_ < other.crtPos_) {
525 std::__throw_out_of_range("underflow");
528 len += crtPos_ - other.crtPos_;
535 * Return the distance from the given IOBuf to the this cursor.
537 size_t operator-(const BufType* buf) const {
540 const BufType* curBuf = buf;
541 while (curBuf != crtBuf_) {
542 len += curBuf->length();
543 curBuf = curBuf->next();
544 if (curBuf == buf || curBuf == buffer_) {
545 std::__throw_out_of_range("wrap-around");
549 len += crtPos_ - crtBegin_;
560 bool tryAdvanceBuffer() {
561 BufType* nextBuf = crtBuf_->next();
562 if (UNLIKELY(nextBuf == buffer_)) {
567 absolutePos_ += crtEnd_ - crtBegin_;
569 crtPos_ = crtBegin_ = crtBuf_->data();
570 crtEnd_ = crtBuf_->tail();
571 static_cast<Derived*>(this)->advanceDone();
575 bool tryRetreatBuffer() {
576 if (UNLIKELY(crtBuf_ == buffer_)) {
580 crtBuf_ = crtBuf_->prev();
581 crtBegin_ = crtBuf_->data();
582 crtPos_ = crtEnd_ = crtBuf_->tail();
583 absolutePos_ -= crtEnd_ - crtBegin_;
584 static_cast<Derived*>(this)->advanceDone();
588 void advanceBufferIfEmpty() {
589 if (crtPos_ == crtEnd_) {
596 const uint8_t* crtBegin_{nullptr};
597 const uint8_t* crtEnd_{nullptr};
598 const uint8_t* crtPos_{nullptr};
599 size_t absolutePos_{0};
603 FOLLY_NOINLINE T readSlow() {
605 pullSlow(&val, sizeof(T));
609 void readFixedStringSlow(std::string* str, size_t len) {
610 for (size_t available; (available = length()) < len; ) {
611 str->append(reinterpret_cast<const char*>(data()), available);
612 if (UNLIKELY(!tryAdvanceBuffer())) {
613 std::__throw_out_of_range("string underflow");
617 str->append(reinterpret_cast<const char*>(data()), len);
619 advanceBufferIfEmpty();
622 size_t pullAtMostSlow(void* buf, size_t len) {
623 uint8_t* p = reinterpret_cast<uint8_t*>(buf);
625 for (size_t available; (available = length()) < len; ) {
626 memcpy(p, data(), available);
628 if (UNLIKELY(!tryAdvanceBuffer())) {
634 memcpy(p, data(), len);
636 advanceBufferIfEmpty();
640 void pullSlow(void* buf, size_t len) {
641 if (UNLIKELY(pullAtMostSlow(buf, len) != len)) {
642 std::__throw_out_of_range("underflow");
646 size_t skipAtMostSlow(size_t len) {
648 for (size_t available; (available = length()) < len; ) {
649 skipped += available;
650 if (UNLIKELY(!tryAdvanceBuffer())) {
656 advanceBufferIfEmpty();
657 return skipped + len;
660 void skipSlow(size_t len) {
661 if (UNLIKELY(skipAtMostSlow(len) != len)) {
662 std::__throw_out_of_range("underflow");
666 size_t retreatAtMostSlow(size_t len) {
667 size_t retreated = 0;
668 for (size_t available; (available = crtPos_ - crtBegin_) < len;) {
669 retreated += available;
670 if (UNLIKELY(!tryRetreatBuffer())) {
676 return retreated + len;
679 void retreatSlow(size_t len) {
680 if (UNLIKELY(retreatAtMostSlow(len) != len)) {
681 std::__throw_out_of_range("underflow");
689 } // namespace detail
691 class Cursor : public detail::CursorBase<Cursor, const IOBuf> {
693 explicit Cursor(const IOBuf* buf)
694 : detail::CursorBase<Cursor, const IOBuf>(buf) {}
696 template <class OtherDerived, class OtherBuf>
697 explicit Cursor(const detail::CursorBase<OtherDerived, OtherBuf>& cursor)
698 : detail::CursorBase<Cursor, const IOBuf>(cursor) {}
703 template <class Derived>
707 typename std::enable_if<std::is_arithmetic<T>::value>::type
709 const uint8_t* u8 = reinterpret_cast<const uint8_t*>(&value);
710 Derived* d = static_cast<Derived*>(this);
711 d->push(u8, sizeof(T));
715 void writeBE(T value) {
716 Derived* d = static_cast<Derived*>(this);
717 d->write(Endian::big(value));
721 void writeLE(T value) {
722 Derived* d = static_cast<Derived*>(this);
723 d->write(Endian::little(value));
726 void push(const uint8_t* buf, size_t len) {
727 Derived* d = static_cast<Derived*>(this);
728 if (d->pushAtMost(buf, len) != len) {
729 std::__throw_out_of_range("overflow");
733 void push(ByteRange buf) {
734 if (this->pushAtMost(buf) != buf.size()) {
735 std::__throw_out_of_range("overflow");
739 size_t pushAtMost(ByteRange buf) {
740 Derived* d = static_cast<Derived*>(this);
741 return d->pushAtMost(buf.data(), buf.size());
745 * push len bytes of data from input cursor, data could be in an IOBuf chain.
746 * If input cursor contains less than len bytes, or this cursor has less than
747 * len bytes writable space, an out_of_range exception will be thrown.
749 void push(Cursor cursor, size_t len) {
750 if (this->pushAtMost(cursor, len) != len) {
751 std::__throw_out_of_range("overflow");
755 size_t pushAtMost(Cursor cursor, size_t len) {
758 auto currentBuffer = cursor.peekBytes();
759 const uint8_t* crtData = currentBuffer.data();
760 size_t available = currentBuffer.size();
761 if (available == 0) {
762 // end of buffer chain
765 // all data is in current buffer
766 if (available >= len) {
767 this->push(crtData, len);
769 return written + len;
772 // write the whole current IOBuf
773 this->push(crtData, available);
774 cursor.skip(available);
775 written += available;
781 } // namespace detail
783 enum class CursorAccess {
788 template <CursorAccess access>
790 : public detail::CursorBase<RWCursor<access>, IOBuf>,
791 public detail::Writable<RWCursor<access>> {
792 friend class detail::CursorBase<RWCursor<access>, IOBuf>;
794 explicit RWCursor(IOBuf* buf)
795 : detail::CursorBase<RWCursor<access>, IOBuf>(buf),
796 maybeShared_(true) {}
798 template <class OtherDerived, class OtherBuf>
799 explicit RWCursor(const detail::CursorBase<OtherDerived, OtherBuf>& cursor)
800 : detail::CursorBase<RWCursor<access>, IOBuf>(cursor),
801 maybeShared_(true) {}
803 * Gather at least n bytes contiguously into the current buffer,
804 * by coalescing subsequent buffers from the chain as necessary.
806 void gather(size_t n) {
807 // Forbid attempts to gather beyond the end of this IOBuf chain.
808 // Otherwise we could try to coalesce the head of the chain and end up
809 // accidentally freeing it, invalidating the pointer owned by external
812 // If crtBuf_ == head() then IOBuf::gather() will perform all necessary
813 // checking. We only have to perform an explicit check here when calling
814 // gather() on a non-head element.
815 if (this->crtBuf_ != this->head() && this->totalLength() < n) {
816 throw std::overflow_error("cannot gather() past the end of the chain");
818 size_t offset = this->crtPos_ - this->crtBegin_;
819 this->crtBuf_->gather(offset + n);
820 this->crtBegin_ = this->crtBuf_->data();
821 this->crtEnd_ = this->crtBuf_->tail();
822 this->crtPos_ = this->crtBegin_ + offset;
824 void gatherAtMost(size_t n) {
825 size_t size = std::min(n, this->totalLength());
826 size_t offset = this->crtPos_ - this->crtBegin_;
827 this->crtBuf_->gather(offset + size);
828 this->crtBegin_ = this->crtBuf_->data();
829 this->crtEnd_ = this->crtBuf_->tail();
830 this->crtPos_ = this->crtBegin_ + offset;
833 using detail::Writable<RWCursor<access>>::pushAtMost;
834 size_t pushAtMost(const uint8_t* buf, size_t len) {
835 // We have to explicitly check for an input length of 0.
836 // We support buf being nullptr in this case, but we need to avoid calling
837 // memcpy() with a null source pointer, since that is undefined behavior
838 // even if the length is 0.
845 // Fast path: the current buffer is big enough.
846 size_t available = this->length();
847 if (LIKELY(available >= len)) {
848 if (access == CursorAccess::UNSHARE) {
851 memcpy(writableData(), buf, len);
852 this->crtPos_ += len;
856 if (access == CursorAccess::UNSHARE) {
859 memcpy(writableData(), buf, available);
861 if (UNLIKELY(!this->tryAdvanceBuffer())) {
869 void insert(std::unique_ptr<folly::IOBuf> buf) {
870 this->absolutePos_ += buf->computeChainDataLength();
871 if (this->crtPos_ == this->crtBegin_ && this->crtBuf_ != this->buffer_) {
873 this->crtBuf_->prependChain(std::move(buf));
876 std::unique_ptr<folly::IOBuf> remaining;
877 if (this->crtPos_ != this->crtEnd_) {
878 // Need to split current IOBuf in two.
879 remaining = this->crtBuf_->cloneOne();
880 remaining->trimStart(this->crtPos_ - this->crtBegin_);
881 nextBuf = remaining.get();
882 buf->prependChain(std::move(remaining));
885 nextBuf = this->crtBuf_->next();
887 this->crtBuf_->trimEnd(this->length());
888 this->absolutePos_ += this->crtPos_ - this->crtBegin_;
889 this->crtBuf_->appendChain(std::move(buf));
891 if (nextBuf == this->buffer_) {
892 // We've just appended to the end of the buffer, so advance to the end.
893 this->crtBuf_ = this->buffer_->prev();
894 this->crtBegin_ = this->crtBuf_->data();
895 this->crtPos_ = this->crtEnd_ = this->crtBuf_->tail();
896 // This has already been accounted for, so remove it.
897 this->absolutePos_ -= this->crtEnd_ - this->crtBegin_;
899 // Jump past the new links
900 this->crtBuf_ = nextBuf;
901 this->crtPos_ = this->crtBegin_ = this->crtBuf_->data();
902 this->crtEnd_ = this->crtBuf_->tail();
907 uint8_t* writableData() {
908 return this->crtBuf_->writableData() + (this->crtPos_ - this->crtBegin_);
912 void maybeUnshare() {
913 if (UNLIKELY(maybeShared_)) {
914 size_t offset = this->crtPos_ - this->crtBegin_;
915 this->crtBuf_->unshareOne();
916 this->crtBegin_ = this->crtBuf_->data();
917 this->crtEnd_ = this->crtBuf_->tail();
918 this->crtPos_ = this->crtBegin_ + offset;
919 maybeShared_ = false;
930 typedef RWCursor<CursorAccess::PRIVATE> RWPrivateCursor;
931 typedef RWCursor<CursorAccess::UNSHARE> RWUnshareCursor;
934 * Append to the end of a buffer chain, growing the chain (by allocating new
935 * buffers) in increments of at least growth bytes every time. Won't grow
936 * (and push() and ensure() will throw) if growth == 0.
938 * TODO(tudorb): add a flavor of Appender that reallocates one IOBuf instead
941 class Appender : public detail::Writable<Appender> {
943 Appender(IOBuf* buf, uint64_t growth)
945 crtBuf_(buf->prev()),
949 uint8_t* writableData() {
950 return crtBuf_->writableTail();
953 size_t length() const {
954 return crtBuf_->tailroom();
958 * Mark n bytes (must be <= length()) as appended, as per the
959 * IOBuf::append() method.
961 void append(size_t n) {
966 * Ensure at least n contiguous bytes available to write.
967 * Postcondition: length() >= n.
969 void ensure(uint64_t n) {
970 if (LIKELY(length() >= n)) {
974 // Waste the rest of the current buffer and allocate a new one.
975 // Don't make it too small, either.
977 std::__throw_out_of_range("can't grow buffer chain");
980 n = std::max(n, growth_);
981 buffer_->prependChain(IOBuf::create(n));
982 crtBuf_ = buffer_->prev();
985 using detail::Writable<Appender>::pushAtMost;
986 size_t pushAtMost(const uint8_t* buf, size_t len) {
987 // We have to explicitly check for an input length of 0.
988 // We support buf being nullptr in this case, but we need to avoid calling
989 // memcpy() with a null source pointer, since that is undefined behavior
990 // even if the length is 0.
997 // Fast path: it all fits in one buffer.
998 size_t available = length();
999 if (LIKELY(available >= len)) {
1000 memcpy(writableData(), buf, len);
1002 return copied + len;
1005 memcpy(writableData(), buf, available);
1007 copied += available;
1008 if (UNLIKELY(!tryGrowChain())) {
1017 * Append to the end of this buffer, using a printf() style
1020 * Note that folly/Format.h provides nicer and more type-safe mechanisms
1021 * for formatting strings, which should generally be preferred over
1022 * printf-style formatting. Appender objects can be used directly as an
1023 * output argument for Formatter objects. For example:
1025 * Appender app(&iobuf);
1026 * format("{} {}", "hello", "world")(app);
1028 * However, printf-style strings are still needed when dealing with existing
1029 * third-party code in some cases.
1031 * This will always add a nul-terminating character after the end
1032 * of the output. However, the buffer data length will only be updated to
1033 * include the data itself. The nul terminator will be the first byte in the
1036 * This method may throw exceptions on error.
1038 void printf(FOLLY_PRINTF_FORMAT const char* fmt, ...)
1039 FOLLY_PRINTF_FORMAT_ATTR(2, 3);
1041 void vprintf(const char* fmt, va_list ap);
1044 * Calling an Appender object with a StringPiece will append the string
1045 * piece. This allows Appender objects to be used directly with
1048 void operator()(StringPiece sp) {
1049 push(ByteRange(sp));
1053 bool tryGrowChain() {
1054 assert(crtBuf_->next() == buffer_);
1059 buffer_->prependChain(IOBuf::create(growth_));
1060 crtBuf_ = buffer_->prev();
1069 class QueueAppender : public detail::Writable<QueueAppender> {
1072 * Create an Appender that writes to a IOBufQueue. When we allocate
1073 * space in the queue, we grow no more than growth bytes at once
1074 * (unless you call ensure() with a bigger value yourself).
1076 QueueAppender(IOBufQueue* queue, uint64_t growth)
1077 : queueCache_(queue), growth_(growth) {}
1079 void reset(IOBufQueue* queue, uint64_t growth) {
1080 queueCache_.reset(queue);
1084 uint8_t* writableData() {
1085 return queueCache_.writableData();
1089 return queueCache_.length();
1092 void append(size_t n) {
1093 queueCache_.append(n);
1096 // Ensure at least n contiguous; can go above growth_, throws if
1098 void ensure(size_t n) {
1105 typename std::enable_if<std::is_arithmetic<T>::value>::type write(T value) {
1107 if (length() >= sizeof(T)) {
1108 storeUnaligned(queueCache_.writableData(), value);
1109 queueCache_.appendUnsafe(sizeof(T));
1111 writeSlow<T>(value);
1115 using detail::Writable<QueueAppender>::pushAtMost;
1116 size_t pushAtMost(const uint8_t* buf, size_t len) {
1117 // Fill the current buffer
1118 const size_t copyLength = std::min(len, length());
1119 if (copyLength != 0) {
1120 memcpy(writableData(), buf, copyLength);
1121 queueCache_.appendUnsafe(copyLength);
1124 size_t remaining = len - copyLength;
1125 // Allocate more buffers as necessary
1126 while (remaining != 0) {
1127 auto p = queueCache_.queue()->preallocate(
1128 std::min(remaining, growth_), growth_, remaining);
1129 memcpy(p.first, buf, p.second);
1130 queueCache_.queue()->postallocate(p.second);
1132 remaining -= p.second;
1137 void insert(std::unique_ptr<folly::IOBuf> buf) {
1139 queueCache_.queue()->append(std::move(buf), true);
1143 void insert(const folly::IOBuf& buf) {
1144 insert(buf.clone());
1148 folly::IOBufQueue::WritableRangeCache queueCache_{nullptr};
1151 FOLLY_NOINLINE void ensureSlow(size_t n) {
1152 queueCache_.queue()->preallocate(n, growth_);
1153 queueCache_.fillCache();
1157 typename std::enable_if<std::is_arithmetic<T>::value>::type FOLLY_NOINLINE
1158 writeSlow(T value) {
1159 queueCache_.queue()->preallocate(sizeof(T), growth_);
1160 queueCache_.fillCache();
1162 storeUnaligned(queueCache_.writableData(), value);
1163 queueCache_.appendUnsafe(sizeof(T));
1168 } // namespace folly
1170 #include <folly/io/Cursor-inl.h>