//# SSMStringHandler.cc: Store Strings in the Standard Storage Manager //# Copyright (C) 2000,2001,2002 //# Associated Universities, Inc. Washington DC, USA. //# //# This library is free software; you can redistribute it and/or modify it //# under the terms of the GNU Library General Public License as published by //# the Free Software Foundation; either version 2 of the License, or (at your //# option) any later version. //# //# This library 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 Library General Public //# License for more details. //# //# You should have received a copy of the GNU Library General Public License //# along with this library; if not, write to the Free Software Foundation, //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. //# //# Correspondence concerning AIPS++ should be addressed as follows: //# Internet email: aips2-request@nrao.edu. //# Postal address: AIPS++ Project Office //# National Radio Astronomy Observatory //# 520 Edgemont Road //# Charlottesville, VA 22903-2475 USA //# //# $Id$ #include #include #include #include #include #include #include namespace casacore { //# NAMESPACE CASACORE - BEGIN SSMStringHandler::SSMStringHandler (SSMBase* aBase): itsSSMPtr (aBase), itsCurrentBucket (-1), itsLength (0), itsNDeleted (0), itsUsedLength (0), itsNextBucket (-1), itsData (0), itsIntBuf (0), isChanged (False), itsLastBucket (-1) { } SSMStringHandler::~SSMStringHandler() { delete [] itsData; delete [] itsIntBuf; } void SSMStringHandler::init() { delete [] itsData; itsData = 0; delete [] itsIntBuf; itsIntBuf = 0; itsIntSize = CanonicalConversion::canonicalSize(&itsUsedLength); itsStart = 4*itsIntSize; itsLength = itsSSMPtr->getBucketSize()-itsStart; itsData = new char[itsLength]; itsIntBuf = new char[itsIntSize]; memset(itsData,0,itsLength); memset(itsIntBuf,0,itsIntSize); } void SSMStringHandler::replace(Int bucketNr, Int offset, Int length, const String& string) { // Check if current bucket is wanted bucket, else get wanted bucket. if (bucketNr != itsCurrentBucket) { getBucket(bucketNr); } replaceData(offset,string.length(),string.chars()); // remove additional space left (if any) if (length - string.length() > 0) { remove (itsCurrentBucket, offset, length-string.length()); } } void SSMStringHandler::replace(Int bucketNr, Int offset, Int length, Int totalLength, const Array& string, Bool handleShape) { const IPosition& aShape = string.shape(); // Check if current bucket is wanted bucket, else get wanted bucket. if (bucketNr != itsCurrentBucket) { getBucket(bucketNr); } Bool deleteIt; const String *aString = string.getStorage(deleteIt); if (handleShape) { CanonicalConversion::fromLocal (itsIntBuf, (uInt) aShape.nelements()); replaceData (offset,itsIntSize, itsIntBuf); for (uInt i=0; i< aShape.nelements();i++) { CanonicalConversion::fromLocal (itsIntBuf, Int(aShape(i))); replaceData (offset,itsIntSize, itsIntBuf); } CanonicalConversion::fromLocal (itsIntBuf,1); replaceData (offset,itsIntSize, itsIntBuf); } for (uInt i=0;i size_t // CanonicalConversion::fromLocal (itsIntBuf, uInt(aString[i].length())); replaceData (offset,itsIntSize, itsIntBuf); replaceData (offset,aString[i].length(), aString[i].chars()); } string.freeStorage(aString,deleteIt); // remove additional space left (if any) if (length - totalLength > 0) { remove (itsCurrentBucket, offset, length-totalLength); } } void SSMStringHandler::replace(Int bucketNr, Int offset, Int length, Int totalLength, const IPosition& aShape) { // Check if current bucket is wanted bucket, else get wanted bucket. if (bucketNr != itsCurrentBucket) { getBucket(bucketNr); } CanonicalConversion::fromLocal (itsIntBuf, uInt(aShape.nelements())); replaceData (offset,itsIntSize, itsIntBuf); for (uInt i=0; i< aShape.nelements();i++) { CanonicalConversion::fromLocal (itsIntBuf, Int(aShape(i))); replaceData (offset,itsIntSize, itsIntBuf); } // write 'empty' flag CanonicalConversion::fromLocal (itsIntBuf,0); replaceData (offset,itsIntSize, itsIntBuf); // remove additional space left (if any) if (length - totalLength > 0) { remove (itsCurrentBucket, offset, length-totalLength); } } void SSMStringHandler::replaceData (Int& offset,Int length, const Char* data) { while (length > 0) { Int nCopy = length; if (length > itsLength-offset) { nCopy = itsLength-offset; } length -= nCopy; memcpy (itsData+offset, data, nCopy); data += nCopy; offset += nCopy; isChanged=True; if (length > 0) { offset = 0; getBucket (itsNextBucket); } } } void SSMStringHandler::put (Int& bucketNr, Int& offset, Int& length, const String& string) { if (length > 0) { if (static_cast(string.length()) > length || string.length() == 0) { remove (bucketNr, offset, length); bucketNr = 0; offset = 0; length = 0; } } if (string.length() == 0) { return; } if (length > 0) { if (itsCurrentBucket != bucketNr) { getBucket(bucketNr); } replace(bucketNr, offset, length, string); length = string.length(); return; } if (itsLastBucket == -1) { getNewBucket(False); } else if (itsCurrentBucket != itsLastBucket) { getBucket(itsLastBucket); } // if Bucket available but string doesn't fit and space < 50 get // a new bucket anyway. if (static_cast(string.length()) > itsLength-itsUsedLength && itsLength-itsUsedLength < 50 ) { getNewBucket(False); } offset = itsUsedLength; bucketNr = itsCurrentBucket; length = string.length(); putData (length, string.chars()); } void SSMStringHandler::put (Int& bucketNr, Int& offset, Int& length, const Array& string, Bool handleShape) { const IPosition& aShape = string.shape(); Int totalLength=0; Bool deleteIt; const String *aString = string.getStorage(deleteIt); for (uInt i=0;i 0) { if (totalLength > length || totalLength == 0) { remove (bucketNr, offset, length); bucketNr = 0; offset = 0; length = 0; } } if (totalLength == 0) { string.freeStorage(aString,deleteIt); return; } if (length > 0) { if (itsCurrentBucket != bucketNr) { getBucket(bucketNr); } replace(bucketNr, offset, length, totalLength,string,handleShape); length = totalLength; string.freeStorage(aString,deleteIt); return; } if (itsLastBucket == -1) { getNewBucket(False); } else if (itsCurrentBucket != itsLastBucket) { getBucket(itsLastBucket); } // if Bucket available but string doesn't fit and space < 50 get // a new bucket anyway. if (totalLength > itsLength-itsUsedLength && itsLength-itsUsedLength < 50 ) { getNewBucket(False); } bucketNr=itsCurrentBucket; offset= itsUsedLength; length= totalLength; if (handleShape) { CanonicalConversion::fromLocal (itsIntBuf, uInt(aShape.nelements())); putData (itsIntSize, itsIntBuf); for (uInt i=0; i< string.ndim();i++) { CanonicalConversion::fromLocal (itsIntBuf, Int(aShape(i))); putData (itsIntSize, itsIntBuf); } CanonicalConversion::fromLocal (itsIntBuf,1); putData (itsIntSize, itsIntBuf); } for (uInt i=0; i< string.nelements();i++) { // // Made it a uInt so the SGI compiler could figure out which overloaded // function to use, since it seemed confused by string::size_t -> size_t // CanonicalConversion::fromLocal (itsIntBuf, uInt(aString[i].length())); putData (itsIntSize, itsIntBuf); putData (aString[i].length(), aString[i].chars()); } string.freeStorage(aString,deleteIt); } void SSMStringHandler::putData (Int length, const Char* data) { while (length > 0) { Int toDo = length; if (toDo > itsLength-itsUsedLength ) { toDo = itsLength-itsUsedLength; } length-=toDo; memcpy (itsData+itsUsedLength, data, toDo); data += toDo; itsNDeleted -= toDo; itsUsedLength += toDo; isChanged=True; if (length > 0) { getNewBucket(True); } } } void SSMStringHandler::getData (Int length, Char* data,Int& offset) { while (length > 0) { Int nCopy = itsUsedLength-offset; if (length < nCopy) { nCopy = length; } length -= nCopy; memcpy (data,itsData+offset, nCopy); data += nCopy; offset += nCopy; if (length > 0) { getBucket(itsNextBucket); offset=0; } } } void SSMStringHandler::remove (Int bucketNr, Int offset, Int length) { if (itsCurrentBucket != bucketNr) { getBucket(bucketNr); } Int n = itsLength-offset; if (length < n) { n = length; } itsNDeleted+=n; // If space was at the end of the bucket, reset used length. if (offset+n == itsUsedLength) { itsUsedLength = offset; } isChanged = True; if (itsNDeleted == itsLength) { itsSSMPtr->removeBucket(itsCurrentBucket); if (itsCurrentBucket == itsLastBucket) { itsLastBucket=-1; } itsCurrentBucket=-1; isChanged = False; } // Check if continuation in next bucket length -= n; if (length > 0) { Int next=itsNextBucket; // We are deleting this concatenated string itsNextBucket=-1; offset=0; remove(next,offset,length); } } void SSMStringHandler::get (String& string, Int bucket, Int offset, Int length) { if (itsCurrentBucket != static_cast(bucket)) { getBucket(bucket); } string.resize (length); // resize storage which adds trailing 0 Char* data = &(string[0]); // get actual string getData(length,data,offset); // terminate string for old strings #ifdef USE_OLD_STRING data[length] = '\0'; #endif } void SSMStringHandler::get (Array& string, Int bucket, Int offset, Int length, Bool handleShape) { IPosition aShape; uInt aFilledFlag=0; String emptyString; if (length >0) { if (itsCurrentBucket != static_cast(bucket)) { getBucket(bucket); } aFilledFlag=1; if (handleShape) { getShape(aShape,bucket,offset,length); DebugAssert (aShape.isEqual (string.shape()),AipsError); // get the 'filled' flag getData (itsIntSize, itsIntBuf,offset); CanonicalConversion::toLocal(aFilledFlag,itsIntBuf); } } Bool deleteIt; String* aString = string.getStorage(deleteIt); for (uInt i=0; i< string.nelements();i++) { if (aFilledFlag == 0) { aString[i] = emptyString; } else { // get length of next string Beware, offset resetting will be done in // getdata, so you don't need to do it here again... getData (itsIntSize, itsIntBuf,offset); Int aL=0; CanonicalConversion::toLocal(aL,itsIntBuf); aString[i].resize (aL); // resize storage which adds trailing 0 Char* aS = &(aString[i][0]); // get actual string // get next string. Beware, offset resetting will be done in // getdata, so you don't need to do it here again... getData (aL, aS, offset); // terminate string #ifdef USE_OLD_STRING aS[aL] = '\0'; #endif } } string.putStorage(aString,deleteIt); } void SSMStringHandler::putShape (Int& bucketNr, Int& offset, Int& length, const IPosition& aShape) { Int totalLength=0; if (itsLastBucket == -1) { getNewBucket(False); } else if (itsCurrentBucket != itsLastBucket) { getBucket(itsLastBucket); } totalLength = (aShape.nelements()+2)*ValType::getCanonicalSize (TpInt); if (length > 0) { if (totalLength > length || totalLength == 0) { remove (bucketNr, offset, length); bucketNr = 0; offset = 0; length = 0; } } if (length > 0) { if (itsCurrentBucket != bucketNr) { getBucket(bucketNr); } replace(bucketNr, offset, length, totalLength,aShape); length = totalLength; return; } if (itsLastBucket == -1) { getNewBucket(False); } else if (itsCurrentBucket != itsLastBucket) { getBucket(itsLastBucket); } // if Bucket available but shape doesn't fit and space < 50 get // a new bucket anyway. if (totalLength > itsLength-itsUsedLength && itsLength-itsUsedLength < 50 ) { getNewBucket(False); } bucketNr=itsCurrentBucket; offset= itsUsedLength; length= totalLength; CanonicalConversion::fromLocal (itsIntBuf, uInt(aShape.nelements())); putData (itsIntSize, itsIntBuf); for (uInt i=0; i< aShape.nelements();i++) { CanonicalConversion::fromLocal (itsIntBuf, Int(aShape(i))); putData (itsIntSize, itsIntBuf); } // write 'empty' flag CanonicalConversion::fromLocal (itsIntBuf,0); putData (itsIntSize, itsIntBuf); } void SSMStringHandler::getShape (IPosition& aShape, Int bucket, Int& offset, Int) { if (itsCurrentBucket != static_cast(bucket)) { getBucket(bucket); } getData (itsIntSize, itsIntBuf,offset); Int nDim=0; CanonicalConversion::toLocal(nDim,itsIntBuf); aShape.resize(nDim); Int tmp; for (Int i=0; i< nDim; i++) { getData (itsIntSize, itsIntBuf,offset); CanonicalConversion::toLocal(tmp, itsIntBuf); aShape(i) = tmp; } } void SSMStringHandler::flush() { if (isChanged) { AlwaysAssert (itsCurrentBucket != -1, AipsError); //save old bucket Char* aPtr = itsSSMPtr->getBucket(itsCurrentBucket); CanonicalConversion::fromLocal (aPtr+itsIntSize, itsUsedLength); CanonicalConversion::fromLocal (aPtr+itsIntSize*2, itsNDeleted); CanonicalConversion::fromLocal (aPtr+itsIntSize*3, itsNextBucket); memcpy (aPtr+itsStart, itsData, itsLength); itsSSMPtr->setBucketDirty(); isChanged = False; } } void SSMStringHandler::getBucket (uInt bucketNr,Bool isNew) { // check if itsCurrentBuffer is in use, if so save this one first flush(); itsCurrentBucket = bucketNr; if (! isNew) { char* aPtr = itsSSMPtr->getBucket(itsCurrentBucket); memcpy (itsData, aPtr+itsStart, itsLength); CanonicalConversion::toLocal (itsUsedLength, aPtr+itsIntSize); CanonicalConversion::toLocal (itsNDeleted, aPtr+2*itsIntSize); CanonicalConversion::toLocal (itsNextBucket, aPtr+3*itsIntSize); } } void SSMStringHandler::getNewBucket(Bool doConcat) { Int bucketNr = itsSSMPtr->getNewBucket(); if (doConcat) { itsNextBucket = bucketNr; // save nextbucket isChanged=True; } getBucket(bucketNr,True); // zero dataspace itsUsedLength = 0; itsNDeleted = itsLength; itsNextBucket=-1; itsLastBucket=itsCurrentBucket; } void SSMStringHandler::resync() { AlwaysAssert (!isChanged,AipsError); itsCurrentBucket = -1; } } //# NAMESPACE CASACORE - END