From 4d968f5a85f31afd2158cb1172aabe184a19ebc5 Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Sun, 1 Jul 2012 22:38:27 +0000 Subject: [PATCH] added: some work in MemBuffer git-svn-id: svn://ttmath.org/publicrep/pikotools/trunk@422 e52654a7-88a9-db11-a3e9-0013d4bc506e --- membuffer/membuffer.h | 661 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 580 insertions(+), 81 deletions(-) diff --git a/membuffer/membuffer.h b/membuffer/membuffer.h index 710c160..dee151a 100644 --- a/membuffer/membuffer.h +++ b/membuffer/membuffer.h @@ -1,113 +1,184 @@ +/* + * 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 -#include - - - namespace PT { +/* -template + + +*/ +template class MemBuffer { public: class Iterator { - size_t vector_index; - size_t array_index; + public: bool operator==(const Iterator & i); bool operator!=(const Iterator & i); - bool operator<(const Iterator & i); - Iterator & operator++(); // prefix ++ + 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 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 MemBuffer; }; + + MemBuffer(); + ~MemBuffer(); + //MemBuffer(const MemBuffer & arg); + //MemBuffer & operator=(const MemBuffer & arg); void Append(ItemType item); void Append(ItemType * item_array, size_t len); - void Size() const; - void Empty() const; + size_t Size() const; + bool Empty() const; - void Reserve(); - void Capacity(); - void SetMinCapacity(); - void Clear(); // frees memory but only to SetMinCapacity() + void Reserve(size_t len); + size_t Capacity() const; + void Clear(); // frees memory but only to Capacity() Iterator Begin(); - ConstIterator Begin() const; - Iterator End(); + + ConstIterator Begin() const; ConstIterator End() const; - // may it's a better to have a static size of dynamic_array items - // so we can have following operators working in O(1) - //ItemType & operator[](size_t i); - //const ItemType operator[](size_t i) const; + ItemType & operator[](size_t i); + const ItemType operator[](size_t i) const; + private: struct MemArray { - size_t size; size_t size_used; ItemType * buf; }; ItemType stack_array[stack_size]; - std::vector dynamic_array; - size_t size_used; // the size of all items - size_t reserve_size; // how many memory is reserved - size_t last_allocated_list; // size of the last allocated vector + 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 -MemBuffer::Iterator & MemBuffer::Iterator::operator++() + +template +typename MemBuffer::Iterator & +MemBuffer::Iterator::operator++() { - if( vector_index == size_t(-1) ) + if( dynamic_array_index == size_t(-1) ) { - array_index += 1; + index += 1; - if( array_index >= stack_size ) + if( index >= stack_size ) { - array_index = 0; - vector_index = 0; + index = 0; + dynamic_array_index = 0; } } else { - // if not it means that this iterator is pointing at End() - if( vector_index < dynamic_array.size() && array_index < dynamic_array.back().size_used ) - { - array_index += 1; + index += 1; - if( array_index >= dynamic_array.back().size ) - { - array_index = 0; - vector_index += 1; - } + if( index >= heap_block_size ) + { + dynamic_array_index += 1; + index = 0; } } @@ -115,8 +186,9 @@ return *this; } -template -MemBuffer::Iterator MemBuffer::Iterator::operator++(int) +template +typename MemBuffer::Iterator +MemBuffer::Iterator::operator++(int) { Iterator old(*this); operator++(); @@ -126,69 +198,303 @@ return old; -template -void MemBuffer::MemBuffer() +template +typename MemBuffer::Iterator & +MemBuffer::Iterator::operator--() { - size_used = 0; - list_size = 0; - reserve_size = stack_size; - last_allocated_list = 512; // minimum 1 -} - - -template -void MemBuffer::Append(ItemType item) -{ - if( size_used < stack_size ) + if( index == 0 ) { - stack_array[size_used]; + dynamic_array_index -= 1; + + if( dynamic_array_index == size_t(-1) ) + index = stack_size - 1; + else + index = heap_block_size - 1; } else { - if( dynamic_array.empty() || dynamic_array.back().size_used >= dynamic_array.back().size ) + 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 ) { - last_allocated_list = last_allocated_list * 2; - dynamic_array.push_back(MemArray()); - dynamic_array.back().size = last_allocated_list; - dynamic_array.back().size_used = 0; - dynamic_array.back().buf = new ItemType[last_allocated_list]; - reserve_size += last_allocated_list; + 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 +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.back().buf[dynamic_array.back().size_used] = item; - dynamic_array.back().size_used += 1; + 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) +template +void MemBuffer::Append(ItemType * item_array, size_t len) { - // in the future we can add a test - // if the array can be placed directly in the last item from std::list - // the we put it all - - if( size_used < stack_size && size_used + len <= stack_size ) + if( size_used + len <= stack_size ) { - // may memcpy in the future? need some tests - for(size_t i=0 ; i::Append(ItemType * item_array, size_t len) + +template +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