Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-17 09:21:21

0001 // Created on: 2002-04-15
0002 // Created by: Alexander Kartomin (akm)
0003 // Copyright (c) 2002-2014 OPEN CASCADE SAS
0004 //
0005 // This file is part of Open CASCADE Technology software library.
0006 //
0007 // This library is free software; you can redistribute it and/or modify it under
0008 // the terms of the GNU Lesser General Public License version 2.1 as published
0009 // by the Free Software Foundation, with special exception defined in the file
0010 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0011 // distribution for complete text of the license and disclaimer of any warranty.
0012 //
0013 // Alternatively, this file may be used under the terms of Open CASCADE
0014 // commercial license or contractual agreement.
0015 
0016 #ifndef NCollection_Array2_HeaderFile
0017 #define NCollection_Array2_HeaderFile
0018 
0019 #include <Standard_DimensionMismatch.hxx>
0020 #include <Standard_OutOfMemory.hxx>
0021 #include <NCollection_Allocator.hxx>
0022 #include <Standard_OutOfRange.hxx>
0023 #include <NCollection_Array1.hxx>
0024 
0025 #include <NCollection_DefineAlloc.hxx>
0026 
0027 // *********************************************** Template for Array2 class
0028 /**
0029  * Purpose:   The class Array2 represents bi-dimensional arrays
0030  *            of fixed size known at run time.
0031  *            The ranges of indices are user defined.
0032  *
0033  *            Class allocates one 1D array storing full data (all Rows and Columns)
0034  *            and extra 1D array storing pointers to each Row.
0035  *
0036  * Warning:   Programs clients of such class must be independent
0037  *            of the range of the first element. Then, a C++ for
0038  *            loop must be written like this
0039  *
0040  *            for (i = A.LowerRow(); i <= A.UpperRow(); i++)
0041  *              for (j = A.LowerCol(); j <= A.UpperCol(); j++)
0042  *
0043  * Zero-based (size_t) construction mode:
0044  *   NCollection_Array2(size_t theNbRows, size_t theNbCols) creates a zero-based array
0045  *   (LowerRow()==0, LowerCol()==0). In this mode At()/ChangeAt() and STL iterators are
0046  *   the preferred access path -- they address elements directly without any offset subtraction.
0047  *   Buffer-reuse variant NCollection_Array2(pointer, size_t, size_t) wraps an existing
0048  *   flat row-major buffer and does NOT own the memory.
0049  */
0050 template <class TheItemType>
0051 class NCollection_Array2 : public NCollection_Array1<TheItemType>
0052 {
0053 public:
0054   //! Memory allocation
0055   DEFINE_STANDARD_ALLOC;
0056   DEFINE_NCOLLECTION_ALLOC;
0057 
0058 public:
0059   typedef NCollection_Allocator<TheItemType> allocator_type;
0060 
0061 public:
0062   // Define various type aliases for convenience
0063   using value_type      = typename NCollection_Array1<TheItemType>::value_type;
0064   using size_type       = typename NCollection_Array1<TheItemType>::size_type;
0065   using difference_type = typename NCollection_Array1<TheItemType>::difference_type;
0066   using pointer         = typename NCollection_Array1<TheItemType>::pointer;
0067   using const_pointer   = typename NCollection_Array1<TheItemType>::const_pointer;
0068   using reference       = typename NCollection_Array1<TheItemType>::reference;
0069   using const_reference = typename NCollection_Array1<TheItemType>::const_reference;
0070 
0071   using iterator       = typename NCollection_Array1<TheItemType>::iterator;
0072   using const_iterator = typename NCollection_Array1<TheItemType>::const_iterator;
0073 
0074   static int BeginPosition(int theRowLower,
0075                            int /*theRowUpper*/,
0076                            int theColLower,
0077                            int theColUpper) noexcept
0078   {
0079     // Calculate the offset for the beginning position
0080     return theColLower + (theRowLower * (theColUpper - theColLower + 1));
0081   }
0082 
0083   static int LastPosition(int theRowLower,
0084                           int theRowUpper,
0085                           int theColLower,
0086                           int theColUpper) noexcept
0087   {
0088     return ((theRowUpper - theRowLower + 1) * (theColUpper - theColLower + 1)) + theColLower
0089            + (theRowLower * (theColUpper - theColLower + 1)) - 1;
0090   }
0091 
0092 public:
0093   // ---------- PUBLIC METHODS ------------
0094 
0095   //! Empty constructor; should be used with caution.
0096   //! @sa methods Resize() and Move().
0097   NCollection_Array2() noexcept
0098       : NCollection_Array1<TheItemType>(),
0099         myLowerRow(1),
0100         mySizeRow(0),
0101         myLowerCol(1),
0102         mySizeCol(0)
0103   {
0104   }
0105 
0106   //! Constructor
0107   NCollection_Array2(const int theRowLower,
0108                      const int theRowUpper,
0109                      const int theColLower,
0110                      const int theColUpper)
0111       : NCollection_Array1<TheItemType>(
0112           BeginPosition(theRowLower, theRowUpper, theColLower, theColUpper),
0113           LastPosition(theRowLower, theRowUpper, theColLower, theColUpper)),
0114         myLowerRow(theRowLower),
0115         mySizeRow(theRowUpper - theRowLower + 1),
0116         myLowerCol(theColLower),
0117         mySizeCol(theColUpper - theColLower + 1)
0118   {
0119   }
0120 
0121   //! Copy constructor
0122   NCollection_Array2(const NCollection_Array2& theOther)
0123       : NCollection_Array1<TheItemType>(theOther),
0124         myLowerRow(theOther.LowerRow()),
0125         mySizeRow(theOther.NbRows()),
0126         myLowerCol(theOther.LowerCol()),
0127         mySizeCol(theOther.NbColumns())
0128   {
0129   }
0130 
0131   //! Move constructor
0132   NCollection_Array2(NCollection_Array2&& theOther) noexcept
0133       : NCollection_Array1<TheItemType>(std::forward<NCollection_Array2>(theOther)),
0134         myLowerRow(theOther.LowerRow()),
0135         mySizeRow(theOther.NbRows()),
0136         myLowerCol(theOther.LowerCol()),
0137         mySizeCol(theOther.NbColumns())
0138   {
0139     theOther.myLowerRow = 1;
0140     theOther.mySizeRow  = 0;
0141     theOther.myLowerCol = 1;
0142     theOther.mySizeCol  = 0;
0143   }
0144 
0145   //! C array-based constructor
0146   explicit NCollection_Array2(const TheItemType& theBegin,
0147                               const int          theRowLower,
0148                               const int          theRowUpper,
0149                               const int          theColLower,
0150                               const int          theColUpper)
0151       : NCollection_Array1<TheItemType>(
0152           theBegin,
0153           BeginPosition(theRowLower, theRowUpper, theColLower, theColUpper),
0154           LastPosition(theRowLower, theRowUpper, theColLower, theColUpper)),
0155         myLowerRow(theRowLower),
0156         mySizeRow(theRowUpper - theRowLower + 1),
0157         myLowerCol(theColLower),
0158         mySizeCol(theColUpper - theColLower + 1)
0159   {
0160   }
0161 
0162   //! Zero-based constructor: allocates theNbRows x theNbCols elements with lower bounds 0.
0163   //! Use At()/ChangeAt() or STL iterators for optimal access (no offset subtraction).
0164   explicit NCollection_Array2(const size_t theNbRows, const size_t theNbCols)
0165       : NCollection_Array1<TheItemType>(theNbRows * theNbCols),
0166         myLowerRow(0),
0167         mySizeRow(theNbRows),
0168         myLowerCol(0),
0169         mySizeCol(theNbCols)
0170   {
0171   }
0172 
0173   //! Zero-based buffer-reuse constructor: wraps an existing flat row-major C array.
0174   //! The array does NOT own the buffer and will NOT free it on destruction.
0175   //! Use At()/ChangeAt() or STL iterators for optimal access (no offset subtraction).
0176   explicit NCollection_Array2(pointer theBegin, const size_t theNbRows, const size_t theNbCols)
0177       : NCollection_Array1<TheItemType>(theBegin, theNbRows * theNbCols),
0178         myLowerRow(0),
0179         mySizeRow(theNbRows),
0180         myLowerCol(0),
0181         mySizeCol(theNbCols)
0182   {
0183   }
0184 
0185   //! Size (number of items).
0186   size_t Size() const noexcept { return mySizeRow * mySizeCol; }
0187 
0188   //! Length (legacy int-returning API).
0189   int Length() const noexcept { return NbRows() * NbColumns(); }
0190 
0191   //! Returns number of rows
0192   int NbRows() const noexcept { return static_cast<int>(mySizeRow); }
0193 
0194   //! Returns number of columns
0195   int NbColumns() const noexcept { return static_cast<int>(mySizeCol); }
0196 
0197   //! Returns length of the row, i.e. number of columns
0198   int RowLength() const noexcept { return NbColumns(); }
0199 
0200   //! Returns length of the column, i.e. number of rows
0201   int ColLength() const noexcept { return NbRows(); }
0202 
0203   //! LowerRow
0204   int LowerRow() const noexcept { return myLowerRow; }
0205 
0206   //! UpperRow
0207   int UpperRow() const noexcept { return myLowerRow + static_cast<int>(mySizeRow) - 1; }
0208 
0209   //! LowerCol
0210   int LowerCol() const noexcept { return myLowerCol; }
0211 
0212   //! UpperCol
0213   int UpperCol() const noexcept { return myLowerCol + static_cast<int>(mySizeCol) - 1; }
0214 
0215   //! Updates lower row
0216   void UpdateLowerRow(const int theLowerRow) noexcept { myLowerRow = theLowerRow; }
0217 
0218   //! Updates lower column
0219   void UpdateLowerCol(const int theLowerCol) noexcept { myLowerCol = theLowerCol; }
0220 
0221   //! Updates upper row
0222   void UpdateUpperRow(const int theUpperRow) noexcept
0223   {
0224     myLowerRow = myLowerRow - UpperRow() + theUpperRow;
0225   }
0226 
0227   //! Updates upper column
0228   void UpdateUpperCol(const int theUpperCol) noexcept
0229   {
0230     myLowerCol = myLowerCol - UpperCol() + theUpperCol;
0231   }
0232 
0233   //! Replaces this array by a copy of theOther array.
0234   //! Row and column bounds are copied from theOther.
0235   NCollection_Array2& Assign(const NCollection_Array2& theOther)
0236   {
0237     if (&theOther == this)
0238     {
0239       return *this;
0240     }
0241     NCollection_Array1<TheItemType>::Assign(theOther);
0242     myLowerRow = theOther.myLowerRow;
0243     mySizeRow  = theOther.mySizeRow;
0244     myLowerCol = theOther.myLowerCol;
0245     mySizeCol  = theOther.mySizeCol;
0246     return *this;
0247   }
0248 
0249   //! Copies values from theOther array without changing this array bounds.
0250   //! This array should be pre-allocated and have the same dimensions as theOther;
0251   //! otherwise exception Standard_DimensionMismatch is thrown.
0252   NCollection_Array2& CopyValues(const NCollection_Array2& theOther)
0253   {
0254     if (&theOther == this)
0255     {
0256       return *this;
0257     }
0258     Standard_DimensionMismatch_Raise_if(mySizeRow != theOther.mySizeRow
0259                                           || mySizeCol != theOther.mySizeCol,
0260                                         "NCollection_Array2::CopyValues");
0261     NCollection_Array1<TheItemType>::CopyValues(theOther);
0262     return *this;
0263   }
0264 
0265   //! Move assignment.
0266   //! This array will borrow all the data from theOther.
0267   //! The moved object will be left uninitialized and should not be used anymore.
0268   NCollection_Array2& Move(NCollection_Array2&& theOther) noexcept
0269   {
0270     if (&theOther == this)
0271     {
0272       return *this;
0273     }
0274     NCollection_Array1<TheItemType>::Move(theOther);
0275     myLowerRow          = theOther.myLowerRow;
0276     mySizeRow           = theOther.mySizeRow;
0277     myLowerCol          = theOther.myLowerCol;
0278     mySizeCol           = theOther.mySizeCol;
0279     theOther.myLowerRow = 1;
0280     theOther.mySizeRow  = 0;
0281     theOther.myLowerCol = 1;
0282     theOther.mySizeCol  = 0;
0283     return *this;
0284   }
0285 
0286   //! Move assignment.
0287   //! This array will borrow all the data from theOther.
0288   //! The moved object will be left uninitialized and should not be used anymore.
0289   NCollection_Array2& Move(NCollection_Array2& theOther) noexcept
0290   {
0291     return Move(std::move(theOther));
0292   }
0293 
0294   //! Assignment operator
0295   NCollection_Array2& operator=(const NCollection_Array2& theOther) { return Assign(theOther); }
0296 
0297   //! Move assignment operator; @sa Move()
0298   NCollection_Array2& operator=(NCollection_Array2&& theOther) noexcept
0299   {
0300     return Move(std::forward<NCollection_Array2>(theOther));
0301   }
0302 
0303   //! Constant value access
0304   const_reference Value(const int theRow, const int theCol) const
0305   {
0306     const size_t aPos = (theRow - myLowerRow) * mySizeCol + (theCol - myLowerCol);
0307     return NCollection_Array1<TheItemType>::at(aPos);
0308   }
0309 
0310   //! operator() - alias to ChangeValue
0311   const_reference operator()(const int theRow, const int theCol) const
0312   {
0313     const size_t aPos = (theRow - myLowerRow) * mySizeCol + (theCol - myLowerCol);
0314     return NCollection_Array1<TheItemType>::at(aPos);
0315   }
0316 
0317   //! Variable value access
0318   reference ChangeValue(const int theRow, const int theCol)
0319   {
0320     const size_t aPos = (theRow - myLowerRow) * mySizeCol + (theCol - myLowerCol);
0321     return NCollection_Array1<TheItemType>::at(aPos);
0322   }
0323 
0324   //! operator() - alias to ChangeValue
0325   reference operator()(const int theRow, const int theCol) { return ChangeValue(theRow, theCol); }
0326 
0327   //! SetValue
0328   void SetValue(const int theRow, const int theCol, const TheItemType& theItem)
0329   {
0330     const size_t aPos = (theRow - myLowerRow) * mySizeCol + (theCol - myLowerCol);
0331     NCollection_Array1<TheItemType>::at(aPos) = theItem;
0332   }
0333 
0334   //! SetValue
0335   void SetValue(const int theRow, const int theCol, TheItemType&& theItem)
0336   {
0337     const size_t aPos = (theRow - myLowerRow) * mySizeCol + (theCol - myLowerCol);
0338     NCollection_Array1<TheItemType>::at(aPos) = std::forward<TheItemType>(theItem);
0339   }
0340 
0341   //! 0-based checked access independent of LowerRow()/LowerCol().
0342   //! @param[in] theRow 0-based row index in [0, NbRows()-1]
0343   //! @param[in] theCol 0-based column index in [0, NbColumns()-1]
0344   const_reference At(const size_t theRow, const size_t theCol) const
0345   {
0346     Standard_OutOfRange_Raise_if(theRow >= mySizeRow || theCol >= mySizeCol,
0347                                  "NCollection_Array2::At");
0348     return NCollection_Array1<TheItemType>::at(theRow * mySizeCol + theCol);
0349   }
0350 
0351   //! 0-based checked mutable access independent of LowerRow()/LowerCol().
0352   //! @param[in] theRow 0-based row index in [0, NbRows()-1]
0353   //! @param[in] theCol 0-based column index in [0, NbColumns()-1]
0354   reference ChangeAt(const size_t theRow, const size_t theCol)
0355   {
0356     Standard_OutOfRange_Raise_if(theRow >= mySizeRow || theCol >= mySizeCol,
0357                                  "NCollection_Array2::ChangeAt");
0358     return NCollection_Array1<TheItemType>::at(theRow * mySizeCol + theCol);
0359   }
0360 
0361   //! Emplace value at the specified row and column, constructing it in-place
0362   //! @param theRow row index at which to emplace the value
0363   //! @param theCol column index at which to emplace the value
0364   //! @param theArgs arguments forwarded to TheItemType constructor
0365   //! @return reference to the newly constructed item
0366   template <typename... Args>
0367   reference EmplaceValue(const int theRow, const int theCol, Args&&... theArgs)
0368   {
0369     const size_t aPos = (theRow - myLowerRow) * mySizeCol + (theCol - myLowerCol);
0370     Standard_OutOfRange_Raise_if(aPos >= this->mySize, "NCollection_Array2::EmplaceValue");
0371     this->myPointer[aPos] = value_type(std::forward<Args>(theArgs)...);
0372     return this->myPointer[aPos];
0373   }
0374 
0375   //! Resizes the array to specified bounds.
0376   //! When theToCopyData is false, the array is re-allocated without preserving data.
0377   //! When theToCopyData is true, copies elements in linear (row-major) order.
0378   //! No re-allocation is done if dimensions are unchanged.
0379   //! @param theRowLower new lower Row of array
0380   //! @param theRowUpper new upper Row of array
0381   //! @param theColLower new lower Column of array
0382   //! @param theColUpper new upper Column of array
0383   //! @param theToCopyData flag to copy existing data into new array
0384   void Resize(int  theRowLower,
0385               int  theRowUpper,
0386               int  theColLower,
0387               int  theColUpper,
0388               bool theToCopyData)
0389   {
0390     if (!theToCopyData)
0391     {
0392       resizeNoData(theRowLower, theRowUpper, theColLower, theColUpper);
0393       return;
0394     }
0395     resizeImpl<false>(theRowLower, theRowUpper, theColLower, theColUpper);
0396   }
0397 
0398   //! Resizes the array preserving 2D element layout.
0399   //! When theToCopyData is false, the array is re-allocated without preserving data.
0400   //! When theToCopyData is true, copies min(oldNbRows,newNbRows) x min(oldNbCols,newNbCols)
0401   //! elements from the top-left corner of the old array to the top-left corner of the new,
0402   //! preserving relative (row, col) offsets from lower bounds. Trimming or growing as needed.
0403   //! No re-allocation is done if dimensions are unchanged.
0404   //! @param theRowLower new lower Row of array
0405   //! @param theRowUpper new upper Row of array
0406   //! @param theColLower new lower Column of array
0407   //! @param theColUpper new upper Column of array
0408   //! @param theToCopyData flag to copy existing data into new array
0409   void ResizeWithTrim(int  theRowLower,
0410                       int  theRowUpper,
0411                       int  theColLower,
0412                       int  theColUpper,
0413                       bool theToCopyData)
0414   {
0415     if (!theToCopyData)
0416     {
0417       resizeNoData(theRowLower, theRowUpper, theColLower, theColUpper);
0418       return;
0419     }
0420     resizeImpl<true>(theRowLower, theRowUpper, theColLower, theColUpper);
0421   }
0422 
0423   //! Zero-based Resize: resizes to theNbRows x theNbCols, keeping lower bounds unchanged.
0424   //! No re-allocation is done if dimensions are unchanged.
0425   //! @param theNbRows new number of rows
0426   //! @param theNbCols new number of columns
0427   //! @param theToCopyData flag to copy existing data into new array
0428   void Resize(const size_t theNbRows, const size_t theNbCols, const bool theToCopyData)
0429   {
0430     Resize(myLowerRow,
0431            myLowerRow + static_cast<int>(theNbRows) - 1,
0432            myLowerCol,
0433            myLowerCol + static_cast<int>(theNbCols) - 1,
0434            theToCopyData);
0435   }
0436 
0437   //! Zero-based ResizeWithTrim: resizes preserving 2D layout, keeping lower bounds unchanged.
0438   //! No re-allocation is done if dimensions are unchanged.
0439   //! @param theNbRows new number of rows
0440   //! @param theNbCols new number of columns
0441   //! @param theToCopyData flag to copy existing data into new array
0442   void ResizeWithTrim(const size_t theNbRows, const size_t theNbCols, const bool theToCopyData)
0443   {
0444     ResizeWithTrim(myLowerRow,
0445                    myLowerRow + static_cast<int>(theNbRows) - 1,
0446                    myLowerCol,
0447                    myLowerCol + static_cast<int>(theNbCols) - 1,
0448                    theToCopyData);
0449   }
0450 
0451 protected:
0452   //! Resize without copying data.
0453   void resizeNoData(int theRowLower, int theRowUpper, int theColLower, int theColUpper)
0454   {
0455     Standard_RangeError_Raise_if(theRowUpper < theRowLower || theColUpper < theColLower,
0456                                  "NCollection_Array2::Resize");
0457     NCollection_Array1<TheItemType>::Resize(
0458       BeginPosition(theRowLower, theRowUpper, theColLower, theColUpper),
0459       LastPosition(theRowLower, theRowUpper, theColLower, theColUpper),
0460       false);
0461     mySizeRow  = theRowUpper - theRowLower + 1;
0462     mySizeCol  = theColUpper - theColLower + 1;
0463     myLowerRow = theRowLower;
0464     myLowerCol = theColLower;
0465   }
0466 
0467   //! Internal resize with data copy.
0468   //! @tparam thePreserve2D if true, copies the common sub-matrix preserving
0469   //!   2D element positions (row, col); if false, copies elements in linear order.
0470   template <bool thePreserve2D>
0471   void resizeImpl(int theRowLower, int theRowUpper, int theColLower, int theColUpper)
0472   {
0473     Standard_RangeError_Raise_if(theRowUpper < theRowLower || theColUpper < theColLower,
0474                                  "NCollection_Array2::Resize");
0475     const size_t aNewNbRows = theRowUpper - theRowLower + 1;
0476     const size_t aNewNbCols = theColUpper - theColLower + 1;
0477     if (mySizeRow == aNewNbRows && mySizeCol == aNewNbCols)
0478     {
0479       myLowerRow = theRowLower;
0480       myLowerCol = theColLower;
0481       NCollection_Array1<TheItemType>::UpdateLowerBound(
0482         BeginPosition(theRowLower, theRowUpper, theColLower, theColUpper));
0483       return;
0484     }
0485     if (mySizeRow == 0 || mySizeCol == 0)
0486     {
0487       resizeNoData(theRowLower, theRowUpper, theColLower, theColUpper);
0488       return;
0489     }
0490     const size_t aNbRowsToCopy = (std::min)(mySizeRow, aNewNbRows);
0491     const size_t aNbColsToCopy = (std::min)(mySizeCol, aNewNbCols);
0492     const size_t aOldStride    = thePreserve2D ? mySizeCol : aNbColsToCopy;
0493 
0494     NCollection_Array2<TheItemType> aTmpMovedCopy(std::move(*this));
0495     TheItemType*                    anOldPointer = &aTmpMovedCopy.ChangeFirst();
0496     NCollection_Array1<TheItemType>::Resize(
0497       BeginPosition(theRowLower, theRowUpper, theColLower, theColUpper),
0498       LastPosition(theRowLower, theRowUpper, theColLower, theColUpper),
0499       false);
0500     mySizeRow  = aNewNbRows;
0501     mySizeCol  = aNewNbCols;
0502     myLowerRow = theRowLower;
0503     myLowerCol = theColLower;
0504     for (size_t aRowIter = 0; aRowIter < aNbRowsToCopy; ++aRowIter)
0505     {
0506       for (size_t aColIter = 0; aColIter < aNbColsToCopy; ++aColIter)
0507       {
0508         NCollection_Array1<TheItemType>::at(aRowIter * aNewNbCols + aColIter) =
0509           std::move(anOldPointer[aRowIter * aOldStride + aColIter]);
0510       }
0511     }
0512   }
0513 
0514 protected:
0515   // ---------- PROTECTED FIELDS -----------
0516   int    myLowerRow;
0517   size_t mySizeRow;
0518   int    myLowerCol;
0519   size_t mySizeCol;
0520 
0521   // ----------- FRIEND CLASSES ------------
0522   friend iterator;
0523   friend const_iterator;
0524 };
0525 
0526 #endif