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