add Cursor::readWhile() and skipWhile()
[folly.git] / folly / io / Cursor.h
1 /*
2  * Copyright 2016 Facebook, Inc.
3  *
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
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #pragma once
18
19 #include <assert.h>
20 #include <cstdarg>
21 #include <stdexcept>
22 #include <string.h>
23 #include <type_traits>
24 #include <memory>
25
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>
33
34 /**
35  * Cursor class for fast iteration over IOBuf chains.
36  *
37  * Cursor - Read-only access
38  *
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
42  *
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).
49  **/
50 namespace folly { namespace io {
51
52 namespace detail {
53
54 template <class Derived, class BufType>
55 class CursorBase {
56   // Make all the templated classes friends for copy constructor.
57   template <class D, typename B> friend class CursorBase;
58  public:
59   explicit CursorBase(BufType* buf) : crtBuf_(buf), buffer_(buf) { }
60
61   /**
62    * Copy constructor.
63    *
64    * This also allows constructing a CursorBase from other derived types.
65    * For instance, this allows constructing a Cursor from an RWPrivateCursor.
66    */
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_) { }
72
73   /**
74    * Reset cursor to point to a new buffer.
75    */
76   void reset(BufType* buf) {
77     crtBuf_ = buf;
78     buffer_ = buf;
79     offset_ = 0;
80   }
81
82   const uint8_t* data() const {
83     return crtBuf_->data() + offset_;
84   }
85
86   /**
87    * Return the remaining space available in the current IOBuf.
88    *
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.
93    */
94   size_t length() const {
95     return crtBuf_->length() - offset_;
96   }
97
98   /**
99    * Return the space available until the end of the entire IOBuf chain.
100    */
101   size_t totalLength() const {
102     if (crtBuf_ == buffer_) {
103       return crtBuf_->computeChainDataLength() - offset_;
104     }
105     CursorBase end(buffer_->prev());
106     end.offset_ = end.buffer_->length();
107     return end - *this;
108   }
109
110   /**
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.
116    */
117   bool canAdvance(size_t amount) const {
118     const IOBuf* nextBuf = crtBuf_;
119     size_t available = length();
120     do {
121       if (available >= amount) {
122         return true;
123       }
124       amount -= available;
125       nextBuf = nextBuf->next();
126       available = nextBuf->length();
127     } while (nextBuf != buffer_);
128     return false;
129   }
130
131   /*
132    * Return true if the cursor is at the end of the entire IOBuf chain.
133    */
134   bool isAtEnd() const {
135     // Check for the simple cases first.
136     if (offset_ != crtBuf_->length()) {
137       return false;
138     }
139     if (crtBuf_ == buffer_->prev()) {
140       return true;
141     }
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
144     // empty.
145     const IOBuf* buf = crtBuf_->next();;
146     while (buf != buffer_) {
147       if (buf->length() > 0) {
148         return false;
149       }
150       buf = buf->next();
151     }
152     return true;
153   }
154
155   Derived& operator+=(size_t offset) {
156     Derived* p = static_cast<Derived*>(this);
157     p->skip(offset);
158     return *p;
159   }
160   Derived operator+(size_t offset) const {
161     Derived other(*this);
162     other.skip(offset);
163     return other;
164   }
165
166   /**
167    * Compare cursors for equality/inequality.
168    *
169    * Two cursors are equal if they are pointing to the same location in the
170    * same IOBuf chain.
171    */
172   bool operator==(const Derived& other) const {
173     return (offset_ == other.offset_) && (crtBuf_ == other.crtBuf_);
174   }
175   bool operator!=(const Derived& other) const {
176     return !operator==(other);
177   }
178
179   template <class T>
180   typename std::enable_if<std::is_arithmetic<T>::value, T>::type read() {
181     T val;
182     if (LIKELY(length() >= sizeof(T))) {
183       val = loadUnaligned<T>(data());
184       offset_ += sizeof(T);
185       advanceBufferIfEmpty();
186     } else {
187       pullSlow(&val, sizeof(T));
188     }
189     return val;
190   }
191
192   template <class T>
193   T readBE() {
194     return Endian::big(read<T>());
195   }
196
197   template <class T>
198   T readLE() {
199     return Endian::little(read<T>());
200   }
201
202   /**
203    * Read a fixed-length string.
204    *
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.
208    */
209   std::string readFixedString(size_t len) {
210     std::string str;
211     str.reserve(len);
212     if (LIKELY(length() >= len)) {
213       str.append(reinterpret_cast<const char*>(data()), len);
214       offset_ += len;
215       advanceBufferIfEmpty();
216     } else {
217       readFixedStringSlow(&str, len);
218     }
219     return str;
220   }
221
222   /**
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.
226    *
227    * See comments in readFixedString() about when it's appropriate to use this
228    * vs. using pull().
229    */
230   std::string readTerminatedString(
231       char termChar = '\0',
232       size_t maxLength = std::numeric_limits<size_t>::max());
233
234   /*
235    * Read all bytes until the specified predicate returns true.
236    *
237    * The predicate will be called on each byte in turn, until it returns false
238    * or until the end of the IOBuf chain is reached.
239    *
240    * Returns the result as a string.
241    */
242   template <typename Predicate>
243   std::string readWhile(const Predicate& predicate);
244
245   /*
246    * Read all bytes until the specified predicate returns true.
247    *
248    * This is a more generic version of readWhile() takes an arbitrary Output
249    * object, and calls Output::append() with each chunk of matching data.
250    */
251   template <typename Predicate, typename Output>
252   void readWhile(const Predicate& predicate, Output& out);
253
254   /*
255    * Skip all bytes until the specified predicate returns true.
256    *
257    * The predicate will be called on each byte in turn, until it returns false
258    * or until the end of the IOBuf chain is reached.
259    */
260   template <typename Predicate>
261   void skipWhile(const Predicate& predicate);
262
263   size_t skipAtMost(size_t len) {
264     if (LIKELY(length() >= len)) {
265       offset_ += len;
266       advanceBufferIfEmpty();
267       return len;
268     }
269     return skipAtMostSlow(len);
270   }
271
272   void skip(size_t len) {
273     if (LIKELY(length() >= len)) {
274       offset_ += len;
275       advanceBufferIfEmpty();
276     } else {
277       skipSlow(len);
278     }
279   }
280
281   size_t pullAtMost(void* buf, size_t len) {
282     // Fast path: it all fits in one buffer.
283     if (LIKELY(length() >= len)) {
284       memcpy(buf, data(), len);
285       offset_ += len;
286       advanceBufferIfEmpty();
287       return len;
288     }
289     return pullAtMostSlow(buf, len);
290   }
291
292   void pull(void* buf, size_t len) {
293     if (LIKELY(length() >= len)) {
294       memcpy(buf, data(), len);
295       offset_ += len;
296       advanceBufferIfEmpty();
297     } else {
298       pullSlow(buf, len);
299     }
300   }
301
302   /**
303    * Return the available data in the current buffer.
304    * If you want to gather more data from the chain into a contiguous region
305    * (for hopefully zero-copy access), use gather() before peekBytes().
306    */
307   ByteRange peekBytes() {
308     // Ensure that we're pointing to valid data
309     size_t available = length();
310     while (UNLIKELY(available == 0 && tryAdvanceBuffer())) {
311       available = length();
312     }
313     return ByteRange{data(), available};
314   }
315
316   /**
317    * Alternate version of peekBytes() that returns a std::pair
318    * instead of a ByteRange.  (This method pre-dates ByteRange.)
319    *
320    * This function will eventually be deprecated.
321    */
322   std::pair<const uint8_t*, size_t> peek() {
323     auto bytes = peekBytes();
324     return std::make_pair(bytes.data(), bytes.size());
325   }
326
327   void clone(std::unique_ptr<folly::IOBuf>& buf, size_t len) {
328     if (UNLIKELY(cloneAtMost(buf, len) != len)) {
329       throw std::out_of_range("underflow");
330     }
331   }
332
333   void clone(folly::IOBuf& buf, size_t len) {
334     if (UNLIKELY(cloneAtMost(buf, len) != len)) {
335       throw std::out_of_range("underflow");
336     }
337   }
338
339   size_t cloneAtMost(folly::IOBuf& buf, size_t len) {
340     std::unique_ptr<folly::IOBuf> tmp;
341     size_t copied = 0;
342     for (int loopCount = 0; true; ++loopCount) {
343       // Fast path: it all fits in one buffer.
344       size_t available = length();
345       if (LIKELY(available >= len)) {
346         if (loopCount == 0) {
347           crtBuf_->cloneOneInto(buf);
348           buf.trimStart(offset_);
349           buf.trimEnd(buf.length() - len);
350         } else {
351           tmp = crtBuf_->cloneOne();
352           tmp->trimStart(offset_);
353           tmp->trimEnd(tmp->length() - len);
354           buf.prependChain(std::move(tmp));
355         }
356
357         offset_ += len;
358         advanceBufferIfEmpty();
359         return copied + len;
360       }
361
362       if (loopCount == 0) {
363         crtBuf_->cloneOneInto(buf);
364         buf.trimStart(offset_);
365       } else {
366         tmp = crtBuf_->cloneOne();
367         tmp->trimStart(offset_);
368         buf.prependChain(std::move(tmp));
369       }
370
371       copied += available;
372       if (UNLIKELY(!tryAdvanceBuffer())) {
373         return copied;
374       }
375       len -= available;
376     }
377   }
378
379   size_t cloneAtMost(std::unique_ptr<folly::IOBuf>& buf, size_t len) {
380     if (!buf) {
381       buf = make_unique<folly::IOBuf>();
382     }
383     return cloneAtMost(*buf, len);
384   }
385
386   /**
387    * Return the distance between two cursors.
388    */
389   size_t operator-(const CursorBase& other) const {
390     BufType *otherBuf = other.crtBuf_;
391     size_t len = 0;
392
393     if (otherBuf != crtBuf_) {
394       len += otherBuf->length() - other.offset_;
395
396       for (otherBuf = otherBuf->next();
397            otherBuf != crtBuf_ && otherBuf != other.buffer_;
398            otherBuf = otherBuf->next()) {
399         len += otherBuf->length();
400       }
401
402       if (otherBuf == other.buffer_) {
403         throw std::out_of_range("wrap-around");
404       }
405
406       len += offset_;
407     } else {
408       if (offset_ < other.offset_) {
409         throw std::out_of_range("underflow");
410       }
411
412       len += offset_ - other.offset_;
413     }
414
415     return len;
416   }
417
418   /**
419    * Return the distance from the given IOBuf to the this cursor.
420    */
421   size_t operator-(const BufType* buf) const {
422     size_t len = 0;
423
424     const BufType* curBuf = buf;
425     while (curBuf != crtBuf_) {
426       len += curBuf->length();
427       curBuf = curBuf->next();
428       if (curBuf == buf || curBuf == buffer_) {
429         throw std::out_of_range("wrap-around");
430       }
431     }
432
433     len += offset_;
434     return len;
435   }
436
437  protected:
438   ~CursorBase() { }
439
440   BufType* head() {
441     return buffer_;
442   }
443
444   bool tryAdvanceBuffer() {
445     BufType* nextBuf = crtBuf_->next();
446     if (UNLIKELY(nextBuf == buffer_)) {
447       offset_ = crtBuf_->length();
448       return false;
449     }
450
451     offset_ = 0;
452     crtBuf_ = nextBuf;
453     static_cast<Derived*>(this)->advanceDone();
454     return true;
455   }
456
457   void advanceBufferIfEmpty() {
458     if (length() == 0) {
459       tryAdvanceBuffer();
460     }
461   }
462
463   BufType* crtBuf_;
464   size_t offset_ = 0;
465
466  private:
467   void readFixedStringSlow(std::string* str, size_t len) {
468     for (size_t available; (available = length()) < len; ) {
469       str->append(reinterpret_cast<const char*>(data()), available);
470       if (UNLIKELY(!tryAdvanceBuffer())) {
471         throw std::out_of_range("string underflow");
472       }
473       len -= available;
474     }
475     str->append(reinterpret_cast<const char*>(data()), len);
476     offset_ += len;
477     advanceBufferIfEmpty();
478   }
479
480   size_t pullAtMostSlow(void* buf, size_t len) {
481     uint8_t* p = reinterpret_cast<uint8_t*>(buf);
482     size_t copied = 0;
483     for (size_t available; (available = length()) < len; ) {
484       memcpy(p, data(), available);
485       copied += available;
486       if (UNLIKELY(!tryAdvanceBuffer())) {
487         return copied;
488       }
489       p += available;
490       len -= available;
491     }
492     memcpy(p, data(), len);
493     offset_ += len;
494     advanceBufferIfEmpty();
495     return copied + len;
496   }
497
498   void pullSlow(void* buf, size_t len) {
499     if (UNLIKELY(pullAtMostSlow(buf, len) != len)) {
500       throw std::out_of_range("underflow");
501     }
502   }
503
504   size_t skipAtMostSlow(size_t len) {
505     size_t skipped = 0;
506     for (size_t available; (available = length()) < len; ) {
507       skipped += available;
508       if (UNLIKELY(!tryAdvanceBuffer())) {
509         return skipped;
510       }
511       len -= available;
512     }
513     offset_ += len;
514     advanceBufferIfEmpty();
515     return skipped + len;
516   }
517
518   void skipSlow(size_t len) {
519     if (UNLIKELY(skipAtMostSlow(len) != len)) {
520       throw std::out_of_range("underflow");
521     }
522   }
523
524   void advanceDone() {
525   }
526
527   BufType* buffer_;
528 };
529
530 }  // namespace detail
531
532 class Cursor : public detail::CursorBase<Cursor, const IOBuf> {
533  public:
534   explicit Cursor(const IOBuf* buf)
535     : detail::CursorBase<Cursor, const IOBuf>(buf) {}
536
537   template <class OtherDerived, class OtherBuf>
538   explicit Cursor(const detail::CursorBase<OtherDerived, OtherBuf>& cursor)
539     : detail::CursorBase<Cursor, const IOBuf>(cursor) {}
540 };
541
542 namespace detail {
543
544 template <class Derived>
545 class Writable {
546  public:
547   template <class T>
548   typename std::enable_if<std::is_arithmetic<T>::value>::type
549   write(T value) {
550     const uint8_t* u8 = reinterpret_cast<const uint8_t*>(&value);
551     Derived* d = static_cast<Derived*>(this);
552     d->push(u8, sizeof(T));
553   }
554
555   template <class T>
556   void writeBE(T value) {
557     Derived* d = static_cast<Derived*>(this);
558     d->write(Endian::big(value));
559   }
560
561   template <class T>
562   void writeLE(T value) {
563     Derived* d = static_cast<Derived*>(this);
564     d->write(Endian::little(value));
565   }
566
567   void push(const uint8_t* buf, size_t len) {
568     Derived* d = static_cast<Derived*>(this);
569     if (d->pushAtMost(buf, len) != len) {
570       throw std::out_of_range("overflow");
571     }
572   }
573
574   void push(ByteRange buf) {
575     if (this->pushAtMost(buf) != buf.size()) {
576       throw std::out_of_range("overflow");
577     }
578   }
579
580   size_t pushAtMost(ByteRange buf) {
581     Derived* d = static_cast<Derived*>(this);
582     return d->pushAtMost(buf.data(), buf.size());
583   }
584
585   /**
586    * push len bytes of data from input cursor, data could be in an IOBuf chain.
587    * If input cursor contains less than len bytes, or this cursor has less than
588    * len bytes writable space, an out_of_range exception will be thrown.
589    */
590   void push(Cursor cursor, size_t len) {
591     if (this->pushAtMost(cursor, len) != len) {
592       throw std::out_of_range("overflow");
593     }
594   }
595
596   size_t pushAtMost(Cursor cursor, size_t len) {
597     size_t written = 0;
598     for(;;) {
599       auto currentBuffer = cursor.peekBytes();
600       const uint8_t* crtData = currentBuffer.data();
601       size_t available = currentBuffer.size();
602       if (available == 0) {
603         // end of buffer chain
604         return written;
605       }
606       // all data is in current buffer
607       if (available >= len) {
608         this->push(crtData, len);
609         cursor.skip(len);
610         return written + len;
611       }
612
613       // write the whole current IOBuf
614       this->push(crtData, available);
615       cursor.skip(available);
616       written += available;
617       len -= available;
618     }
619   }
620 };
621
622 } // namespace detail
623
624 enum class CursorAccess {
625   PRIVATE,
626   UNSHARE
627 };
628
629 template <CursorAccess access>
630 class RWCursor
631   : public detail::CursorBase<RWCursor<access>, IOBuf>,
632     public detail::Writable<RWCursor<access>> {
633   friend class detail::CursorBase<RWCursor<access>, IOBuf>;
634  public:
635   explicit RWCursor(IOBuf* buf)
636     : detail::CursorBase<RWCursor<access>, IOBuf>(buf),
637       maybeShared_(true) {}
638
639   template <class OtherDerived, class OtherBuf>
640   explicit RWCursor(const detail::CursorBase<OtherDerived, OtherBuf>& cursor)
641     : detail::CursorBase<RWCursor<access>, IOBuf>(cursor),
642       maybeShared_(true) {}
643   /**
644    * Gather at least n bytes contiguously into the current buffer,
645    * by coalescing subsequent buffers from the chain as necessary.
646    */
647   void gather(size_t n) {
648     // Forbid attempts to gather beyond the end of this IOBuf chain.
649     // Otherwise we could try to coalesce the head of the chain and end up
650     // accidentally freeing it, invalidating the pointer owned by external
651     // code.
652     //
653     // If crtBuf_ == head() then IOBuf::gather() will perform all necessary
654     // checking.  We only have to perform an explicit check here when calling
655     // gather() on a non-head element.
656     if (this->crtBuf_ != this->head() && this->totalLength() < n) {
657       throw std::overflow_error("cannot gather() past the end of the chain");
658     }
659     this->crtBuf_->gather(this->offset_ + n);
660   }
661   void gatherAtMost(size_t n) {
662     size_t size = std::min(n, this->totalLength());
663     return this->crtBuf_->gather(this->offset_ + size);
664   }
665
666   using detail::Writable<RWCursor<access>>::pushAtMost;
667   size_t pushAtMost(const uint8_t* buf, size_t len) {
668     size_t copied = 0;
669     for (;;) {
670       // Fast path: the current buffer is big enough.
671       size_t available = this->length();
672       if (LIKELY(available >= len)) {
673         if (access == CursorAccess::UNSHARE) {
674           maybeUnshare();
675         }
676         memcpy(writableData(), buf, len);
677         this->offset_ += len;
678         return copied + len;
679       }
680
681       if (access == CursorAccess::UNSHARE) {
682         maybeUnshare();
683       }
684       memcpy(writableData(), buf, available);
685       copied += available;
686       if (UNLIKELY(!this->tryAdvanceBuffer())) {
687         return copied;
688       }
689       buf += available;
690       len -= available;
691     }
692   }
693
694   void insert(std::unique_ptr<folly::IOBuf> buf) {
695     folly::IOBuf* nextBuf;
696     if (this->offset_ == 0) {
697       // Can just prepend
698       nextBuf = this->crtBuf_;
699       this->crtBuf_->prependChain(std::move(buf));
700     } else {
701       std::unique_ptr<folly::IOBuf> remaining;
702       if (this->crtBuf_->length() - this->offset_ > 0) {
703         // Need to split current IOBuf in two.
704         remaining = this->crtBuf_->cloneOne();
705         remaining->trimStart(this->offset_);
706         nextBuf = remaining.get();
707         buf->prependChain(std::move(remaining));
708       } else {
709         // Can just append
710         nextBuf = this->crtBuf_->next();
711       }
712       this->crtBuf_->trimEnd(this->length());
713       this->crtBuf_->appendChain(std::move(buf));
714     }
715     // Jump past the new links
716     this->offset_ = 0;
717     this->crtBuf_ = nextBuf;
718   }
719
720   uint8_t* writableData() {
721     return this->crtBuf_->writableData() + this->offset_;
722   }
723
724  private:
725   void maybeUnshare() {
726     if (UNLIKELY(maybeShared_)) {
727       this->crtBuf_->unshareOne();
728       maybeShared_ = false;
729     }
730   }
731
732   void advanceDone() {
733     maybeShared_ = true;
734   }
735
736   bool maybeShared_;
737 };
738
739 typedef RWCursor<CursorAccess::PRIVATE> RWPrivateCursor;
740 typedef RWCursor<CursorAccess::UNSHARE> RWUnshareCursor;
741
742 /**
743  * Append to the end of a buffer chain, growing the chain (by allocating new
744  * buffers) in increments of at least growth bytes every time.  Won't grow
745  * (and push() and ensure() will throw) if growth == 0.
746  *
747  * TODO(tudorb): add a flavor of Appender that reallocates one IOBuf instead
748  * of chaining.
749  */
750 class Appender : public detail::Writable<Appender> {
751  public:
752   Appender(IOBuf* buf, uint64_t growth)
753     : buffer_(buf),
754       crtBuf_(buf->prev()),
755       growth_(growth) {
756   }
757
758   uint8_t* writableData() {
759     return crtBuf_->writableTail();
760   }
761
762   size_t length() const {
763     return crtBuf_->tailroom();
764   }
765
766   /**
767    * Mark n bytes (must be <= length()) as appended, as per the
768    * IOBuf::append() method.
769    */
770   void append(size_t n) {
771     crtBuf_->append(n);
772   }
773
774   /**
775    * Ensure at least n contiguous bytes available to write.
776    * Postcondition: length() >= n.
777    */
778   void ensure(uint64_t n) {
779     if (LIKELY(length() >= n)) {
780       return;
781     }
782
783     // Waste the rest of the current buffer and allocate a new one.
784     // Don't make it too small, either.
785     if (growth_ == 0) {
786       throw std::out_of_range("can't grow buffer chain");
787     }
788
789     n = std::max(n, growth_);
790     buffer_->prependChain(IOBuf::create(n));
791     crtBuf_ = buffer_->prev();
792   }
793
794   using detail::Writable<Appender>::pushAtMost;
795   size_t pushAtMost(const uint8_t* buf, size_t len) {
796     size_t copied = 0;
797     for (;;) {
798       // Fast path: it all fits in one buffer.
799       size_t available = length();
800       if (LIKELY(available >= len)) {
801         memcpy(writableData(), buf, len);
802         append(len);
803         return copied + len;
804       }
805
806       memcpy(writableData(), buf, available);
807       append(available);
808       copied += available;
809       if (UNLIKELY(!tryGrowChain())) {
810         return copied;
811       }
812       buf += available;
813       len -= available;
814     }
815   }
816
817   /*
818    * Append to the end of this buffer, using a printf() style
819    * format specifier.
820    *
821    * Note that folly/Format.h provides nicer and more type-safe mechanisms
822    * for formatting strings, which should generally be preferred over
823    * printf-style formatting.  Appender objects can be used directly as an
824    * output argument for Formatter objects.  For example:
825    *
826    *   Appender app(&iobuf);
827    *   format("{} {}", "hello", "world")(app);
828    *
829    * However, printf-style strings are still needed when dealing with existing
830    * third-party code in some cases.
831    *
832    * This will always add a nul-terminating character after the end
833    * of the output.  However, the buffer data length will only be updated to
834    * include the data itself.  The nul terminator will be the first byte in the
835    * buffer tailroom.
836    *
837    * This method may throw exceptions on error.
838    */
839   void printf(FOLLY_PRINTF_FORMAT const char* fmt, ...)
840     FOLLY_PRINTF_FORMAT_ATTR(2, 3);
841
842   void vprintf(const char* fmt, va_list ap);
843
844   /*
845    * Calling an Appender object with a StringPiece will append the string
846    * piece.  This allows Appender objects to be used directly with
847    * Formatter.
848    */
849   void operator()(StringPiece sp) {
850     push(ByteRange(sp));
851   }
852
853  private:
854   bool tryGrowChain() {
855     assert(crtBuf_->next() == buffer_);
856     if (growth_ == 0) {
857       return false;
858     }
859
860     buffer_->prependChain(IOBuf::create(growth_));
861     crtBuf_ = buffer_->prev();
862     return true;
863   }
864
865   IOBuf* buffer_;
866   IOBuf* crtBuf_;
867   uint64_t growth_;
868 };
869
870 class QueueAppender : public detail::Writable<QueueAppender> {
871  public:
872   /**
873    * Create an Appender that writes to a IOBufQueue.  When we allocate
874    * space in the queue, we grow no more than growth bytes at once
875    * (unless you call ensure() with a bigger value yourself).
876    */
877   QueueAppender(IOBufQueue* queue, uint64_t growth) {
878     reset(queue, growth);
879   }
880
881   void reset(IOBufQueue* queue, uint64_t growth) {
882     queue_ = queue;
883     growth_ = growth;
884   }
885
886   uint8_t* writableData() {
887     return static_cast<uint8_t*>(queue_->writableTail());
888   }
889
890   size_t length() const { return queue_->tailroom(); }
891
892   void append(size_t n) { queue_->postallocate(n); }
893
894   // Ensure at least n contiguous; can go above growth_, throws if
895   // not enough room.
896   void ensure(uint64_t n) { queue_->preallocate(n, growth_); }
897
898   template <class T>
899   typename std::enable_if<std::is_arithmetic<T>::value>::type
900   write(T value) {
901     // We can't fail.
902     auto p = queue_->preallocate(sizeof(T), growth_);
903     storeUnaligned(p.first, value);
904     queue_->postallocate(sizeof(T));
905   }
906
907   using detail::Writable<QueueAppender>::pushAtMost;
908   size_t pushAtMost(const uint8_t* buf, size_t len) {
909     size_t remaining = len;
910     while (remaining != 0) {
911       auto p = queue_->preallocate(std::min(remaining, growth_),
912                                    growth_,
913                                    remaining);
914       memcpy(p.first, buf, p.second);
915       queue_->postallocate(p.second);
916       buf += p.second;
917       remaining -= p.second;
918     }
919
920     return len;
921   }
922
923   void insert(std::unique_ptr<folly::IOBuf> buf) {
924     if (buf) {
925       queue_->append(std::move(buf), true);
926     }
927   }
928
929   void insert(const folly::IOBuf& buf) {
930     insert(buf.clone());
931   }
932
933  private:
934   folly::IOBufQueue* queue_;
935   size_t growth_;
936 };
937
938 }}  // folly::io
939
940 #include <folly/io/Cursor-inl.h>