bdaeabe3d292bf0a9d67f2b3e9be1a9fd34b3783
[folly.git] / folly / io / Cursor.h
1 /*
2  * Copyright 2013-present 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 #pragma once
17
18 #include <cassert>
19 #include <cstdarg>
20 #include <cstring>
21 #include <memory>
22 #include <stdexcept>
23 #include <type_traits>
24
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>
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 chain
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 {
51 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     if (crtBuf_) {
62       crtPos_ = crtBegin_ = crtBuf_->data();
63       crtEnd_ = crtBuf_->tail();
64     }
65   }
66
67   /**
68    * Copy constructor.
69    *
70    * This also allows constructing a CursorBase from other derived types.
71    * For instance, this allows constructing a Cursor from an RWPrivateCursor.
72    */
73   template <class OtherDerived, class OtherBuf>
74   explicit CursorBase(const CursorBase<OtherDerived, OtherBuf>& cursor)
75       : crtBuf_(cursor.crtBuf_),
76         crtBegin_(cursor.crtBegin_),
77         crtEnd_(cursor.crtEnd_),
78         crtPos_(cursor.crtPos_),
79         buffer_(cursor.buffer_) {}
80
81   /**
82    * Reset cursor to point to a new buffer.
83    */
84   void reset(BufType* buf) {
85     crtBuf_ = buf;
86     buffer_ = buf;
87     if (crtBuf_) {
88       crtPos_ = crtBegin_ = crtBuf_->data();
89       crtEnd_ = crtBuf_->tail();
90     }
91   }
92
93   const uint8_t* data() const {
94     return crtPos_;
95   }
96
97   /**
98    * Return the remaining space available in the current IOBuf.
99    *
100    * May return 0 if the cursor is at the end of an IOBuf.  Use peekBytes()
101    * instead if you want to avoid this.  peekBytes() will advance to the next
102    * non-empty IOBuf (up to the end of the chain) if the cursor is currently
103    * pointing at the end of a buffer.
104    */
105   size_t length() const {
106     return crtEnd_ - crtPos_;
107   }
108
109   /**
110    * Return the space available until the end of the entire IOBuf chain.
111    */
112   size_t totalLength() const {
113     if (crtBuf_ == buffer_) {
114       return crtBuf_->computeChainDataLength() - (crtPos_ - crtBegin_);
115     }
116     CursorBase end(buffer_->prev());
117     end.crtPos_ = end.crtEnd_;
118     return end - *this;
119   }
120
121   /**
122    * Return true if the cursor could advance the specified number of bytes
123    * from its current position.
124    * This is useful for applications that want to do checked reads instead of
125    * catching exceptions and is more efficient than using totalLength as it
126    * walks the minimal set of buffers in the chain to determine the result.
127    */
128   bool canAdvance(size_t amount) const {
129     const IOBuf* nextBuf = crtBuf_;
130     size_t available = length();
131     do {
132       if (available >= amount) {
133         return true;
134       }
135       amount -= available;
136       nextBuf = nextBuf->next();
137       available = nextBuf->length();
138     } while (nextBuf != buffer_);
139     return false;
140   }
141
142   /*
143    * Return true if the cursor is at the end of the entire IOBuf chain.
144    */
145   bool isAtEnd() const {
146     // Check for the simple cases first.
147     if (crtPos_ != crtEnd_) {
148       return false;
149     }
150     if (crtBuf_ == buffer_->prev()) {
151       return true;
152     }
153     // We are at the end of a buffer, but it isn't the last buffer.
154     // We might still be at the end if the remaining buffers in the chain are
155     // empty.
156     const IOBuf* buf = crtBuf_->next();;
157     while (buf != buffer_) {
158       if (buf->length() > 0) {
159         return false;
160       }
161       buf = buf->next();
162     }
163     return true;
164   }
165
166   /**
167    * Advances the cursor to the end of the entire IOBuf chain.
168    */
169   void advanceToEnd() {
170     crtBegin_ = buffer_->prev()->data();
171     crtPos_ = crtEnd_ = buffer_->prev()->tail();
172     if (crtBuf_ != buffer_->prev()) {
173       crtBuf_ = buffer_->prev();
174       static_cast<Derived*>(this)->advanceDone();
175     }
176   }
177
178   Derived& operator+=(size_t offset) {
179     Derived* p = static_cast<Derived*>(this);
180     p->skip(offset);
181     return *p;
182   }
183   Derived operator+(size_t offset) const {
184     Derived other(*this);
185     other.skip(offset);
186     return other;
187   }
188
189   Derived& operator-=(size_t offset) {
190     Derived* p = static_cast<Derived*>(this);
191     p->retreat(offset);
192     return *p;
193   }
194   Derived operator-(size_t offset) const {
195     Derived other(*this);
196     other.retreat(offset);
197     return other;
198   }
199
200   /**
201    * Compare cursors for equality/inequality.
202    *
203    * Two cursors are equal if they are pointing to the same location in the
204    * same IOBuf chain.
205    */
206   bool operator==(const Derived& other) const {
207     const IOBuf* crtBuf = crtBuf_;
208     auto crtPos = crtPos_;
209     // We can be pointing to the end of a buffer chunk, find first non-empty.
210     while (crtPos == crtBuf->tail() && crtBuf != buffer_->prev()) {
211       crtBuf = crtBuf->next();
212       crtPos = crtBuf->data();
213     }
214
215     const IOBuf* crtBufOther = other.crtBuf_;
216     auto crtPosOther = other.crtPos_;
217     // We can be pointing to the end of a buffer chunk, find first non-empty.
218     while (crtPosOther == crtBufOther->tail() &&
219            crtBufOther != other.buffer_->prev()) {
220       crtBufOther = crtBufOther->next();
221       crtPosOther = crtBufOther->data();
222     }
223     return (crtPos == crtPosOther) && (crtBuf == crtBufOther);
224   }
225   bool operator!=(const Derived& other) const {
226     return !operator==(other);
227   }
228
229   template <class T>
230   typename std::enable_if<std::is_arithmetic<T>::value, bool>::type tryRead(
231       T& val) {
232     if (LIKELY(crtPos_ + sizeof(T) <= crtEnd_)) {
233       val = loadUnaligned<T>(data());
234       crtPos_ += sizeof(T);
235       return true;
236     }
237     return pullAtMostSlow(&val, sizeof(T)) == sizeof(T);
238   }
239
240   template <class T>
241   bool tryReadBE(T& val) {
242     const bool result = tryRead(val);
243     val = Endian::big(val);
244     return result;
245   }
246
247   template <class T>
248   bool tryReadLE(T& val) {
249     const bool result = tryRead(val);
250     val = Endian::little(val);
251     return result;
252   }
253
254   template <class T>
255   T read() {
256     if (LIKELY(crtPos_ + sizeof(T) <= crtEnd_)) {
257       T val = loadUnaligned<T>(data());
258       crtPos_ += sizeof(T);
259       return val;
260     } else {
261       return readSlow<T>();
262     }
263   }
264
265   template <class T>
266   T readBE() {
267     return Endian::big(read<T>());
268   }
269
270   template <class T>
271   T readLE() {
272     return Endian::little(read<T>());
273   }
274
275   /**
276    * Read a fixed-length string.
277    *
278    * The std::string-based APIs should probably be avoided unless you
279    * ultimately want the data to live in an std::string. You're better off
280    * using the pull() APIs to copy into a raw buffer otherwise.
281    */
282   std::string readFixedString(size_t len) {
283     std::string str;
284     str.reserve(len);
285     if (LIKELY(length() >= len)) {
286       str.append(reinterpret_cast<const char*>(data()), len);
287       crtPos_ += len;
288     } else {
289       readFixedStringSlow(&str, len);
290     }
291     return str;
292   }
293
294   /**
295    * Read a string consisting of bytes until the given terminator character is
296    * seen. Raises an std::length_error if maxLength bytes have been processed
297    * before the terminator is seen.
298    *
299    * See comments in readFixedString() about when it's appropriate to use this
300    * vs. using pull().
301    */
302   std::string readTerminatedString(
303       char termChar = '\0',
304       size_t maxLength = std::numeric_limits<size_t>::max());
305
306   /*
307    * Read all bytes until the specified predicate returns true.
308    *
309    * The predicate will be called on each byte in turn, until it returns false
310    * or until the end of the IOBuf chain is reached.
311    *
312    * Returns the result as a string.
313    */
314   template <typename Predicate>
315   std::string readWhile(const Predicate& predicate);
316
317   /*
318    * Read all bytes until the specified predicate returns true.
319    *
320    * This is a more generic version of readWhile() takes an arbitrary Output
321    * object, and calls Output::append() with each chunk of matching data.
322    */
323   template <typename Predicate, typename Output>
324   void readWhile(const Predicate& predicate, Output& out);
325
326   /*
327    * Skip all bytes until the specified predicate returns true.
328    *
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.
331    */
332   template <typename Predicate>
333   void skipWhile(const Predicate& predicate);
334
335   size_t skipAtMost(size_t len) {
336     if (LIKELY(crtPos_ + len < crtEnd_)) {
337       crtPos_ += len;
338       return len;
339     }
340     return skipAtMostSlow(len);
341   }
342
343   void skip(size_t len) {
344     if (LIKELY(crtPos_ + len < crtEnd_)) {
345       crtPos_ += len;
346     } else {
347       skipSlow(len);
348     }
349   }
350
351   /**
352    * Skip bytes in the current IOBuf without advancing to the next one.
353    * Precondition: length() >= len
354    */
355   void skipNoAdvance(size_t len) {
356     DCHECK_LE(len, length());
357     crtPos_ += len;
358   }
359
360   size_t retreatAtMost(size_t len) {
361     if (len <= static_cast<size_t>(crtPos_ - crtBegin_)) {
362       crtPos_ -= len;
363       return len;
364     }
365     return retreatAtMostSlow(len);
366   }
367
368   void retreat(size_t len) {
369     if (len <= static_cast<size_t>(crtPos_ - crtBegin_)) {
370       crtPos_ -= len;
371     } else {
372       retreatSlow(len);
373     }
374   }
375
376   size_t pullAtMost(void* buf, size_t len) {
377     // Fast path: it all fits in one buffer.
378     if (LIKELY(crtPos_ + len <= crtEnd_)) {
379       memcpy(buf, data(), len);
380       crtPos_ += len;
381       return len;
382     }
383     return pullAtMostSlow(buf, len);
384   }
385
386   void pull(void* buf, size_t len) {
387     if (LIKELY(crtPos_ + len <= crtEnd_)) {
388       memcpy(buf, data(), len);
389       crtPos_ += len;
390     } else {
391       pullSlow(buf, len);
392     }
393   }
394
395   /**
396    * Return the available data in the current buffer.
397    * If you want to gather more data from the chain into a contiguous region
398    * (for hopefully zero-copy access), use gather() before peekBytes().
399    */
400   ByteRange peekBytes() {
401     // Ensure that we're pointing to valid data
402     size_t available = length();
403     while (UNLIKELY(available == 0 && tryAdvanceBuffer())) {
404       available = length();
405     }
406     return ByteRange{data(), available};
407   }
408
409   /**
410    * Alternate version of peekBytes() that returns a std::pair
411    * instead of a ByteRange.  (This method pre-dates ByteRange.)
412    *
413    * This function will eventually be deprecated.
414    */
415   std::pair<const uint8_t*, size_t> peek() {
416     auto bytes = peekBytes();
417     return std::make_pair(bytes.data(), bytes.size());
418   }
419
420   void clone(std::unique_ptr<folly::IOBuf>& buf, size_t len) {
421     if (UNLIKELY(cloneAtMost(buf, len) != len)) {
422       std::__throw_out_of_range("underflow");
423     }
424   }
425
426   void clone(folly::IOBuf& buf, size_t len) {
427     if (UNLIKELY(cloneAtMost(buf, len) != len)) {
428       std::__throw_out_of_range("underflow");
429     }
430   }
431
432   size_t cloneAtMost(folly::IOBuf& buf, size_t len) {
433     // We might be at the end of buffer.
434     advanceBufferIfEmpty();
435
436     std::unique_ptr<folly::IOBuf> tmp;
437     size_t copied = 0;
438     for (int loopCount = 0; true; ++loopCount) {
439       // Fast path: it all fits in one buffer.
440       size_t available = length();
441       if (LIKELY(available >= len)) {
442         if (loopCount == 0) {
443           crtBuf_->cloneOneInto(buf);
444           buf.trimStart(crtPos_ - crtBegin_);
445           buf.trimEnd(buf.length() - len);
446         } else {
447           tmp = crtBuf_->cloneOne();
448           tmp->trimStart(crtPos_ - crtBegin_);
449           tmp->trimEnd(tmp->length() - len);
450           buf.prependChain(std::move(tmp));
451         }
452
453         crtPos_ += len;
454         advanceBufferIfEmpty();
455         return copied + len;
456       }
457
458       if (loopCount == 0) {
459         crtBuf_->cloneOneInto(buf);
460         buf.trimStart(crtPos_ - crtBegin_);
461       } else {
462         tmp = crtBuf_->cloneOne();
463         tmp->trimStart(crtPos_ - crtBegin_);
464         buf.prependChain(std::move(tmp));
465       }
466
467       copied += available;
468       if (UNLIKELY(!tryAdvanceBuffer())) {
469         return copied;
470       }
471       len -= available;
472     }
473   }
474
475   size_t cloneAtMost(std::unique_ptr<folly::IOBuf>& buf, size_t len) {
476     if (!buf) {
477       buf = std::make_unique<folly::IOBuf>();
478     }
479     return cloneAtMost(*buf, len);
480   }
481
482   /**
483    * Return the distance between two cursors.
484    */
485   size_t operator-(const CursorBase& other) const {
486     BufType *otherBuf = other.crtBuf_;
487     size_t len = 0;
488
489     if (otherBuf != crtBuf_) {
490       len += other.crtEnd_ - other.crtPos_;
491
492       for (otherBuf = otherBuf->next();
493            otherBuf != crtBuf_ && otherBuf != other.buffer_;
494            otherBuf = otherBuf->next()) {
495         len += otherBuf->length();
496       }
497
498       if (otherBuf == other.buffer_) {
499         std::__throw_out_of_range("wrap-around");
500       }
501
502       len += crtPos_ - crtBegin_;
503     } else {
504       if (crtPos_ < other.crtPos_) {
505         std::__throw_out_of_range("underflow");
506       }
507
508       len += crtPos_ - other.crtPos_;
509     }
510
511     return len;
512   }
513
514   /**
515    * Return the distance from the given IOBuf to the this cursor.
516    */
517   size_t operator-(const BufType* buf) const {
518     size_t len = 0;
519
520     const BufType* curBuf = buf;
521     while (curBuf != crtBuf_) {
522       len += curBuf->length();
523       curBuf = curBuf->next();
524       if (curBuf == buf || curBuf == buffer_) {
525         std::__throw_out_of_range("wrap-around");
526       }
527     }
528
529     len += crtPos_ - crtBegin_;
530     return len;
531   }
532
533  protected:
534   ~CursorBase() { }
535
536   BufType* head() {
537     return buffer_;
538   }
539
540   bool tryAdvanceBuffer() {
541     BufType* nextBuf = crtBuf_->next();
542     if (UNLIKELY(nextBuf == buffer_)) {
543       crtPos_ = crtEnd_;
544       return false;
545     }
546
547     crtBuf_ = nextBuf;
548     crtPos_ = crtBegin_ = crtBuf_->data();
549     crtEnd_ = crtBuf_->tail();
550     static_cast<Derived*>(this)->advanceDone();
551     return true;
552   }
553
554   bool tryRetreatBuffer() {
555     if (UNLIKELY(crtBuf_ == buffer_)) {
556       crtPos_ = crtBegin_;
557       return false;
558     }
559     crtBuf_ = crtBuf_->prev();
560     crtBegin_ = crtBuf_->data();
561     crtPos_ = crtEnd_ = crtBuf_->tail();
562     static_cast<Derived*>(this)->advanceDone();
563     return true;
564   }
565
566   void advanceBufferIfEmpty() {
567     if (crtPos_ == crtEnd_) {
568       tryAdvanceBuffer();
569     }
570   }
571
572   BufType* crtBuf_;
573   const uint8_t* crtBegin_{nullptr};
574   const uint8_t* crtEnd_{nullptr};
575   const uint8_t* crtPos_{nullptr};
576
577  private:
578   template <class T>
579   FOLLY_NOINLINE T readSlow() {
580     T val;
581     pullSlow(&val, sizeof(T));
582     return val;
583   }
584
585   void readFixedStringSlow(std::string* str, size_t len) {
586     for (size_t available; (available = length()) < len; ) {
587       str->append(reinterpret_cast<const char*>(data()), available);
588       if (UNLIKELY(!tryAdvanceBuffer())) {
589         std::__throw_out_of_range("string underflow");
590       }
591       len -= available;
592     }
593     str->append(reinterpret_cast<const char*>(data()), len);
594     crtPos_ += len;
595     advanceBufferIfEmpty();
596   }
597
598   size_t pullAtMostSlow(void* buf, size_t len) {
599     uint8_t* p = reinterpret_cast<uint8_t*>(buf);
600     size_t copied = 0;
601     for (size_t available; (available = length()) < len; ) {
602       memcpy(p, data(), available);
603       copied += available;
604       if (UNLIKELY(!tryAdvanceBuffer())) {
605         return copied;
606       }
607       p += available;
608       len -= available;
609     }
610     memcpy(p, data(), len);
611     crtPos_ += len;
612     advanceBufferIfEmpty();
613     return copied + len;
614   }
615
616   void pullSlow(void* buf, size_t len) {
617     if (UNLIKELY(pullAtMostSlow(buf, len) != len)) {
618       std::__throw_out_of_range("underflow");
619     }
620   }
621
622   size_t skipAtMostSlow(size_t len) {
623     size_t skipped = 0;
624     for (size_t available; (available = length()) < len; ) {
625       skipped += available;
626       if (UNLIKELY(!tryAdvanceBuffer())) {
627         return skipped;
628       }
629       len -= available;
630     }
631     crtPos_ += len;
632     advanceBufferIfEmpty();
633     return skipped + len;
634   }
635
636   void skipSlow(size_t len) {
637     if (UNLIKELY(skipAtMostSlow(len) != len)) {
638       std::__throw_out_of_range("underflow");
639     }
640   }
641
642   size_t retreatAtMostSlow(size_t len) {
643     size_t retreated = 0;
644     for (size_t available; (available = crtPos_ - crtBegin_) < len;) {
645       retreated += available;
646       if (UNLIKELY(!tryRetreatBuffer())) {
647         return retreated;
648       }
649       len -= available;
650     }
651     crtPos_ -= len;
652     return retreated + len;
653   }
654
655   void retreatSlow(size_t len) {
656     if (UNLIKELY(retreatAtMostSlow(len) != len)) {
657       std::__throw_out_of_range("underflow");
658     }
659   }
660
661   void advanceDone() {
662   }
663
664   BufType* buffer_;
665 };
666
667 } // namespace detail
668
669 class Cursor : public detail::CursorBase<Cursor, const IOBuf> {
670  public:
671   explicit Cursor(const IOBuf* buf)
672     : detail::CursorBase<Cursor, const IOBuf>(buf) {}
673
674   template <class OtherDerived, class OtherBuf>
675   explicit Cursor(const detail::CursorBase<OtherDerived, OtherBuf>& cursor)
676     : detail::CursorBase<Cursor, const IOBuf>(cursor) {}
677 };
678
679 namespace detail {
680
681 template <class Derived>
682 class Writable {
683  public:
684   template <class T>
685   typename std::enable_if<std::is_arithmetic<T>::value>::type
686   write(T value) {
687     const uint8_t* u8 = reinterpret_cast<const uint8_t*>(&value);
688     Derived* d = static_cast<Derived*>(this);
689     d->push(u8, sizeof(T));
690   }
691
692   template <class T>
693   void writeBE(T value) {
694     Derived* d = static_cast<Derived*>(this);
695     d->write(Endian::big(value));
696   }
697
698   template <class T>
699   void writeLE(T value) {
700     Derived* d = static_cast<Derived*>(this);
701     d->write(Endian::little(value));
702   }
703
704   void push(const uint8_t* buf, size_t len) {
705     Derived* d = static_cast<Derived*>(this);
706     if (d->pushAtMost(buf, len) != len) {
707       std::__throw_out_of_range("overflow");
708     }
709   }
710
711   void push(ByteRange buf) {
712     if (this->pushAtMost(buf) != buf.size()) {
713       std::__throw_out_of_range("overflow");
714     }
715   }
716
717   size_t pushAtMost(ByteRange buf) {
718     Derived* d = static_cast<Derived*>(this);
719     return d->pushAtMost(buf.data(), buf.size());
720   }
721
722   /**
723    * push len bytes of data from input cursor, data could be in an IOBuf chain.
724    * If input cursor contains less than len bytes, or this cursor has less than
725    * len bytes writable space, an out_of_range exception will be thrown.
726    */
727   void push(Cursor cursor, size_t len) {
728     if (this->pushAtMost(cursor, len) != len) {
729       std::__throw_out_of_range("overflow");
730     }
731   }
732
733   size_t pushAtMost(Cursor cursor, size_t len) {
734     size_t written = 0;
735     for(;;) {
736       auto currentBuffer = cursor.peekBytes();
737       const uint8_t* crtData = currentBuffer.data();
738       size_t available = currentBuffer.size();
739       if (available == 0) {
740         // end of buffer chain
741         return written;
742       }
743       // all data is in current buffer
744       if (available >= len) {
745         this->push(crtData, len);
746         cursor.skip(len);
747         return written + len;
748       }
749
750       // write the whole current IOBuf
751       this->push(crtData, available);
752       cursor.skip(available);
753       written += available;
754       len -= available;
755     }
756   }
757 };
758
759 } // namespace detail
760
761 enum class CursorAccess {
762   PRIVATE,
763   UNSHARE
764 };
765
766 template <CursorAccess access>
767 class RWCursor
768   : public detail::CursorBase<RWCursor<access>, IOBuf>,
769     public detail::Writable<RWCursor<access>> {
770   friend class detail::CursorBase<RWCursor<access>, IOBuf>;
771  public:
772   explicit RWCursor(IOBuf* buf)
773     : detail::CursorBase<RWCursor<access>, IOBuf>(buf),
774       maybeShared_(true) {}
775
776   template <class OtherDerived, class OtherBuf>
777   explicit RWCursor(const detail::CursorBase<OtherDerived, OtherBuf>& cursor)
778     : detail::CursorBase<RWCursor<access>, IOBuf>(cursor),
779       maybeShared_(true) {}
780   /**
781    * Gather at least n bytes contiguously into the current buffer,
782    * by coalescing subsequent buffers from the chain as necessary.
783    */
784   void gather(size_t n) {
785     // Forbid attempts to gather beyond the end of this IOBuf chain.
786     // Otherwise we could try to coalesce the head of the chain and end up
787     // accidentally freeing it, invalidating the pointer owned by external
788     // code.
789     //
790     // If crtBuf_ == head() then IOBuf::gather() will perform all necessary
791     // checking.  We only have to perform an explicit check here when calling
792     // gather() on a non-head element.
793     if (this->crtBuf_ != this->head() && this->totalLength() < n) {
794       throw std::overflow_error("cannot gather() past the end of the chain");
795     }
796     size_t offset = this->crtPos_ - this->crtBegin_;
797     this->crtBuf_->gather(offset + n);
798     this->crtBegin_ = this->crtBuf_->data();
799     this->crtEnd_ = this->crtBuf_->tail();
800     this->crtPos_ = this->crtBegin_ + offset;
801   }
802   void gatherAtMost(size_t n) {
803     size_t size = std::min(n, this->totalLength());
804     size_t offset = this->crtPos_ - this->crtBegin_;
805     this->crtBuf_->gather(offset + size);
806     this->crtBegin_ = this->crtBuf_->data();
807     this->crtEnd_ = this->crtBuf_->tail();
808     this->crtPos_ = this->crtBegin_ + offset;
809   }
810
811   using detail::Writable<RWCursor<access>>::pushAtMost;
812   size_t pushAtMost(const uint8_t* buf, size_t len) {
813     // We have to explicitly check for an input length of 0.
814     // We support buf being nullptr in this case, but we need to avoid calling
815     // memcpy() with a null source pointer, since that is undefined behavior
816     // even if the length is 0.
817     if (len == 0) {
818       return 0;
819     }
820
821     size_t copied = 0;
822     for (;;) {
823       // Fast path: the current buffer is big enough.
824       size_t available = this->length();
825       if (LIKELY(available >= len)) {
826         if (access == CursorAccess::UNSHARE) {
827           maybeUnshare();
828         }
829         memcpy(writableData(), buf, len);
830         this->crtPos_ += len;
831         return copied + len;
832       }
833
834       if (access == CursorAccess::UNSHARE) {
835         maybeUnshare();
836       }
837       memcpy(writableData(), buf, available);
838       copied += available;
839       if (UNLIKELY(!this->tryAdvanceBuffer())) {
840         return copied;
841       }
842       buf += available;
843       len -= available;
844     }
845   }
846
847   void insert(std::unique_ptr<folly::IOBuf> buf) {
848     folly::IOBuf* nextBuf;
849     if (this->crtPos_ == this->crtBegin_) {
850       // Can just prepend
851       nextBuf = this->crtBuf_;
852       this->crtBuf_->prependChain(std::move(buf));
853     } else {
854       std::unique_ptr<folly::IOBuf> remaining;
855       if (this->crtPos_ != this->crtEnd_) {
856         // Need to split current IOBuf in two.
857         remaining = this->crtBuf_->cloneOne();
858         remaining->trimStart(this->crtPos_ - this->crtBegin_);
859         nextBuf = remaining.get();
860         buf->prependChain(std::move(remaining));
861       } else {
862         // Can just append
863         nextBuf = this->crtBuf_->next();
864       }
865       this->crtBuf_->trimEnd(this->length());
866       this->crtBuf_->appendChain(std::move(buf));
867
868       // Jump past the new links
869       this->crtBuf_ = nextBuf;
870       this->crtPos_ = this->crtBegin_ = this->crtBuf_->data();
871       this->crtEnd_ = this->crtBuf_->tail();
872     }
873   }
874
875   uint8_t* writableData() {
876     return this->crtBuf_->writableData() + (this->crtPos_ - this->crtBegin_);
877   }
878
879  private:
880   void maybeUnshare() {
881     if (UNLIKELY(maybeShared_)) {
882       size_t offset = this->crtPos_ - this->crtBegin_;
883       this->crtBuf_->unshareOne();
884       this->crtBegin_ = this->crtBuf_->data();
885       this->crtEnd_ = this->crtBuf_->tail();
886       this->crtPos_ = this->crtBegin_ + offset;
887       maybeShared_ = false;
888     }
889   }
890
891   void advanceDone() {
892     maybeShared_ = true;
893   }
894
895   bool maybeShared_;
896 };
897
898 typedef RWCursor<CursorAccess::PRIVATE> RWPrivateCursor;
899 typedef RWCursor<CursorAccess::UNSHARE> RWUnshareCursor;
900
901 /**
902  * Append to the end of a buffer chain, growing the chain (by allocating new
903  * buffers) in increments of at least growth bytes every time.  Won't grow
904  * (and push() and ensure() will throw) if growth == 0.
905  *
906  * TODO(tudorb): add a flavor of Appender that reallocates one IOBuf instead
907  * of chaining.
908  */
909 class Appender : public detail::Writable<Appender> {
910  public:
911   Appender(IOBuf* buf, uint64_t growth)
912     : buffer_(buf),
913       crtBuf_(buf->prev()),
914       growth_(growth) {
915   }
916
917   uint8_t* writableData() {
918     return crtBuf_->writableTail();
919   }
920
921   size_t length() const {
922     return crtBuf_->tailroom();
923   }
924
925   /**
926    * Mark n bytes (must be <= length()) as appended, as per the
927    * IOBuf::append() method.
928    */
929   void append(size_t n) {
930     crtBuf_->append(n);
931   }
932
933   /**
934    * Ensure at least n contiguous bytes available to write.
935    * Postcondition: length() >= n.
936    */
937   void ensure(uint64_t n) {
938     if (LIKELY(length() >= n)) {
939       return;
940     }
941
942     // Waste the rest of the current buffer and allocate a new one.
943     // Don't make it too small, either.
944     if (growth_ == 0) {
945       std::__throw_out_of_range("can't grow buffer chain");
946     }
947
948     n = std::max(n, growth_);
949     buffer_->prependChain(IOBuf::create(n));
950     crtBuf_ = buffer_->prev();
951   }
952
953   using detail::Writable<Appender>::pushAtMost;
954   size_t pushAtMost(const uint8_t* buf, size_t len) {
955     // We have to explicitly check for an input length of 0.
956     // We support buf being nullptr in this case, but we need to avoid calling
957     // memcpy() with a null source pointer, since that is undefined behavior
958     // even if the length is 0.
959     if (len == 0) {
960       return 0;
961     }
962
963     size_t copied = 0;
964     for (;;) {
965       // Fast path: it all fits in one buffer.
966       size_t available = length();
967       if (LIKELY(available >= len)) {
968         memcpy(writableData(), buf, len);
969         append(len);
970         return copied + len;
971       }
972
973       memcpy(writableData(), buf, available);
974       append(available);
975       copied += available;
976       if (UNLIKELY(!tryGrowChain())) {
977         return copied;
978       }
979       buf += available;
980       len -= available;
981     }
982   }
983
984   /*
985    * Append to the end of this buffer, using a printf() style
986    * format specifier.
987    *
988    * Note that folly/Format.h provides nicer and more type-safe mechanisms
989    * for formatting strings, which should generally be preferred over
990    * printf-style formatting.  Appender objects can be used directly as an
991    * output argument for Formatter objects.  For example:
992    *
993    *   Appender app(&iobuf);
994    *   format("{} {}", "hello", "world")(app);
995    *
996    * However, printf-style strings are still needed when dealing with existing
997    * third-party code in some cases.
998    *
999    * This will always add a nul-terminating character after the end
1000    * of the output.  However, the buffer data length will only be updated to
1001    * include the data itself.  The nul terminator will be the first byte in the
1002    * buffer tailroom.
1003    *
1004    * This method may throw exceptions on error.
1005    */
1006   void printf(FOLLY_PRINTF_FORMAT const char* fmt, ...)
1007     FOLLY_PRINTF_FORMAT_ATTR(2, 3);
1008
1009   void vprintf(const char* fmt, va_list ap);
1010
1011   /*
1012    * Calling an Appender object with a StringPiece will append the string
1013    * piece.  This allows Appender objects to be used directly with
1014    * Formatter.
1015    */
1016   void operator()(StringPiece sp) {
1017     push(ByteRange(sp));
1018   }
1019
1020  private:
1021   bool tryGrowChain() {
1022     assert(crtBuf_->next() == buffer_);
1023     if (growth_ == 0) {
1024       return false;
1025     }
1026
1027     buffer_->prependChain(IOBuf::create(growth_));
1028     crtBuf_ = buffer_->prev();
1029     return true;
1030   }
1031
1032   IOBuf* buffer_;
1033   IOBuf* crtBuf_;
1034   uint64_t growth_;
1035 };
1036
1037 class QueueAppender : public detail::Writable<QueueAppender> {
1038  public:
1039   /**
1040    * Create an Appender that writes to a IOBufQueue.  When we allocate
1041    * space in the queue, we grow no more than growth bytes at once
1042    * (unless you call ensure() with a bigger value yourself).
1043    */
1044   QueueAppender(IOBufQueue* queue, uint64_t growth)
1045       : queueCache_(queue), growth_(growth) {}
1046
1047   void reset(IOBufQueue* queue, uint64_t growth) {
1048     queueCache_.reset(queue);
1049     growth_ = growth;
1050   }
1051
1052   uint8_t* writableData() {
1053     return queueCache_.writableData();
1054   }
1055
1056   size_t length() {
1057     return queueCache_.length();
1058   }
1059
1060   void append(size_t n) {
1061     queueCache_.append(n);
1062   }
1063
1064   // Ensure at least n contiguous; can go above growth_, throws if
1065   // not enough room.
1066   void ensure(size_t n) {
1067     if (length() < n) {
1068       ensureSlow(n);
1069     }
1070   }
1071
1072   template <class T>
1073   typename std::enable_if<std::is_arithmetic<T>::value>::type write(T value) {
1074     // We can't fail.
1075     if (length() >= sizeof(T)) {
1076       storeUnaligned(queueCache_.writableData(), value);
1077       queueCache_.appendUnsafe(sizeof(T));
1078     } else {
1079       writeSlow<T>(value);
1080     }
1081   }
1082
1083   using detail::Writable<QueueAppender>::pushAtMost;
1084   size_t pushAtMost(const uint8_t* buf, size_t len) {
1085     // Fill the current buffer
1086     const size_t copyLength = std::min(len, length());
1087     if (copyLength != 0) {
1088       memcpy(writableData(), buf, copyLength);
1089       queueCache_.appendUnsafe(copyLength);
1090       buf += copyLength;
1091     }
1092     size_t remaining = len - copyLength;
1093     // Allocate more buffers as necessary
1094     while (remaining != 0) {
1095       auto p = queueCache_.queue()->preallocate(
1096           std::min(remaining, growth_), growth_, remaining);
1097       memcpy(p.first, buf, p.second);
1098       queueCache_.queue()->postallocate(p.second);
1099       buf += p.second;
1100       remaining -= p.second;
1101     }
1102     return len;
1103   }
1104
1105   void insert(std::unique_ptr<folly::IOBuf> buf) {
1106     if (buf) {
1107       queueCache_.queue()->append(std::move(buf), true);
1108     }
1109   }
1110
1111   void insert(const folly::IOBuf& buf) {
1112     insert(buf.clone());
1113   }
1114
1115  private:
1116   folly::IOBufQueue::WritableRangeCache queueCache_{nullptr};
1117   size_t growth_{0};
1118
1119   FOLLY_NOINLINE void ensureSlow(size_t n) {
1120     queueCache_.queue()->preallocate(n, growth_);
1121     queueCache_.fillCache();
1122   }
1123
1124   template <class T>
1125   typename std::enable_if<std::is_arithmetic<T>::value>::type FOLLY_NOINLINE
1126   writeSlow(T value) {
1127     queueCache_.queue()->preallocate(sizeof(T), growth_);
1128     queueCache_.fillCache();
1129
1130     storeUnaligned(queueCache_.writableData(), value);
1131     queueCache_.appendUnsafe(sizeof(T));
1132   }
1133 };
1134
1135 } // namespace io
1136 } // namespace folly
1137
1138 #include <folly/io/Cursor-inl.h>