Files
OCCT/src/FoundationClasses/TKernel/NCollection/NCollection_Array1.hxx
T
Pasukhin Dmitry 14d4e91171 Coding - Global Refactoring OCCT as a part of 8.0.0 (#955)
- Added automated migration scripts for handle syntax, standard types, and macros
- Deprecated legacy `Standard_*` types and macros in favor of native C++ equivalents
- Introduced modern `occ` namespace with template-based type checking helpers
- Enhanced NCollection macros to support variadic arguments for complex template types- Added automated migration scripts for handle syntax, standard types, and macros
- Deprecated legacy `Standard_*` types and macros in favor of native C++ equivalents
- Introduced modern `occ` namespace with template-based type checking helpers
- Enhanced NCollection macros to support variadic arguments for complex template types
2025-12-28 14:38:06 +00:00

462 lines
14 KiB
C++

// Copyright (c) 2002-2023 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_Array1_HeaderFile
#define NCollection_Array1_HeaderFile
#include <Standard_DimensionMismatch.hxx>
#include <Standard_OutOfMemory.hxx>
#include <Standard_NotImplemented.hxx>
#include <Standard_OutOfRange.hxx>
#include <NCollection_DefineAlloc.hxx>
#include <NCollection_Iterator.hxx>
#include <NCollection_Allocator.hxx>
#include <StdFail_NotDone.hxx>
#include <NCollection_IndexedIterator.hxx>
#include <algorithm>
//! The class NCollection_Array1 represents unidimensional arrays of fixed size known at run time.
//! The range of the index is user defined.
//! An array1 can be constructed with a "C array".
//! This functionality is useful to call methods expecting an Array1.
//! It allows to carry the bounds inside the arrays.
//!
//! Examples:
//! @code
//! Item tab[100]; // an example with a C array
//! NCollection_Array1<Item> ttab (tab[0], 1, 100);
//!
//! NCollection_Array1<Item> tttab (ttab(10), 10, 20); // a slice of ttab
//! @endcode
//! If you want to reindex an array from 1 to Length do:
//! @code
//! NCollection_Array1<Item> tab1 (tab (tab.Lower()), 1, tab.Length());
//! @endcode
//! Warning: Programs client of such a class must be independent of the range of the first element.
//! Then, a C++ for loop must be written like this
//! @code
//! for (i = A.Lower(); i <= A.Upper(); i++)
//! @endcode
template <class TheItemType>
class NCollection_Array1
{
public:
//! Memory allocation
DEFINE_STANDARD_ALLOC;
DEFINE_NCOLLECTION_ALLOC;
public:
typedef NCollection_Allocator<TheItemType> allocator_type;
public:
// Define various type aliases for convenience
using value_type = TheItemType;
using size_type = size_t;
using difference_type = size_t;
using pointer = TheItemType*;
using const_pointer = const TheItemType*;
using reference = TheItemType&;
using const_reference = const TheItemType&;
using iterator = NCollection_IndexedIterator<std::random_access_iterator_tag,
NCollection_Array1,
value_type,
false>;
using const_iterator = NCollection_IndexedIterator<std::random_access_iterator_tag,
NCollection_Array1,
value_type,
true>;
using Iterator = NCollection_Iterator<NCollection_Array1<TheItemType>>;
public:
const_iterator begin() const noexcept { return const_iterator(*this); }
iterator begin() noexcept { return iterator(*this); }
const_iterator cbegin() const noexcept { return const_iterator(*this); }
iterator end() noexcept { return iterator(mySize, *this); }
const_iterator end() const noexcept { return const_iterator(mySize, *this); }
const_iterator cend() const noexcept { return const_iterator(mySize, *this); }
public:
// Constructors
NCollection_Array1() noexcept
: myLowerBound(1),
mySize(0)
{
}
explicit NCollection_Array1(const int theLower, const int theUpper)
: myLowerBound(theLower),
mySize(theUpper - theLower + 1)
{
if (mySize == 0)
{
return;
}
myPointer = myAllocator.allocate(mySize);
myIsOwner = true;
construct(0, mySize);
}
explicit NCollection_Array1(const allocator_type& theAlloc,
const int theLower,
const int theUpper)
: myLowerBound(theLower),
mySize(theUpper - theLower + 1),
myPointer(nullptr),
myIsOwner(false),
myAllocator(theAlloc)
{
if (mySize == 0)
{
return;
}
myPointer = myAllocator.allocate(mySize);
myIsOwner = true;
construct(0, mySize);
}
explicit NCollection_Array1(const_reference theBegin,
const int theLower,
const int theUpper,
const bool theUseBuffer = true)
: myLowerBound(theLower),
mySize(theUpper - theLower + 1),
myPointer(theUseBuffer ? const_cast<pointer>(&theBegin) : nullptr),
myIsOwner(!theUseBuffer)
{
if (!myIsOwner)
{
return;
}
myPointer = myAllocator.allocate(mySize);
myIsOwner = true;
construct(0, mySize);
}
//! Copy constructor
NCollection_Array1(const NCollection_Array1& theOther)
: myLowerBound(theOther.myLowerBound),
mySize(theOther.mySize)
{
if (mySize == 0)
{
return;
}
myPointer = myAllocator.allocate(mySize);
myIsOwner = true;
copyConstruct(theOther.myPointer, mySize);
}
//! Move constructor
NCollection_Array1(NCollection_Array1&& theOther) noexcept
: myLowerBound(theOther.myLowerBound),
mySize(theOther.mySize),
myPointer(theOther.myPointer),
myIsOwner(theOther.myIsOwner)
{
theOther.myIsOwner = false;
theOther.myPointer = nullptr;
theOther.mySize = 0;
theOther.myLowerBound = 1;
}
virtual ~NCollection_Array1()
{
if (!myIsOwner)
{
return;
}
destroy(myPointer, 0, mySize);
myAllocator.deallocate(myPointer, mySize);
}
//! Initialise the items with theValue
void Init(const_reference theValue)
{
for (size_t anIter = 0; anIter < mySize; anIter++)
{
myPointer[anIter] = theValue;
}
}
//! Size query
int Size() const noexcept { return Length(); }
//! Length query (the same)
int Length() const noexcept { return static_cast<int>(mySize); }
//! Return TRUE if array has zero length.
bool IsEmpty() const noexcept { return mySize == 0; }
//! Lower bound
int Lower() const noexcept { return myLowerBound; }
//! Upper bound
int Upper() const noexcept { return myLowerBound + static_cast<int>(mySize) - 1; }
//! Copies data of theOther array to this.
//! This array should be pre-allocated and have the same length as theOther;
//! otherwise exception Standard_DimensionMismatch is thrown.
NCollection_Array1& Assign(const NCollection_Array1& theOther)
{
if (&theOther == this)
{
return *this;
}
Standard_DimensionMismatch_Raise_if(mySize != theOther.mySize, "NCollection_Array1::operator=");
for (size_t anInd = 0; anInd < mySize; anInd++)
{
myPointer[anInd] = theOther.myPointer[anInd];
}
// Current implementation disable changing bounds by assigning
return *this;
}
//! Move assignment.
//! This array will borrow all the data from theOther.
//! The moved object will keep pointer to the memory buffer and
//! range, but it will not free the buffer on destruction.
NCollection_Array1& Move(NCollection_Array1&& theOther) noexcept
{
if (&theOther == this)
{
return *this;
}
if (myIsOwner)
{
destroy(myPointer, 0, mySize);
myAllocator.deallocate(myPointer, mySize);
}
myLowerBound = theOther.myLowerBound;
mySize = theOther.mySize;
myPointer = theOther.myPointer;
myIsOwner = theOther.myIsOwner;
theOther.myIsOwner = false;
theOther.myPointer = nullptr;
theOther.mySize = 0;
theOther.myLowerBound = 1;
return *this;
}
NCollection_Array1& Move(NCollection_Array1& theOther) noexcept
{
return Move(std::move(theOther));
}
//! Assignment operator; @sa Assign()
NCollection_Array1& operator=(const NCollection_Array1& theOther) { return Assign(theOther); }
//! Move assignment operator; @sa Move()
NCollection_Array1& operator=(NCollection_Array1&& theOther) noexcept
{
return Move(std::forward<NCollection_Array1>(theOther));
}
//! @return first element
const_reference First() const noexcept { return myPointer[0]; }
//! @return first element
reference ChangeFirst() noexcept { return myPointer[0]; }
//! @return last element
const_reference Last() const noexcept { return myPointer[mySize - 1]; }
//! @return last element
reference ChangeLast() noexcept { return myPointer[mySize - 1]; }
//! Constant value access
const_reference Value(const int theIndex) const
{
const size_t aPos = theIndex - myLowerBound;
Standard_OutOfRange_Raise_if(aPos >= mySize, "NCollection_Array1::Value");
return myPointer[aPos];
}
//! operator() - alias to Value
const_reference operator()(const int theIndex) const { return Value(theIndex); }
//! operator[] - alias to Value
const_reference operator[](const int theIndex) const { return Value(theIndex); }
//! Variable value access
reference ChangeValue(const int theIndex)
{
const size_t aPos = theIndex - myLowerBound;
Standard_OutOfRange_Raise_if(aPos >= mySize, "NCollection_Array1::ChangeValue");
return myPointer[aPos];
}
//! operator() - alias to ChangeValue
reference operator()(const int theIndex) { return ChangeValue(theIndex); }
//! operator[] - alias to ChangeValue
reference operator[](const int theIndex) { return ChangeValue(theIndex); }
//! Set value
void SetValue(const int theIndex, const value_type& theItem)
{
const size_t aPos = theIndex - myLowerBound;
Standard_OutOfRange_Raise_if(aPos >= mySize, "NCollection_Array1::SetValue");
myPointer[aPos] = theItem;
}
//! Set value
void SetValue(const int theIndex, value_type&& theItem)
{
const size_t aPos = theIndex - myLowerBound;
Standard_OutOfRange_Raise_if(aPos >= mySize, "NCollection_Array1::SetValue");
myPointer[aPos] = std::forward<value_type>(theItem);
}
//! Changes the lowest bound. Do not move data
void UpdateLowerBound(const int theLower) noexcept { myLowerBound = theLower; }
//! Changes the upper bound. Do not move data
void UpdateUpperBound(const int theUpper) noexcept
{
myLowerBound = myLowerBound - Upper() + theUpper;
}
//! Resizes the array to specified bounds.
//! No re-allocation will be done if length of array does not change,
//! but existing values will not be discarded if theToCopyData set to FALSE.
//! @param theLower new lower bound of array
//! @param theUpper new upper bound of array
//! @param theToCopyData flag to copy existing data into new array
void Resize(const int theLower, const int theUpper, const bool theToCopyData)
{
Standard_RangeError_Raise_if(theUpper < theLower, "NCollection_Array1::Resize");
const size_t aNewSize = static_cast<size_t>(theUpper - theLower + 1);
pointer aPrevContPnt = myPointer;
if (aNewSize == mySize)
{
myLowerBound = theLower;
return;
}
if (myIsOwner)
{
if (theToCopyData)
destroy(myPointer, aNewSize, mySize);
else
destroy(myPointer, 0, mySize);
}
myLowerBound = theLower;
if (theToCopyData)
{
const size_t aMinSize = (std::min)(aNewSize, mySize);
if (myIsOwner)
{
myPointer = myAllocator.reallocate(myPointer, aNewSize);
}
else
{
myPointer = myAllocator.allocate(aNewSize);
copyConstruct(aPrevContPnt, aMinSize);
}
construct(mySize, aNewSize);
}
else
{
if (myIsOwner)
myAllocator.deallocate(aPrevContPnt, mySize);
myPointer = myAllocator.allocate(aNewSize);
construct(0, aNewSize);
}
mySize = aNewSize;
myIsOwner = true;
}
bool IsDeletable() const noexcept { return myIsOwner; }
friend iterator;
friend const_iterator;
protected:
const_reference at(const size_t theIndex) const
{
Standard_OutOfRange_Raise_if(theIndex >= mySize, "NCollection_Array1::at");
return myPointer[theIndex];
}
reference at(const size_t theIndex)
{
Standard_OutOfRange_Raise_if(theIndex >= mySize, "NCollection_Array1::at");
return myPointer[theIndex];
}
protected:
template <typename U = TheItemType>
typename std::enable_if<std::is_trivially_default_constructible<U>::value, void>::type construct(
const size_t,
const size_t)
{
// Do nothing
}
template <typename U = TheItemType>
typename std::enable_if<!std::is_trivially_default_constructible<U>::value, void>::type construct(
const size_t theFrom,
const size_t theTo)
{
for (size_t anInd = theFrom; anInd < theTo; anInd++)
{
myAllocator.construct(myPointer + anInd);
}
}
template <typename U = TheItemType>
typename std::enable_if<std::is_trivially_destructible<U>::value, void>::type destroy(
pointer,
const size_t,
const size_t)
{
// Do nothing
}
template <typename U = TheItemType>
typename std::enable_if<!std::is_trivially_destructible<U>::value, void>::type destroy(
pointer theWhat,
const size_t theFrom,
const size_t theTo)
{
for (size_t anInd = theFrom; anInd < theTo; anInd++)
{
myAllocator.destroy(theWhat + anInd);
}
}
void copyConstruct(const pointer theFrom, const size_t theCount)
{
for (size_t anInd = 0; anInd < theCount; anInd++)
{
myAllocator.construct(myPointer + anInd, theFrom[anInd]);
}
}
// ---------- PROTECTED FIELDS -----------
int myLowerBound;
size_t mySize;
pointer myPointer = nullptr;
bool myIsOwner = false;
allocator_type myAllocator;
};
#endif