Nebula
Loading...
Searching...
No Matches
pinnedarray.h
Go to the documentation of this file.
1#pragma once
2//------------------------------------------------------------------------------
9//------------------------------------------------------------------------------
10#include "array.h"
11
12namespace Util
13{
14
15template<int MAX_ALLOCS, class TYPE>
16class PinnedArray : public Array<TYPE>
17{
18
19public:
20
28 PinnedArray(SizeT initialSize, SizeT grow, const TYPE& initialValue);
30 PinnedArray(const TYPE* const buf, SizeT num);
32 PinnedArray(std::initializer_list<TYPE> list);
35
40
42 template <typename ...ELEM_TYPE>
43 void Append(const TYPE& first, const ELEM_TYPE&... elements);
45 void Append(const TYPE& elm);
47 void Append(const TYPE&& elm);
49 TYPE& Emplace();
51 void Insert(IndexT index, const TYPE& elm);
53 IndexT InsertSorted(const TYPE& elm);
55 IndexT InsertAtEndOfIdenticalRange(IndexT startIndex, const TYPE& elm);
56
60 void AppendArray(const TYPE* arr, const SizeT count);
62 TYPE* EmplaceArray(const SizeT count);
63
65 void Fill(IndexT first, SizeT num, const TYPE& elm);
66
68 void Reserve(const SizeT count);
72 void Resize(SizeT num);
74 void Extend(SizeT num);
75
77 void Free();
78
80 void Fit();
81private:
83 void Grow();
85 void GrowTo(SizeT newCapacity);
87 void Delete();
91 void Move(IndexT fromIndex, IndexT toIndex);
92};
93
94//------------------------------------------------------------------------------
97template<int MAX_ALLOCS, class TYPE>
98inline
100{
101 this->grow = 16;
102 this->capacity = 0;
103 this->count = 0;
104 this->elements = nullptr;
105}
106
107//------------------------------------------------------------------------------
110template<int MAX_ALLOCS, class TYPE>
111inline
116
117//------------------------------------------------------------------------------
120template<int MAX_ALLOCS, class TYPE>
121inline
123{
124 this->grow = grow;
125 this->capacity = 0;
126 this->count = 0;
127 this->elements = nullptr;
128 if (0 == this->grow)
129 {
130 this->grow = 16;
131 }
132 this->GrowTo(capacity);
133}
134
135//------------------------------------------------------------------------------
138template<int MAX_ALLOCS, class TYPE>
139inline
140PinnedArray<MAX_ALLOCS, TYPE>::PinnedArray(SizeT initialSize, SizeT grow, const TYPE& initialValue)
141{
142 this->grow = grow;
143 this->capacity = 0;
144 this->count = 0;
145 this->elements = nullptr;
146 if (0 == this->grow)
147 {
148 this->grow = 16;
149 }
150
151 this->GrowTo(initialSize);
152 this->count = initialSize;
153 IndexT i;
154 for (i = 0; i < initialSize; i++)
155 {
156 this->elements[i] = initialValue;
157 }
158}
159
160//------------------------------------------------------------------------------
163template<int MAX_ALLOCS, class TYPE>
164inline
166{
167 this->grow = 16;
168 this->capacity = 0;
169 this->count = 0;
170 this->elements = nullptr;
171
172 static_assert(std::is_trivially_copyable<TYPE>::value, "TYPE is not trivially copyable; Util::Array cannot be constructed from pointer of TYPE.");
173 this->GrowTo(num);
174 this->count = num;
175 const SizeT bytes = num * sizeof(TYPE);
176 Memory::Copy(buf, this->elements, bytes);
177}
178
179//------------------------------------------------------------------------------
182template<int MAX_ALLOCS, class TYPE>
183inline
184PinnedArray<MAX_ALLOCS, TYPE>::PinnedArray(std::initializer_list<TYPE> list)
185{
186 this->grow = 16;
187 this->capacity = 0;
188 this->count = 0;
189 this->elements = nullptr;
190
191 this->GrowTo((SizeT)list.size());
192 this->count = (SizeT)list.size();
193 IndexT i;
194 for (i = 0; i < this->count; i++)
195 {
196 this->elements[i] = list.begin()[i];
197 }
198}
199
200//------------------------------------------------------------------------------
203template<int MAX_ALLOCS, class TYPE>
204inline
206{
207 this->Delete();
208}
209
210//------------------------------------------------------------------------------
213template<int MAX_ALLOCS, class TYPE>
214inline void
216{
217 if (this != &rhs)
218 {
219 if ((this->capacity > 0) && (rhs.count <= this->capacity))
220 {
221 // source array fits into our capacity, copy in place
222 n_assert(0 != this->elements);
223
224 this->CopyRange(this->elements, rhs.elements, rhs.count);
225 if (rhs.count < this->count)
226 {
227 this->DestroyRange(rhs.count, this->count);
228 }
229 this->grow = rhs.grow;
230 this->count = rhs.count;
231 }
232 else
233 {
234 // source array doesn't fit into our capacity, need to reallocate
235 this->Delete();
236 this->Copy(rhs);
237 }
238 }
239}
240
241//------------------------------------------------------------------------------
244template<int MAX_ALLOCS, class TYPE>
245inline void
247{
248 if (this != &rhs)
249 {
250 this->Delete();
251
252 // If rhs is not using stack, simply reassign pointers
253 if (rhs.elements != rhs.stackElements.data())
254 {
255 this->elements = rhs.elements;
256 rhs.elements = nullptr;
257 }
258 else
259 {
260 // Otherwise, move every element over to the stack of this array
261 this->MoveRange(this->elements, rhs.elements, rhs.count);
262 }
263
264 this->grow = rhs.grow;
265 this->count = rhs.count;
266 this->capacity = rhs.capacity;
267 rhs.count = 0;
268 rhs.capacity = 0;
269 }
270}
271
272
273//------------------------------------------------------------------------------
276template<int MAX_ALLOCS, class TYPE>
277template<typename ...ELEM_TYPE>
278inline void
279PinnedArray<MAX_ALLOCS, TYPE>::Append(const TYPE& first, const ELEM_TYPE & ...elements)
280{
281 // The plus one is for the first element
282 const int size = sizeof...(elements) + 1;
283 this->Reserve(size);
284 TYPE res[size] = { first, elements... };
285 for (IndexT i = 0; i < size; i++)
286 {
287 this->elements[this->count++] = res[i];
288 }
289}
290
291//------------------------------------------------------------------------------
294template<int MAX_ALLOCS, class TYPE>
295inline void
297{
298 // grow allocated space if exhausted
299 if (this->count == this->capacity)
300 {
301 this->Grow();
302 }
303#if NEBULA_BOUNDSCHECKS
304 n_assert(this->elements);
305#endif
306 this->elements[this->count++] = std::move(elm);
307}
308
309//------------------------------------------------------------------------------
312template<int MAX_ALLOCS, class TYPE>
313inline void
315{
316 // grow allocated space if exhausted
317 if (this->count == this->capacity)
318 {
319 this->Grow();
320 }
321#if NEBULA_BOUNDSCHECKS
322 n_assert(this->elements);
323#endif
324 this->elements[this->count++] = std::move(elm);
325}
326
327//------------------------------------------------------------------------------
330template<int MAX_ALLOCS, class TYPE>
331inline TYPE&
333{
334 // grow allocated space if exhausted
335 if (this->count == this->capacity)
336 {
337 this->Grow();
338 }
339#if NEBULA_BOUNDSCHECKS
340 n_assert(this->elements);
341#endif
342 this->elements[this->count] = TYPE();
343 return this->elements[this->count++];
344}
345
346//------------------------------------------------------------------------------
349template<int MAX_ALLOCS, class TYPE>
350inline void
352{
353#if NEBULA_BOUNDSCHECKS
354 n_assert(index <= this->count && (index >= 0));
355#endif
356 if (index == this->count)
357 {
358 // special case: append element to back
359 this->Append(elm);
360 }
361 else
362 {
363 this->Move(index, index + 1);
364 this->elements[index] = elm;
365 }
366}
367
368//------------------------------------------------------------------------------
371template<int MAX_ALLOCS, class TYPE>
373{
374 SizeT num = this->Size();
375 if (num == 0)
376 {
377 // array is currently empty
378 this->Append(elm);
379 return this->Size() - 1;
380 }
381 else
382 {
383 IndexT half;
384 IndexT lo = 0;
385 IndexT hi = num - 1;
386 IndexT mid;
387 while (lo <= hi)
388 {
389 if (0 != (half = num / 2))
390 {
391 mid = lo + ((num & 1) ? half : (half - 1));
392 if (elm < this->elements[mid])
393 {
394 hi = mid - 1;
395 num = num & 1 ? half : half - 1;
396 }
397 else if (elm > this->elements[mid])
398 {
399 lo = mid + 1;
400 num = half;
401 }
402 else
403 {
404 // element already exists at [mid], append the
405 // new element to the end of the range
406 return this->InsertAtEndOfIdenticalRange(mid, elm);
407 }
408 }
409 else if (0 != num)
410 {
411 if (elm < this->elements[lo])
412 {
413 this->Insert(lo, elm);
414 return lo;
415 }
416 else if (elm > this->elements[lo])
417 {
418 this->Insert(lo + 1, elm);
419 return lo + 1;
420 }
421 else
422 {
423 // element already exists at [low], append
424 // the new element to the end of the range
425 return this->InsertAtEndOfIdenticalRange(lo, elm);
426 }
427 }
428 else
429 {
430#if NEBULA_BOUNDSCHECKS
431 n_assert(0 == lo);
432#endif
433 this->Insert(lo, elm);
434 return lo;
435 }
436 }
437 if (elm < this->elements[lo])
438 {
439 this->Insert(lo, elm);
440 return lo;
441 }
442 else if (elm > this->elements[lo])
443 {
444 this->Insert(lo + 1, elm);
445 return lo + 1;
446 }
447 else
448 {
449 // can't happen(?)
450 }
451 }
452 // can't happen
453 n_error("Array::InsertSorted: Can't happen!");
454 return InvalidIndex;
455}
456
457//------------------------------------------------------------------------------
460template<int MAX_ALLOCS, class TYPE>
462{
463 IndexT i = startIndex + 1;
464 for (; i < this->count; i++)
465 {
466 if (this->elements[i] != elm)
467 {
468 this->Insert(i, elm);
469 return i;
470 }
471 }
472
473 // fallthrough: new element needs to be appended to end
474 this->Append(elm);
475 return (this->Size() - 1);
476}
477
478//------------------------------------------------------------------------------
481template<int MAX_ALLOCS, class TYPE>
482inline void
484{
485 SizeT neededCapacity = this->count + src.count;
486 if (neededCapacity > this->capacity)
487 {
488 this->GrowTo(neededCapacity);
489 }
490
491 // forward elements from array
492 IndexT i;
493 for (i = 0; i < src.count; i++)
494 {
495 this->elements[this->count + i] = src.elements[i];
496 }
497 this->count += src.count;
498}
499
500//------------------------------------------------------------------------------
503template<int MAX_ALLOCS, class TYPE>
504inline void
506{
507 SizeT neededCapacity = this->count + count;
508 if (neededCapacity > this->capacity)
509 {
510 this->GrowTo(neededCapacity);
511 }
512
513 // forward elements from array
514 IndexT i;
515 for (i = 0; i < count; i++)
516 {
517 this->elements[this->count + i] = arr[i];
518 }
519 this->count += count;
520}
521
522//------------------------------------------------------------------------------
525template<int MAX_ALLOCS, class TYPE>
526inline TYPE*
528{
529 SizeT neededCapacity = this->count + count;
530 if (neededCapacity > this->capacity)
531 {
532 this->GrowTo(neededCapacity);
533 }
534
535 // forward elements from array
536 IndexT i;
537 for (i = 0; i < count; i++)
538 {
539 this->elements[this->count + i] = TYPE();
540 }
541 TYPE* first = this->elements[this->count];
542 this->count += count;
543 return first;
544}
545
546//------------------------------------------------------------------------------
549template<int MAX_ALLOCS, class TYPE>
550inline void
552{
553 if ((first + num) > this->count)
554 {
555 this->GrowTo(first + num);
556 this->count = first + num;
557 }
558
559 IndexT i;
560 for (i = first; i < (first + num); i++)
561 {
562 this->elements[i] = elm;
563 }
564}
565
566//------------------------------------------------------------------------------
569template<int MAX_ALLOCS, class TYPE>
570inline void
572{
573#if NEBULA_BOUNDSCHECKS
574 n_assert(count >= 0);
575#endif
576
577 SizeT neededCapacity = this->count + count;
578 if (neededCapacity > this->capacity)
579 {
580 this->GrowTo(neededCapacity);
581 }
582}
583
584//------------------------------------------------------------------------------
587template<int MAX_ALLOCS, class TYPE>
588inline void
590{
591 this->Delete();
592 this->grow = grow;
593 this->capacity = capacity;
594 this->count = capacity;
595 if (this->capacity > 0)
596 {
597 this->GrowTo(this->capacity);
598 }
599 else
600 {
601 this->elements = 0;
602 }
603}
604
605//------------------------------------------------------------------------------
608template<int MAX_ALLOCS, class TYPE>
609inline void
611{
612 if (num < this->count)
613 {
614 this->DestroyRange(num, this->count);
615 }
616 else if (num > this->capacity)
617 {
618 this->GrowTo(num);
619 }
620
621 this->count = num;
622}
623
624//------------------------------------------------------------------------------
627template<int MAX_ALLOCS, class TYPE>
628inline void
630{
631 if (num > this->capacity)
632 {
633 this->GrowTo(num);
634 }
635 this->count = Math::max(num, this->count);
636}
637
638//------------------------------------------------------------------------------
641template<int MAX_ALLOCS, class TYPE>
642inline void
644{
645 this->Delete();
646 this->grow = 16;
647}
648
649//------------------------------------------------------------------------------
652template<int MAX_ALLOCS, class TYPE>
653inline void
655{
656 // The start offset of the memory has to be aligned to the page size
657 SizeT numUsedBytes = Math::align(this->count * sizeof(TYPE), System::PageSize);
658 SizeT numNeededPages = numUsedBytes / System::PageSize;
659 SizeT numUsedPages = this->capacity * sizeof(TYPE) / System::PageSize;
660 SizeT numFreeablePages = numUsedPages - numNeededPages;
661
662 Memory::DecommitVirtual(((byte*)this->elements) + numUsedBytes, numFreeablePages * System::PageSize);
663 this->capacity = this->count;
664}
665
666//------------------------------------------------------------------------------
669template<int MAX_ALLOCS, class TYPE>
670inline void
672{
673#if NEBULA_BOUNDSCHECKS
674 n_assert(this->grow > 0);
675#endif
676
677 SizeT growToSize;
678 if (0 == this->capacity)
679 {
680 growToSize = this->grow;
681 }
682 else
683 {
684 // grow by half of the current capacity, but never more then MaxGrowSize
685 SizeT growBy = this->capacity >> 1;
686 if (growBy == 0)
687 {
689 }
690 else if (growBy > Array<TYPE>::MaxGrowSize)
691 {
693 }
694 growToSize = this->capacity + growBy;
695 }
696 this->GrowTo(growToSize);
697}
698
699//------------------------------------------------------------------------------
702template<int MAX_ALLOCS, class TYPE>
703inline void
705{
706 if (this->elements == nullptr)
707 {
708 SizeT pageSize = System::PageSize;
709 SizeT reservationSize = Math::align(MAX_ALLOCS * sizeof(TYPE), pageSize);
710 this->elements = (TYPE*)Memory::AllocVirtual(reservationSize);
711 }
712
713 SizeT pageSize = System::PageSize;
714
715 // Total amount of bytes needed to fill new capacity
716 SizeT totalByteSize = newCapacity * sizeof(TYPE);
717
718 // Rounded up to the page size so we don't waste memory we allocate anyways
719 SizeT totalBytesNeeded = Math::align(totalByteSize, pageSize);
720
721#if NEBULA_DEBUG
722 if (totalBytesNeeded > MAX_ALLOCS * sizeof(TYPE))
723 {
724 n_printf("[PinnedArray] MAX_ALLOCS '%d' and item size '%d' will waste '%d' byte(s) due to alignment of page size '%d'", MAX_ALLOCS, sizeof(TYPE), totalBytesNeeded - MAX_ALLOCS * sizeof(TYPE), pageSize);
725 }
726#endif
727 SizeT roundedUpNewCapacity = totalBytesNeeded / sizeof(TYPE);
728 SizeT offset = Math::align(this->capacity * sizeof(TYPE), pageSize);
729 if (totalBytesNeeded > offset)
730 {
731 // The amount of bytes we need to commit is the difference between the new and the old capacity
732 SizeT commitSize = Math::align((roundedUpNewCapacity - this->capacity) * sizeof(TYPE), pageSize);
733 this->capacity = roundedUpNewCapacity;
734
735 Memory::CommitVirtual(((byte*)this->elements) + offset, commitSize);
736 }
737}
738
739//------------------------------------------------------------------------------
742template<int MAX_ALLOCS, class TYPE>
743inline void
745{
746 this->grow = 16;
747
748 if (this->capacity > 0)
749 {
750 // If in small vector, run destructor
751 this->DestroyRange(0, this->count);
752 Memory::FreeVirtual(this->elements, this->capacity * sizeof(TYPE));
753 }
754 this->elements = nullptr;
755 this->capacity = 0;
756 this->count = 0;
757}
758
759//------------------------------------------------------------------------------
762template<int MAX_ALLOCS, class TYPE>
763inline void
765{
766#if NEBULA_BOUNDSCHECKS
767// Make sure array is either empty, or stack array before copy
768 n_assert(this->stackElements.data() == this->elements);
769#endif
770
771 this->GrowTo(src.capacity);
772 this->grow = src.grow;
773 this->count = src.count;
774 IndexT i;
775 for (i = 0; i < this->count; i++)
776 {
777 this->elements[i] = src.elements[i];
778 }
779}
780
781//------------------------------------------------------------------------------
784template<int MAX_ALLOCS, class TYPE>
785inline void
787{
788#if NEBULA_BOUNDSCHECKS
789 n_assert(this->elements);
790 n_assert(fromIndex < this->count);
791#endif
792
793// nothing to move?
794 if (fromIndex == toIndex)
795 {
796 return;
797 }
798
799 // compute number of elements to move
800 SizeT num = this->count - fromIndex;
801
802 // check if array needs to grow
803 SizeT neededSize = toIndex + num;
804 while (neededSize > this->capacity)
805 {
806 this->Grow();
807 }
808
809 if (fromIndex > toIndex)
810 {
811 // this is a backward move
812 this->MoveRange(&this->elements[toIndex], &this->elements[fromIndex], num);
813 this->DestroyRange(fromIndex + num - 1, this->count);
814 }
815 else
816 {
817 // this is a forward move
818 int i; // NOTE: this must remain signed for the following loop to work!!!
819 for (i = num - 1; i >= 0; --i)
820 {
821 this->elements[toIndex + i] = this->elements[fromIndex + i];
822 }
823
824 // destroy freed elements
825 this->DestroyRange(fromIndex, toIndex);
826 }
827
828 // adjust array size
829 this->count = toIndex + num;
830}
831
832} // namespace Util
Definition half.h:20
Nebula's dynamic array class.
Definition array.h:60
SizeT capacity
Definition array.h:246
SizeT count
Definition array.h:247
TYPE * elements
Definition array.h:248
SizeT grow
Definition array.h:245
Definition pinnedarray.h:17
void Copy(const PinnedArray< MAX_ALLOCS, TYPE > &src)
Copy from array.
Definition pinnedarray.h:764
IndexT InsertSorted(const TYPE &elm)
insert element into sorted array, return index where element was included
Definition pinnedarray.h:372
~PinnedArray()
Destructor.
Definition pinnedarray.h:205
void Delete()
Delete array.
Definition pinnedarray.h:744
PinnedArray(SizeT capacity, SizeT grow)
Construct from capacity and grow.
Definition pinnedarray.h:122
void GrowTo(SizeT newCapacity)
Grow array by size.
Definition pinnedarray.h:704
void Append(const TYPE &&elm)
Append single element as rhs.
Definition pinnedarray.h:314
PinnedArray(std::initializer_list< TYPE > list)
Construct from initializer list.
Definition pinnedarray.h:184
IndexT InsertAtEndOfIdenticalRange(IndexT startIndex, const TYPE &elm)
insert element at the first non-identical position, return index of inclusion position
Definition pinnedarray.h:461
void AppendArray(const TYPE *arr, const SizeT count)
Append contents of C array.
Definition pinnedarray.h:505
void Move(IndexT fromIndex, IndexT toIndex)
move elements, grows array if needed
Definition pinnedarray.h:786
void Reserve(const SizeT count)
Reserve an amount of memory (commits to memory)
Definition pinnedarray.h:571
void AppendArray(const PinnedArray< MAX_ALLOCS, TYPE > &src)
Append contents of another array.
Definition pinnedarray.h:483
void Fit()
Fit array to capacity.
Definition pinnedarray.h:654
void Realloc(SizeT capacity, SizeT grow)
Reallocate and clear.
Definition pinnedarray.h:589
void Insert(IndexT index, const TYPE &elm)
insert element before element at index
Definition pinnedarray.h:351
PinnedArray(SizeT initialSize, SizeT grow, const TYPE &initialValue)
Construct from initial commit size, grow and value.
Definition pinnedarray.h:140
TYPE * EmplaceArray(const SizeT count)
Emplace an array of elements and return pointer.
Definition pinnedarray.h:527
void Resize(SizeT num)
Resize to fit, destroys elements outside of new size.
Definition pinnedarray.h:610
TYPE & Emplace()
Emplace element and return reference to it.
Definition pinnedarray.h:332
void Extend(SizeT num)
Resize to fit the provided value, but don't shrink if the new size is smaller.
Definition pinnedarray.h:629
void Fill(IndexT first, SizeT num, const TYPE &elm)
Fill array with element.
Definition pinnedarray.h:551
void operator=(const PinnedArray< MAX_ALLOCS, TYPE > &rhs)
assignment operator
Definition pinnedarray.h:215
PinnedArray(const TYPE *const buf, SizeT num)
Construct from pointer and size.
Definition pinnedarray.h:165
void Grow()
Grow array using growth parameter.
Definition pinnedarray.h:671
void Append(const TYPE &elm)
Append single element.
Definition pinnedarray.h:296
void Append(const TYPE &first, const ELEM_TYPE &... elements)
Append multiple elements to the end of the array.
Definition pinnedarray.h:279
PinnedArray(const PinnedArray< MAX_ALLOCS, TYPE > &rhs)
Construct from other pinned array.
Definition pinnedarray.h:112
void Free()
Free memory.
Definition pinnedarray.h:643
void operator=(PinnedArray< MAX_ALLOCS, TYPE > &&rhs) noexcept
move operator
Definition pinnedarray.h:246
PinnedArray()
Default constructor.
Definition pinnedarray.h:99
void __cdecl n_error(const char *msg,...)
This function is called when a serious situation is encountered which requires abortion of the applic...
Definition debug.cc:138
void __cdecl n_printf(const char *msg,...)
Nebula's printf replacement.
Definition debug.cc:209
#define n_assert(exp)
Definition debug.h:50
__forceinline unsigned int align(unsigned int alignant, unsigned int alignment)
Definition scalar.h:722
__forceinline TYPE max(TYPE a, TYPE b)
Definition scalar.h:359
__forceinline void FreeVirtual(void *ptr, size_t size)
free virtual memory
Definition posixmemory.h:146
void Copy(const void *from, void *to, size_t numBytes)
Copy a chunk of memory (note the argument order is different from memcpy()!!!)
Definition osxmemory.cc:213
__forceinline void CommitVirtual(void *ptr, size_t size)
commit virtual memory
Definition posixmemory.h:135
__forceinline void * AllocVirtual(size_t size)
allocate a range of virtual memory space
Definition posixmemory.h:112
__forceinline void DecommitVirtual(void *ptr, size_t size)
decommit virtual memory
Definition posixmemory.h:123
SizeT PageSize
Definition posixsysteminfo.cc:14
A pinned array is an array which manages its own virtual memory.
Definition String.cs:6
static const int InvalidIndex
Definition types.h:54
int SizeT
Definition types.h:49
int IndexT
Definition types.h:48