// This file defines the block buffer #ifndef BASE_MEMORY_BLOCKBUFFER_H_ #define BASE_MEMORY_BLOCKBUFFER_H_ #include #include #include #include namespace nbase { // boost::pool min accord template struct default_block_allocator_malloc_free { enum { requested_size = BlockSize }; static char * ordered_malloc(size_t n) { return (char *)malloc(requested_size * n); } static void ordered_free(char * const block, size_t) { free(block); } }; template struct default_block_allocator_new_delete { enum { requested_size = BlockSize }; static char * ordered_malloc(size_t n) { return new (std::nothrow) char[requested_size * n]; } static void ordered_free(char * const block, size_t) { delete [] block; } }; #ifdef USE_ALLOCATOR_NEW_DELETE typedef default_block_allocator_new_delete<1*1024> def_block_alloc_1k; typedef default_block_allocator_new_delete<2*1024> def_block_alloc_2k; typedef default_block_allocator_new_delete<4*1024> def_block_alloc_4k; typedef default_block_allocator_new_delete<8*1024> def_block_alloc_8k; typedef default_block_allocator_new_delete<16*1024> def_block_alloc_16k; typedef default_block_allocator_new_delete<32*1024> def_block_alloc_32k; #else typedef default_block_allocator_malloc_free<1*1024> def_block_alloc_1k; typedef default_block_allocator_malloc_free<2*1024> def_block_alloc_2k; typedef default_block_allocator_malloc_free<4*1024> def_block_alloc_4k; typedef default_block_allocator_malloc_free<8*1024> def_block_alloc_8k; typedef default_block_allocator_malloc_free<16*1024> def_block_alloc_16k; typedef default_block_allocator_malloc_free<32*1024> def_block_alloc_32k; #endif // USE_ALLOCATOR_NEW_DELETE template class BlockBuffer { public: typedef BlockAllocator allocator; enum { max_blocks = MaxBlocks }; enum { npos = size_t(-1) }; BlockBuffer() { block_ = 0; size_ = 0; data_ = (char *)""; } virtual ~BlockBuffer() { free(); } inline bool empty() const { return size() == 0; } inline size_t block() const { return block_; } inline size_t blocksize() const { return allocator::requested_size; } inline size_t capacity() const { return block_ * allocator::requested_size; } inline size_t maxsize() const { return max_blocks * allocator::requested_size; } inline size_t maxfree() const { return maxsize() - size(); } inline size_t freespace() const { return capacity() - size(); } inline char * data() { return data_; } inline size_t size() const { return size_; } bool resize(size_t n, char c = 0); bool reserve(size_t n); bool append(const char *app, size_t len); bool replace(size_t pos, const char *rep, size_t n); void erase(size_t pos = 0, size_t n = npos, bool hold = false); static size_t current_total_blocks() { return s_current_total_blocks; } static size_t peak_total_blocks() { return s_peak_total_blocks; } protected: bool increase_capacity(size_t increase_size); char * tail() { return data_ + size_; } void size(size_t size) { assert(size <= capacity()); size_ = size; } private: void free(); static size_t s_current_total_blocks; static size_t s_peak_total_blocks; char *data_; size_t size_; size_t block_; BlockBuffer(const BlockBuffer&); void operator = (const BlockBuffer &); }; template size_t BlockBuffer::s_current_total_blocks = 0; template size_t BlockBuffer::s_peak_total_blocks = 0; template inline void BlockBuffer::free() { if (block_ > 0) { allocator::ordered_free(data_, block_); s_current_total_blocks -= block_; data_ = (char *)""; block_ = 0; } } template inline bool BlockBuffer::append(const char *app, size_t len) { if (len == 0) return true; // no data if (increase_capacity(len)) { memmove(tail(), app, len); // append size_ += len; return true; } return false; } template inline bool BlockBuffer::reserve(size_t n) { return (n <= capacity() || increase_capacity(n - capacity())); } template inline bool BlockBuffer::resize(size_t n, char c) { if (n > size()) // increase { size_t len = n - size(); if (!increase_capacity(len)) return false; memset(tail(), c, len); } size_ = n; return true; } template inline bool BlockBuffer::replace(size_t pos, const char *rep, size_t n) { if (pos >= size()) // out_of_range ? return append(rep, n); if (pos + n >= size()) // replace all beginning with position pos { size_ = pos; return append(rep, n); } if (n > 0) memmove(data_ + pos, rep, n); return true; } template inline void BlockBuffer::erase(size_t pos, size_t n, bool hold) { assert(pos <= size()); // out_of_range debug. size_t m = size() - pos; // can erase if (n >= m) size_ = pos; // all clear after pos else { size_ -= n; memmove(data_ + pos, data_ + pos + n, m - n); } if (empty() && !hold) free(); } /* * after success increase_capacity : freespace() >= increase_size * if false : does not affect exist data */ template inline bool BlockBuffer::increase_capacity(size_t increase_size) { if (increase_size == 0) return true; size_t newblock = block_; size_t free = freespace(); //if (increase_size > maxsize() - free) throw std::out_of_range("BlockBuffer out of range"); if (free >= increase_size) return true; increase_size -= free; newblock += increase_size / allocator::requested_size; if ((increase_size % allocator::requested_size) > 0) newblock ++; if (newblock > max_blocks) return false; char *newdata = (char *)(allocator::ordered_malloc(newblock)); if (0 == newdata) return false; if (block_ > 0) { // copy old data and free old block memcpy(newdata, data_, size_); allocator::ordered_free(data_, block_); } s_current_total_blocks += newblock - block_; if (s_current_total_blocks > s_peak_total_blocks) s_peak_total_blocks = s_current_total_blocks; data_ = newdata; block_ = newblock; return true; } template class ForwardBuffer { public: ForwardBuffer(Buffer &buffer) : buffer_(&buffer), position_(0) {} ~ForwardBuffer() { if (buffer_) buffer_->erase(0, position_); } char * data() { return buffer_->data() + position_; } size_t size() { return buffer_->size() - position_; } void erase(size_t pos, size_t n) { if (pos == 0) { position_ += n; assert(position_ <= buffer_->size()); } else buffer_->erase(position_ + pos, n); } bool empty() const { return buffer_->size() == position_; } void release() { buffer_ = NULL; } private: Buffer *buffer_; // release need pointer. size_t position_; }; } // namespace nbase #endif // BASE_MEMORY_BLOCKBUFFER_H_