mirror of
https://github.com/Open-Cascade-SAS/OCCT.git
synced 2026-08-13 12:14:45 +08:00
56e162c480
Interface_ParamSet: - Eliminate use-after-free in Append() by deleting old buffer through a temp variable after reassigning the member pointer (CodeQL #5132/#2684) delabella.cpp: - Fix upcast array pointer arithmetic by parenthesizing cast to ensure pointer arithmetic uses derived class (Vert) size rather than base class (DelaBella_Vertex) size (CodeQL #5131) NCollection_SparseArrayBase: - Rework to replace virtual dispatch (createItem/destroyItem/copyItem) with function pointers passed as arguments to protected methods - Store only DestroyItemFunc in base class to enable safe cleanup in destructor without virtual dispatch - Pass CreateItemFunc and CopyItemFunc as arguments with zero per-instance storage overhead - Move Clear() and UnsetValue() from base public API to protected clearItems()/unsetValue() with function pointer parameters; template class provides public wrappers - Remove vtable entirely (no virtual methods remain) - This eliminates the pure virtual call during base class destruction (CodeQL #5012) AdvApp2Var_MathBase: - Rewrite comparison to avoid potential signed integer overflow: *ncfnew + 1 > ncut becomes *ncfnew >= ncut (CodeQL #2692)
287 lines
10 KiB
C++
287 lines
10 KiB
C++
// Created on: 2007-01-23
|
|
// 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.
|
|
|
|
#ifndef NCollection_SparseArrayBase_HeaderFile
|
|
#define NCollection_SparseArrayBase_HeaderFile
|
|
|
|
#include <Standard.hxx>
|
|
#include <Standard_TypeDef.hxx>
|
|
#include <Standard_OutOfRange.hxx>
|
|
|
|
/**
|
|
* Base class for NCollection_SparseArray;
|
|
* provides non-template implementation of general mechanics
|
|
* of block allocation, items creation / deletion etc.
|
|
*
|
|
* Type-specific item operations (construction, destruction, copy)
|
|
* are provided by the derived template class via function pointers
|
|
* passed as arguments to the protected methods.
|
|
*/
|
|
|
|
class NCollection_SparseArrayBase
|
|
{
|
|
public:
|
|
//!@name Function pointer types for type-specific item operations
|
|
//!@{
|
|
|
|
//! Copy-construct a new item at theAddress from theOther
|
|
using CreateItemFunc = void (*)(void* theAddress, void* theOther);
|
|
//! Destroy the item at theAddress
|
|
using DestroyItemFunc = void (*)(void* theAddress);
|
|
//! Copy-assign the item at theAddress from theOther
|
|
using CopyItemFunc = void (*)(void* theAddress, void* theOther);
|
|
|
|
//!@}
|
|
|
|
public:
|
|
//!@name Type-independent public interface
|
|
//!@{
|
|
|
|
//! Returns number of currently contained items
|
|
size_t Size() const noexcept { return mySize; }
|
|
|
|
//! Check whether the value at given index is set
|
|
Standard_EXPORT bool HasValue(const size_t theIndex) const;
|
|
|
|
//!@}
|
|
|
|
private:
|
|
/**
|
|
* The block of data contains array of items, counter
|
|
* and bit field, allocated as single piece of memory addressed
|
|
* from the blocks array (myData).
|
|
*
|
|
* The Block structure provides a logical view on the block,
|
|
* and provides methods to work with bit map.
|
|
*
|
|
* Note that NCollection_SparseArrayBase class takes responsibility
|
|
* for correct allocation/deallocation of all the data.
|
|
*/
|
|
|
|
class Block
|
|
{
|
|
public:
|
|
typedef unsigned char Cell; //!< type of items used to hold bits
|
|
|
|
//! Number of bits in each cell
|
|
static constexpr size_t BitsPerCell() noexcept { return sizeof(Cell) * 8; }
|
|
|
|
public:
|
|
//! Initializes the block by pointer to block data
|
|
Block(void* const theAddr, const size_t theNbItems, const size_t theItemSize)
|
|
: Count((size_t*)theAddr),
|
|
Array((char*)theAddr + sizeof(size_t)),
|
|
Bits((Cell*)((char*)theAddr + sizeof(size_t) + theNbItems * theItemSize))
|
|
{
|
|
}
|
|
|
|
//! Compute required size for block data, in bytes
|
|
static constexpr size_t Size(const size_t theNbItems, const size_t theItemSize) noexcept
|
|
{
|
|
return sizeof(size_t) + sizeof(Cell) * ((theNbItems + BitsPerCell() - 1) / BitsPerCell())
|
|
+ theNbItems * theItemSize;
|
|
}
|
|
|
|
//! Returns address of array from address of block
|
|
static char* ToArray(void* const theAddress,
|
|
const size_t /*theNbItems*/,
|
|
const size_t /*theItemSize*/) noexcept
|
|
{
|
|
return (char*)theAddress + sizeof(size_t);
|
|
}
|
|
|
|
public:
|
|
//! Set bit for i-th item; returns non-null if that bit has
|
|
//! not been set previously
|
|
Cell Set(size_t i) noexcept
|
|
{
|
|
Cell* abyte = Bits + i / BitsPerCell();
|
|
Cell amask = (Cell)('\1' << (i % BitsPerCell()));
|
|
Cell anold = (Cell)(*abyte & amask);
|
|
*abyte = (Cell)(*abyte | amask);
|
|
return !anold;
|
|
}
|
|
|
|
//! Check bit for i-th item; returns non-null if that bit is set
|
|
Cell IsSet(size_t i) noexcept
|
|
{
|
|
Cell* abyte = Bits + i / BitsPerCell();
|
|
Cell amask = (Cell)('\1' << (i % BitsPerCell()));
|
|
return (Cell)(*abyte & amask);
|
|
}
|
|
|
|
//! Unset bit for i-th item; returns non-null if that bit
|
|
//! has been set previously
|
|
Cell Unset(size_t i) noexcept
|
|
{
|
|
Cell* abyte = Bits + i / BitsPerCell();
|
|
Cell amask = (Cell)('\1' << (i % BitsPerCell()));
|
|
Cell anold = (Cell)(*abyte & amask);
|
|
*abyte = (Cell)(*abyte & ~amask);
|
|
return anold;
|
|
}
|
|
|
|
public:
|
|
size_t* Count; //!< items counter
|
|
void* Array; //!< pointer to the data items array
|
|
Cell* Bits; //!< bit map for defined/undefined flags
|
|
};
|
|
|
|
public:
|
|
/**
|
|
* Iterator
|
|
*/
|
|
|
|
class Iterator
|
|
{
|
|
public:
|
|
// Public interface
|
|
|
|
//! Restart iterations on the same array
|
|
void Restart() { init(myArr); }
|
|
|
|
//! Returns True if current item is available
|
|
bool More() const noexcept { return myHasMore; }
|
|
|
|
//! Advances to the next item
|
|
Standard_EXPORT void Next();
|
|
|
|
//! Returns current index
|
|
size_t Index() const noexcept { return myIBlock * myArr->myBlockSize + myInd; }
|
|
|
|
protected:
|
|
// Methods for descendant
|
|
|
|
//! Empty constructor
|
|
Standard_EXPORT Iterator(const NCollection_SparseArrayBase* theArray = nullptr);
|
|
|
|
//! Initialize by the specified array
|
|
Standard_EXPORT void init(const NCollection_SparseArrayBase* theArray);
|
|
|
|
//! Returns address of the current item
|
|
void* value() const noexcept { return myArr->getItem(myBlock, myInd); }
|
|
|
|
private:
|
|
const NCollection_SparseArrayBase* myArr;
|
|
bool myHasMore;
|
|
size_t myIBlock;
|
|
size_t myInd;
|
|
Block myBlock;
|
|
};
|
|
friend class Iterator;
|
|
|
|
private:
|
|
// Copy constructor and assignment operator are deleted
|
|
NCollection_SparseArrayBase(const NCollection_SparseArrayBase&) = delete;
|
|
NCollection_SparseArrayBase& operator=(const NCollection_SparseArrayBase&) = delete;
|
|
|
|
protected:
|
|
// Object life
|
|
|
|
//! Constructor; initialized by size of item, block size, and item destructor function.
|
|
//! @param theDestroyItem is stored to enable proper item destruction in the base destructor
|
|
NCollection_SparseArrayBase(size_t theItemSize,
|
|
size_t theBlockSize,
|
|
DestroyItemFunc theDestroyItem) noexcept
|
|
: myItemSize(theItemSize),
|
|
myBlockSize(theBlockSize),
|
|
myNbBlocks(0),
|
|
mySize(0),
|
|
myData(nullptr),
|
|
myDestroyItem(theDestroyItem)
|
|
{
|
|
}
|
|
|
|
//! Destructor; properly destroys all items and frees all memory.
|
|
//! Uses the stored DestroyItemFunc, so no virtual dispatch is needed.
|
|
~NCollection_SparseArrayBase() { clearItems(myDestroyItem); }
|
|
|
|
protected:
|
|
// Data access interface for descendants
|
|
|
|
//! Creates Block structure for block pointed by theAddr
|
|
Block getBlock(void* const theAddr) const noexcept
|
|
{
|
|
return Block(theAddr, myBlockSize, myItemSize);
|
|
}
|
|
|
|
//! Find address of the item in the block by index (in the block)
|
|
void* getItem(const Block& theBlock, size_t theInd) const noexcept
|
|
{
|
|
return ((char*)theBlock.Array) + myItemSize * theInd;
|
|
}
|
|
|
|
//! Direct const access to the item
|
|
void* getValue(const size_t theIndex) const
|
|
{
|
|
Standard_OutOfRange_Raise_if(
|
|
!HasValue(theIndex),
|
|
"NCollection_SparseArray::Value()") return Block::ToArray(myData[theIndex / myBlockSize],
|
|
myBlockSize,
|
|
myItemSize)
|
|
+ myItemSize * (theIndex % myBlockSize);
|
|
}
|
|
|
|
//! Clears all items and frees all memory.
|
|
//! @param theDestroyItem function to call destructor on each item
|
|
Standard_EXPORT void clearItems(DestroyItemFunc theDestroyItem);
|
|
|
|
//! Deletes the item at theIndex from the array;
|
|
//! returns True if the item was defined.
|
|
//! @param theDestroyItem function to call destructor on the item
|
|
Standard_EXPORT bool unsetValue(const size_t theIndex, DestroyItemFunc theDestroyItem);
|
|
|
|
//! Set a value to the specified item; returns address of the set item.
|
|
//! @param theCreateItem function to copy-construct a new item
|
|
//! @param theCopyItem function to copy-assign an existing item
|
|
Standard_EXPORT void* setValue(const size_t theIndex,
|
|
void* const theValue,
|
|
CreateItemFunc theCreateItem,
|
|
CopyItemFunc theCopyItem);
|
|
|
|
//! Copy contents of theOther to this;
|
|
//! assumes that this and theOther have exactly the same type of arguments.
|
|
//! @param theCreateItem function to copy-construct a new item
|
|
//! @param theDestroyItem function to call destructor on an item
|
|
//! @param theCopyItem function to copy-assign an existing item
|
|
Standard_EXPORT void assign(const NCollection_SparseArrayBase& theOther,
|
|
CreateItemFunc theCreateItem,
|
|
DestroyItemFunc theDestroyItem,
|
|
CopyItemFunc theCopyItem);
|
|
|
|
//! Exchange contents of theOther and this;
|
|
//! assumes that this and theOther have exactly the same type of arguments
|
|
Standard_EXPORT void exchange(NCollection_SparseArrayBase& theOther) noexcept;
|
|
|
|
private:
|
|
// Implementation of memory allocation/deallocation and access mechanics
|
|
|
|
//! Allocate space for at least iBlock+1 blocks
|
|
void allocData(const size_t iBlock);
|
|
|
|
//! Free specified block, destroying all items via theDestroyItem
|
|
void freeBlock(const size_t iBlock, DestroyItemFunc theDestroyItem);
|
|
|
|
protected:
|
|
size_t myItemSize; //!< size of item
|
|
size_t myBlockSize; //!< block size (in items)
|
|
size_t myNbBlocks; //!< allocated size of blocks table
|
|
size_t mySize; //!< number of currently defined items
|
|
void** myData; //!< array of pointers to data blocks
|
|
DestroyItemFunc myDestroyItem; //!< function to call destructor on items
|
|
};
|
|
|
|
#endif
|