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