Created
August 13, 2011 10:19
-
-
Save jeffhung/1143708 to your computer and use it in GitHub Desktop.
Two buffer classes I wrote before, for slightly different purpose.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* The auto_buffer class acts as a buffer of @p T, but allocate statically or | |
* dynamically according to requested buffer size. If requested buffer size | |
* is greater than @p StaticBytes, auto_buffer will dynamically allocate | |
* required memory space for the buffer, instead of statically as a member | |
* array. | |
* | |
* Usually, dynamic allocation gets more overheads, but if requested size is | |
* too large, we may exceed stack limit too soon. So, a smarter strategy is | |
* to allocate statically if required size is small, and turn to dynamic | |
* allocation if required size is big. | |
* | |
* Below is a typical code example of the described strategy: | |
* | |
* @code | |
* // calls wcstombs(), but throw if wcstombs() failed instead of returning | |
* // (size_t)-1. | |
* size_t wcstombs_ex(char* mbs, const wchar_t* wcs, size_t nbytes); | |
* | |
* // Convert from wide-character string to multi-byte character string. | |
* std::string wcs_to_mbs(const wchar_t* wcs) | |
* { | |
* char buffer[128]; // may not big enough | |
* char* pbuf = buffer; // point to statically allocated buffer by default | |
* size_t buf_nbytes = sizeof(buffer); // size of buffer pointed by pbuf | |
* | |
* // Get number of bytes required to store the converted multi-byte | |
* // string. The value returned by wcstombs do not include the | |
* // terminating null, so we add 1 by our self. | |
* size_t need_nbytes = wcstombs_ex(NULL, wcs, 0) + 1; | |
* if (need_nbytes > buf_nbytes) { | |
* // the buffer pointed by pbuf is not big enough, | |
* // dynamically allocate a new one instead: | |
* buf_nbytes = need_nbytes; | |
* pbuf = (char*)malloc(buf_nbytes); | |
* } | |
* | |
* // Do the real convertion. | |
* need_nbytes = wcstombs_ex(pbuf, wcs, buf_nbytes); | |
* pbuf[need_nbytes] = 0; // null terminate the string | |
* std::string mbs(pbuf); // save the std::string object for return | |
* | |
* // If pbuf was dynamically allocated, we need to free it before return. | |
* if (pbuf != buffer) { | |
* free(pbuf); | |
* } | |
* | |
* return mbs; | |
* } | |
* @endcode | |
* | |
* The above implementation may have memory leak, since we may throw in any | |
* point before releasing dynamically allocated memory. The auto_buffer class | |
* encapsulate the same strategy, and is exception-safe because the destructor | |
* will be called even if we throw in the middle. | |
* | |
* @attention The auto_buffer simply allocate required memory buffer, no | |
* object will be constructed. | |
* | |
* @attention Note that @p StaticBytes counts by number of bytes, not number | |
* of @p T elements. However, all member functions counts by | |
* number of @p T elements, to ease programming. | |
* | |
* @attention Since get() will get the internal buffer, we do not provide | |
* thread-safety guarantees. It is the caller's responsibility to | |
* properly protect the buffer. | |
* | |
* @todo Make allocation customizable by adding Allocator template parameter. | |
* | |
* @tparam T the type of objects to be holded in the buffer | |
* @tparam StaticBytes the buffer size, in number of bytes | |
* | |
* @internal | |
* This class is going to replace static_first_buffer. | |
*/ | |
template < typename T | |
, int StaticBytes = 1024 // in bytes | |
> | |
class auto_buffer : private noncopyable | |
{ | |
friend class auto_buffer_test; // for white-box testing | |
public: | |
/** | |
* Construct an auto_buffer object, with given required buffer size, @p | |
* nelems, in number of elements. | |
* | |
* @note Note that the unit of @p nelems is different with @p StaticBytes. | |
* The former is number of @p T elements while an element may occupy | |
* more than one bytes; and the later is number of bytes, so we can | |
* control the memory usage without dynamic allocation precisely. | |
* | |
* @param[in] nelems required buffer size, in number of elements | |
*/ | |
auto_buffer(size_t nelems = (StaticBytes / sizeof(T))); | |
/** | |
* Destruct the auto_buffer object. If the memory was allocated | |
* dynamically, it will be released automatically. This provide extra | |
* exception-safety since code may throw in any point within a function, | |
* and may not be able to reach the point of releasing memory at the end | |
* of function. | |
*/ | |
~auto_buffer(); | |
/** | |
* Resize the buffer to @p nelems, in number of elements. Like realloc(), | |
* data in original buffer will be copied to new buffer bit-wisely. That | |
* is, the contents of the memory are unchanged up to the lesser of the | |
* new and old sizes. If the new size is larger, the contents of the | |
* newly allocated portion of the memory are undefined. | |
* | |
* @param[in] nelems required buffer size, in number of elements | |
*/ | |
void resize(size_t nelems); | |
/** | |
* Reset to initial size, the size specified in constructor or a default | |
* size if not given. | |
*/ | |
void reset_size(); | |
/** | |
* Get pointer to the actual buffer. | |
* @{ | |
*/ | |
T* get(); | |
const T* get() const; | |
/** @} */ | |
/** | |
* Get size of the buffer, in number of elements. | |
*/ | |
size_t size() const; | |
/** | |
* Get size of the buffer, in number of bytes. | |
*/ | |
size_t nbytes() const; | |
private: | |
size_t size_; //!< buffer size of @p pbuf_, in number of elements | |
byte_t* pbuf_; //!< pointer point to the actural buffer | |
byte_t sbuf_[StaticBytes]; //!< static allocated buffer, used when size_ is small enough | |
}; | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* The byte_buffer class wraps common buffer operations for easy accessing. | |
* The size of the buffer will grow/shrink automatically. | |
*/ | |
class byte_buffer | |
{ | |
public: | |
byte_buffer(); | |
byte_buffer(const byte_buffer& x); | |
~byte_buffer(); | |
byte_buffer& operator = (const byte_buffer& x); | |
void swap(byte_buffer& x); | |
bool empty() const; | |
size_t size() const; | |
size_t capacity() const; | |
size_t push_back(const byte_t* buf, size_t nbytes); | |
size_t push_back(const char* buf, size_t nbytes); | |
size_t push_back(const void* buf, size_t nbytes); | |
size_t pop_front(byte_t* buf, size_t nbytes); | |
size_t pop_front(char* buf, size_t nbytes); | |
size_t pop_front(void* buf, size_t nbytes); | |
const byte_t* data() const; | |
byte_t at(size_t i) const; | |
private: | |
size_t size_; | |
byte_t* data_; | |
}; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment