0032402: Coding Rules - eliminate msvc warning C4668 (symbol is not defined as a...
[occt.git] / src / NCollection / NCollection_AliasedArray.hxx
1 // Copyright (c) 2021 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
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.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #ifndef _NCollection_AliasedArray_HeaderFile
15 #define _NCollection_AliasedArray_HeaderFile
16
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>
23
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
32 {
33 public:
34   DEFINE_STANDARD_ALLOC
35 public:
36
37   //! Empty constructor.
38   NCollection_AliasedArray (Standard_Integer theStride)
39   : myData (NULL), myStride (theStride), mySize (0), myDeletable (false)
40   {
41     if (theStride <= 0) { throw Standard_RangeError ("NCollection_AliasedArray, stride should be positive"); }
42   }
43
44   //! Constructor
45   NCollection_AliasedArray (Standard_Integer theStride,
46                             Standard_Integer theLength)
47   : myData (NULL), myStride (theStride), mySize (theLength), myDeletable (true)
48   {
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"); }
52   }
53
54   //! Copy constructor 
55   NCollection_AliasedArray (const NCollection_AliasedArray& theOther)
56   : myData (NULL), myStride (theOther.myStride), mySize (theOther.mySize), myDeletable (false)
57   {
58     if (mySize != 0)
59     {
60       myDeletable = true;
61       myData = (Standard_Byte* )Standard::AllocateAligned (SizeBytes(), MyAlignSize);
62       if (myData == NULL) { throw Standard_OutOfMemory ("NCollection_AliasedArray, allocation failed"); }
63       Assign (theOther);
64     }
65   }
66
67 #ifndef OCCT_NO_RVALUE_REFERENCE
68   //! Move constructor
69   NCollection_AliasedArray (NCollection_AliasedArray&& theOther)
70   : myData (theOther.myData), myStride (theOther.myStride), mySize (theOther.mySize), myDeletable (theOther.myDeletable)
71   {
72     theOther.myDeletable = false;
73   }
74 #endif
75
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)
81   {
82     if (theLength <= 0) { throw Standard_RangeError ("NCollection_AliasedArray, length should be positive"); }
83   }
84
85   //! Returns an element size in bytes.
86   Standard_Integer Stride() const { return myStride; }
87
88   //! Size query
89   Standard_Integer Size() const { return mySize; }
90
91   //! Length query (the same as Size())
92   Standard_Integer Length() const { return mySize; }
93
94   //! Return TRUE if array has zero length.
95   Standard_Boolean IsEmpty() const { return mySize == 0; }
96
97   //! Lower bound
98   Standard_Integer Lower() const { return 0; }
99
100   //! Upper bound
101   Standard_Integer Upper() const { return mySize - 1; }
102
103   //! myDeletable flag
104   Standard_Boolean IsDeletable() const { return myDeletable; }
105
106   //! IsAllocated flag - for naming compatibility
107   Standard_Boolean IsAllocated() const { return myDeletable; }
108
109   //! Return buffer size in bytes.
110   Standard_Size SizeBytes() const { return size_t(myStride) * size_t(mySize); }
111
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)
116   {
117     if (&theOther != this)
118     {
119       if (myStride != theOther.myStride || mySize != theOther.mySize)
120       {
121         throw Standard_DimensionMismatch ("NCollection_AliasedArray::Assign(), arrays have different size");
122       }
123       if (myData != NULL)
124       {
125         memcpy (myData, theOther.myData, SizeBytes());
126       }
127     }
128     return *this;
129   }
130
131   //! Move assignment.
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)
136   {
137     if (&theOther != this)
138     {
139       if (myDeletable)
140       {
141         Standard::FreeAligned (myData);
142       }
143       myStride    = theOther.myStride;
144       mySize      = theOther.mySize;
145       myDeletable = theOther.myDeletable;
146       myData      = theOther.myData;
147       theOther.myDeletable = false;
148     }
149     return *this;
150   }
151
152   //! Assignment operator; @sa Assign()
153   NCollection_AliasedArray& operator= (const NCollection_AliasedArray& theOther)
154   { 
155     return Assign (theOther);
156   }
157
158 #ifndef OCCT_NO_RVALUE_REFERENCE
159   //! Move assignment operator; @sa Move()
160   NCollection_AliasedArray& operator= (NCollection_AliasedArray&& theOther)
161   {
162     return Move (theOther);
163   }
164 #endif
165
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)
173   {
174     if (theLength <= 0) { throw Standard_RangeError ("NCollection_AliasedArray::Resize, length should be positive"); }
175     if (mySize == theLength)
176     {
177       return;
178     }
179
180     const Standard_Integer anOldLen  = mySize;
181     const Standard_Byte*   anOldData = myData;
182     mySize = theLength;
183     if (!theToCopyData && myDeletable)
184     {
185       Standard::FreeAligned (myData);
186     }
187     myData = (Standard_Byte* )Standard::AllocateAligned (SizeBytes(), MyAlignSize);
188     if (myData == NULL) { throw Standard_OutOfMemory ("NCollection_AliasedArray, allocation failed"); }
189     if (!theToCopyData)
190     {
191       myDeletable = true;
192       return;
193     }
194
195     const size_t aLenCopy = size_t(Min (anOldLen, theLength)) * size_t(myStride);
196     memcpy (myData, anOldData, aLenCopy);
197     if (myDeletable)
198     {
199       Standard::FreeAligned (anOldData);
200     }
201     myDeletable = true;
202   }
203
204   //! Destructor - releases the memory
205   ~NCollection_AliasedArray()
206   { 
207     if (myDeletable)
208     {
209       Standard::FreeAligned (myData);
210     }
211   }
212
213 public:
214
215   //! Access raw bytes of specified element.
216   const Standard_Byte* value (Standard_Integer theIndex) const
217   {
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);
220   }
221
222   //! Access raw bytes of specified element.
223   Standard_Byte* changeValue (Standard_Integer theIndex)
224   {
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);
227   }
228
229   //! Initialize the items with theValue
230   template<typename Type_t> void Init (const Type_t& theValue)
231   {
232     for (Standard_Integer anIter = 0; anIter < mySize; ++anIter)
233     {
234       ChangeValue<Type_t> (anIter) = theValue;
235     }
236   }
237
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
241   {
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));
244   }
245
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
249   {
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));
252   }
253
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)
257   {
258     Standard_TypeMismatch_Raise_if(size_t(myStride) != sizeof(Type_t), "NCollection_AliasedArray::ChangeValue(), wrong type");
259     return *reinterpret_cast<Type_t* >(changeValue (theIndex));
260   }
261
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
265   {
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));
268   }
269
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
273   {
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));
276   }
277
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)
282   {
283     Standard_TypeMismatch_Raise_if(size_t(myStride) < sizeof(Type_t), "NCollection_AliasedArray::ChangeValue2(), wrong type");
284     return *reinterpret_cast<Type_t* >(changeValue (theIndex));
285   }
286
287   //! Return first element
288   template<typename Type_t> const Type_t& First() const { return Value<Type_t> (0); }
289
290   //! Return first element
291   template<typename Type_t> Type_t& ChangeFirst() { return ChangeValue<Type_t> (0); }
292
293   //! Return last element
294   template<typename Type_t> const Type_t& Last() const { return Value<Type_t> (mySize - 1); }
295
296   //! Return last element
297   template<typename Type_t> Type_t& ChangeLast() { return Value<Type_t> (mySize - 1); }
298
299 protected:
300
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
305
306 };
307
308 #endif // _NCollection_AliasedArray_HeaderFile