1103eb60 |
1 | // Copyright (c) 2002-2023 OPEN CASCADE SAS |
b311480e |
2 | // |
973c2be1 |
3 | // This file is part of Open CASCADE Technology software library. |
b311480e |
4 | // |
d5f74e42 |
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 |
973c2be1 |
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. |
b311480e |
10 | // |
973c2be1 |
11 | // Alternatively, this file may be used under the terms of Open CASCADE |
12 | // commercial license or contractual agreement. |
7fd59977 |
13 | |
14 | #ifndef NCollection_Array1_HeaderFile |
15 | #define NCollection_Array1_HeaderFile |
16 | |
7fd59977 |
17 | #include <Standard_DimensionMismatch.hxx> |
18 | #include <Standard_OutOfMemory.hxx> |
1103eb60 |
19 | #include <Standard_NotImplemented.hxx> |
7fd59977 |
20 | #include <Standard_OutOfRange.hxx> |
7fd59977 |
21 | |
ddf2fe8e |
22 | #include <NCollection_DefineAlloc.hxx> |
1103eb60 |
23 | #include <NCollection_Iterator.hxx> |
24 | #include <NCollection_Allocator.hxx> |
25 | #include <StdFail_NotDone.hxx> |
26 | #include <NCollection_IndexedIterator.hxx> |
27 | |
28 | #include <algorithm> |
29 | #include <array> |
30 | #include <vector> |
7fd59977 |
31 | |
5e6e5914 |
32 | //! The class NCollection_Array1 represents unidimensional arrays of fixed size known at run time. |
33 | //! The range of the index is user defined. |
34 | //! An array1 can be constructed with a "C array". |
35 | //! This functionality is useful to call methods expecting an Array1. |
36 | //! It allows to carry the bounds inside the arrays. |
37 | //! |
38 | //! Examples: |
39 | //! @code |
40 | //! Item tab[100]; // an example with a C array |
41 | //! NCollection_Array1<Item> ttab (tab[0], 1, 100); |
42 | //! |
43 | //! NCollection_Array1<Item> tttab (ttab(10), 10, 20); // a slice of ttab |
44 | //! @endcode |
45 | //! If you want to reindex an array from 1 to Length do: |
46 | //! @code |
47 | //! NCollection_Array1<Item> tab1 (tab (tab.Lower()), 1, tab.Length()); |
48 | //! @endcode |
49 | //! Warning: Programs client of such a class must be independent of the range of the first element. |
50 | //! Then, a C++ for loop must be written like this |
51 | //! @code |
52 | //! for (i = A.Lower(); i <= A.Upper(); i++) |
53 | //! @endcode |
ddf2fe8e |
54 | template <class TheItemType> |
55 | class NCollection_Array1 |
7fd59977 |
56 | { |
79a35943 |
57 | public: |
1103eb60 |
58 | //! Memory allocation |
59 | DEFINE_STANDARD_ALLOC; |
60 | DEFINE_NCOLLECTION_ALLOC; |
61 | public: |
62 | typedef NCollection_Allocator<TheItemType> allocator_type; |
63 | public: |
64 | // Define various type aliases for convenience |
65 | using value_type = TheItemType; |
66 | using size_type = size_t; |
67 | using difference_type = size_t; |
68 | using pointer = TheItemType*; |
69 | using const_pointer = const TheItemType*; |
70 | using reference = TheItemType&; |
71 | using const_reference = const TheItemType&; |
72 | |
73 | using iterator = NCollection_IndexedIterator<std::random_access_iterator_tag, NCollection_Array1, value_type, false>; |
74 | using const_iterator = NCollection_IndexedIterator<std::random_access_iterator_tag, NCollection_Array1, value_type, true>; |
ffd7a3aa |
75 | using Iterator = NCollection_Iterator<NCollection_Array1<TheItemType>>; |
7fd59977 |
76 | |
79a35943 |
77 | public: |
1103eb60 |
78 | |
1103eb60 |
79 | const_iterator begin() const |
80 | { |
81 | return const_iterator(*this); |
82 | } |
79a35943 |
83 | |
1103eb60 |
84 | iterator begin() |
85 | { |
86 | return iterator(*this); |
87 | } |
79a35943 |
88 | |
1103eb60 |
89 | const_iterator cbegin() const |
90 | { |
91 | return const_iterator(*this); |
92 | } |
79a35943 |
93 | |
1103eb60 |
94 | iterator end() |
95 | { |
96 | return iterator(mySize, *this); |
97 | } |
79a35943 |
98 | |
1103eb60 |
99 | const_iterator end() const |
100 | { |
101 | return const_iterator(mySize, *this); |
102 | } |
79a35943 |
103 | |
1103eb60 |
104 | const_iterator cend() const |
105 | { |
106 | return const_iterator(mySize, *this); |
107 | } |
7fd59977 |
108 | |
1103eb60 |
109 | public: |
110 | // Constructors |
111 | NCollection_Array1() : |
112 | myLowerBound(1), |
113 | mySize(0) |
114 | {} |
115 | |
116 | explicit NCollection_Array1(const Standard_Integer theLower, |
117 | const Standard_Integer theUpper) : |
118 | myLowerBound(theLower), |
119 | mySize(theUpper - theLower + 1) |
4954e497 |
120 | { |
1103eb60 |
121 | if (mySize == 0) |
122 | { |
123 | return; |
124 | } |
125 | myPointer = myAllocator.allocate(mySize); |
126 | myIsOwner = true; |
127 | construct(); |
4954e497 |
128 | } |
129 | |
1103eb60 |
130 | explicit NCollection_Array1(const allocator_type& theAlloc, |
131 | const Standard_Integer theLower, |
132 | const Standard_Integer theUpper) : |
133 | myLowerBound(theLower), |
134 | mySize(theUpper - theLower + 1), |
135 | myPointer(nullptr), |
136 | myIsOwner(false), |
ffd7a3aa |
137 | myAllocator(theAlloc) |
7fd59977 |
138 | { |
1103eb60 |
139 | if (mySize == 0) |
140 | { |
141 | return; |
142 | } |
143 | myPointer = myAllocator.allocate(mySize); |
144 | myIsOwner = true; |
145 | construct(); |
146 | } |
7fd59977 |
147 | |
1103eb60 |
148 | explicit NCollection_Array1(const_reference theBegin, |
149 | const Standard_Integer theLower, |
150 | const Standard_Integer theUpper, |
151 | const bool theUseBuffer = true) : |
152 | myLowerBound(theLower), |
153 | mySize(theUpper - theLower + 1), |
154 | myPointer(theUseBuffer ? const_cast<pointer>(&theBegin) : nullptr), |
155 | myIsOwner(!theUseBuffer) |
156 | { |
157 | if (!myIsOwner) |
158 | { |
159 | return; |
160 | } |
161 | myPointer = myAllocator.allocate(mySize); |
162 | myIsOwner = true; |
163 | construct(); |
7fd59977 |
164 | } |
165 | |
166 | //! Copy constructor |
1103eb60 |
167 | NCollection_Array1(const NCollection_Array1& theOther) : |
168 | myLowerBound(theOther.myLowerBound), |
169 | mySize(theOther.mySize) |
7fd59977 |
170 | { |
1103eb60 |
171 | if (mySize == 0) |
172 | { |
173 | return; |
174 | } |
175 | myPointer = myAllocator.allocate(mySize); |
176 | myIsOwner = true; |
177 | copyConstruct(theOther.myPointer, mySize); |
7fd59977 |
178 | } |
179 | |
4954e497 |
180 | //! Move constructor |
1103eb60 |
181 | NCollection_Array1(NCollection_Array1&& theOther) noexcept : |
182 | myLowerBound(theOther.myLowerBound), |
183 | mySize(theOther.mySize), |
184 | myPointer(theOther.myPointer), |
185 | myIsOwner(theOther.myIsOwner) |
186 | { |
187 | theOther.myIsOwner = false; |
188 | } |
189 | |
190 | virtual ~NCollection_Array1() |
191 | { |
192 | if (!myIsOwner) |
193 | { |
194 | return; |
195 | } |
196 | destroy(); |
197 | myAllocator.deallocate(myPointer, mySize); |
7fd59977 |
198 | } |
199 | |
200 | //! Initialise the items with theValue |
1103eb60 |
201 | void Init(const_reference theValue) |
7fd59977 |
202 | { |
1103eb60 |
203 | for (size_t anIter = 0; anIter < mySize; anIter++) |
204 | { |
205 | myPointer[anIter] = theValue; |
206 | } |
7fd59977 |
207 | } |
208 | |
209 | //! Size query |
1103eb60 |
210 | Standard_Integer Size() const |
211 | { |
212 | return Length(); |
213 | } |
214 | |
7fd59977 |
215 | //! Length query (the same) |
1103eb60 |
216 | Standard_Integer Length() const |
217 | { |
218 | return static_cast<Standard_Integer>(mySize); |
219 | } |
7fd59977 |
220 | |
4954e497 |
221 | //! Return TRUE if array has zero length. |
1103eb60 |
222 | Standard_Boolean IsEmpty() const |
223 | { |
224 | return mySize == 0; |
225 | } |
4954e497 |
226 | |
7fd59977 |
227 | //! Lower bound |
1103eb60 |
228 | Standard_Integer Lower() const |
229 | { |
230 | return myLowerBound; |
231 | } |
7fd59977 |
232 | |
1103eb60 |
233 | //! Upper bound |
234 | Standard_Integer Upper() const |
235 | { |
236 | return myLowerBound + static_cast<int>(mySize) - 1; |
237 | } |
7fd59977 |
238 | |
6286195c |
239 | //! Copies data of theOther array to this. |
240 | //! This array should be pre-allocated and have the same length as theOther; |
241 | //! otherwise exception Standard_DimensionMismatch is thrown. |
1103eb60 |
242 | NCollection_Array1& Assign(const NCollection_Array1& theOther) |
7fd59977 |
243 | { |
244 | if (&theOther == this) |
4954e497 |
245 | { |
246 | return *this; |
247 | } |
1103eb60 |
248 | Standard_DimensionMismatch_Raise_if(mySize != theOther.mySize, "NCollection_Array1::operator="); |
249 | for (size_t anInd = 0; anInd < mySize; anInd++) |
250 | { |
251 | myPointer[anInd] = theOther.myPointer[anInd]; |
252 | } |
253 | // Current implementation disable changing bounds by assigning |
4954e497 |
254 | return *this; |
255 | } |
256 | |
6286195c |
257 | //! Move assignment. |
258 | //! This array will borrow all the data from theOther. |
259 | //! The moved object will keep pointer to the memory buffer and |
260 | //! range, but it will not free the buffer on destruction. |
1103eb60 |
261 | NCollection_Array1& Move(NCollection_Array1&& theOther) noexcept |
4954e497 |
262 | { |
263 | if (&theOther == this) |
264 | { |
265 | return *this; |
266 | } |
1103eb60 |
267 | if (myIsOwner) |
4954e497 |
268 | { |
1103eb60 |
269 | destroy(); |
270 | myAllocator.deallocate(myPointer, mySize); |
4954e497 |
271 | } |
272 | myLowerBound = theOther.myLowerBound; |
1103eb60 |
273 | mySize = theOther.mySize; |
274 | myPointer = theOther.myPointer; |
275 | myIsOwner = theOther.myIsOwner; |
276 | theOther.myIsOwner = false; |
4954e497 |
277 | return *this; |
7fd59977 |
278 | } |
279 | |
1103eb60 |
280 | NCollection_Array1& Move(NCollection_Array1& theOther) |
281 | { |
282 | return Move(std::move(theOther)); |
283 | } |
284 | |
6286195c |
285 | //! Assignment operator; @sa Assign() |
ddf2fe8e |
286 | NCollection_Array1& operator= (const NCollection_Array1& theOther) |
1103eb60 |
287 | { |
288 | return Assign(theOther); |
ddf2fe8e |
289 | } |
290 | |
6286195c |
291 | //! Move assignment operator; @sa Move() |
1103eb60 |
292 | NCollection_Array1& operator= (NCollection_Array1&& theOther) noexcept |
4954e497 |
293 | { |
1103eb60 |
294 | return Move(std::forward<NCollection_Array1>(theOther)); |
4954e497 |
295 | } |
296 | |
a174a3c5 |
297 | //! @return first element |
1103eb60 |
298 | const_reference First() const |
a174a3c5 |
299 | { |
1103eb60 |
300 | return myPointer[0]; |
a174a3c5 |
301 | } |
302 | |
303 | //! @return first element |
1103eb60 |
304 | reference ChangeFirst() |
a174a3c5 |
305 | { |
1103eb60 |
306 | return myPointer[0]; |
a174a3c5 |
307 | } |
308 | |
309 | //! @return last element |
1103eb60 |
310 | const_reference Last() const |
a174a3c5 |
311 | { |
1103eb60 |
312 | return myPointer[mySize - 1]; |
a174a3c5 |
313 | } |
314 | |
315 | //! @return last element |
1103eb60 |
316 | reference ChangeLast() |
a174a3c5 |
317 | { |
1103eb60 |
318 | return myPointer[mySize - 1]; |
a174a3c5 |
319 | } |
320 | |
7fd59977 |
321 | //! Constant value access |
1103eb60 |
322 | const_reference Value(const Standard_Integer theIndex) const |
7fd59977 |
323 | { |
1103eb60 |
324 | const size_t aPos = theIndex - myLowerBound; |
325 | Standard_OutOfRange_Raise_if(aPos >= mySize, "NCollection_Array1::Value"); |
326 | return myPointer[aPos]; |
7fd59977 |
327 | } |
328 | |
329 | //! operator() - alias to Value |
1103eb60 |
330 | const_reference operator() (const Standard_Integer theIndex) const |
331 | { |
332 | return Value(theIndex); |
333 | } |
7fd59977 |
334 | |
b8f7f608 |
335 | //! operator[] - alias to Value |
1103eb60 |
336 | const_reference operator[] (const Standard_Integer theIndex) const |
337 | { |
338 | return Value(theIndex); |
339 | } |
b8f7f608 |
340 | |
7fd59977 |
341 | //! Variable value access |
1103eb60 |
342 | reference ChangeValue(const Standard_Integer theIndex) |
7fd59977 |
343 | { |
1103eb60 |
344 | const size_t aPos = theIndex - myLowerBound; |
345 | Standard_OutOfRange_Raise_if(aPos >= mySize, "NCollection_Array1::ChangeValue"); |
346 | return myPointer[aPos]; |
7fd59977 |
347 | } |
348 | |
349 | //! operator() - alias to ChangeValue |
1103eb60 |
350 | reference operator() (const Standard_Integer theIndex) |
351 | { |
352 | return ChangeValue(theIndex); |
353 | } |
7fd59977 |
354 | |
b8f7f608 |
355 | //! operator[] - alias to ChangeValue |
1103eb60 |
356 | reference operator[] (const Standard_Integer theIndex) |
357 | { |
358 | return ChangeValue(theIndex); |
359 | } |
360 | |
361 | //! Set value |
362 | void SetValue(const Standard_Integer theIndex, |
363 | const value_type& theItem) |
364 | { |
365 | const size_t aPos = theIndex - myLowerBound; |
366 | Standard_OutOfRange_Raise_if(aPos >= mySize, "NCollection_Array1::SetValue"); |
367 | myPointer[aPos] = theItem; |
368 | } |
b8f7f608 |
369 | |
7fd59977 |
370 | //! Set value |
1103eb60 |
371 | void SetValue(const Standard_Integer theIndex, |
372 | value_type&& theItem) |
7fd59977 |
373 | { |
1103eb60 |
374 | const size_t aPos = theIndex - myLowerBound; |
375 | Standard_OutOfRange_Raise_if(aPos >= mySize, "NCollection_Array1::SetValue"); |
376 | myPointer[aPos] = std::forward<value_type>(theItem); |
377 | } |
378 | |
379 | //! Changes the lowest bound. Do not move data |
380 | void UpdateLowerBound(const Standard_Integer theLower) |
381 | { |
382 | myLowerBound = theLower; |
383 | } |
384 | |
385 | //! Changes the upper bound. Do not move data |
386 | void UpdateUpperBound(const Standard_Integer theUpper) |
387 | { |
388 | myLowerBound = myLowerBound - Upper() + theUpper; |
7fd59977 |
389 | } |
390 | |
4954e497 |
391 | //! Resizes the array to specified bounds. |
392 | //! No re-allocation will be done if length of array does not change, |
393 | //! but existing values will not be discarded if theToCopyData set to FALSE. |
394 | //! @param theLower new lower bound of array |
395 | //! @param theUpper new upper bound of array |
396 | //! @param theToCopyData flag to copy existing data into new array |
1103eb60 |
397 | void Resize(const Standard_Integer theLower, |
398 | const Standard_Integer theUpper, |
399 | const Standard_Boolean theToCopyData) |
4954e497 |
400 | { |
1103eb60 |
401 | Standard_RangeError_Raise_if(theUpper < theLower, "NCollection_Array1::Resize"); |
402 | const size_t aNewSize = static_cast<size_t>(theUpper - theLower + 1); |
403 | const size_t anOldSize = mySize; |
404 | pointer aPrevContPnt = myPointer; |
405 | if (aNewSize == anOldSize) |
4954e497 |
406 | { |
1103eb60 |
407 | myLowerBound = theLower; |
4954e497 |
408 | return; |
409 | } |
1103eb60 |
410 | if (myIsOwner) |
411 | { |
412 | if (theToCopyData) |
413 | destroy(myPointer, aNewSize, mySize); |
414 | else |
415 | destroy(); |
416 | } |
417 | myLowerBound = theLower; |
418 | mySize = aNewSize; |
419 | if (theToCopyData) |
420 | { |
421 | const size_t aMinSize = std::min<size_t>(aNewSize, anOldSize); |
422 | if (myIsOwner) |
423 | { |
424 | myPointer = myAllocator.reallocate(myPointer, aNewSize); |
425 | } |
426 | else |
427 | { |
428 | myPointer = myAllocator.allocate(aNewSize); |
429 | copyConstruct(aPrevContPnt, aMinSize); |
430 | } |
431 | construct(anOldSize, aNewSize); |
432 | } |
433 | else |
434 | { |
435 | if (myIsOwner) |
436 | myAllocator.deallocate(aPrevContPnt, mySize); |
437 | myPointer = myAllocator.allocate(aNewSize); |
438 | construct(); |
439 | } |
440 | myIsOwner = true; |
441 | } |
442 | |
443 | bool IsDeletable() const |
444 | { |
445 | return myIsOwner; |
446 | } |
447 | |
448 | friend iterator; |
449 | friend const_iterator; |
450 | |
451 | protected: |
452 | |
453 | const_reference at(const size_t theIndex) const |
454 | { |
455 | Standard_OutOfRange_Raise_if(theIndex >= mySize, "NCollection_Array1::at"); |
456 | return myPointer[theIndex]; |
457 | } |
458 | |
459 | reference at(const size_t theIndex) |
460 | { |
461 | Standard_OutOfRange_Raise_if(theIndex >= mySize, "NCollection_Array1::at"); |
462 | return myPointer[theIndex]; |
463 | } |
464 | |
465 | protected: |
466 | |
467 | template <typename U = TheItemType> |
468 | typename std::enable_if<std::is_arithmetic<U>::value, void>::type construct() |
469 | { |
470 | // Do nothing |
471 | } |
4954e497 |
472 | |
1103eb60 |
473 | template <typename U = TheItemType> |
474 | typename std::enable_if<!std::is_arithmetic<U>::value, void>::type construct() |
475 | { |
476 | for (size_t anInd = 0; anInd < mySize; anInd++) |
4954e497 |
477 | { |
1103eb60 |
478 | myAllocator.construct(myPointer + anInd); |
4954e497 |
479 | } |
1103eb60 |
480 | } |
481 | |
482 | template <typename U = TheItemType> |
483 | typename std::enable_if<std::is_arithmetic<U>::value, void>::type construct(const size_t, |
484 | const size_t) |
485 | { |
486 | // Do nothing |
487 | } |
488 | |
489 | template <typename U = TheItemType> |
490 | typename std::enable_if<!std::is_arithmetic<U>::value, void>::type construct(const size_t theFrom, |
491 | const size_t theTo) |
492 | { |
493 | for (size_t anInd = theFrom; anInd < theTo; anInd++) |
4954e497 |
494 | { |
1103eb60 |
495 | myAllocator.construct(myPointer + anInd); |
4954e497 |
496 | } |
1103eb60 |
497 | } |
4954e497 |
498 | |
1103eb60 |
499 | template <typename U = TheItemType> |
500 | typename std::enable_if<std::is_arithmetic<U>::value, void>::type destroy() |
501 | { |
502 | // Do nothing |
503 | } |
504 | |
505 | template <typename U = TheItemType> |
506 | typename std::enable_if<!std::is_arithmetic<U>::value, void>::type destroy() |
507 | { |
508 | for (size_t anInd = 0; anInd < mySize; anInd++) |
4954e497 |
509 | { |
1103eb60 |
510 | myAllocator.destroy(myPointer + anInd); |
4954e497 |
511 | } |
1103eb60 |
512 | } |
513 | |
514 | template <typename U = TheItemType> |
515 | typename std::enable_if<std::is_arithmetic<U>::value, void>::type destroy(pointer, |
516 | const size_t, |
517 | const size_t) |
518 | { |
519 | // Do nothing |
520 | } |
521 | |
522 | template <typename U = TheItemType> |
523 | typename std::enable_if<!std::is_arithmetic<U>::value, void>::type destroy(pointer theWhat, |
524 | const size_t theFrom, |
525 | const size_t theTo) |
526 | { |
527 | for (size_t anInd = theFrom; anInd < theTo; anInd++) |
4954e497 |
528 | { |
1103eb60 |
529 | myAllocator.destroy(theWhat + anInd); |
4954e497 |
530 | } |
4954e497 |
531 | } |
532 | |
1103eb60 |
533 | void copyConstruct(const pointer theFrom, |
534 | const size_t theCount) |
535 | { |
536 | for (size_t anInd = 0; anInd < theCount; anInd++) |
537 | { |
538 | myAllocator.construct(myPointer + anInd, theFrom[anInd]); |
539 | } |
6286195c |
540 | } |
7fd59977 |
541 | |
7fd59977 |
542 | // ---------- PROTECTED FIELDS ----------- |
1103eb60 |
543 | Standard_Integer myLowerBound; |
544 | size_t mySize; |
545 | pointer myPointer = nullptr; |
546 | bool myIsOwner = false; |
547 | allocator_type myAllocator; |
7fd59977 |
548 | }; |
549 | |
7fd59977 |
550 | #endif |