/* ---- This file is part of SECONDO. Copyright (C) 2004, University in Hagen, Department of Computer Science, Database Systems for New Applications. SECONDO is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. SECONDO is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with SECONDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ---- //paragraph [10] title: [{\Large \bf ] [}] //paragraph [11] title: [{\large \bf ] [}] //paragraph [12] title: [{\normalsize \bf ] [}] //paragraph [21] table1column: [\begin{quote}\begin{tabular}{l}] [\end{tabular}\end{quote}] //paragraph [22] table2columns: [\begin{quote}\begin{tabular}{ll}] [\end{tabular}\end{quote}] //paragraph [23] table3columns: [\begin{quote}\begin{tabular}{lll}] [\end{tabular}\end{quote}] //paragraph [24] table4columns: [\begin{quote}\begin{tabular}{llll}] [\end{tabular}\end{quote}] //[--------] [\hline] //characters [1] verbatim: [$] [$] //characters [2] formula: [$] [$] //characters [3] capital: [\textsc{] [}] //characters [4] teletype: [\texttt{] [}] //[ae] [\"a] //[oe] [\"o] //[ue] [\"u] //[ss] [{\ss}] //[<=] [$\leq$] //[#] [\neq] //[tilde] [\verb|~|] 1 Header File: DbArray Version: 0.7 August 2002 RHG April 2003 Victor Almeida chaged the implementation to not use templates. June 2010 Christian Duentgen: The Flob interface and implementation has been changed entirely by Thomas Behr. As a consequence, the functions Put() and Get() now expect the target buffer to be provided (and deleted) by the caller. 1.1 Overview This module offers a generic persistent array implemented on top of the ~Flob~ interface. 1.2 Interface methods This module offers the following methods: [23] Creation/Removal & Access & Inquiries \\ [--------] DbArray & Get & NoComponents \\ [tilde]DbArray & Put & Id \\ Destroy & resize & GetFlobSize \\ & Append & GetUsedSize \\ & clean & GetElemSize \\ & Find & GetCapacity \\ & Sort & \\ & Restrict & \\ & copyTo & \\ & copyFrom & \\ Operations have to follow the protocol shown below: Figure 1: Protocol [Protocol.eps] 1.3 Class ~DbArray~SetPersistentCache An instance of the class is a handle to a persistent array of fixed size. */ #ifndef DBARRAY_H #define DBARRAY_H #include #include #include #include "Flob.h" #include "Serialize.h" #include template class DbArray : public Flob { public: /* ~Standard constructor~ Does nothing. Should only be used within Cast functions. */ inline DbArray() : Flob() {} /* ~Constructor~ Creates a DbArray with a given capacity. Use this instead of the standard constructor to create a new ~DbArray~! */ inline DbArray( const int n ): Flob( n * sizeof( DbArrayElement ) ), nElements( 0 ), maxElements( n ) {} /* ~Destructor~ */ inline ~DbArray() {} /* ~Resize~ Changes the capacity of the DbArray. */ bool resize( const SmiSize& newSize ){ if(newSize==0){ return clean(); } if( newSize < nElements ){ // reduce size nElements = newSize; } maxElements = newSize; return Flob::resize( newSize * sizeof( DbArrayElement ) ); } virtual bool clean() { nElements = 0; maxElements = 0; return Flob::clean(); } inline bool Destroy() { nElements = 0; maxElements = 0; return Flob::destroy(); } inline bool Append( const DbArrayElement& elem ) { return Put( nElements, elem ); } inline bool Append(const DbArray& a){ if( a.nElements == 0){ // nothing to do return true; } if(nElements + a.nElements > maxElements){ // resize of the underlying Flob required if(!resize((nElements + a.nElements)*2)){ return false; } } // copy the FlobData size_t size = a.nElements * sizeof(DbArrayElement); char* buffer = new char[size]; if(!a.Flob::read(buffer, size, 0)){ return false; } bool ok = Flob::write(buffer, size, (nElements)*sizeof(DbArrayElement)); delete [] buffer; nElements += a.nElements; return ok; } /* This function copies a range from this DbArray into dest. The destOffset must be less than or equal to the size of dest. That is, it allows only for overwriting dest elems or appending to them, such that no gaps of uninitialized values occur within dest. If the size of dest doesn't fit the copied range, it will be resized automatically. */ inline bool copyTo(DbArray& dest, int sourceOffset, int numberOfElems, int destOffset) { if( numberOfElems == 0) { // nothing to do return true; } if( numberOfElems < 0 || sourceOffset < 0 || destOffset < 0 || (int) nElements < sourceOffset + numberOfElems || destOffset > (int)dest.nElements) { //wrong arguments return false; } if((int)dest.maxElements < destOffset + numberOfElems){ // resize of the destination Flob if(!dest.resize(destOffset + numberOfElems)){ return false; } } // copy the FlobData size_t size = numberOfElems * sizeof(DbArrayElement); size_t readOffset = sourceOffset * sizeof(DbArrayElement); char* buffer = new char[size]; if(!Flob::read(buffer, size, readOffset)){ return false; } size_t writeOffset = destOffset * sizeof(DbArrayElement); bool ok = dest.Flob::write(buffer, size, writeOffset); delete [] buffer; dest.nElements = ((int)dest.nElements > (numberOfElems + destOffset))? dest.nElements: (numberOfElems + destOffset); return ok; } /* ~Put~ Puts elem to the given position in the array. If the array is not large enough, the array is growed automatically. */ bool Put( const int index, const DbArrayElement& elem ) { if((size_t) index >= nElements){ // put a new element nElements = index + 1; if((size_t)index >= maxElements){ // underlying flob is too small maxElements = index + 1; if(maxElements <=9){ maxElements = 16; } else { maxElements = maxElements * 2; } if(!Flob::resize( maxElements * sizeof( DbArrayElement ) )){ return false; } } } return Flob::write((char*)&elem, // buffer sizeof(DbArrayElement), // size index * sizeof(DbArrayElement)); // offset } /* ~Get~ Returns the element stored at position __index__ within the array. */ inline bool Get( int index, DbArrayElement* elem ) const{ //assert( index >= 0 ); //assert( (size_t) index < nElements ); if(!Flob::read((char*)elem, sizeof(DbArrayElement), index*sizeof(DbArrayElement))){ //memset(elem, 0, sizeof(DbArrayElement)); //elem = (new ((void*)elem) DbArrayElement); return false; } elem = (new ((void*)elem) DbArrayElement); return true; } inline bool Get( int index, DbArrayElement& elem ) const{ return Get(index, &elem); } /* ~Size~ Returns the number of stored Elements. */ inline int Size() const { return nElements; } /* ~TrimToSize~ Reduces a DbArray to the capacity to store exacly all stored elements. */ bool TrimToSize() { bool ok = true; if (maxElements > nElements) { if (nElements == 0) { ok = Flob::clean(); } else { ok = Flob::resize(nElements * sizeof(DbArrayElement)); } } maxElements = nElements; return ok; } /* ~Sort~ Sorts this array according to the given comparison function. In the current state, we assume that the complete Flob can be hold in main memory. */ bool Sort( int (*cmp)( const void *a, const void *b) ) { if( nElements <= 1 ){ return true; } uint32_t size = nElements * sizeof(DbArrayElement); char* buffer = new char[size]; if(!Flob::read(buffer, size, 0)){ delete [] buffer; return false; } qsort( buffer, nElements, sizeof( DbArrayElement ), cmp ); bool res = Flob::write(buffer, size, 0); delete[] buffer; return res; } /* ~Find~ Searches (binary search) for a given key in the database array given the ~cmp~ comparison criteria. It is assumed that the array is sorted. The function returns true if the ~key~ is in the array and false otherwise. The position is returned in the ~result~ argument. If ~key~ is not in the array, then ~result~ contains the position where it should be. */ bool Find( const void *key, int (*cmp)( const void *a, const void *b), int& result ) const { DbArrayElement elem; if(nElements == 0) { result = 0; return false; } // check if key is smaller than the smallest element Get( 0, &elem ); if( cmp( key, &elem ) < 0 ) { result = 0; return false; } // check if key is larger than the largest element Get( nElements - 1, elem ); if( cmp( key, &elem ) > 0 ) { result = nElements; return false; } int first = 0, last = nElements - 1, mid; while (first <= last) { mid = ( first + last ) / 2; Get( mid, &elem ); if( cmp( key, &elem ) > 0 ){ first = mid + 1; } else if( cmp( key, &elem ) < 0 ) { last = mid - 1; } else { result = mid; return true; } } result = first < last ? first + 1 : last + 1; return false; } /* Restricts the DbArray to the interval set of indices passed as argument. */ virtual bool Restrict( const std::vector< std::pair >& intervals, DbArray& result ) const{ // compute the result size unsigned int newSize = 0; for( std::vector< std::pair >::const_iterator it= intervals.begin(); it < intervals.end(); it++ ) { assert( it->first <= it->second ); newSize += ( ( it->second - it->first ) + 1 ) * sizeof( DbArrayElement ); } assert( newSize <= Flob::getSize() ); DbArray res(newSize/sizeof(DbArrayElement)); if( newSize > 0 ){ size_t targetoffset = 0; // copy value into the temporarly buffer for( std::vector< std::pair >::const_iterator it = intervals.begin(); it < intervals.end(); it++ ) { // copy the whole interval into a buffer ibuffer size_t start = it->first; size_t end = it->second; size_t bufsize = ((end-start)+1) * sizeof(DbArrayElement); char* ibuffer = new char[bufsize]; Flob::read(ibuffer, bufsize, start*sizeof(DbArrayElement)); // write ibuffer into res res.Flob::write(ibuffer, bufsize, targetoffset); targetoffset += bufsize; delete[] ibuffer; } } res.nElements = newSize/sizeof(DbArrayElement); res.maxElements = newSize/sizeof(DbArrayElement); result = res; return true; } /* ~GetFlobSize~ Returns the capacity of the underlying Flob. */ size_t GetFlobSize() const { return Flob::getSize(); } /* ~GetUsedSize~ Returns the total size occupied by the managed elements. */ size_t GetUsedSize() const { return nElements * sizeof(DbArrayElement); } /* ~GetElemSize~ Returns the size of a single element. */ size_t GetElemSize() const { return sizeof(DbArrayElement); } /* ~GetCapacity~ Returns the capacity of the array. */ size_t GetCapacity() const { return maxElements; } inline static size_t headerSize() { return Flob::headerSize() + 2*sizeof(SmiSize); } /* ~SaveHeader~ Saves header information (this) to a record. */ virtual size_t serializeHeader( char* buffer, SmiSize& offset) const { // first save the flob SmiSize sz = Flob::serializeHeader(buffer, offset); // append nElements and maxElements WriteVar(nElements, buffer, offset); WriteVar(maxElements, buffer, offset); sz += 2*sizeof(SmiSize); return sz; } virtual void restoreHeader(char* buffer, SmiSize& offset) { Flob::restoreHeader(buffer, offset); ReadVar(nElements, buffer, offset); ReadVar(maxElements, buffer, offset); } bool copyFrom(const DbArray& src){ bool res = Flob::copyFrom(src); nElements = src.nElements; maxElements = src.maxElements; return res; } bool copyTo(DbArray& dest){ bool res = Flob::copyTo(dest); dest.nElements = nElements; dest.maxElements = maxElements; return res; } bool copyFrom(const Flob& src){ DbArray const* dbsrc = static_cast const* >(&src); return copyFrom(*dbsrc); } bool copyTo(Flob& dest) const{ DbArray* dbdest = static_cast* >(&dest); bool res = Flob::copyTo(dest); dbdest->nElements = nElements; dbdest->maxElements = maxElements; return res; } class const_iterator{ friend class DbArray; public: const_iterator(const const_iterator& other): dbarray(other.dbarray), position(other.position), elem(other.elem) {} const_iterator& operator=(const const_iterator& other){ dbarray = other.dbarray; position = other.position; elem = other.elem; return *this; } const_iterator& operator++(){ if(dbarray){ if(positionSize()){ position++; if(positionSize()){ dbarray->Get(position,elem); } } else { // end() reached position = dbarray->Size(); } } else { // single element iterator if(position<=0){ // 0 or -1 allowed position++; } } return *this; } const_iterator& operator++(int dummy){ if(dbarray){ if(positionSize()){ position++; if(positionSize()){ dbarray->Get(position,elem); } } else { // end() reached position = dbarray->Size(); } } else { // single element iterator if(position<=0){ // 0 or -1 allowed position++; } } return *this; } const_iterator& operator--(){ if(dbarray){ if(position>=0){ position--; if(position>=0 && positionSize()){ dbarray->Get(position, elem); } } else { position = -1; } } else { if(position >=0){ position--; } } return *this; } const_iterator& operator--(int dummy){ if(dbarray){ if(position>=0){ position--; if(position>=0 && positionSize()){ dbarray->Get(position, elem); } } else { position = -1; } } else { if(position >=0){ position--; } } return *this; } const DbArrayElement& operator*() const{ if(dbarray){ assert(position>=0); assert(position < dbarray->Size()); return elem; } else { assert(position==0); return elem; } } bool operator==(const const_iterator& other) const{ return position == other.position; } bool operator<(const const_iterator& other) const{ return position < other.position; } bool operator>(const const_iterator& other) const{ return position > other.position; } bool operator!=(const const_iterator& other) const{ return position != other.position; } bool operator<=(const const_iterator& other) const{ return position <= other.position; } bool operator>=(const const_iterator& other) const{ return position >= other.position; } private: const DbArray* dbarray; int position; DbArrayElement elem; const_iterator(const DbArray* dbarray_, const int position_ = 0 ): dbarray(dbarray_), position(position_) { if(position<0){ position=-1; } else if(position < dbarray->Size()){ dbarray->Get(position,elem); } else { position = dbarray->Size(); } } const_iterator(const DbArrayElement& elem_): dbarray(0),position(0), elem(elem_) {} }; const_iterator begin() const{ const_iterator it(this); return it; } const_iterator end() const{ const_iterator it(this,Size()); return it; } static const_iterator elem_iter_begin(const DbArrayElement& elem){ const_iterator it(elem); return it; } static const_iterator elem_iter_end(const DbArrayElement& elem){ const_iterator it(elem); it++; return it; } private: SmiSize nElements; /* Stores the number of elements currently managed (contained) by the array. */ SmiSize maxElements; /* Stores the total number of elements that can currently could be managed by this array (without resizing it). */ }; #endif //DBARRAY_H