mirror of
https://github.com/zeldaret/botw
synced 2026-08-21 06:08:24 -04:00
Switch to subrepos
git subrepo clone https://github.com/open-ead/sead lib/sead subrepo: subdir: "lib/sead" merged: "1b66e825d" upstream: origin: "https://github.com/open-ead/sead" branch: "master" commit: "1b66e825d" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo" commit: "2f68596" git subrepo clone (merge) https://github.com/open-ead/nnheaders lib/NintendoSDK subrepo: subdir: "lib/NintendoSDK" merged: "9ee21399f" upstream: origin: "https://github.com/open-ead/nnheaders" branch: "master" commit: "9ee21399f" git-subrepo: version: "0.4.3" origin: "ssh://git@github.com/ingydotnet/git-subrepo" commit: "2f68596" git subrepo clone https://github.com/open-ead/agl lib/agl subrepo: subdir: "lib/agl" merged: "7c063271b" upstream: origin: "https://github.com/open-ead/agl" branch: "master" commit: "7c063271b" git-subrepo: version: "0.4.3" origin: "ssh://git@github.com/ingydotnet/git-subrepo" commit: "2f68596" git subrepo clone https://github.com/open-ead/EventFlow lib/EventFlow subrepo: subdir: "lib/EventFlow" merged: "c35d21b34" upstream: origin: "https://github.com/open-ead/EventFlow" branch: "master" commit: "c35d21b34" git-subrepo: version: "0.4.3" origin: "ssh://git@github.com/ingydotnet/git-subrepo" commit: "2f68596"
This commit is contained in:
@@ -0,0 +1,271 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include "basis/seadNew.h"
|
||||
#include "basis/seadRawPrint.h"
|
||||
#include "container/seadFreeList.h"
|
||||
#include "container/seadPtrArray.h"
|
||||
|
||||
namespace sead
|
||||
{
|
||||
/// An ObjArray is a container that allocates elements using a FreeList and also keeps an array of
|
||||
/// pointers for fast access to each element.
|
||||
template <typename T>
|
||||
class ObjArray : public PtrArrayImpl
|
||||
{
|
||||
public:
|
||||
ObjArray() = default;
|
||||
ObjArray(s32 max_num, void* buf) { setBuffer(max_num, buf); }
|
||||
|
||||
void allocBuffer(s32 capacity, Heap* heap, s32 alignment = sizeof(void*))
|
||||
{
|
||||
SEAD_ASSERT(mPtrs == nullptr);
|
||||
|
||||
if (capacity < 1)
|
||||
{
|
||||
SEAD_ASSERT_MSG(false, "capacity[%d] must be larger than zero", capacity);
|
||||
return;
|
||||
}
|
||||
|
||||
setBuffer(capacity,
|
||||
new (heap, alignment, std::nothrow) u8[calculateWorkBufferSize(capacity)]);
|
||||
}
|
||||
|
||||
bool tryAllocBuffer(s32 capacity, Heap* heap, s32 alignment = sizeof(void*))
|
||||
{
|
||||
SEAD_ASSERT(mPtrs == nullptr);
|
||||
|
||||
if (capacity < 1)
|
||||
{
|
||||
SEAD_ASSERT_MSG(false, "capacity[%d] must be larger than zero", capacity);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* buf = new (heap, alignment, std::nothrow) u8[calculateWorkBufferSize(capacity)];
|
||||
if (!buf)
|
||||
return false;
|
||||
|
||||
setBuffer(capacity, buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
void setBuffer(s32 max_num, void* buf)
|
||||
{
|
||||
if (!buf)
|
||||
{
|
||||
SEAD_ASSERT_MSG(false, "buf is null");
|
||||
return;
|
||||
}
|
||||
|
||||
mFreeList.setWork(buf, ElementSize, max_num);
|
||||
PtrArrayImpl::setBuffer(max_num, reinterpret_cast<u8*>(buf) + ElementSize * max_num);
|
||||
}
|
||||
|
||||
void freeBuffer()
|
||||
{
|
||||
if (!isBufferReady())
|
||||
return;
|
||||
|
||||
clear();
|
||||
|
||||
if (mFreeList.work())
|
||||
delete[] static_cast<u8*>(mFreeList.work());
|
||||
|
||||
mFreeList.reset();
|
||||
mPtrs = nullptr;
|
||||
mPtrNumMax = 0;
|
||||
}
|
||||
|
||||
T* at(s32 pos) const { return static_cast<T*>(PtrArrayImpl::at(pos)); }
|
||||
T* unsafeAt(s32 pos) const { return static_cast<T*>(PtrArrayImpl::unsafeAt(pos)); }
|
||||
T* operator()(s32 pos) const { return unsafeAt(pos); }
|
||||
T* operator[](s32 pos) const { return at(pos); }
|
||||
|
||||
// XXX: Does this use at()?
|
||||
T* front() const { return at(0); }
|
||||
T* back() const { return at(mPtrNum - 1); }
|
||||
|
||||
void pushBack(const T& item)
|
||||
{
|
||||
if (isFull())
|
||||
SEAD_ASSERT_MSG(false, "buffer full.");
|
||||
else
|
||||
PtrArrayImpl::pushBack(alloc(item));
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
T* emplaceBack(Args&&... args)
|
||||
{
|
||||
if (isFull())
|
||||
{
|
||||
SEAD_ASSERT_MSG(false, "buffer full.");
|
||||
return nullptr;
|
||||
}
|
||||
T* item = new (mFreeList.alloc()) T(std::forward<Args>(args)...);
|
||||
PtrArrayImpl::pushBack(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
void insert(s32 pos, const T& item) { PtrArrayImpl::insert(pos, alloc(item)); }
|
||||
|
||||
void erase(int index) { erase(index, 1); }
|
||||
|
||||
void erase(int index, int count)
|
||||
{
|
||||
if (index + count <= size())
|
||||
{
|
||||
for (int i = index; i < index + count; ++i)
|
||||
{
|
||||
auto* ptr = unsafeAt(i);
|
||||
ptr->~T();
|
||||
mFreeList.free(ptr);
|
||||
}
|
||||
}
|
||||
PtrArrayImpl::erase(index, count);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (s32 i = 0; i < mPtrNum; ++i)
|
||||
{
|
||||
auto* ptr = unsafeAt(i);
|
||||
ptr->~T();
|
||||
mFreeList.free(ptr);
|
||||
}
|
||||
mPtrNum = 0;
|
||||
}
|
||||
|
||||
using CompareCallback = s32 (*)(const T*, const T*);
|
||||
|
||||
void sort() { sort(compareT); }
|
||||
void sort(CompareCallback cmp) { PtrArrayImpl::sort_<T>(cmp); }
|
||||
void heapSort() { heapSort(compareT); }
|
||||
void heapSort(CompareCallback cmp) { PtrArrayImpl::heapSort_<T>(cmp); }
|
||||
|
||||
bool equal(const ObjArray& other, CompareCallback cmp) const
|
||||
{
|
||||
return PtrArrayImpl::equal(other, cmp);
|
||||
}
|
||||
|
||||
s32 compare(const ObjArray& other, CompareCallback cmp) const
|
||||
{
|
||||
return PtrArrayImpl::compare(other, cmp);
|
||||
}
|
||||
|
||||
s32 binarySearch(const T* ptr) const { return PtrArrayImpl::binarySearch(ptr, compareT); }
|
||||
s32 binarySearch(const T* ptr, CompareCallback cmp) const
|
||||
{
|
||||
return PtrArrayImpl::binarySearch(ptr, cmp);
|
||||
}
|
||||
|
||||
bool operator==(const ObjArray& other) const { return equal(other, compareT); }
|
||||
bool operator!=(const ObjArray& other) const { return !(*this == other); }
|
||||
bool operator<(const ObjArray& other) const { return compare(other) < 0; }
|
||||
bool operator<=(const ObjArray& other) const { return compare(other) <= 0; }
|
||||
bool operator>(const ObjArray& other) const { return compare(other) > 0; }
|
||||
bool operator>=(const ObjArray& other) const { return compare(other) >= 0; }
|
||||
|
||||
void uniq() { PtrArrayImpl::uniq(compareT); }
|
||||
void uniq(CompareCallback cmp) { PtrArrayImpl::uniq(cmp); }
|
||||
|
||||
class iterator
|
||||
{
|
||||
public:
|
||||
iterator(T* const* pptr) : mPPtr{pptr} {}
|
||||
bool operator==(const iterator& other) const { return mPPtr == other.mPPtr; }
|
||||
bool operator!=(const iterator& other) const { return !(*this == other); }
|
||||
iterator& operator++()
|
||||
{
|
||||
++mPPtr;
|
||||
return *this;
|
||||
}
|
||||
T& operator*() const { return **mPPtr; }
|
||||
T* operator->() const { return *mPPtr; }
|
||||
|
||||
private:
|
||||
T* const* mPPtr;
|
||||
};
|
||||
|
||||
iterator begin() const { return iterator(data()); }
|
||||
iterator end() const { return iterator(data() + mPtrNum); }
|
||||
|
||||
class constIterator
|
||||
{
|
||||
public:
|
||||
constIterator(const T* const* pptr) : mPPtr{pptr} {}
|
||||
bool operator==(const constIterator& other) const { return mPPtr == other.mPPtr; }
|
||||
bool operator!=(const constIterator& other) const { return !(*this == other); }
|
||||
constIterator& operator++()
|
||||
{
|
||||
++mPPtr;
|
||||
return *this;
|
||||
}
|
||||
const T& operator*() const { return **mPPtr; }
|
||||
const T* operator->() const { return *mPPtr; }
|
||||
|
||||
private:
|
||||
const T* const* mPPtr;
|
||||
};
|
||||
|
||||
constIterator constBegin() const { return constIterator(data()); }
|
||||
constIterator constEnd() const { return constIterator(data() + mPtrNum); }
|
||||
|
||||
T** data() const { return reinterpret_cast<T**>(mPtrs); }
|
||||
|
||||
private:
|
||||
union Node
|
||||
{
|
||||
void* next_node;
|
||||
T elem;
|
||||
};
|
||||
|
||||
public:
|
||||
static constexpr size_t ElementSize = sizeof(Node);
|
||||
|
||||
static constexpr size_t calculateWorkBufferSize(size_t n)
|
||||
{
|
||||
return n * (ElementSize + sizeof(T*));
|
||||
}
|
||||
|
||||
protected:
|
||||
T* alloc(const T& item)
|
||||
{
|
||||
void* storage = mFreeList.alloc();
|
||||
if (!storage)
|
||||
return nullptr;
|
||||
return new (storage) T(item);
|
||||
}
|
||||
|
||||
static int compareT(const void* a_, const void* b_)
|
||||
{
|
||||
const T* a = static_cast<const T*>(a_);
|
||||
const T* b = static_cast<const T*>(b_);
|
||||
if (*a < *b)
|
||||
return -1;
|
||||
if (*b < *a)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sead::FreeList mFreeList;
|
||||
};
|
||||
|
||||
template <typename T, s32 N>
|
||||
class FixedObjArray : public ObjArray<T>
|
||||
{
|
||||
public:
|
||||
FixedObjArray() : ObjArray<T>(N, &mWork) {}
|
||||
|
||||
// These do not make sense for a *fixed* array.
|
||||
void setBuffer(s32 ptrNumMax, void* buf) = delete;
|
||||
void allocBuffer(s32 ptrNumMax, Heap* heap, s32 alignment = sizeof(void*)) = delete;
|
||||
bool tryAllocBuffer(s32 ptrNumMax, Heap* heap, s32 alignment = sizeof(void*)) = delete;
|
||||
void freeBuffer() = delete;
|
||||
|
||||
private:
|
||||
std::aligned_storage_t<ObjArray<T>::calculateWorkBufferSize(N),
|
||||
std::max(alignof(T), alignof(T*))>
|
||||
mWork;
|
||||
};
|
||||
|
||||
} // namespace sead
|
||||
Reference in New Issue
Block a user