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