6#include "Stroika/Foundation/Containers/Support/ReserveTweaks.h"
8#include "Stroika/Foundation/Execution/Throw.h"
9#include "Stroika/Foundation/Memory/Common.h"
14#ifndef qStroika_Foundation_Containers_DataStructures_Array_IncludeSlowDebugChecks_
15#define qStroika_Foundation_Containers_DataStructures_Array_IncludeSlowDebugChecks_ 0
24 inline void Array<T>::Invariant () const noexcept
26#if qStroika_Foundation_Debug_AssertionsChecked
31 Array<T>::Array (
const Array& from)
34 reserve (from.size ());
39 size_t newLength = from.size ();
42 const T* rhs = &from.fItems_[0];
43 T* end = &fItems_[newLength];
46 }
while (++lhs < end);
52 Array<T>::Array (Array&& from) noexcept
53 : fItems_{move (from.fItems_)}
54 , fLength_{from.fLength_}
57 from.fItems_ =
nullptr;
64 Insert (index, span{&item, 1});
66#if qCompilerAndStdLib_MemoryInsertAt_Buggy
73 Require (index <= fLength_);
80 size_t oldLength = fLength_;
81 SetLength (oldLength + 1, item);
82 if (index < oldLength) {
86 Assert (fLength_ >= 2);
87 T* lhs = &fItems_[fLength_ - 1];
88 T* rhs = &fItems_[fLength_ - 2];
89 size_t i = fLength_ - 1;
91 for (; i > index; --i) {
95 Assert (lhs == &fItems_[index]);
101 template <
typename T>
102 template <Memory::ISpanOfT<T> SPAN_T>
107 Require (at <= fLength_);
109 size_t n2Add = copyFrom.size ();
110 if (n2Add != 0) [[likely]] {
112 size_t newSz = sz + n2Add;
113 ReserveAtLeast (newSz);
114#if qCompilerAndStdLib_MemoryInsertAt_Buggy
117 for (
size_t i = 0; i < copyFrom.size (); ++i) {
118 this->Insert_BWA (i + at, copyFrom[i]);
121 this->fLength_ = Memory::Insert (span{this->data (), sz}, span{this->data (), capacity ()}, at, copyFrom).size ();
123 Assert (this->fLength_ == newSz);
127 template <
typename T>
128 inline void Array<T>::Insert (
const ForwardIterator& i, ArgByValueType<T> newValue)
131 Require (i._fData ==
this);
133 Insert (i.CurrentIndex (), newValue);
135 template <
typename T>
136 inline void Array<T>::Insert (
const BackwardIterator& i, ArgByValueType<T> newValue)
139 Require (i._fData ==
this);
141 Insert (i.CurrentIndex (), newValue);
143 template <
typename T>
146 Insert (this->size (), item);
148 template <
typename T>
152 Require (index >= 0);
153 Require (index < fLength_);
155 (void)Memory::Remove (span{this->data (), size ()}, span{this->data (), capacity ()}, index, index + 1);
159 template <
typename T>
164 fLength_ = Memory::Remove (span{this->data (), size ()}, span{this->data (), capacity ()}, from, to).size ();
167 template <
typename T>
173 for (
size_t i = fLength_; i > 0; --i, ++p) {
179 template <
typename T>
180 template <invocable<T> FUNCTION>
184 const T* start = &fItems_[0];
185 const T* end = &fItems_[fLength_];
188 for_each (start, end, forward<FUNCTION> (doToElement));
191#if __cpp_lib_execution >= 201603L
192 for_each (execution::par, start, end, forward<FUNCTION> (doToElement));
194 for_each (start, end, forward<FUNCTION> (doToElement));
199 template <
typename T>
200 inline auto Array<T>::begin () const -> ForwardIterator
202 return ForwardIterator{
this, 0};
204 template <
typename T>
205 constexpr auto Array<T>::end () const -> ForwardIterator
207 return ForwardIterator{};
209 template <
typename T>
210 template <predicate<T> FUNCTION>
211 auto Array<T>::Find (FUNCTION&& firstThat)
const -> ForwardIterator
214 const T* start = &fItems_[0];
216 const T* last = &fItems_[fLength_];
217 for (; i < last; ++i) {
218 if (forward<FUNCTION> (firstThat) (*i)) {
219 return ForwardIterator{
this,
static_cast<size_t> (i - start)};
224 template <
typename T>
225 template <
typename EQUALS_COMPARER>
226 const T*
Array<T>::Find (ArgByValueType<T> item, EQUALS_COMPARER&& equalsComparer)
const
228 const T* start = &fItems_[0];
229 const T* last = &fItems_[fLength_];
230 for (
const T* i = start; i < last; ++i) {
231 if (forward<EQUALS_COMPARER> (equalsComparer) (i->fItem, item)) {
237 template <
typename T>
238 template <
typename EQUALS_COMPARER>
241 const T* start = &fItems_[0];
242 const T* last = &fItems_[fLength_];
243 for (
const T* i = start; i < last; ++i) {
244 if (forward<EQUALS_COMPARER> (equalsComparer) (i->fItem, item)) {
250 template <
typename T>
256 Require (size () <= slotsAlloced);
258 if (fSlotsAllocated_ != slotsAlloced) {
259 if (slotsAlloced == 0) {
260 if constexpr (kUseMalloc_) {
261 if (fItems_ !=
nullptr) {
267 delete[] (
char*)fItems_;
276 if (fItems_ ==
nullptr) {
277 if constexpr (kUseMalloc_) {
278 fItems_ = (T*)malloc (
sizeof (T) * slotsAlloced);
282 fItems_ = (T*)
new char[
sizeof (T) * slotsAlloced];
286 if constexpr (kUseMalloc_) {
287 auto newVal = (T*)realloc (fItems_,
sizeof (T) * slotsAlloced);
295 T* newV = (T*)
new char[
sizeof (T) * slotsAlloced];
297 size_t n2Copy = fLength_;
298 uninitialized_copy_n (&fItems_[0], n2Copy, newV);
301 delete[] (
char*)newV;
305 T* end = &fItems_[fLength_];
306 for (T* p = &fItems_[0]; p != end; ++p) {
310 delete[] (
char*)fItems_;
315 fSlotsAllocated_ = slotsAlloced;
319 template <
typename T>
322 if (slotsAlloced > capacity ()) [[unlikely]] {
331 reserve (Support::ReserveTweaks::GetScaledUpCapacity (slotsAlloced,
sizeof (T)));
333 Ensure (size () <= capacity ());
334 Ensure (capacity () >= slotsAlloced);
336 template <
typename T>
341 size_t newLength = list.size ();
350 reserve (max (capacity (), newLength));
355 size_t commonLength = Stroika::Foundation::min (fLength_, newLength);
356 T* lhs = &fItems_[0];
357 T* rhs = &list.fItems_[0];
358 for (
size_t i = commonLength; i-- > 0;) {
366 Assert (lhs == &fItems_[commonLength]);
367 if (fLength_ > newLength) {
368 T* end = &fItems_[fLength_];
375 }
while (++lhs < end);
377 else if (fLength_ < newLength) {
378 T* end = &fItems_[newLength];
382 }
while (++lhs < end);
384 fLength_ = newLength;
388 template <
typename T>
398 ReserveAtLeast (newLength);
399 T* cur = &fItems_[fLength_];
400 T* end = &fItems_[newLength];
401 if (newLength > fLength_) {
404 new (cur) T{fillValue};
405 }
while (++cur < end);
409 while (cur-- > end) {
413 fLength_ = newLength;
416#if qStroika_Foundation_Debug_AssertionsChecked
417 template <
typename T>
420#if qStroika_Foundation_Containers_DataStructures_Array_IncludeSlowDebugChecks_
423 Assert ((fSlotsAllocated_ == 0) == (fItems_ ==
nullptr));
424 Assert (fLength_ <= fSlotsAllocated_);
427 template <
typename T>
428 inline Array<T>::~Array ()
431 if constexpr (kUseMalloc_) {
432 if (fItems_ !=
nullptr) {
437 delete[] (
char*)fItems_;
440 template <
typename T>
441 inline void Array<T>::MoveIteratorHereAfterClone (IteratorBase* pi, [[maybe_unused]]
const Array<T>* movedFrom)
const
446 Require (pi->CurrentIndex () <= this->size ());
447 Require (pi->_fData == movedFrom);
450 template <
typename T>
456 template <
typename T>
462 template <
typename T>
467 Require (i < fLength_);
470 template <
typename T>
475 Require (i < fLength_);
478 template <
typename T>
483 Require (i < fLength_);
486 template <
typename T>
491 Require (i < fLength_);
494 template <
typename T>
499 Require (i < fLength_);
502 template <
typename T>
507 Require (i < fLength_);
510 template <
typename T>
516 template <
typename T>
520 return fLength_ == 0;
522 template <
typename T>
526 return fSlotsAllocated_;
528 template <
typename T>
529 inline void Array<T>::shrink_to_fit ()
534 template <
typename T>
538 Require (not i.Done ());
539 Require (i._fData ==
this);
540 this->Remove (i.CurrentIndex ());
542 template <
typename T>
546 Require (not i.Done ());
547 Require (i._fData ==
this);
548 size_t idx = i.CurrentIndex ();
550 if (idx == this->fLength_) {
557 template <
typename T>
561 Require (not i.Done ());
562 this->Remove (i.CurrentIndex ());
564 template <
typename T>
565 inline void Array<T>::SetAt (
const ForwardIterator& i, ArgByValueType<T> newValue)
568 Require (i._fData ==
this);
569 Require (not i.Done ());
570 SetAt (i.CurrentIndex (), newValue);
572 template <
typename T>
573 inline void Array<T>::SetAt (
const BackwardIterator& i, ArgByValueType<T> newValue)
576 Require (not i.Done ());
577 SetAt (i.CurrentIndex (), newValue);
585 template <
typename T>
586 inline Array<T>::IteratorBase::IteratorBase (
const Array* data)
591#if qStroika_Foundation_Debug_AssertionsChecked
592 template <
typename T>
593 inline Array<T>::IteratorBase::~IteratorBase ()
595#if qStroika_Foundation_Debug_AssertionsChecked
597 _fData =
reinterpret_cast<Array<T>*
> (-1);
598 _fCurrentIdx = numeric_limits<size_t>::max ();
602 template <
typename T>
603 inline size_t Array<T>::IteratorBase::CurrentIndex ()
const
612 template <
typename T>
613 inline const T& Array<T>::IteratorBase::operator* ()
const
618 Require (0 <= _fCurrentIdx and _fCurrentIdx < _fData->fLength_);
619 return _fData->fItems_[_fCurrentIdx];
621 template <
typename T>
622 inline const T* Array<T>::IteratorBase::operator->()
const
627 Require (0 <= _fCurrentIdx and _fCurrentIdx < _fData->fLength_);
628 return _fData->PeekAt (_fCurrentIdx);
630 template <
typename T>
631 inline void Array<T>::IteratorBase::SetIndex (
size_t i)
635 Require (i <= _fData->fLength_);
638 template <
typename T>
648 template <
typename T>
653 Require (i <= _fData->fLength_);
656 template <
typename T>
659#if qStroika_Foundation_Debug_AssertionsChecked
660 Require (
data == _fData);
663 template <
typename T>
666#if qStroika_Foundation_Debug_AssertionsChecked
670#if qStroika_Foundation_Debug_AssertionsChecked
671 template <
typename T>
674 Assert (0 <= _fCurrentIdx);
675 if (_fData !=
nullptr) {
676#if qStroika_Foundation_Containers_DataStructures_Array_IncludeSlowDebugChecks_
679 Assert (_fCurrentIdx <= _fData->fLength_);
689 template <
typename T>
694 this->_fCurrentIdx = startAt;
697 template <
typename T>
700 this->_fData = -src._fData;
701 this->_fCurrentIdx = src._fCurrentIdx;
702 src._fData =
nullptr;
704 template <
typename T>
709 template <
typename T>
712 if (this->_fData ==
nullptr) {
713 Assert (this->_fCurrentIdx == 0);
716#if qStroika_Foundation_Containers_DataStructures_Array_IncludeSlowDebugChecks_
722 template <
typename T>
723 inline auto Array<T>::ForwardIterator::operator++ () noexcept -> ForwardIterator&
726 Require (not this->Done ());
728 Assert (this->_fCurrentIdx < this->_fData->fLength_);
729 ++this->_fCurrentIdx;
733 template <
typename T>
734 inline auto Array<T>::ForwardIterator::operator++ (
int)
noexcept -> ForwardIterator
736 ForwardIterator result = *
this;
740 template <
typename T>
741 inline bool Array<T>::ForwardIterator::operator== (
const ForwardIterator& rhs)
const
743 auto thisDone = this->Done ();
744 bool rhsDone = rhs.Done ();
745 if (thisDone or rhsDone) {
746 return thisDone and rhsDone;
748 Require (this->_fData == rhs._fData);
749 return this->_fCurrentIdx == rhs._fCurrentIdx;
757 template <
typename T>
762 this->_fCurrent = startAt;
765 template <
typename T>
766 inline Array<T>::BackwardIterator::BackwardIterator (
const Array*
data)
770 template <
typename T>
771 inline bool Array<T>::BackwardIterator::Done () const noexcept
773#if qStroika_Foundation_Containers_DataStructures_Array_IncludeSlowDebugChecks_
777 return bool (this->
CurrentIndex () == this->_fData->fLength_);
779 template <
typename T>
780 inline auto Array<T>::BackwardIterator::operator++ () noexcept -> BackwardIterator&
783 Require (not this->Done ());
785 if (this->_fCurrent == this->_fStart) {
786 this->_fCurrent = this->_fEnd;
787 Ensure (this->Done ());
791 Ensure (not this->Done ());
796 template <
typename T>
797 inline bool Array<T>::BackwardIterator::operator== (
const BackwardIterator& rhs)
const
799 auto thisDone = this->Done ();
800 bool rhsDone = rhs.Done ();
801 if (thisDone or rhsDone) {
802 return thisDone and rhsDone;
804 Require (this->_fData == rhs._fData);
805 return this->_fCurrentIdx == rhs._fCurrentIdx;
#define RequireNotNull(p)
constexpr ForwardIterator() noexcept=default
constexpr void AssertDataMatches(const Array *data) const
very similar to std::vector<T>
nonvirtual void Apply(FUNCTION &&doToElement, Execution::SequencePolicy seq=Execution::SequencePolicy::eDEFAULT) const
nonvirtual ForwardIterator Find(FUNCTION &&firstThat) const
nonvirtual T GetAt(size_t i) const
nonvirtual T * PeekAt(size_t i)
nonvirtual void Remove(const ForwardIterator &i)
nonvirtual void push_back(ArgByValueType< T > item)
STL-ish alias for Insert (size(), item)
nonvirtual void Insert(size_t index, ArgByValueType< T > item)
nonvirtual bool empty() const
nonvirtual T * data() noexcept
returns internal pointer to data - which is unsynchronized, and only guaranteed valid until the next ...
nonvirtual void SetAt(size_t i, ArgByValueType< T > item)
nonvirtual void reserve(size_t slotsAlloced)
sets the reserved capacity to slotsAlloced
nonvirtual void ReserveAtLeast(size_t slotsAlloced)
nonvirtual T & operator[](size_t i)
size_t UnderlyingIteratorRep
nonvirtual void SetLength(size_t newLength, ArgByValueType< T > fillValue)
nonvirtual ForwardIterator erase(const ForwardIterator &i)
remove the element at i, and return valid iterator to the element that was following it (which can be...
nonvirtual size_t size() const
shared_lock< const AssertExternallySynchronizedMutex > ReadContext
Instantiate AssertExternallySynchronizedMutex::ReadContext to designate an area of code where protect...
unique_lock< AssertExternallySynchronizedMutex > WriteContext
Instantiate AssertExternallySynchronizedMutex::WriteContext to designate an area of code where protec...
nonvirtual ForwardIterator & operator++() noexcept
nonvirtual size_t CurrentIndex(const DoublyLinkedList *data) const
SequencePolicy
equivalent which of 4 types being used std::execution::sequenced_policy, parallel_policy,...
@ eSeq
default case - not parallelized
void ThrowIfNull(const Private_::ConstVoidStar &p, const HRESULT &hr)
Template specialization for ThrowIfNull (), for thing being thrown HRESULT - really throw HRESULTErro...