/* * This file is a part of PikoTools * and is distributed under the (new) BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2012, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name Tomasz Sowa nor the names of contributors to this * project may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef headerfile_picotools_membuffer_membuffer #define headerfile_picotools_membuffer_membuffer namespace PT { /* */ template class MemBuffer { public: class Iterator { public: bool operator==(const Iterator & i); bool operator!=(const Iterator & i); Iterator & operator++(); // prefix ++ Iterator operator++(int); // postfix ++ Iterator & operator--(); // prefix -- Iterator operator--(int); // postfix -- ItemType & operator*(); private: MemBuffer * mem_buffer; size_t dynamic_array_index; size_t index; friend class MemBuffer; }; class ConstIterator { public: bool operator==(const ConstIterator & i); bool operator!=(const ConstIterator & i); ConstIterator & operator++(); // prefix ++ ConstIterator operator++(int); // postfix ++ ConstIterator & operator--(); // prefix -- ConstIterator operator--(int); // postfix -- ItemType operator*(); private: const MemBuffer * mem_buffer; size_t dynamic_array_index; size_t index; friend class MemBuffer; }; MemBuffer(); ~MemBuffer(); MemBuffer(const MemBuffer & arg); MemBuffer & operator=(const MemBuffer & arg); void Append(ItemType item); void Append(ItemType * item_array, size_t len); size_t Size() const; bool Empty() const; void Reserve(size_t len); size_t Capacity() const; void Clear(); // frees memory but only to Capacity() Iterator Begin(); Iterator End(); ConstIterator Begin() const; ConstIterator End() const; ItemType & operator[](size_t i); const ItemType operator[](size_t i) const; private: struct MemArray { size_t size_used; ItemType * buf; }; ItemType stack_array[stack_size]; MemArray * dynamic_array; // dynamic array of MemArray descriptors size_t dynamic_array_index; // index of a MemArray to which the last insertion was made // size_t(-1) means the stack_array size_t dynamic_array_used; // how many MemArray-s have been inited in dynamic_array size_t dynamic_array_size; // the size of the dynamic_array size_t size_used; // the size of all valid items size_t size_allocated; // how many memory is reserved size_t size_reserved; // memory reserved by Reserve(), it is used by Clear() void AddDynamicNode(); }; /* Iterator */ template typename MemBuffer::Iterator & MemBuffer::Iterator::operator++() { if( dynamic_array_index == size_t(-1) ) { index += 1; if( index >= stack_size ) { index = 0; dynamic_array_index = 0; } } else { index += 1; if( index >= heap_block_size ) { dynamic_array_index += 1; index = 0; } } return *this; } template typename MemBuffer::Iterator MemBuffer::Iterator::operator++(int) { Iterator old(*this); operator++(); return old; } template typename MemBuffer::Iterator & MemBuffer::Iterator::operator--() { if( index == 0 ) { dynamic_array_index -= 1; if( dynamic_array_index == size_t(-1) ) index = stack_size - 1; else index = heap_block_size - 1; } else { index -= 1; } return *this; } template typename MemBuffer::Iterator MemBuffer::Iterator::operator--(int) { Iterator old(*this); operator++(); return old; } template ItemType & MemBuffer::Iterator::operator*() { if( dynamic_array_index == size_t(-1) ) { return mem_buffer->stack_array[index]; } else { return mem_buffer->dynamic_array[dynamic_array_index].buf[index]; } } template bool MemBuffer::Iterator::operator==(const Iterator & i) { return mem_buffer == i.mem_buffer && dynamic_array_index == i.dynamic_array_index && index == i.index; } template bool MemBuffer::Iterator::operator!=(const Iterator & i) { return mem_buffer != i.mem_buffer || dynamic_array_index != i.dynamic_array_index || index != i.index; } /* ConstIterator */ template typename MemBuffer::ConstIterator & MemBuffer::ConstIterator::operator++() { if( dynamic_array_index == size_t(-1) ) { index += 1; if( index >= stack_size ) { index = 0; dynamic_array_index = 0; } } else { index += 1; if( index >= heap_block_size ) { dynamic_array_index += 1; index = 0; } } return *this; } template typename MemBuffer::ConstIterator MemBuffer::ConstIterator::operator++(int) { ConstIterator old(*this); operator++(); return old; } template typename MemBuffer::ConstIterator & MemBuffer::ConstIterator::operator--() { if( index == 0 ) { dynamic_array_index -= 1; if( dynamic_array_index == size_t(-1) ) index = stack_size - 1; else index = heap_block_size - 1; } else { index -= 1; } return *this; } template typename MemBuffer::ConstIterator MemBuffer::ConstIterator::operator--(int) { ConstIterator old(*this); operator++(); return old; } template ItemType MemBuffer::ConstIterator::operator*() { if( dynamic_array_index == size_t(-1) ) { return mem_buffer->stack_array[index]; } else { return mem_buffer->dynamic_array[dynamic_array_index].buf[index]; } } template bool MemBuffer::ConstIterator::operator==(const ConstIterator & i) { return mem_buffer == i.mem_buffer && dynamic_array_index == i.dynamic_array_index && index == i.index; } template bool MemBuffer::ConstIterator::operator!=(const ConstIterator & i) { return mem_buffer != i.mem_buffer || dynamic_array_index != i.dynamic_array_index || index != i.index; } /* MemBuffer */ template MemBuffer::MemBuffer() { size_reserved = 0; size_used = 0; size_allocated = stack_size; dynamic_array = 0; dynamic_array_index = size_t(-1); dynamic_array_used = 0; dynamic_array_size = 0; } template MemBuffer::~MemBuffer() { if( dynamic_array ) { for(size_t i=0 ; i MemBuffer::MemBuffer(const MemBuffer & arg) { operator=(arg); } template MemBuffer & MemBuffer::operator=(const MemBuffer & arg) { if( size_used > 0 ) Clear(); ConstIterator i = arg.Begin(); for( ; i != arg.End() ; ++i) Append(*i); return *this; } template void MemBuffer::AddDynamicNode() { if( dynamic_array_used >= dynamic_array_size ) { // reallocating dynamic_array_size += 2; // 64; MemArray * new_array = new MemArray[dynamic_array_size]; for(size_t i=0 ; i void MemBuffer::Append(ItemType item) { if( size_used < stack_size ) { stack_array[size_used] = item; } else { if( dynamic_array_index == size_t(-1) ) { dynamic_array_index = 0; if( dynamic_array_index >= dynamic_array_used ) AddDynamicNode(); dynamic_array[dynamic_array_index].size_used = 0; } else if( dynamic_array[dynamic_array_index].size_used >= heap_block_size ) { dynamic_array_index += 1; if( dynamic_array_index >= dynamic_array_used ) AddDynamicNode(); dynamic_array[dynamic_array_index].size_used = 0; } dynamic_array[dynamic_array_index].buf[dynamic_array[dynamic_array_index].size_used] = item; dynamic_array[dynamic_array_index].size_used += 1; } size_used += 1; } template void MemBuffer::Append(ItemType * item_array, size_t len) { if( size_used + len <= stack_size ) { for(size_t i=0 ; i ItemType & MemBuffer::operator[](size_t i) { if( i < stack_size ) { return stack_array[i]; } else { i -= stack_size; size_t index = i / heap_block_size; size_t offset = i % heap_block_size; return dynamic_array[index].buf[offset]; } } template const ItemType MemBuffer::operator[](size_t i) const { if( i < stack_size ) { return stack_array[i]; } else { i -= stack_size; size_t index = i / heap_block_size; size_t offset = i % heap_block_size; return dynamic_array[index].buf[offset]; } } template size_t MemBuffer::Size() const { return size_used; } template bool MemBuffer::Empty() const { return size_used == 0; } template typename MemBuffer::Iterator MemBuffer::Begin() { Iterator i; i.mem_buffer = this; i.dynamic_array_index = size_t(-1); i.index = 0; return i; } template typename MemBuffer::Iterator MemBuffer::End() { Iterator i; i.mem_buffer = this; if( size_used <= stack_size ) { i.dynamic_array_index = size_t(-1); i.index = size_used; if( i.index >= stack_size ) { i.dynamic_array_index = 0; i.index = 0; } } else { i.dynamic_array_index = dynamic_array_index; i.index = dynamic_array[dynamic_array_index].size_used; if( i.index >= heap_block_size ) { i.dynamic_array_index += 1; i.index = 0; } } return i; } template typename MemBuffer::ConstIterator MemBuffer::Begin() const { ConstIterator i; i.mem_buffer = this; i.dynamic_array_index = size_t(-1); i.index = 0; return i; } template typename MemBuffer::ConstIterator MemBuffer::End() const { ConstIterator i; i.mem_buffer = this; if( size_used <= stack_size ) { i.dynamic_array_index = size_t(-1); i.index = size_used; if( i.index >= stack_size ) { i.dynamic_array_index = 0; i.index = 0; } } else { i.dynamic_array_index = dynamic_array_index; i.index = dynamic_array[dynamic_array_index].size_used; if( i.index >= heap_block_size ) { i.dynamic_array_index += 1; i.index = 0; } } return i; } template void MemBuffer::Reserve(size_t len) { size_reserved = len; while( size_allocated < size_reserved ) AddDynamicNode(); } template size_t MemBuffer::Capacity() const { return size_allocated; } template void MemBuffer::Clear() { size_t index = 0; if( size_reserved > stack_size ) { index = (size_reserved - stack_size) / heap_block_size + 1; size_t old_index = index; for(; index < dynamic_array_used ; ++index) { size_allocated -= heap_block_size; delete [] dynamic_array[index].buf; } dynamic_array_used = old_index; } size_used = 0; dynamic_array_index = size_t(-1); } } // namespace #endif