1 // Copyright (c) 2021 OPEN CASCADE SAS
3 // This file is part of Open CASCADE Technology software library.
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
14 #ifndef _NCollection_AliasedArray_HeaderFile
15 #define _NCollection_AliasedArray_HeaderFile
17 #include <NCollection_DefineAlloc.hxx>
18 #include <NCollection_StlIterator.hxx>
19 #include <Standard_DimensionMismatch.hxx>
20 #include <Standard_OutOfMemory.hxx>
21 #include <Standard_OutOfRange.hxx>
22 #include <Standard_TypeMismatch.hxx>
24 //! Defines an array of values of configurable size.
25 //! For instance, this class allows defining an array of 32-bit or 64-bit integer values with bitness determined in runtime.
26 //! The element size in bytes (stride) should be specified at construction time.
27 //! Indexation starts from 0 index.
28 //! As actual type of element varies at runtime, element accessors are defined as templates.
29 //! Memory for array is allocated with the given alignment (template parameter).
30 template<int MyAlignSize = 16>
31 class NCollection_AliasedArray
37 //! Empty constructor.
38 NCollection_AliasedArray (Standard_Integer theStride)
39 : myData (NULL), myStride (theStride), mySize (0), myDeletable (false)
41 if (theStride <= 0) { throw Standard_RangeError ("NCollection_AliasedArray, stride should be positive"); }
45 NCollection_AliasedArray (Standard_Integer theStride,
46 Standard_Integer theLength)
47 : myData (NULL), myStride (theStride), mySize (theLength), myDeletable (true)
49 if (theLength <= 0 || myStride <= 0) { throw Standard_RangeError ("NCollection_AliasedArray, stride and length should be positive"); }
50 myData = (Standard_Byte* )Standard::AllocateAligned (SizeBytes(), MyAlignSize);
51 if (myData == NULL) { throw Standard_OutOfMemory ("NCollection_AliasedArray, allocation failed"); }
55 NCollection_AliasedArray (const NCollection_AliasedArray& theOther)
56 : myData (NULL), myStride (theOther.myStride), mySize (theOther.mySize), myDeletable (false)
61 myData = (Standard_Byte* )Standard::AllocateAligned (SizeBytes(), MyAlignSize);
62 if (myData == NULL) { throw Standard_OutOfMemory ("NCollection_AliasedArray, allocation failed"); }
67 #ifndef OCCT_NO_RVALUE_REFERENCE
69 NCollection_AliasedArray (NCollection_AliasedArray&& theOther)
70 : myData (theOther.myData), myStride (theOther.myStride), mySize (theOther.mySize), myDeletable (theOther.myDeletable)
72 theOther.myDeletable = false;
76 //! Constructor wrapping pre-allocated C-array of values without copying them.
77 template<typename Type_t>
78 NCollection_AliasedArray (const Type_t& theBegin,
79 Standard_Integer theLength)
80 : myData ((Standard_Byte* )&theBegin), myStride ((int )sizeof(Type_t)), mySize (theLength), myDeletable (false)
82 if (theLength <= 0) { throw Standard_RangeError ("NCollection_AliasedArray, length should be positive"); }
85 //! Returns an element size in bytes.
86 Standard_Integer Stride() const { return myStride; }
89 Standard_Integer Size() const { return mySize; }
91 //! Length query (the same as Size())
92 Standard_Integer Length() const { return mySize; }
94 //! Return TRUE if array has zero length.
95 Standard_Boolean IsEmpty() const { return mySize == 0; }
98 Standard_Integer Lower() const { return 0; }
101 Standard_Integer Upper() const { return mySize - 1; }
104 Standard_Boolean IsDeletable() const { return myDeletable; }
106 //! IsAllocated flag - for naming compatibility
107 Standard_Boolean IsAllocated() const { return myDeletable; }
109 //! Return buffer size in bytes.
110 Standard_Size SizeBytes() const { return size_t(myStride) * size_t(mySize); }
112 //! Copies data of theOther array to this.
113 //! This array should be pre-allocated and have the same length as theOther;
114 //! otherwise exception Standard_DimensionMismatch is thrown.
115 NCollection_AliasedArray& Assign (const NCollection_AliasedArray& theOther)
117 if (&theOther != this)
119 if (myStride != theOther.myStride || mySize != theOther.mySize)
121 throw Standard_DimensionMismatch ("NCollection_AliasedArray::Assign(), arrays have different size");
125 memcpy (myData, theOther.myData, SizeBytes());
132 //! This array will borrow all the data from theOther.
133 //! The moved object will keep pointer to the memory buffer and
134 //! range, but it will not free the buffer on destruction.
135 NCollection_AliasedArray& Move (NCollection_AliasedArray& theOther)
137 if (&theOther != this)
141 Standard::FreeAligned (myData);
143 myStride = theOther.myStride;
144 mySize = theOther.mySize;
145 myDeletable = theOther.myDeletable;
146 myData = theOther.myData;
147 theOther.myDeletable = false;
152 //! Assignment operator; @sa Assign()
153 NCollection_AliasedArray& operator= (const NCollection_AliasedArray& theOther)
155 return Assign (theOther);
158 #ifndef OCCT_NO_RVALUE_REFERENCE
159 //! Move assignment operator; @sa Move()
160 NCollection_AliasedArray& operator= (NCollection_AliasedArray&& theOther)
162 return Move (theOther);
166 //! Resizes the array to specified bounds.
167 //! No re-allocation will be done if length of array does not change,
168 //! but existing values will not be discarded if theToCopyData set to FALSE.
169 //! @param theLength new length of array
170 //! @param theToCopyData flag to copy existing data into new array
171 void Resize (Standard_Integer theLength,
172 Standard_Boolean theToCopyData)
174 if (theLength <= 0) { throw Standard_RangeError ("NCollection_AliasedArray::Resize, length should be positive"); }
175 if (mySize == theLength)
180 const Standard_Integer anOldLen = mySize;
181 const Standard_Byte* anOldData = myData;
183 if (!theToCopyData && myDeletable)
185 Standard::FreeAligned (myData);
187 myData = (Standard_Byte* )Standard::AllocateAligned (SizeBytes(), MyAlignSize);
188 if (myData == NULL) { throw Standard_OutOfMemory ("NCollection_AliasedArray, allocation failed"); }
195 const size_t aLenCopy = size_t(Min (anOldLen, theLength)) * size_t(myStride);
196 memcpy (myData, anOldData, aLenCopy);
199 Standard::FreeAligned (anOldData);
204 //! Destructor - releases the memory
205 ~NCollection_AliasedArray()
209 Standard::FreeAligned (myData);
215 //! Access raw bytes of specified element.
216 const Standard_Byte* value (Standard_Integer theIndex) const
218 Standard_OutOfRange_Raise_if (theIndex < 0 || theIndex >= mySize, "NCollection_AliasedArray::value(), out of range index");
219 return myData + size_t(myStride) * size_t(theIndex);
222 //! Access raw bytes of specified element.
223 Standard_Byte* changeValue (Standard_Integer theIndex)
225 Standard_OutOfRange_Raise_if (theIndex < 0 || theIndex >= mySize, "NCollection_AliasedArray::changeValue(), out of range index");
226 return myData + size_t(myStride) * size_t(theIndex);
229 //! Initialize the items with theValue
230 template<typename Type_t> void Init (const Type_t& theValue)
232 for (Standard_Integer anIter = 0; anIter < mySize; ++anIter)
234 ChangeValue<Type_t> (anIter) = theValue;
238 //! Access element with specified position and type.
239 //! This method requires size of a type matching stride value.
240 template<typename Type_t> const Type_t& Value (Standard_Integer theIndex) const
242 Standard_TypeMismatch_Raise_if(size_t(myStride) != sizeof(Type_t), "NCollection_AliasedArray::Value(), wrong type");
243 return *reinterpret_cast<const Type_t*>(value (theIndex));
246 //! Access element with specified position and type.
247 //! This method requires size of a type matching stride value.
248 template<typename Type_t> void Value (Standard_Integer theIndex, Type_t& theValue) const
250 Standard_TypeMismatch_Raise_if(size_t(myStride) != sizeof(Type_t), "NCollection_AliasedArray::Value(), wrong type");
251 theValue = *reinterpret_cast<const Type_t*>(value (theIndex));
254 //! Access element with specified position and type.
255 //! This method requires size of a type matching stride value.
256 template<typename Type_t> Type_t& ChangeValue (Standard_Integer theIndex)
258 Standard_TypeMismatch_Raise_if(size_t(myStride) != sizeof(Type_t), "NCollection_AliasedArray::ChangeValue(), wrong type");
259 return *reinterpret_cast<Type_t* >(changeValue (theIndex));
262 //! Access element with specified position and type.
263 //! This method allows wrapping element into smaller type (e.g. to alias 2-components within 3-component vector).
264 template<typename Type_t> const Type_t& Value2 (Standard_Integer theIndex) const
266 Standard_TypeMismatch_Raise_if(size_t(myStride) < sizeof(Type_t), "NCollection_AliasedArray::Value2(), wrong type");
267 return *reinterpret_cast<const Type_t*>(value (theIndex));
270 //! Access element with specified position and type.
271 //! This method allows wrapping element into smaller type (e.g. to alias 2-components within 3-component vector).
272 template<typename Type_t> void Value2 (Standard_Integer theIndex, Type_t& theValue) const
274 Standard_TypeMismatch_Raise_if(size_t(myStride) < sizeof(Type_t), "NCollection_AliasedArray::Value2(), wrong type");
275 theValue = *reinterpret_cast<const Type_t*>(value (theIndex));
278 //! Access element with specified position and type.
279 //! This method allows wrapping element into smaller type (e.g. to alias 2-components within 3-component vector).
280 template<typename Type_t>
281 Type_t& ChangeValue2 (Standard_Integer theIndex)
283 Standard_TypeMismatch_Raise_if(size_t(myStride) < sizeof(Type_t), "NCollection_AliasedArray::ChangeValue2(), wrong type");
284 return *reinterpret_cast<Type_t* >(changeValue (theIndex));
287 //! Return first element
288 template<typename Type_t> const Type_t& First() const { return Value<Type_t> (0); }
290 //! Return first element
291 template<typename Type_t> Type_t& ChangeFirst() { return ChangeValue<Type_t> (0); }
293 //! Return last element
294 template<typename Type_t> const Type_t& Last() const { return Value<Type_t> (mySize - 1); }
296 //! Return last element
297 template<typename Type_t> Type_t& ChangeLast() { return Value<Type_t> (mySize - 1); }
301 Standard_Byte* myData; //!< data pointer
302 Standard_Integer myStride; //!< element size
303 Standard_Integer mySize; //!< number of elements
304 Standard_Boolean myDeletable; //!< flag showing who allocated the array
308 #endif // _NCollection_AliasedArray_HeaderFile