5e1ce527b5c0ed28548471280460df7a719af436
[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     std::string str;
234
235     while (!isAtEnd()) {
236       const uint8_t* buf = data();
237       size_t buflen = length();
238
239       size_t i = 0;
240       while (i < buflen && buf[i] != termChar) {
241         ++i;
242
243         // Do this check after incrementing 'i', as even though we start at the
244         // 0 byte, it still represents a single character
245         if (str.length() + i >= maxLength) {
246           throw std::length_error("string overflow");
247         }
248       }
249
250       str.append(reinterpret_cast<const char*>(buf), i);
251       if (i < buflen) {
252         skip(i + 1);
253         return str;
254       }
255
256       skip(i);
257     }
258     throw std::out_of_range("terminator not found");
259   }
260
261   size_t skipAtMost(size_t len) {
262     if (LIKELY(length() >= len)) {
263       offset_ += len;
264       advanceBufferIfEmpty();
265       return len;
266     }
267     return skipAtMostSlow(len);
268   }
269
270   void skip(size_t len) {
271     if (LIKELY(length() >= len)) {
272       offset_ += len;
273       advanceBufferIfEmpty();
274     } else {
275       skipSlow(len);
276     }
277   }
278
279   size_t pullAtMost(void* buf, size_t len) {
280     // Fast path: it all fits in one buffer.
281     if (LIKELY(length() >= len)) {
282       memcpy(buf, data(), len);
283       offset_ += len;
284       advanceBufferIfEmpty();
285       return len;
286     }
287     return pullAtMostSlow(buf, len);
288   }
289
290   void pull(void* buf, size_t len) {
291     if (LIKELY(length() >= len)) {
292       memcpy(buf, data(), len);
293       offset_ += len;
294       advanceBufferIfEmpty();
295     } else {
296       pullSlow(buf, len);
297     }
298   }
299
300   /**
301    * Return the available data in the current buffer.
302    * If you want to gather more data from the chain into a contiguous region
303    * (for hopefully zero-copy access), use gather() before peekBytes().
304    */
305   ByteRange peekBytes() {
306     // Ensure that we're pointing to valid data
307     size_t available = length();
308     while (UNLIKELY(available == 0 && tryAdvanceBuffer())) {
309       available = length();
310     }
311     return ByteRange{data(), available};
312   }
313
314   /**
315    * Alternate version of peekBytes() that returns a std::pair
316    * instead of a ByteRange.  (This method pre-dates ByteRange.)
317    *
318    * This function will eventually be deprecated.
319    */
320   std::pair<const uint8_t*, size_t> peek() {
321     auto bytes = peekBytes();
322     return std::make_pair(bytes.data(), bytes.size());
323   }
324
325   void clone(std::unique_ptr<folly::IOBuf>& buf, size_t len) {
326     if (UNLIKELY(cloneAtMost(buf, len) != len)) {
327       throw std::out_of_range("underflow");
328     }
329   }
330
331   void clone(folly::IOBuf& buf, size_t len) {
332     if (UNLIKELY(cloneAtMost(buf, len) != len)) {
333       throw std::out_of_range("underflow");
334     }
335   }
336
337   size_t cloneAtMost(folly::IOBuf& buf, size_t len) {
338     std::unique_ptr<folly::IOBuf> tmp;
339     size_t copied = 0;
340     for (int loopCount = 0; true; ++loopCount) {
341       // Fast path: it all fits in one buffer.
342       size_t available = length();
343       if (LIKELY(available >= len)) {
344         if (loopCount == 0) {
345           crtBuf_->cloneOneInto(buf);
346           buf.trimStart(offset_);
347           buf.trimEnd(buf.length() - len);
348         } else {
349           tmp = crtBuf_->cloneOne();
350           tmp->trimStart(offset_);
351           tmp->trimEnd(tmp->length() - len);
352           buf.prependChain(std::move(tmp));
353         }
354
355         offset_ += len;
356         advanceBufferIfEmpty();
357         return copied + len;
358       }
359
360       if (loopCount == 0) {
361         crtBuf_->cloneOneInto(buf);
362         buf.trimStart(offset_);
363       } else {
364         tmp = crtBuf_->cloneOne();
365         tmp->trimStart(offset_);
366         buf.prependChain(std::move(tmp));
367       }
368
369       copied += available;
370       if (UNLIKELY(!tryAdvanceBuffer())) {
371         return copied;
372       }
373       len -= available;
374     }
375   }
376
377   size_t cloneAtMost(std::unique_ptr<folly::IOBuf>& buf, size_t len) {
378     if (!buf) {
379       buf = make_unique<folly::IOBuf>();
380     }
381     return cloneAtMost(*buf, len);
382   }
383
384   /**
385    * Return the distance between two cursors.
386    */
387   size_t operator-(const CursorBase& other) const {
388     BufType *otherBuf = other.crtBuf_;
389     size_t len = 0;
390
391     if (otherBuf != crtBuf_) {
392       len += otherBuf->length() - other.offset_;
393
394       for (otherBuf = otherBuf->next();
395            otherBuf != crtBuf_ && otherBuf != other.buffer_;
396            otherBuf = otherBuf->next()) {
397         len += otherBuf->length();
398       }
399
400       if (otherBuf == other.buffer_) {
401         throw std::out_of_range("wrap-around");
402       }
403
404       len += offset_;
405     } else {
406       if (offset_ < other.offset_) {
407         throw std::out_of_range("underflow");
408       }
409
410       len += offset_ - other.offset_;
411     }
412
413     return len;
414   }
415
416   /**
417    * Return the distance from the given IOBuf to the this cursor.
418    */
419   size_t operator-(const BufType* buf) const {
420     size_t len = 0;
421
422     BufType *curBuf = buf;
423     while (curBuf != crtBuf_) {
424       len += curBuf->length();
425       curBuf = curBuf->next();
426       if (curBuf == buf || curBuf == buffer_) {
427         throw std::out_of_range("wrap-around");
428       }
429     }
430
431     len += offset_;
432     return len;
433   }
434
435  protected:
436   ~CursorBase() { }
437
438   BufType* head() {
439     return buffer_;
440   }
441
442   bool tryAdvanceBuffer() {
443     BufType* nextBuf = crtBuf_->next();
444     if (UNLIKELY(nextBuf == buffer_)) {
445       offset_ = crtBuf_->length();
446       return false;
447     }
448
449     offset_ = 0;
450     crtBuf_ = nextBuf;
451     static_cast<Derived*>(this)->advanceDone();
452     return true;
453   }
454
455   void advanceBufferIfEmpty() {
456     if (length() == 0) {
457       tryAdvanceBuffer();
458     }
459   }
460
461   BufType* crtBuf_;
462   size_t offset_ = 0;
463
464  private:
465   void readFixedStringSlow(std::string* str, size_t len) {
466     for (size_t available; (available = length()) < len; ) {
467       str->append(reinterpret_cast<const char*>(data()), available);
468       if (UNLIKELY(!tryAdvanceBuffer())) {
469         throw std::out_of_range("string underflow");
470       }
471       len -= available;
472     }
473     str->append(reinterpret_cast<const char*>(data()), len);
474     offset_ += len;
475     advanceBufferIfEmpty();
476   }
477
478   size_t pullAtMostSlow(void* buf, size_t len) {
479     uint8_t* p = reinterpret_cast<uint8_t*>(buf);
480     size_t copied = 0;
481     for (size_t available; (available = length()) < len; ) {
482       memcpy(p, data(), available);
483       copied += available;
484       if (UNLIKELY(!tryAdvanceBuffer())) {
485         return copied;
486       }
487       p += available;
488       len -= available;
489     }
490     memcpy(p, data(), len);
491     offset_ += len;
492     advanceBufferIfEmpty();
493     return copied + len;
494   }
495
496   void pullSlow(void* buf, size_t len) {
497     if (UNLIKELY(pullAtMostSlow(buf, len) != len)) {
498       throw std::out_of_range("underflow");
499     }
500   }
501
502   size_t skipAtMostSlow(size_t len) {
503     size_t skipped = 0;
504     for (size_t available; (available = length()) < len; ) {
505       skipped += available;
506       if (UNLIKELY(!tryAdvanceBuffer())) {
507         return skipped;
508       }
509       len -= available;
510     }
511     offset_ += len;
512     advanceBufferIfEmpty();
513     return skipped + len;
514   }
515
516   void skipSlow(size_t len) {
517     if (UNLIKELY(skipAtMostSlow(len) != len)) {
518       throw std::out_of_range("underflow");
519     }
520   }
521
522   void advanceDone() {
523   }
524
525   BufType* buffer_;
526 };
527
528 }  // namespace detail
529
530 class Cursor : public detail::CursorBase<Cursor, const IOBuf> {
531  public:
532   explicit Cursor(const IOBuf* buf)
533     : detail::CursorBase<Cursor, const IOBuf>(buf) {}
534
535   template <class OtherDerived, class OtherBuf>
536   explicit Cursor(const detail::CursorBase<OtherDerived, OtherBuf>& cursor)
537     : detail::CursorBase<Cursor, const IOBuf>(cursor) {}
538 };
539
540 namespace detail {
541
542 template <class Derived>
543 class Writable {
544  public:
545   template <class T>
546   typename std::enable_if<std::is_arithmetic<T>::value>::type
547   write(T value) {
548     const uint8_t* u8 = reinterpret_cast<const uint8_t*>(&value);
549     Derived* d = static_cast<Derived*>(this);
550     d->push(u8, sizeof(T));
551   }
552
553   template <class T>
554   void writeBE(T value) {
555     Derived* d = static_cast<Derived*>(this);
556     d->write(Endian::big(value));
557   }
558
559   template <class T>
560   void writeLE(T value) {
561     Derived* d = static_cast<Derived*>(this);
562     d->write(Endian::little(value));
563   }
564
565   void push(const uint8_t* buf, size_t len) {
566     Derived* d = static_cast<Derived*>(this);
567     if (d->pushAtMost(buf, len) != len) {
568       throw std::out_of_range("overflow");
569     }
570   }
571
572   void push(ByteRange buf) {
573     if (this->pushAtMost(buf) != buf.size()) {
574       throw std::out_of_range("overflow");
575     }
576   }
577
578   size_t pushAtMost(ByteRange buf) {
579     Derived* d = static_cast<Derived*>(this);
580     return d->pushAtMost(buf.data(), buf.size());
581   }
582
583   /**
584    * push len bytes of data from input cursor, data could be in an IOBuf chain.
585    * If input cursor contains less than len bytes, or this cursor has less than
586    * len bytes writable space, an out_of_range exception will be thrown.
587    */
588   void push(Cursor cursor, size_t len) {
589     if (this->pushAtMost(cursor, len) != len) {
590       throw std::out_of_range("overflow");
591     }
592   }
593
594   size_t pushAtMost(Cursor cursor, size_t len) {
595     size_t written = 0;
596     for(;;) {
597       auto currentBuffer = cursor.peekBytes();
598       const uint8_t* crtData = currentBuffer.data();
599       size_t available = currentBuffer.size();
600       if (available == 0) {
601         // end of buffer chain
602         return written;
603       }
604       // all data is in current buffer
605       if (available >= len) {
606         this->push(crtData, len);
607         cursor.skip(len);
608         return written + len;
609       }
610
611       // write the whole current IOBuf
612       this->push(crtData, available);
613       cursor.skip(available);
614       written += available;
615       len -= available;
616     }
617   }
618 };
619
620 } // namespace detail
621
622 enum class CursorAccess {
623   PRIVATE,
624   UNSHARE
625 };
626
627 template <CursorAccess access>
628 class RWCursor
629   : public detail::CursorBase<RWCursor<access>, IOBuf>,
630     public detail::Writable<RWCursor<access>> {
631   friend class detail::CursorBase<RWCursor<access>, IOBuf>;
632  public:
633   explicit RWCursor(IOBuf* buf)
634     : detail::CursorBase<RWCursor<access>, IOBuf>(buf),
635       maybeShared_(true) {}
636
637   template <class OtherDerived, class OtherBuf>
638   explicit RWCursor(const detail::CursorBase<OtherDerived, OtherBuf>& cursor)
639     : detail::CursorBase<RWCursor<access>, IOBuf>(cursor),
640       maybeShared_(true) {}
641   /**
642    * Gather at least n bytes contiguously into the current buffer,
643    * by coalescing subsequent buffers from the chain as necessary.
644    */
645   void gather(size_t n) {
646     // Forbid attempts to gather beyond the end of this IOBuf chain.
647     // Otherwise we could try to coalesce the head of the chain and end up
648     // accidentally freeing it, invalidating the pointer owned by external
649     // code.
650     //
651     // If crtBuf_ == head() then IOBuf::gather() will perform all necessary
652     // checking.  We only have to perform an explicit check here when calling
653     // gather() on a non-head element.
654     if (this->crtBuf_ != this->head() && this->totalLength() < n) {
655       throw std::overflow_error("cannot gather() past the end of the chain");
656     }
657     this->crtBuf_->gather(this->offset_ + n);
658   }
659   void gatherAtMost(size_t n) {
660     size_t size = std::min(n, this->totalLength());
661     return this->crtBuf_->gather(this->offset_ + size);
662   }
663
664   using detail::Writable<RWCursor<access>>::pushAtMost;
665   size_t pushAtMost(const uint8_t* buf, size_t len) {
666     size_t copied = 0;
667     for (;;) {
668       // Fast path: the current buffer is big enough.
669       size_t available = this->length();
670       if (LIKELY(available >= len)) {
671         if (access == CursorAccess::UNSHARE) {
672           maybeUnshare();
673         }
674         memcpy(writableData(), buf, len);
675         this->offset_ += len;
676         return copied + len;
677       }
678
679       if (access == CursorAccess::UNSHARE) {
680         maybeUnshare();
681       }
682       memcpy(writableData(), buf, available);
683       copied += available;
684       if (UNLIKELY(!this->tryAdvanceBuffer())) {
685         return copied;
686       }
687       buf += available;
688       len -= available;
689     }
690   }
691
692   void insert(std::unique_ptr<folly::IOBuf> buf) {
693     folly::IOBuf* nextBuf;
694     if (this->offset_ == 0) {
695       // Can just prepend
696       nextBuf = this->crtBuf_;
697       this->crtBuf_->prependChain(std::move(buf));
698     } else {
699       std::unique_ptr<folly::IOBuf> remaining;
700       if (this->crtBuf_->length() - this->offset_ > 0) {
701         // Need to split current IOBuf in two.
702         remaining = this->crtBuf_->cloneOne();
703         remaining->trimStart(this->offset_);
704         nextBuf = remaining.get();
705         buf->prependChain(std::move(remaining));
706       } else {
707         // Can just append
708         nextBuf = this->crtBuf_->next();
709       }
710       this->crtBuf_->trimEnd(this->length());
711       this->crtBuf_->appendChain(std::move(buf));
712     }
713     // Jump past the new links
714     this->offset_ = 0;
715     this->crtBuf_ = nextBuf;
716   }
717
718   uint8_t* writableData() {
719     return this->crtBuf_->writableData() + this->offset_;
720   }
721
722  private:
723   void maybeUnshare() {
724     if (UNLIKELY(maybeShared_)) {
725       this->crtBuf_->unshareOne();
726       maybeShared_ = false;
727     }
728   }
729
730   void advanceDone() {
731     maybeShared_ = true;
732   }
733
734   bool maybeShared_;
735 };
736
737 typedef RWCursor<CursorAccess::PRIVATE> RWPrivateCursor;
738 typedef RWCursor<CursorAccess::UNSHARE> RWUnshareCursor;
739
740 /**
741  * Append to the end of a buffer chain, growing the chain (by allocating new
742  * buffers) in increments of at least growth bytes every time.  Won't grow
743  * (and push() and ensure() will throw) if growth == 0.
744  *
745  * TODO(tudorb): add a flavor of Appender that reallocates one IOBuf instead
746  * of chaining.
747  */
748 class Appender : public detail::Writable<Appender> {
749  public:
750   Appender(IOBuf* buf, uint64_t growth)
751     : buffer_(buf),
752       crtBuf_(buf->prev()),
753       growth_(growth) {
754   }
755
756   uint8_t* writableData() {
757     return crtBuf_->writableTail();
758   }
759
760   size_t length() const {
761     return crtBuf_->tailroom();
762   }
763
764   /**
765    * Mark n bytes (must be <= length()) as appended, as per the
766    * IOBuf::append() method.
767    */
768   void append(size_t n) {
769     crtBuf_->append(n);
770   }
771
772   /**
773    * Ensure at least n contiguous bytes available to write.
774    * Postcondition: length() >= n.
775    */
776   void ensure(uint64_t n) {
777     if (LIKELY(length() >= n)) {
778       return;
779     }
780
781     // Waste the rest of the current buffer and allocate a new one.
782     // Don't make it too small, either.
783     if (growth_ == 0) {
784       throw std::out_of_range("can't grow buffer chain");
785     }
786
787     n = std::max(n, growth_);
788     buffer_->prependChain(IOBuf::create(n));
789     crtBuf_ = buffer_->prev();
790   }
791
792   using detail::Writable<Appender>::pushAtMost;
793   size_t pushAtMost(const uint8_t* buf, size_t len) {
794     size_t copied = 0;
795     for (;;) {
796       // Fast path: it all fits in one buffer.
797       size_t available = length();
798       if (LIKELY(available >= len)) {
799         memcpy(writableData(), buf, len);
800         append(len);
801         return copied + len;
802       }
803
804       memcpy(writableData(), buf, available);
805       append(available);
806       copied += available;
807       if (UNLIKELY(!tryGrowChain())) {
808         return copied;
809       }
810       buf += available;
811       len -= available;
812     }
813   }
814
815   /*
816    * Append to the end of this buffer, using a printf() style
817    * format specifier.
818    *
819    * Note that folly/Format.h provides nicer and more type-safe mechanisms
820    * for formatting strings, which should generally be preferred over
821    * printf-style formatting.  Appender objects can be used directly as an
822    * output argument for Formatter objects.  For example:
823    *
824    *   Appender app(&iobuf);
825    *   format("{} {}", "hello", "world")(app);
826    *
827    * However, printf-style strings are still needed when dealing with existing
828    * third-party code in some cases.
829    *
830    * This will always add a nul-terminating character after the end
831    * of the output.  However, the buffer data length will only be updated to
832    * include the data itself.  The nul terminator will be the first byte in the
833    * buffer tailroom.
834    *
835    * This method may throw exceptions on error.
836    */
837   void printf(FOLLY_PRINTF_FORMAT const char* fmt, ...)
838     FOLLY_PRINTF_FORMAT_ATTR(2, 3);
839
840   void vprintf(const char* fmt, va_list ap);
841
842   /*
843    * Calling an Appender object with a StringPiece will append the string
844    * piece.  This allows Appender objects to be used directly with
845    * Formatter.
846    */
847   void operator()(StringPiece sp) {
848     push(ByteRange(sp));
849   }
850
851  private:
852   bool tryGrowChain() {
853     assert(crtBuf_->next() == buffer_);
854     if (growth_ == 0) {
855       return false;
856     }
857
858     buffer_->prependChain(IOBuf::create(growth_));
859     crtBuf_ = buffer_->prev();
860     return true;
861   }
862
863   IOBuf* buffer_;
864   IOBuf* crtBuf_;
865   uint64_t growth_;
866 };
867
868 class QueueAppender : public detail::Writable<QueueAppender> {
869  public:
870   /**
871    * Create an Appender that writes to a IOBufQueue.  When we allocate
872    * space in the queue, we grow no more than growth bytes at once
873    * (unless you call ensure() with a bigger value yourself).
874    */
875   QueueAppender(IOBufQueue* queue, uint64_t growth) {
876     reset(queue, growth);
877   }
878
879   void reset(IOBufQueue* queue, uint64_t growth) {
880     queue_ = queue;
881     growth_ = growth;
882   }
883
884   uint8_t* writableData() {
885     return static_cast<uint8_t*>(queue_->writableTail());
886   }
887
888   size_t length() const { return queue_->tailroom(); }
889
890   void append(size_t n) { queue_->postallocate(n); }
891
892   // Ensure at least n contiguous; can go above growth_, throws if
893   // not enough room.
894   void ensure(uint64_t n) { queue_->preallocate(n, growth_); }
895
896   template <class T>
897   typename std::enable_if<std::is_arithmetic<T>::value>::type
898   write(T value) {
899     // We can't fail.
900     auto p = queue_->preallocate(sizeof(T), growth_);
901     storeUnaligned(p.first, value);
902     queue_->postallocate(sizeof(T));
903   }
904
905   using detail::Writable<QueueAppender>::pushAtMost;
906   size_t pushAtMost(const uint8_t* buf, size_t len) {
907     size_t remaining = len;
908     while (remaining != 0) {
909       auto p = queue_->preallocate(std::min(remaining, growth_),
910                                    growth_,
911                                    remaining);
912       memcpy(p.first, buf, p.second);
913       queue_->postallocate(p.second);
914       buf += p.second;
915       remaining -= p.second;
916     }
917
918     return len;
919   }
920
921   void insert(std::unique_ptr<folly::IOBuf> buf) {
922     if (buf) {
923       queue_->append(std::move(buf), true);
924     }
925   }
926
927   void insert(const folly::IOBuf& buf) {
928     insert(buf.clone());
929   }
930
931  private:
932   folly::IOBufQueue* queue_;
933   size_t growth_;
934 };
935
936 }}  // folly::io