Skip to content

Instantly share code, notes, and snippets.

@anhldbk
Last active August 3, 2017 04:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anhldbk/3ee4225e7c44209861e0bd18ae98d6a7 to your computer and use it in GitHub Desktop.
Save anhldbk/3ee4225e7c44209861e0bd18ae98d6a7 to your computer and use it in GitHub Desktop.
Thrift transport
/**
* Generic interface for a method of transporting data. A TTransport may be
* capable of either reading or writing, but not necessarily both.
*
*/
class TTransport {
/**
* Attempt to read up to the specified number of bytes into the string.
*
* @param buf Reference to the location to write the data
* @param len How many bytes to read
* @return How many bytes were actually read
* @throws TTransportException If an error occurs
*/
uint32_t read(uint8_t* buf, uint32_t len) {
T_VIRTUAL_CALL();
return read_virt(buf, len);
}
virtual uint32_t read_virt(uint8_t* /* buf */, uint32_t /* len */) {
throw TTransportException(TTransportException::NOT_OPEN, "Base TTransport cannot read.");
}
// ...
}
/**
* Helper class that provides default implementations of TTransport methods.
*
* This class provides default implementations of read(), readAll(), write(),
* borrow() and consume().
*
* In the TTransport base class, each of these methods simply invokes its
* virtual counterpart. This class overrides them to always perform the
* default behavior, without a virtual function call.
*
* The primary purpose of this class is to serve as a base class for
* TVirtualTransport, and prevent infinite recursion if one of its subclasses
* does not override the TTransport implementation of these methods. (Since
* TVirtualTransport::read_virt() calls read(), and TTransport::read() calls
* read_virt().)
*/
class TTransportDefaults : public TTransport {
public:
/*
* TTransport *_virt() methods provide reasonable default implementations.
* Invoke them non-virtually.
*/
uint32_t read(uint8_t* buf, uint32_t len) { return this->TTransport::read_virt(buf, len); }
uint32_t readAll(uint8_t* buf, uint32_t len) { return this->TTransport::readAll_virt(buf, len); }
void write(const uint8_t* buf, uint32_t len) { this->TTransport::write_virt(buf, len); }
const uint8_t* borrow(uint8_t* buf, uint32_t* len) {
return this->TTransport::borrow_virt(buf, len);
}
void consume(uint32_t len) { this->TTransport::consume_virt(len); }
protected:
TTransportDefaults() {}
};
/**
* Helper class to provide polymorphism for subclasses of TTransport.
*
* This class implements *_virt() methods of TTransport, to call the
* non-virtual versions of these functions in the proper subclass.
*
* To define your own transport class using TVirtualTransport:
* 1) Derive your subclass from TVirtualTransport<your class>
* e.g: class MyTransport : public TVirtualTransport<MyTransport> {
* 2) Provide your own implementations of read(), readAll(), etc.
* These methods should be non-virtual.
*
* Transport implementations that need to use virtual inheritance when
* inheriting from TTransport cannot use TVirtualTransport.
*
* @author Chad Walters <chad@powerset.com>
*/
template <class Transport_, class Super_ = TTransportDefaults>
class TVirtualTransport : public Super_ {
public:
/*
* Implementations of the *_virt() functions, to call the subclass's
* non-virtual implementation function.
*/
virtual uint32_t read_virt(uint8_t* buf, uint32_t len) {
return static_cast<Transport_*>(this)->read(buf, len);
}
}
/**
* Base class for all transports that use read/write buffers for performance.
*
* TBufferBase is designed to implement the fast-path "memcpy" style
* operations that work in the common case. It does so with small and
* (eventually) nonvirtual, inlinable methods. TBufferBase is an abstract
* class. Subclasses are expected to define the "slow path" operations
* that have to be done when the buffers are full or empty.
*
*/
class TBufferBase : public TVirtualTransport<TBufferBase> {
public:
/**
* Fast-path read.
*
* When we have enough data buffered to fulfill the read, we can satisfy it
* with a single memcpy, then adjust our internal pointers. If the buffer
* is empty, we call out to our slow path, implemented by a subclass.
* This method is meant to eventually be nonvirtual and inlinable.
*/
uint32_t read(uint8_t* buf, uint32_t len) {
uint8_t* new_rBase = rBase_ + len;
if (TDB_LIKELY(new_rBase <= rBound_)) {
std::memcpy(buf, rBase_, len);
rBase_ = new_rBase;
return len;
}
return readSlow(buf, len);
}
}
/**
* Buffered transport. For reads it will read more data than is requested
* and will serve future data out of a local buffer. For writes, data is
* stored to an in memory buffer before being written out.
*
*/
class TBufferedTransport : public TVirtualTransport<TBufferedTransport, TBufferBase> {
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment