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