1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-09 13:22:24 +03:00
Files
occt/src/NCollection/NCollection_SparseArrayBase.cxx
abv d5f74e42d6 0024624: Lost word in license statement in source files
License statement text corrected; compiler warnings caused by Bison 2.41 disabled for MSVC; a few other compiler warnings on 54-bit Windows eliminated by appropriate type cast
Wrong license statements corrected in several files.
Copyright and license statements added in XSD and GLSL files.
Copyright year updated in some files.
Obsolete documentation files removed from DrawResources.
2014-02-20 16:15:17 +04:00

352 lines
10 KiB
C++

// Created on: 2007-02-06
// Created by: Andrey BETENEV
// Copyright (c) 2007-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <NCollection_SparseArrayBase.hxx>
#include <Standard_ProgramError.hxx>
//=======================================================================
//function : allocData
//purpose :
//=======================================================================
void NCollection_SparseArrayBase::allocData (const Standard_Size iBlock)
{
if ( iBlock < myNbBlocks )
return;
// the allocation of blocks starts from myBlockSize items
// and then is multiplied by 2 every time reallocation is needed
Standard_Size newNbBlocks = ( myNbBlocks ? myNbBlocks * 2 : myBlockSize );
while (iBlock >= newNbBlocks) newNbBlocks *= 2;
Standard_Address* newData =
(Standard_Address*)malloc(newNbBlocks*sizeof(Standard_Address));
if ( myNbBlocks >0 )
memcpy (newData, myData, myNbBlocks*sizeof(Standard_Address));
memset (newData+myNbBlocks, 0, (newNbBlocks-myNbBlocks)*sizeof(Standard_Address));
free (myData);
myData = newData;
myNbBlocks = newNbBlocks;
}
//=======================================================================
//function : freeBlock
//purpose :
//=======================================================================
void NCollection_SparseArrayBase::freeBlock (const Standard_Size iBlock)
{
Standard_Address & anAddr = myData[iBlock];
Block aBlock = getBlock(anAddr);
for (Standard_Size anInd=0; anInd < myBlockSize; anInd++)
if ( aBlock.IsSet(anInd) )
{
destroyItem (getItem (aBlock, anInd));
mySize--;
}
free (anAddr);
anAddr = 0;
}
//=======================================================================
//function : Clear
//purpose :
//=======================================================================
void NCollection_SparseArrayBase::Clear ()
{
// free block data
for (Standard_Size iBlock=0; iBlock < myNbBlocks; iBlock++)
if ( myData[iBlock] )
freeBlock (iBlock);
// free blocks and reset counters
free (myData);
myData = 0;
myNbBlocks = 0;
// consistency check
Standard_ProgramError_Raise_if (mySize!=0,"NCollection_SparseArrayBase: Implementation error: inconsistent items count")
}
//=======================================================================
//function : assign
//purpose :
//=======================================================================
void NCollection_SparseArrayBase::assign (const NCollection_SparseArrayBase& theOther)
{
if (this == &theOther)
return;
// if block size is different, clear all data
if ( myBlockSize != theOther.myBlockSize )
Clear();
myBlockSize = theOther.myBlockSize;
// iterate by blocks in theOther
Standard_Size iBlock=0;
for (; iBlock < theOther.myNbBlocks; iBlock++)
{
if ( ! theOther.myData[iBlock] )
{
// if other block is empty, just make sure to empty that block in "this"
if ( iBlock < myNbBlocks && myData[iBlock] )
freeBlock (iBlock);
continue;
}
if ( iBlock >= myNbBlocks )
allocData(iBlock);
Block anOtherBlock = getBlock(theOther.myData[iBlock]);
// if block not yet allocated, just allocate and fill
Standard_Address & anAddr = myData[iBlock];
if ( ! anAddr )
{
anAddr = calloc (Block::Size(myBlockSize, myItemSize), sizeof(char));
Block aBlock ( getBlock(anAddr) );
for (Standard_Size anInd=0; anInd < myBlockSize; anInd++)
if ( anOtherBlock.IsSet(anInd) )
{
Standard_Address anItem = getItem (aBlock, anInd);
aBlock.Set(anInd);
(*aBlock.Count)++;
mySize++;
createItem (anItem, getItem(anOtherBlock, anInd));
}
}
// else perform copying item-by-item
else
{
Block aBlock ( getBlock(anAddr) );
for (Standard_Size anInd=0; anInd < myBlockSize; anInd++)
{
Standard_Address anItem = getItem (aBlock, anInd);
if ( anOtherBlock.IsSet(anInd) )
{
Standard_Address anOtherItem = getItem (anOtherBlock, anInd);
if ( aBlock.IsSet(anInd) ) // copy
{
copyItem (anItem, anOtherItem);
}
else // create
{
aBlock.Set(anInd);
(*aBlock.Count)++;
mySize++;
createItem (anItem, getItem(anOtherBlock, anInd));
}
}
else if ( aBlock.IsSet(anInd) ) // delete
{
aBlock.Set(anInd);
(*aBlock.Count)--;
mySize--;
destroyItem (anItem);
}
}
}
}
// clear any remaining blocks in this
for (; iBlock < myNbBlocks; iBlock++)
if ( myData[iBlock] )
freeBlock (iBlock);
// consistency check
Standard_ProgramError_Raise_if (mySize!=theOther.mySize,
"NCollection_SparseArrayBase: Implementation error: inconsistent items count")
}
//=======================================================================
//function : exchange
//purpose :
//=======================================================================
template<class T> static inline void sswap (T &a, T &b) { T c = a; a = b; b = c; }
void NCollection_SparseArrayBase::exchange (NCollection_SparseArrayBase& theOther)
{
if (this == &theOther)
return;
// swap fields of this and theOther
sswap (myItemSize, theOther.myItemSize);
sswap (myBlockSize,theOther.myBlockSize);
sswap (myNbBlocks, theOther.myNbBlocks);
sswap (mySize, theOther.mySize);
sswap (myData, theOther.myData);
}
//=======================================================================
//function : setValue
//purpose :
//=======================================================================
Standard_Address NCollection_SparseArrayBase::setValue (const Standard_Size theIndex,
const Standard_Address theValue)
{
Standard_Size iBlock = theIndex / myBlockSize;
// resize blocks array if necessary
if ( iBlock >= myNbBlocks )
allocData (iBlock);
// allocate block if necessary
Standard_Address & anAddr = myData[iBlock];
if ( ! anAddr )
anAddr = calloc (Block::Size(myBlockSize, myItemSize), sizeof(char));
// get a block
Block aBlock (getBlock (anAddr));
// mark item as defined
Standard_Size anInd = theIndex % myBlockSize;
Standard_Address anItem = getItem (aBlock, anInd);
// either create an item by copy constructor if it is new, or assign it
if ( aBlock.Set(anInd) )
{
(*aBlock.Count)++;
mySize++;
createItem (anItem, theValue);
}
else
copyItem (anItem, theValue);
return anItem;
}
//=======================================================================
//function : HasValue
//purpose :
//=======================================================================
Standard_Boolean NCollection_SparseArrayBase::HasValue (const Standard_Size theIndex) const
{
Standard_Size iBlock = theIndex / myBlockSize;
if ( iBlock >= myNbBlocks ||
! myData[iBlock] )
return Standard_False;
return getBlock(myData[iBlock]).IsSet(theIndex % myBlockSize) ? Standard_True : Standard_False;
}
//=======================================================================
//function : UnsetValue
//purpose :
//=======================================================================
Standard_Boolean NCollection_SparseArrayBase::UnsetValue (const Standard_Size theIndex)
{
// check that the item is defined
Standard_Size iBlock = theIndex / myBlockSize;
if ( iBlock >= myNbBlocks || ! myData[iBlock] )
return Standard_False;
Block aBlock (getBlock(myData[iBlock]));
Standard_Size anInd = theIndex % myBlockSize;
if ( ! aBlock.Unset(anInd) )
return Standard_False;
// destroy the item
destroyItem (getItem (aBlock, anInd));
(*aBlock.Count)--;
mySize--;
// free block if it becomes empty
if ( ! (*aBlock.Count) )
freeBlock (iBlock);
return Standard_True;
}
//=======================================================================
//function : Iterator::Iterator
//purpose :
//=======================================================================
NCollection_SparseArrayBase::Iterator::Iterator (const NCollection_SparseArrayBase* theArray)
: myArr((NCollection_SparseArrayBase*)theArray),
myHasMore(Standard_False), myIBlock(0), myInd(0),
myBlock(0,0,0)
{
init(theArray);
}
//=======================================================================
//function : Iterator::Next
//purpose :
//=======================================================================
void NCollection_SparseArrayBase::Iterator::Next ()
{
if ( ! myArr || ! myHasMore )
return;
// iterate by items and blocks
for ( myInd++; ; myInd++ ) {
// if index is over the block size, advance to the next non-empty block
if ( myInd >= myArr->myBlockSize )
{
for ( myIBlock++; ; myIBlock++ ) {
if ( myIBlock >= myArr->myNbBlocks ) // end
{
myHasMore = Standard_False;
return;
}
if ( myArr->myData[myIBlock] )
{
myInd = 0;
myBlock = Block (myArr->myData[myIBlock], myArr->myBlockSize, myArr->myItemSize );
break;
}
}
}
// check if item is defined
if ( myBlock.IsSet (myInd) )
return;
}
}
//=======================================================================
//function : Iterator::init
//purpose :
//=======================================================================
void NCollection_SparseArrayBase::Iterator::init (const NCollection_SparseArrayBase* theArray)
{
myArr = (NCollection_SparseArrayBase*)theArray;
myHasMore = Standard_False;
if ( myArr )
{
myInd = 0;
// find first non-empty block
for ( myIBlock=0; myIBlock < myArr->myNbBlocks; myIBlock++ )
{
if ( ! myArr->myData[myIBlock] )
continue;
myHasMore = Standard_True;
myBlock = Block (myArr->myData[myIBlock], myArr->myBlockSize, myArr->myItemSize );
// if first item in the block is not set, advance to the next defined item
if ( ! myBlock.IsSet(myInd) )
Next();
return;
}
}
}