diff --git a/include/container/seadObjArray.h b/include/container/seadObjArray.h index a6759a85..db75ff06 100644 --- a/include/container/seadObjArray.h +++ b/include/container/seadObjArray.h @@ -152,7 +152,11 @@ class ObjArray : public PtrArrayImpl return PtrArrayImpl::compare(other, cmp); } - s32 binarySearch(const T* ptr) const { return PtrArrayImpl::binarySearch(ptr, compareT); } + __attribute__((noinline)) s32 binarySearch(const T* ptr) const + { + return PtrArrayImpl::binarySearch(ptr, compareT); + } + s32 binarySearch(const T* ptr, CompareCallback cmp) const { return PtrArrayImpl::binarySearch(ptr, cmp); diff --git a/include/container/seadPtrArray.h b/include/container/seadPtrArray.h index e094fc1b..2323927a 100644 --- a/include/container/seadPtrArray.h +++ b/include/container/seadPtrArray.h @@ -154,12 +154,12 @@ class PtrArrayImpl if (mPtrNum <= pos) return; - MemUtil::copyOverlap(mPtrs + pos + count, mPtrs + pos, + MemUtil::copyOverlap(&mPtrs[pos + count], &mPtrs[pos], s32(sizeof(void*)) * (mPtrNum - pos)); } void insert(s32 idx, void* ptr); - void insertArray(s32 idx, void* array, s32 array_length, s32 elem_size); + void insertArray(s32 idx, void* array, s32 arrayLength, s32 elementSize); bool checkInsert(s32 idx, s32 num); template @@ -188,30 +188,7 @@ class PtrArrayImpl s32 compare(const PtrArrayImpl& other, CompareCallbackImpl cmp) const; void uniq(CompareCallbackImpl cmp); - s32 binarySearch(const void* ptr, CompareCallbackImpl cmp) const - { - if (mPtrNum == 0) - return -1; - - s32 a = 0; - s32 b = mPtrNum - 1; - while (a < b) - { - const s32 m = (a + b) / 2; - const s32 c = cmp(mPtrs[m], ptr); - if (c == 0) - return m; - if (c < 0) - a = m + 1; - else - b = m; - } - - if (cmp(mPtrs[a], ptr) == 0) - return a; - - return -1; - } + s32 binarySearch(const void* ptr, CompareCallbackImpl cmp) const; s32 mPtrNum = 0; s32 mPtrNumMax = 0; diff --git a/modules/src/container/seadPtrArray.cpp b/modules/src/container/seadPtrArray.cpp index 87ea5435..2382eacb 100644 --- a/modules/src/container/seadPtrArray.cpp +++ b/modules/src/container/seadPtrArray.cpp @@ -93,10 +93,10 @@ void PtrArrayImpl::erase(s32 pos, s32 count) mPtrNum -= count; } -// NON_MATCHING: semantically equivalent void PtrArrayImpl::reverse() { - for (s32 i = 0; i < mPtrNum / 2; ++i) + s32 size = mPtrNum / 2; + for (s32 i = 0; i < size; i++) swap(mPtrNum - i - 1, i); } @@ -104,7 +104,7 @@ void PtrArrayImpl::reverse() void PtrArrayImpl::shuffle(Random* random) { SEAD_ASSERT(random); - for (s32 i = mPtrNum - 1; i > 0; --i) + for (s32 i = mPtrNum - 1; i > 0; i--) swap(i, random->getS32Range(0, i + 1)); } @@ -141,20 +141,167 @@ bool PtrArrayImpl::checkInsert(s32 pos, s32 num) return true; } -// TODO: PtrArrayImpl::insertArray +// NON-MATCHING: Inverted registers https://decomp.me/scratch/fBexb +void PtrArrayImpl::insertArray(s32 idx, void* array, s32 arrayLength, s32 elementSize) +{ + if (!checkInsert(idx, arrayLength)) + return; + + createVacancy(idx, arrayLength); + + for (s32 i = 0; i < arrayLength; i++) + mPtrs[idx + i] = (u8*)array + (elementSize * i); + + mPtrNum += arrayLength; +} +// Bidirectional bubble sort void PtrArrayImpl::sort(CompareCallbackImpl cmp) { - // Note: Nintendo did not use - std::sort(mPtrs, mPtrs + size(), [&](const void* a, const void* b) { return cmp(a, b) < 0; }); + if (mPtrNum < 2) + return; + + void** ptrs = mPtrs; + s32 left = 0; + s32 right = mPtrNum - 1; + + do + { + s32 lastSwapForward = left; + for (s32 i = left; i < right; i++) + { + if (cmp(ptrs[i], ptrs[i + 1]) > 0) + { + void* temp = ptrs[i + 1]; + ptrs[i + 1] = ptrs[i]; + ptrs[i] = temp; + lastSwapForward = i; + } + } + right = lastSwapForward; + + if (left == right) + break; + + s32 lastSwapBackward = right; + for (s32 i = right; i > left; i--) + { + if (cmp(ptrs[i], ptrs[i - 1]) < 0) + { + void* temp = ptrs[i - 1]; + ptrs[i - 1] = ptrs[i]; + ptrs[i] = temp; + lastSwapBackward = i; + } + } + left = lastSwapBackward; + } while (left != right); } -// TODO: PtrArrayImpl::heapSort +void PtrArrayImpl::heapSort(CompareCallbackImpl cmp) +{ + if (mPtrNum < 2) + return; + + void** ptrs = mPtrs; + s32 i = mPtrNum / 2; + s32 n = mPtrNum; + + do + { + s32 parent = i--; + void* val = ptrs[parent - 1]; + + while (parent * 2 <= n) + { + s32 child = parent * 2; + if (child < n && cmp(ptrs[child - 1], ptrs[child]) < 0) + child++; + + if (cmp(val, ptrs[child - 1]) >= 0) + break; + + ptrs[parent - 1] = ptrs[child - 1]; + parent = child; + } + + ptrs[parent - 1] = val; + } while (i > 0); + + while (n > 1) + { + void* val = ptrs[n - 1]; + ptrs[--n] = ptrs[0]; -// TODO: PtrArrayImpl::compare + s32 parent = 1; + while (parent * 2 <= n) + { + s32 child = parent * 2; + if (child < n && cmp(ptrs[child - 1], ptrs[child]) < 0) + child++; -// TODO: PtrArrayImpl::uniq + if (cmp(val, ptrs[child - 1]) >= 0) + break; -// TODO: PtrArrayImpl::binarySearch + ptrs[parent - 1] = ptrs[child - 1]; + parent = child; + } + ptrs[parent - 1] = val; + } +} + +s32 PtrArrayImpl::compare(const PtrArrayImpl& other, CompareCallbackImpl cmp) const +{ + for (s32 i = 0; i < size(); i++) + { + if (i >= other.size()) + return 1; + + const s32 c = cmp(mPtrs[i], other.unsafeAt(i)); + if (c != 0) + return c; + } + + return size() != other.size() ? -1 : 0; +} + +void PtrArrayImpl::uniq(CompareCallbackImpl cmp) +{ + for (s32 i = 0; i < size() - 1; i++) + { + for (s32 e = i + 1; e < size();) + { + if (cmp(mPtrs[i], mPtrs[e]) == 0) + erase(e, 1); + else + e++; + } + } +} + +s32 PtrArrayImpl::binarySearch(const void* ptr, CompareCallbackImpl cmp) const +{ + if (mPtrNum == 0) + return -1; + + s32 low = 0; + s32 high = size() - 1; + while (low < high) + { + const s32 mid = (low + high) / 2; + const s32 c = cmp(mPtrs[mid], ptr); + if (c == 0) + return mid; + if (c < 0) + low = mid + 1; + else + high = mid; + } + + if (cmp(mPtrs[low], ptr) == 0) + return low; + + return -1; +} } // namespace sead