/* * This file is a part of PikoTools * and is distributed under the 2-Clause BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2012-2021, 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: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. 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. * * 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 HOLDER 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_pikotools_src_membuffer_membuffer #define headerfile_pikotools_src_membuffer_membuffer #include namespace pt { /* stack_size and heap_block_size have to be *greater* than zero */ template class MemBuffer { public: class iterator { public: bool operator==(const iterator & i) const; bool operator!=(const iterator & i) const; iterator & operator++(); // prefix ++ iterator operator++(int); // postfix ++ iterator & operator--(); // prefix -- iterator operator--(int); // postfix -- item_type & operator*(); private: MemBuffer * mem_buffer; size_t dynamic_array_index; size_t index; friend class MemBuffer; }; class const_iterator { public: const_iterator(); const_iterator(const const_iterator & i); const_iterator(const iterator & i); const_iterator & operator=(const const_iterator & i); const_iterator & operator=(const iterator & i); bool operator==(const const_iterator & i) const; bool operator!=(const const_iterator & i) const; const_iterator & operator++(); // prefix ++ const_iterator operator++(int); // postfix ++ const_iterator & operator--(); // prefix -- const_iterator operator--(int); // postfix -- item_type 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(item_type item); void append(const item_type * item_array, size_t len); template void append(const in_item_type * item_array, size_t len); template void append(const MemBuffer & arg); 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(); const_iterator begin() const; const_iterator end() const; item_type & operator[](size_t i); const item_type operator[](size_t i) const; private: struct MemArray { size_t size_used; item_type * buf; }; item_type 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() // used by ctors void Initialize(); void add_dynamic_node(); }; /* 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 item_type & 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) const { return mem_buffer == i.mem_buffer && dynamic_array_index == i.dynamic_array_index && index == i.index; } template bool MemBuffer::iterator::operator!=(const iterator & i) const { return mem_buffer != i.mem_buffer || dynamic_array_index != i.dynamic_array_index || index != i.index; } /* const_iterator */ template MemBuffer::const_iterator::const_iterator() { } template MemBuffer::const_iterator::const_iterator(const const_iterator & i) { operator=(i); } template MemBuffer::const_iterator::const_iterator(const iterator & i) { operator=(i); } template typename MemBuffer::const_iterator & MemBuffer::const_iterator::operator=(const const_iterator & i) { mem_buffer = i.mem_buffer; dynamic_array_index = i.dynamic_array_index; index = i.index; return *this; } template typename MemBuffer::const_iterator & MemBuffer::const_iterator::operator=(const iterator & i) { mem_buffer = i.mem_buffer; dynamic_array_index = i.dynamic_array_index; index = i.index; return *this; } template typename MemBuffer::const_iterator & MemBuffer::const_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::const_iterator MemBuffer::const_iterator::operator++(int) { const_iterator old(*this); operator++(); return old; } template typename MemBuffer::const_iterator & MemBuffer::const_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::const_iterator MemBuffer::const_iterator::operator--(int) { const_iterator old(*this); operator++(); return old; } template item_type MemBuffer::const_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::const_iterator::operator==(const const_iterator & i) const { return mem_buffer == i.mem_buffer && dynamic_array_index == i.dynamic_array_index && index == i.index; } template bool MemBuffer::const_iterator::operator!=(const const_iterator & i) const { return mem_buffer != i.mem_buffer || dynamic_array_index != i.dynamic_array_index || index != i.index; } /* MemBuffer */ template void MemBuffer::Initialize() { 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() { Initialize(); } template MemBuffer::~MemBuffer() { if( dynamic_array ) { for(size_t i=0 ; i MemBuffer::MemBuffer(const MemBuffer & arg) { Initialize(); operator=(arg); } template MemBuffer & MemBuffer::operator=(const MemBuffer & arg) { if( size_used > 0 ) clear(); const_iterator i = arg.begin(); for( ; i != arg.end() ; ++i) append(*i); return *this; } template void MemBuffer::add_dynamic_node() { 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(item_type 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 ) add_dynamic_node(); 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 ) add_dynamic_node(); 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(const item_type * item_array, size_t len) { if( size_used + len <= stack_size ) { for(size_t i=0 ; i template void MemBuffer::append(const in_item_type * item_array, size_t len) { for(size_t i=0 ; i(item_array[i])); } template template void MemBuffer::append( const MemBuffer & arg) { typename MemBuffer::const_iterator i = arg.begin(); for( ; i != arg.end() ; ++i) append(static_cast(*i)); } template item_type & 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 item_type 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::const_iterator MemBuffer::begin() const { const_iterator i; i.mem_buffer = this; i.dynamic_array_index = size_t(-1); i.index = 0; return i; } template typename MemBuffer::const_iterator MemBuffer::end() const { const_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 void MemBuffer::reserve(size_t len) { size_reserved = len; while( size_allocated < size_reserved ) add_dynamic_node(); } 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