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