1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #ifndef _THRIFT_TRANSPORT_TBUFFERTRANSPORTS_H_
21 #define _THRIFT_TRANSPORT_TBUFFERTRANSPORTS_H_ 1
22 
23 #include <cstring>
24 #include <boost/scoped_array.hpp>
25 
26 #include <thrift/transport/TTransport.h>
27 #include <thrift/transport/TVirtualTransport.h>
28 
29 #ifdef __GNUC__
30 #define TDB_LIKELY(val) (__builtin_expect((val), 1))
31 #define TDB_UNLIKELY(val) (__builtin_expect((val), 0))
32 #else
33 #define TDB_LIKELY(val) (val)
34 #define TDB_UNLIKELY(val) (val)
35 #endif
36 
37 namespace apache
38 {
39 namespace thrift
40 {
41 namespace transport
42 {
43 
44 
45 /**
46  * Base class for all transports that use read/write buffers for performance.
47  *
48  * TBufferBase is designed to implement the fast-path "memcpy" style
49  * operations that work in the common case.  It does so with small and
50  * (eventually) nonvirtual, inlinable methods.  TBufferBase is an abstract
51  * class.  Subclasses are expected to define the "slow path" operations
52  * that have to be done when the buffers are full or empty.
53  *
54  */
55 class TBufferBase : public TVirtualTransport<TBufferBase>
56 {
57 
58 public:
59 
60     /**
61      * Fast-path read.
62      *
63      * When we have enough data buffered to fulfill the read, we can satisfy it
64      * with a single memcpy, then adjust our internal pointers.  If the buffer
65      * is empty, we call out to our slow path, implemented by a subclass.
66      * This method is meant to eventually be nonvirtual and inlinable.
67      */
read(uint8_t * buf,uint32_t len)68     uint32_t read(uint8_t* buf, uint32_t len)
69     {
70         uint8_t* new_rBase = rBase_ + len;
71 
72         if (TDB_LIKELY(new_rBase <= rBound_))
73         {
74             std::memcpy(buf, rBase_, len);
75             rBase_ = new_rBase;
76             return len;
77         }
78 
79         return readSlow(buf, len);
80     }
81 
82     /**
83      * Shortcutted version of readAll.
84      */
readAll(uint8_t * buf,uint32_t len)85     uint32_t readAll(uint8_t* buf, uint32_t len)
86     {
87         uint8_t* new_rBase = rBase_ + len;
88 
89         if (TDB_LIKELY(new_rBase <= rBound_))
90         {
91             std::memcpy(buf, rBase_, len);
92             rBase_ = new_rBase;
93             return len;
94         }
95 
96         return apache::thrift::transport::readAll(*this, buf, len);
97     }
98 
99     /**
100      * Fast-path write.
101      *
102      * When we have enough empty space in our buffer to accomodate the write, we
103      * can satisfy it with a single memcpy, then adjust our internal pointers.
104      * If the buffer is full, we call out to our slow path, implemented by a
105      * subclass.  This method is meant to eventually be nonvirtual and
106      * inlinable.
107      */
write(const uint8_t * buf,uint32_t len)108     void write(const uint8_t* buf, uint32_t len)
109     {
110         uint8_t* new_wBase = wBase_ + len;
111 
112         if (TDB_LIKELY(new_wBase <= wBound_))
113         {
114             std::memcpy(wBase_, buf, len);
115             wBase_ = new_wBase;
116             return;
117         }
118 
119         writeSlow(buf, len);
120     }
121 
122     /**
123      * Fast-path borrow.  A lot like the fast-path read.
124      */
borrow(uint8_t * buf,uint32_t * len)125     const uint8_t* borrow(uint8_t* buf, uint32_t* len)
126     {
127         if (TDB_LIKELY(static_cast<ptrdiff_t>(*len) <= rBound_ - rBase_))
128         {
129             // With strict aliasing, writing to len shouldn't force us to
130             // refetch rBase_ from memory.  TODO(dreiss): Verify this.
131             *len = static_cast<uint32_t>(rBound_ - rBase_);
132             return rBase_;
133         }
134 
135         return borrowSlow(buf, len);
136     }
137 
138     /**
139      * Consume doesn't require a slow path.
140      */
consume(uint32_t len)141     void consume(uint32_t len)
142     {
143         if (TDB_LIKELY(static_cast<ptrdiff_t>(len) <= rBound_ - rBase_))
144         {
145             rBase_ += len;
146         }
147         else
148         {
149             throw TTransportException(TTransportException::BAD_ARGS,
150                                       "consume did not follow a borrow.");
151         }
152     }
153 
154 
155 protected:
156 
157     /// Slow path read.
158     virtual uint32_t readSlow(uint8_t* buf, uint32_t len) = 0;
159 
160     /// Slow path write.
161     virtual void writeSlow(const uint8_t* buf, uint32_t len) = 0;
162 
163     /**
164      * Slow path borrow.
165      *
166      * POSTCONDITION: return == NULL || rBound_ - rBase_ >= *len
167      */
168     virtual const uint8_t* borrowSlow(uint8_t* buf, uint32_t* len) = 0;
169 
170     /**
171      * Trivial constructor.
172      *
173      * Initialize pointers safely.  Constructing is not a very
174      * performance-sensitive operation, so it is okay to just leave it to
175      * the concrete class to set up pointers correctly.
176      */
TBufferBase()177     TBufferBase()
178         : rBase_(NULL)
179         , rBound_(NULL)
180         , wBase_(NULL)
181         , wBound_(NULL)
182     {}
183 
184     /// Convenience mutator for setting the read buffer.
setReadBuffer(uint8_t * buf,uint32_t len)185     void setReadBuffer(uint8_t* buf, uint32_t len)
186     {
187         rBase_ = buf;
188         rBound_ = buf + len;
189     }
190 
191     /// Convenience mutator for setting the write buffer.
setWriteBuffer(uint8_t * buf,uint32_t len)192     void setWriteBuffer(uint8_t* buf, uint32_t len)
193     {
194         wBase_ = buf;
195         wBound_ = buf + len;
196     }
197 
~TBufferBase()198     virtual ~TBufferBase() {}
199 
200     /// Reads begin here.
201     uint8_t* rBase_;
202     /// Reads may extend to just before here.
203     uint8_t* rBound_;
204 
205     /// Writes begin here.
206     uint8_t* wBase_;
207     /// Writes may extend to just before here.
208     uint8_t* wBound_;
209 };
210 
211 
212 /**
213  * Buffered transport. For reads it will read more data than is requested
214  * and will serve future data out of a local buffer. For writes, data is
215  * stored to an in memory buffer before being written out.
216  *
217  */
218 class TBufferedTransport
219     : public TVirtualTransport<TBufferedTransport, TBufferBase>
220 {
221 public:
222 
223     static const int DEFAULT_BUFFER_SIZE = 512;
224 
225     /// Use default buffer sizes.
TBufferedTransport(boost::shared_ptr<TTransport> transport)226     TBufferedTransport(boost::shared_ptr<TTransport> transport)
227         : transport_(transport)
228         , rBufSize_(DEFAULT_BUFFER_SIZE)
229         , wBufSize_(DEFAULT_BUFFER_SIZE)
230         , rBuf_(new uint8_t[rBufSize_])
231         , wBuf_(new uint8_t[wBufSize_])
232     {
233         initPointers();
234     }
235 
236     /// Use specified buffer sizes.
TBufferedTransport(boost::shared_ptr<TTransport> transport,uint32_t sz)237     TBufferedTransport(boost::shared_ptr<TTransport> transport, uint32_t sz)
238         : transport_(transport)
239         , rBufSize_(sz)
240         , wBufSize_(sz)
241         , rBuf_(new uint8_t[rBufSize_])
242         , wBuf_(new uint8_t[wBufSize_])
243     {
244         initPointers();
245     }
246 
247     /// Use specified read and write buffer sizes.
TBufferedTransport(boost::shared_ptr<TTransport> transport,uint32_t rsz,uint32_t wsz)248     TBufferedTransport(boost::shared_ptr<TTransport> transport, uint32_t rsz, uint32_t wsz)
249         : transport_(transport)
250         , rBufSize_(rsz)
251         , wBufSize_(wsz)
252         , rBuf_(new uint8_t[rBufSize_])
253         , wBuf_(new uint8_t[wBufSize_])
254     {
255         initPointers();
256     }
257 
open()258     void open()
259     {
260         transport_->open();
261     }
262 
isOpen()263     bool isOpen()
264     {
265         return transport_->isOpen();
266     }
267 
peek()268     bool peek()
269     {
270         if (rBase_ == rBound_)
271         {
272             setReadBuffer(rBuf_.get(), transport_->read(rBuf_.get(), rBufSize_));
273         }
274 
275         return (rBound_ > rBase_);
276     }
277 
close()278     void close()
279     {
280         flush();
281         transport_->close();
282     }
283 
284     virtual uint32_t readSlow(uint8_t* buf, uint32_t len);
285 
286     virtual void writeSlow(const uint8_t* buf, uint32_t len);
287 
288     void flush();
289 
290 
291     /**
292      * The following behavior is currently implemented by TBufferedTransport,
293      * but that may change in a future version:
294      * 1/ If len is at most rBufSize_, borrow will never return NULL.
295      *    Depending on the underlying transport, it could throw an exception
296      *    or hang forever.
297      * 2/ Some borrow requests may copy bytes internally.  However,
298      *    if len is at most rBufSize_/2, none of the copied bytes
299      *    will ever have to be copied again.  For optimial performance,
300      *    stay under this limit.
301      */
302     virtual const uint8_t* borrowSlow(uint8_t* buf, uint32_t* len);
303 
getUnderlyingTransport()304     boost::shared_ptr<TTransport> getUnderlyingTransport()
305     {
306         return transport_;
307     }
308 
309     /*
310      * TVirtualTransport provides a default implementation of readAll().
311      * We want to use the TBufferBase version instead.
312      */
readAll(uint8_t * buf,uint32_t len)313     uint32_t readAll(uint8_t* buf, uint32_t len)
314     {
315         return TBufferBase::readAll(buf, len);
316     }
317 
318 protected:
initPointers()319     void initPointers()
320     {
321         setReadBuffer(rBuf_.get(), 0);
322         setWriteBuffer(wBuf_.get(), wBufSize_);
323         // Write size never changes.
324     }
325 
326     boost::shared_ptr<TTransport> transport_;
327 
328     uint32_t rBufSize_;
329     uint32_t wBufSize_;
330     boost::scoped_array<uint8_t> rBuf_;
331     boost::scoped_array<uint8_t> wBuf_;
332 };
333 
334 
335 /**
336  * Wraps a transport into a buffered one.
337  *
338  */
339 class TBufferedTransportFactory : public TTransportFactory
340 {
341 public:
TBufferedTransportFactory()342     TBufferedTransportFactory() {}
343 
~TBufferedTransportFactory()344     virtual ~TBufferedTransportFactory() {}
345 
346     /**
347      * Wraps the transport into a buffered one.
348      */
getTransport(boost::shared_ptr<TTransport> trans)349     virtual boost::shared_ptr<TTransport> getTransport(boost::shared_ptr<TTransport> trans)
350     {
351         return boost::shared_ptr<TTransport>(new TBufferedTransport(trans));
352     }
353 
354 };
355 
356 
357 /**
358  * Framed transport. All writes go into an in-memory buffer until flush is
359  * called, at which point the transport writes the length of the entire
360  * binary chunk followed by the data payload. This allows the receiver on the
361  * other end to always do fixed-length reads.
362  *
363  */
364 class TFramedTransport
365     : public TVirtualTransport<TFramedTransport, TBufferBase>
366 {
367 public:
368 
369     static const int DEFAULT_BUFFER_SIZE = 512;
370 
371     /// Use default buffer sizes.
TFramedTransport(boost::shared_ptr<TTransport> transport)372     TFramedTransport(boost::shared_ptr<TTransport> transport)
373         : transport_(transport)
374         , rBufSize_(0)
375         , wBufSize_(DEFAULT_BUFFER_SIZE)
376         , rBuf_()
377         , wBuf_(new uint8_t[wBufSize_])
378     {
379         initPointers();
380     }
381 
TFramedTransport(boost::shared_ptr<TTransport> transport,uint32_t sz)382     TFramedTransport(boost::shared_ptr<TTransport> transport, uint32_t sz)
383         : transport_(transport)
384         , rBufSize_(0)
385         , wBufSize_(sz)
386         , rBuf_()
387         , wBuf_(new uint8_t[wBufSize_])
388     {
389         initPointers();
390     }
391 
open()392     void open()
393     {
394         transport_->open();
395     }
396 
isOpen()397     bool isOpen()
398     {
399         return transport_->isOpen();
400     }
401 
peek()402     bool peek()
403     {
404         return (rBase_ < rBound_) || transport_->peek();
405     }
406 
close()407     void close()
408     {
409         flush();
410         transport_->close();
411     }
412 
413     virtual uint32_t readSlow(uint8_t* buf, uint32_t len);
414 
415     virtual void writeSlow(const uint8_t* buf, uint32_t len);
416 
417     virtual void flush();
418 
419     uint32_t readEnd();
420 
421     uint32_t writeEnd();
422 
423     const uint8_t* borrowSlow(uint8_t* buf, uint32_t* len);
424 
getUnderlyingTransport()425     boost::shared_ptr<TTransport> getUnderlyingTransport()
426     {
427         return transport_;
428     }
429 
430     /*
431      * TVirtualTransport provides a default implementation of readAll().
432      * We want to use the TBufferBase version instead.
433      */
readAll(uint8_t * buf,uint32_t len)434     uint32_t readAll(uint8_t* buf, uint32_t len)
435     {
436         return TBufferBase::readAll(buf, len);
437     }
438 
439 protected:
440     /**
441      * Reads a frame of input from the underlying stream.
442      *
443      * Returns true if a frame was read successfully, or false on EOF.
444      * (Raises a TTransportException if EOF occurs after a partial frame.)
445      */
446     bool readFrame();
447 
initPointers()448     void initPointers()
449     {
450         setReadBuffer(NULL, 0);
451         setWriteBuffer(wBuf_.get(), wBufSize_);
452 
453         // Pad the buffer so we can insert the size later.
454         int32_t pad = 0;
455         this->write((uint8_t*)&pad, sizeof(pad));
456     }
457 
458     boost::shared_ptr<TTransport> transport_;
459 
460     uint32_t rBufSize_;
461     uint32_t wBufSize_;
462     boost::scoped_array<uint8_t> rBuf_;
463     boost::scoped_array<uint8_t> wBuf_;
464 };
465 
466 /**
467  * Wraps a transport into a framed one.
468  *
469  */
470 class TFramedTransportFactory : public TTransportFactory
471 {
472 public:
TFramedTransportFactory()473     TFramedTransportFactory() {}
474 
~TFramedTransportFactory()475     virtual ~TFramedTransportFactory() {}
476 
477     /**
478      * Wraps the transport into a framed one.
479      */
getTransport(boost::shared_ptr<TTransport> trans)480     virtual boost::shared_ptr<TTransport> getTransport(boost::shared_ptr<TTransport> trans)
481     {
482         return boost::shared_ptr<TTransport>(new TFramedTransport(trans));
483     }
484 
485 };
486 
487 
488 /**
489  * A memory buffer is a tranpsort that simply reads from and writes to an
490  * in memory buffer. Anytime you call write on it, the data is simply placed
491  * into a buffer, and anytime you call read, data is read from that buffer.
492  *
493  * The buffers are allocated using C constructs malloc,realloc, and the size
494  * doubles as necessary.  We've considered using scoped
495  *
496  */
497 class TMemoryBuffer : public TVirtualTransport<TMemoryBuffer, TBufferBase>
498 {
499 private:
500 
501     // Common initialization done by all constructors.
initCommon(uint8_t * buf,uint32_t size,bool owner,uint32_t wPos)502     void initCommon(uint8_t* buf, uint32_t size, bool owner, uint32_t wPos)
503     {
504         if (buf == NULL && size != 0)
505         {
506             assert(owner);
507             buf = (uint8_t*)std::malloc(size);
508 
509             if (buf == NULL)
510             {
511                 throw std::bad_alloc();
512             }
513         }
514 
515         buffer_ = buf;
516         bufferSize_ = size;
517 
518         rBase_ = buffer_;
519         rBound_ = buffer_ + wPos;
520         // TODO(dreiss): Investigate NULL-ing this if !owner.
521         wBase_ = buffer_ + wPos;
522         wBound_ = buffer_ + bufferSize_;
523 
524         owner_ = owner;
525 
526         // rBound_ is really an artifact.  In principle, it should always be
527         // equal to wBase_.  We update it in a few places (computeRead, etc.).
528     }
529 
530 public:
531     static const uint32_t defaultSize = 1024;
532 
533     /**
534      * This enum specifies how a TMemoryBuffer should treat
535      * memory passed to it via constructors or resetBuffer.
536      *
537      * OBSERVE:
538      *   TMemoryBuffer will simply store a pointer to the memory.
539      *   It is the callers responsibility to ensure that the pointer
540      *   remains valid for the lifetime of the TMemoryBuffer,
541      *   and that it is properly cleaned up.
542      *   Note that no data can be written to observed buffers.
543      *
544      * COPY:
545      *   TMemoryBuffer will make an internal copy of the buffer.
546      *   The caller has no responsibilities.
547      *
548      * TAKE_OWNERSHIP:
549      *   TMemoryBuffer will become the "owner" of the buffer,
550      *   and will be responsible for freeing it.
551      *   The membory must have been allocated with malloc.
552      */
553     enum MemoryPolicy
554     {
555         OBSERVE = 1
556         , COPY = 2
557         , TAKE_OWNERSHIP = 3
558     };
559 
560     /**
561      * Construct a TMemoryBuffer with a default-sized buffer,
562      * owned by the TMemoryBuffer object.
563      */
TMemoryBuffer()564     TMemoryBuffer()
565     {
566         initCommon(NULL, defaultSize, true, 0);
567     }
568 
569     /**
570      * Construct a TMemoryBuffer with a buffer of a specified size,
571      * owned by the TMemoryBuffer object.
572      *
573      * @param sz  The initial size of the buffer.
574      */
TMemoryBuffer(uint32_t sz)575     TMemoryBuffer(uint32_t sz)
576     {
577         initCommon(NULL, sz, true, 0);
578     }
579 
580     /**
581      * Construct a TMemoryBuffer with buf as its initial contents.
582      *
583      * @param buf    The initial contents of the buffer.
584      *               Note that, while buf is a non-const pointer,
585      *               TMemoryBuffer will not write to it if policy == OBSERVE,
586      *               so it is safe to const_cast<uint8_t*>(whatever).
587      * @param sz     The size of @c buf.
588      * @param policy See @link MemoryPolicy @endlink .
589      */
590     TMemoryBuffer(uint8_t* buf, uint32_t sz, MemoryPolicy policy = OBSERVE)
591     {
592         if (buf == NULL && sz != 0)
593         {
594             throw TTransportException(TTransportException::BAD_ARGS,
595                                       "TMemoryBuffer given null buffer with non-zero size.");
596         }
597 
598         switch (policy)
599         {
600             case OBSERVE:
601             case TAKE_OWNERSHIP:
602                 initCommon(buf, sz, policy == TAKE_OWNERSHIP, sz);
603                 break;
604 
605             case COPY:
606                 initCommon(NULL, sz, true, 0);
607                 this->write(buf, sz);
608                 break;
609 
610             default:
611                 throw TTransportException(TTransportException::BAD_ARGS,
612                                           "Invalid MemoryPolicy for TMemoryBuffer");
613         }
614     }
615 
~TMemoryBuffer()616     ~TMemoryBuffer()
617     {
618         if (owner_)
619         {
620             std::free(buffer_);
621         }
622     }
623 
isOpen()624     bool isOpen()
625     {
626         return true;
627     }
628 
peek()629     bool peek()
630     {
631         return (rBase_ < wBase_);
632     }
633 
open()634     void open() {}
635 
close()636     void close() {}
637 
638     // TODO(dreiss): Make bufPtr const.
getBuffer(uint8_t ** bufPtr,uint32_t * sz)639     void getBuffer(uint8_t** bufPtr, uint32_t* sz)
640     {
641         *bufPtr = rBase_;
642         *sz = static_cast<uint32_t>(wBase_ - rBase_);
643     }
644 
getBufferAsString()645     std::string getBufferAsString()
646     {
647         if (buffer_ == NULL)
648         {
649             return "";
650         }
651 
652         uint8_t* buf;
653         uint32_t sz;
654         getBuffer(&buf, &sz);
655         return std::string((char*)buf, (std::string::size_type)sz);
656     }
657 
appendBufferToString(std::string & str)658     void appendBufferToString(std::string& str)
659     {
660         if (buffer_ == NULL)
661         {
662             return;
663         }
664 
665         uint8_t* buf;
666         uint32_t sz;
667         getBuffer(&buf, &sz);
668         str.append((char*)buf, sz);
669     }
670 
resetBuffer()671     void resetBuffer()
672     {
673         rBase_ = buffer_;
674         rBound_ = buffer_;
675         wBase_ = buffer_;
676 
677         // It isn't safe to write into a buffer we don't own.
678         if (!owner_)
679         {
680             wBound_ = wBase_;
681             bufferSize_ = 0;
682         }
683     }
684 
685     /// See constructor documentation.
686     void resetBuffer(uint8_t* buf, uint32_t sz, MemoryPolicy policy = OBSERVE)
687     {
688         // Use a variant of the copy-and-swap trick for assignment operators.
689         // This is sub-optimal in terms of performance for two reasons:
690         //   1/ The constructing and swapping of the (small) values
691         //      in the temporary object takes some time, and is not necessary.
692         //   2/ If policy == COPY, we allocate the new buffer before
693         //      freeing the old one, precluding the possibility of
694         //      reusing that memory.
695         // I doubt that either of these problems could be optimized away,
696         // but the second is probably no a common case, and the first is minor.
697         // I don't expect resetBuffer to be a common operation, so I'm willing to
698         // bite the performance bullet to make the method this simple.
699 
700         // Construct the new buffer.
701         TMemoryBuffer new_buffer(buf, sz, policy);
702         // Move it into ourself.
703         this->swap(new_buffer);
704         // Our old self gets destroyed.
705     }
706 
707     /// See constructor documentation.
resetBuffer(uint32_t sz)708     void resetBuffer(uint32_t sz)
709     {
710         // Construct the new buffer.
711         TMemoryBuffer new_buffer(sz);
712         // Move it into ourself.
713         this->swap(new_buffer);
714         // Our old self gets destroyed.
715     }
716 
readAsString(uint32_t len)717     std::string readAsString(uint32_t len)
718     {
719         std::string str;
720         (void)readAppendToString(str, len);
721         return str;
722     }
723 
724     uint32_t readAppendToString(std::string& str, uint32_t len);
725 
726     // return number of bytes read
readEnd()727     uint32_t readEnd()
728     {
729         //This cast should be safe, because buffer_'s size is a uint32_t
730         uint32_t bytes = static_cast<uint32_t>(rBase_ - buffer_);
731 
732         if (rBase_ == wBase_)
733         {
734             resetBuffer();
735         }
736 
737         return bytes;
738     }
739 
740     // Return number of bytes written
writeEnd()741     uint32_t writeEnd()
742     {
743         //This cast should be safe, because buffer_'s size is a uint32_t
744         return static_cast<uint32_t>(wBase_ - buffer_);
745     }
746 
available_read()747     uint32_t available_read() const
748     {
749         // Remember, wBase_ is the real rBound_.
750         return static_cast<uint32_t>(wBase_ - rBase_);
751     }
752 
available_write()753     uint32_t available_write() const
754     {
755         return static_cast<uint32_t>(wBound_ - wBase_);
756     }
757 
758     // Returns a pointer to where the client can write data to append to
759     // the TMemoryBuffer, and ensures the buffer is big enough to accomodate a
760     // write of the provided length.  The returned pointer is very convenient for
761     // passing to read(), recv(), or similar. You must call wroteBytes() as soon
762     // as data is written or the buffer will not be aware that data has changed.
getWritePtr(uint32_t len)763     uint8_t* getWritePtr(uint32_t len)
764     {
765         ensureCanWrite(len);
766         return wBase_;
767     }
768 
769     // Informs the buffer that the client has written 'len' bytes into storage
770     // that had been provided by getWritePtr().
771     void wroteBytes(uint32_t len);
772 
773     /*
774      * TVirtualTransport provides a default implementation of readAll().
775      * We want to use the TBufferBase version instead.
776      */
readAll(uint8_t * buf,uint32_t len)777     uint32_t readAll(uint8_t* buf, uint32_t len)
778     {
779         return TBufferBase::readAll(buf, len);
780     }
781 
782 protected:
swap(TMemoryBuffer & that)783     void swap(TMemoryBuffer& that)
784     {
785         using std::swap;
786         swap(buffer_,     that.buffer_);
787         swap(bufferSize_, that.bufferSize_);
788 
789         swap(rBase_,      that.rBase_);
790         swap(rBound_,     that.rBound_);
791         swap(wBase_,      that.wBase_);
792         swap(wBound_,     that.wBound_);
793 
794         swap(owner_,      that.owner_);
795     }
796 
797     // Make sure there's at least 'len' bytes available for writing.
798     void ensureCanWrite(uint32_t len);
799 
800     // Compute the position and available data for reading.
801     void computeRead(uint32_t len, uint8_t** out_start, uint32_t* out_give);
802 
803     uint32_t readSlow(uint8_t* buf, uint32_t len);
804 
805     void writeSlow(const uint8_t* buf, uint32_t len);
806 
807     const uint8_t* borrowSlow(uint8_t* buf, uint32_t* len);
808 
809     // Data buffer
810     uint8_t* buffer_;
811 
812     // Allocated buffer size
813     uint32_t bufferSize_;
814 
815     // Is this object the owner of the buffer?
816     bool owner_;
817 
818     // Don't forget to update constrctors, initCommon, and swap if
819     // you add new members.
820 };
821 
822 }
823 }
824 } // apache::thrift::transport
825 
826 #endif // #ifndef _THRIFT_TRANSPORT_TBUFFERTRANSPORTS_H_
827