diff --git a/include/Kyoto/Alloc/CCircularBuffer.hpp b/include/Kyoto/Alloc/CCircularBuffer.hpp index 82f14a4..7385a1f 100644 --- a/include/Kyoto/Alloc/CCircularBuffer.hpp +++ b/include/Kyoto/Alloc/CCircularBuffer.hpp @@ -2,6 +2,7 @@ #define _CCIRCULARBUFFER #include +#include class CCircularBuffer { public: @@ -12,10 +13,12 @@ class CCircularBuffer { void* Alloc(int len); void Free(void* ptr, int len); int GetAllocatedAmount() const; + void* GetOffsettedMemory(int offset) { + return x0_ptr.get() + offset; + } private: - uchar x0_owned; - void* x4_ptr; + rstl::auto_ptr x0_ptr; int x8_bufferLen; int xc_; int x10_nextFreeAddr; diff --git a/include/Kyoto/Alloc/CGameAllocator.hpp b/include/Kyoto/Alloc/CGameAllocator.hpp index eea7123..34172e0 100644 --- a/include/Kyoto/Alloc/CGameAllocator.hpp +++ b/include/Kyoto/Alloc/CGameAllocator.hpp @@ -41,6 +41,7 @@ class CGameAllocator : public IAllocator { uint GetNextMaskedFlags(); void SetTopOfHeapAllocated(bool topOfHeap); size_t GetLength() const { return x4_len; } + void SetLength(size_t len) { x4_len = len; } SGameMemInfo* GetNextFree() const { return (SGameMemInfo*)((size_t)x18_nextFree & ~31); } void SetNextFree(SGameMemInfo* info) { void* ptr = x18_nextFree; @@ -49,6 +50,10 @@ class CGameAllocator : public IAllocator { } bool IsAllocated() const { return ((size_t)x10_prev) & 1; } + void SetNotAllocated() { + void* ptr = x10_prev; + x10_prev = (SGameMemInfo*)((size_t)ptr & ~1); + } bool IsPostGuardIntact() const { return x1c_postGuard == 0xeaeaeaea; } bool IsPriorGuardIntact() const { return x0_priorGuard == 0xefefefef; } diff --git a/include/Kyoto/Alloc/CMediumAllocPool.hpp b/include/Kyoto/Alloc/CMediumAllocPool.hpp index 4c5be42..3ef2879 100644 --- a/include/Kyoto/Alloc/CMediumAllocPool.hpp +++ b/include/Kyoto/Alloc/CMediumAllocPool.hpp @@ -1,27 +1,43 @@ #ifndef _CMEDIUMALLOCPOOL #define _CMEDIUMALLOCPOOL +#include #include +struct SMediumAllocPuddle { + SMediumAllocPuddle(const uint numBlocks, void* data, const bool canErase); + ~SMediumAllocPuddle(); + void* FindFree(uint blockCount); + void* FindFreeEntry(uint blockCount); + void Free(const void* ptr); + + const uint GetNumBlocks() const { return x14_numBlocks; } + const uint GetNumAllocs() const { return x18_numAllocs; } + const uint GetNumEntries() const { return x1c_numEntries; } + const bool CanErase() const { return x20_canErase; } + const uint GetPtrOffset(const void* ptr) const { return (uchar*)ptr - x0_mainData.get(); } + static ushort GetBlockOffset(const void* ptrA, const void* ptrB); + static void InitBookKeeping(uchar* bookKeepingPtr, const ushort blockCount); + +private: + rstl::auto_ptr< uchar > x0_mainData; + uchar* x8_bookKeeping; + uchar* xc_cachedBookKeepingAddr; + uint x10_unused; + uint x14_numBlocks; + uint x18_numAllocs; + uint x1c_numEntries; + bool x20_canErase : 1; +}; + class CMediumAllocPool { public: - struct SMediumAllocPuddle { - uchar unk; - void* x4_mainData; - void* x8_bookKeeping; - void* xc_cachedBookKeepingOffset; - int x10_; - int x14_numBlocks; - int x18_numAllocs; - int x1c_numEntries; - }; - rstl::list< SMediumAllocPuddle > x0_list; - /*rstl::list_node* x18_lastNodePrev; */ - void* x18_lastNodePrev; + rstl::list< SMediumAllocPuddle >::iterator x18_lastNodePrev; + CMediumAllocPool(); void* Alloc(uint size); bool HasPuddles() const; - void AddPuddle(uint, void*, int); + void AddPuddle(const uint, void*, const bool); void ClearPuddles(); int Free(const void* ptr); @@ -29,6 +45,8 @@ class CMediumAllocPool { uint GetTotalEntries(); uint GetNumBlocksAvailable(); uint GetNumAllocs(); + + static CMediumAllocPool* gMediumAllocPtr; }; #endif // _CMEDIUMALLOCPOOL diff --git a/include/Kyoto/Alloc/CMemory.hpp b/include/Kyoto/Alloc/CMemory.hpp index 6f64968..cb0e339 100644 --- a/include/Kyoto/Alloc/CMemory.hpp +++ b/include/Kyoto/Alloc/CMemory.hpp @@ -18,7 +18,7 @@ class CMemory { static void* Alloc(size_t len, IAllocator::EHint hint = IAllocator::kHI_None, IAllocator::EScope scope = IAllocator::kSC_Unk1, IAllocator::EType type = IAllocator::kTP_Heap, - const CCallStack& callstack = CCallStack(-1, "??(??)")); + const CCallStack& callstack = CCallStack(-1, "\?\?(\?\?)")); static void Free(const void* ptr); static void SetOutOfMemoryCallback(IAllocator::FOutOfMemoryCb callback, const void* context); static void OffsetFakeStatics(int); @@ -44,11 +44,11 @@ inline void* operator new(size_t n, void* ptr) { return ptr; }; #ifdef __MWERKS__ inline void operator delete(void* ptr) { CMemory::Free(ptr); } inline void operator delete[](void* ptr) { CMemory::Free(ptr); } -#define NEW new ("??(??)", nullptr) +#define rs_new new ("\?\?(\?\?)", nullptr) #else -__attribute__((weak)) void operator delete(void* ptr) { CMemory::Free(ptr); } -__attribute__((weak)) void operator delete[](void* ptr) { CMemory::Free(ptr); } -#define NEW new +// void operator delete(void* ptr); +// void operator delete[](void* ptr); +#define rs_new new #endif #endif // _CMEMORY diff --git a/include/Kyoto/Streams/CInputStream.hpp b/include/Kyoto/Streams/CInputStream.hpp index ada032c..97f2a54 100644 --- a/include/Kyoto/Streams/CInputStream.hpp +++ b/include/Kyoto/Streams/CInputStream.hpp @@ -149,8 +149,8 @@ inline rstl::vector< T, Alloc >::vector(CInputStream& in, const Alloc& allocator iterator out = begin() + x4_count; for (int i = 0; i < count; i++) { // Maybe this got improved? - // push_back(in.Get(TType< T >())); - out++ = in.Get(TType< T >()); + push_back(in.Get(TType< T >())); + // out++ = in.Get(TType< T >()); ++x4_count; } } diff --git a/include/rstl/algorithm.hpp b/include/rstl/algorithm.hpp index ce3780f..c34388d 100644 --- a/include/rstl/algorithm.hpp +++ b/include/rstl/algorithm.hpp @@ -24,12 +24,13 @@ template < typename I1, typename I2 > inline void iter_swap(I1 a, I2 b) { swap(*a, *b); } +template < class T, class Cmp > +void __sort3(T& a, T& b, T& c, Cmp comp); // TODO template < typename It, class Cmp > void __insertion_sort(It first, It last, Cmp cmp); -template < class T, class Cmp > -void __sort3(T& a, T& b, T& c, Cmp comp); // TODO + template < typename It, class Cmp > void sort(It first, It last, Cmp cmp); // TODO @@ -38,20 +39,22 @@ void sort(It first, It last, Cmp cmp); // TODO template < typename It, class Cmp > void __insertion_sort(It first, It last, Cmp cmp) { - for (It next = first + 1; next < last; ++next) { + It next = first; + for (++next; next < last; ++next) { typename iterator_traits< It >::value_type value = *next; It t1 = next - 1; It t2 = next; while (first < t2 && cmp(value, *t1)) { - *t2-- = *t1--; + *t2-- = *t1; + --t1; } *t2 = value; } } template < typename T, class Cmp > -void __sort3(T& a, T& b, T& c, Cmp comp) { +void __sort3(T& a, T& b, T& c, const Cmp comp) { if (comp(b, a)) { swap(a, b); } @@ -70,28 +73,30 @@ void __sort3(T& a, T& b, T& c, Cmp comp) { template < typename It, class Cmp > void sort(It first, It last, Cmp cmp) { int count = last - first; // use distance? - if (count > 1) { - if (count <= 20) { - __insertion_sort(first, last, cmp); - } else { - It pivot = first + count / 2; - It end = last; - __sort3(*first, *pivot, *--end, cmp); - typename iterator_traits< It >::value_type value = *pivot; - It it = first + 1; - --end; - while (true) { - while (cmp(*it, value)) - ++it; - while (cmp(value, *end)) - --end; - if (it >= end) - break; - iter_swap(it++, end--); - } - sort(first, it, cmp); - sort(it, last, cmp); + if (count <= 1) { + return; + } + if (20 >= count) { + __insertion_sort(first, last, cmp); + } else { + It pivot = first + count / 2; + It end = last; + __sort3(*first, *pivot, *--end, cmp); + typename iterator_traits< It >::value_type value = *pivot; + It it = first + 1; + --end; + while (true) { + while (cmp(*it, value)) + ++it; + while (cmp(value, *end)) + --end; + if (it >= end) + break; + iter_swap(it, end--); + ++it; } + sort(first, it, cmp); + sort(it, last, cmp); } } @@ -147,18 +152,21 @@ class pair_sorter_finder< pair< K, V >, Cmp > { bool operator()(const pair< K, V >& a, const pair< K, V >& b) const; }; -template -inline pair_sorter_finder< typename T::value_type, less< typename select1st< typename T::value_type >::value_type > > default_pair_sorter_finder() -{ - less< typename select1st< typename T::value_type >::value_type > l; - pair_sorter_finder< typename T::value_type, less< typename select1st< typename T::value_type >::value_type > > a(l); - return a; +template < typename T > +inline pair_sorter_finder< typename T::value_type, + less< typename select1st< typename T::value_type >::value_type > > +default_pair_sorter_finder() { + less< typename select1st< typename T::value_type >::value_type > l; + pair_sorter_finder< typename T::value_type, + less< typename select1st< typename T::value_type >::value_type > > + a(l); + return a; } template < typename K, typename V, typename Cmp > inline bool pair_sorter_finder< pair< K, V >, Cmp >::operator()(const K& a, const pair< K, V >& b) const { - return cmp(a, b.first); + return !!cmp(a, b.first); } template < typename K, typename V, typename Cmp > @@ -181,8 +189,15 @@ find_by_key(const T& container, template < typename T > typename T::const_iterator inline find_by_key( const T& container, const typename select1st< typename T::value_type >::value_type& key) { + return binary_find(container.begin(), container.end(), key, default_pair_sorter_finder< T >()); +} + +template < typename T, class Cmp > +typename T::const_iterator inline find_by_key( + const T& container, const typename select1st< typename T::value_type >::value_type& key, + Cmp cmp) { return binary_find(container.begin(), container.end(), key, - default_pair_sorter_finder()); + pair_sorter_finder< typename T::value_type, Cmp >(cmp)); } template < typename T > @@ -192,8 +207,12 @@ find_by_key_nc(T& container, const typename select1st< typename T::value_type >: template < typename T > typename T::iterator inline find_by_key_nc( T& container, const typename select1st< typename T::value_type >::value_type& key) { - return binary_find(container.begin(), container.end(), key, - default_pair_sorter_finder()); + return binary_find(container.begin(), container.end(), key, default_pair_sorter_finder< T >()); +} + +template < typename T, class Cmp > +inline void sort_by_key(T& container, const Cmp& cmp) { + sort(container.begin(), container.end(), pair_sorter_finder< typename T::value_type, Cmp >(cmp)); } } // namespace rstl diff --git a/include/rstl/auto_ptr.hpp b/include/rstl/auto_ptr.hpp index 777b66c..297ac36 100644 --- a/include/rstl/auto_ptr.hpp +++ b/include/rstl/auto_ptr.hpp @@ -22,14 +22,15 @@ class auto_ptr { other.x0_has = false; } auto_ptr& operator=(const auto_ptr& other) { - if (&other != this) { - if (x0_has) { - delete x4_item; - } - x0_has = other.x0_has; - x4_item = other.x4_item; - other.x0_has = false; + if (&other == this) { + return *this; } + if (x0_has) { + delete x4_item; + } + x0_has = other.x0_has; + x4_item = other.x4_item; + other.x0_has = false; return *this; } T* get() const { return x4_item; } @@ -40,6 +41,10 @@ class auto_ptr { return x4_item; } bool null() const { return x4_item == nullptr; } + void reset() { + x0_has = false; + x4_item = nullptr; + } }; } // namespace rstl diff --git a/include/rstl/construct.hpp b/include/rstl/construct.hpp index 0a8fa6e..22ebef2 100644 --- a/include/rstl/construct.hpp +++ b/include/rstl/construct.hpp @@ -25,11 +25,14 @@ inline void destroy(It begin, It end) { } template < typename It, typename T > -inline void uninitialized_copy(It begin, It end, T* out) { +inline T* uninitialized_copy(It begin, It end, T* out) { + T* tmp = out; It cur = begin; - for (; cur != end; ++out, ++cur) { - construct(out, *cur); + for (; cur != end; ++tmp, ++cur) { + construct(tmp, *cur); } + + return tmp; } template < typename S, typename D > diff --git a/include/rstl/hash_map.hpp b/include/rstl/hash_map.hpp index d936682..0cb71bc 100644 --- a/include/rstl/hash_map.hpp +++ b/include/rstl/hash_map.hpp @@ -13,6 +13,8 @@ namespace rstl { template < typename K, typename P, int unk, typename Select, typename Hash, typename Equal, typename Alloc = rmemory_allocator > class hash_table { +public: + int size() const { return x.size(); } private: rstl::vector< rstl::list< P, Alloc > /*::iterator*/, Alloc > x; }; @@ -21,6 +23,8 @@ template < typename K, typename V, typename Hash, typename Equal, typename Alloc = rmemory_allocator > class hash_map { typedef rstl::pair< K, V > Pair; +public: + int size() const { return table.size(); } private: hash_table< K, Pair, 0, select1st< Pair >, Hash, Equal, Alloc > table; diff --git a/include/rstl/iterator.hpp b/include/rstl/iterator.hpp index 6b53dec..d1c3349 100644 --- a/include/rstl/iterator.hpp +++ b/include/rstl/iterator.hpp @@ -21,7 +21,7 @@ typename It::difference_type __distance(It first, It last, forward_iterator_tag) } template < typename It > -inline typename It::difference_type distance(It first, It last) { +typename It::difference_type distance(It first, It last) { return __distance(first, last, typename It::iterator_category()); } @@ -33,8 +33,8 @@ void __advance(It& it, S count, forward_iterator_tag) { } template < typename It, typename S > -inline void advance(It& it, S count) { - return __advance(it, count, typename It::iterator_category()); +void advance(It& it, S count) { + __advance(it, count, typename It::iterator_category()); } } // namespace rstl diff --git a/include/rstl/list.hpp b/include/rstl/list.hpp index c29d233..3c8ca4d 100644 --- a/include/rstl/list.hpp +++ b/include/rstl/list.hpp @@ -12,11 +12,12 @@ class list { public: class iterator; class const_iterator; - iterator erase(const iterator& item); + iterator erase(const iterator& item) { return do_erase(item.get_node()); } -private: + // private: +#pragma pack(push, 1) struct node; - node* erase(node* item); +#pragma pack(pop) public: list() @@ -26,16 +27,16 @@ class list { , x10_empty_next(reinterpret_cast< node* >(&xc_empty_prev)) , x14_count(0) {} ~list(); + node* do_erase(node* item); + void push_front(const T& val) { do_insert_before(x4_start, val); } void push_back(const T& val) { do_insert_before(x8_end, val); } void clear() { erase(begin(), end()); } size_t size() const { return x14_count; } bool empty() const { return x14_count == 0; } - void pop_front() { - erase(x4_start); - } + void pop_front() { erase(x4_start); } iterator begin() { return iterator(x4_start); } const_iterator begin() const { return const_iterator(x4_start); } @@ -45,20 +46,21 @@ class list { iterator erase(const iterator& start, const iterator& end) { node* last = end.get_node(); node* it = start.get_node(); + for (node* t = it; t != last; t = t->get_next()) { + } + while (it != last) { - it = erase(it); + it = do_erase(it); } return iterator(it); } -private: struct node { node* x0_prev; node* x4_next; uchar x8_item[sizeof(T)]; node(node* prev, node* next) : x0_prev(prev), x4_next(next) {} - ~node() { get_value()->~T(); } node* get_prev() const { return x0_prev; } node* get_next() const { return x4_next; } @@ -71,12 +73,12 @@ class list { node* create_node(node* prev, node* next, const T& val) { node* n; x0_allocator.allocate(n, 1); - new(n) node(prev, next); - construct(n->get_value(), val); + new (n) node(prev, next); + new (n->get_value()) T(val); return n; } - void do_insert_before(node* n, const T& val) { + node* do_insert_before(node* n, const T& val) { node* nn = create_node(n->get_prev(), n, val); if (n == x4_start) { x4_start = nn; @@ -84,15 +86,19 @@ class list { nn->get_prev()->set_next(nn); nn->get_next()->set_prev(nn); ++x14_count; + + return nn; } + void remove(const T& val); + public: class const_iterator { public: typedef T* value_type; const_iterator() : current(nullptr) {} - const_iterator(const node* begin) : current(begin) {} + const_iterator(node* begin) : current(begin) {} const_iterator& operator++() { this->current = this->current->x4_next; return *this; @@ -109,13 +115,13 @@ class list { bool operator==(const const_iterator& other) const { return current == other.current; } bool operator!=(const const_iterator& other) const { return current != other.current; } - const node* get_node() const { return current; } + node* get_node() const { return current; } protected: - const node* current; + node* current; }; - class iterator : const_iterator { + class iterator : public const_iterator { public: typedef T* value_type; @@ -135,16 +141,11 @@ class list { return *this; } iterator operator--(int) { return iterator(this->curent->x0_prev); } - T* get_pointer() const { return current->get_value(); } - T& operator*() const { return *current->get_value(); } - T* operator->() const { return current->get_value(); } - bool operator==(const iterator& other) const { return current == other.current; } - bool operator!=(const iterator& other) const { return current != other.current; } - - node* get_node() const { return current; } - - protected: - node* current; + T* get_pointer() const { return this->current->get_value(); } + T& operator*() const { return *this->current->get_value(); } + T* operator->() const { return this->current->get_value(); } + bool operator==(const iterator& other) const { return this->current == other.current; } + bool operator!=(const iterator& other) const { return this->current != other.current; } }; private: @@ -163,21 +164,20 @@ list< T, Alloc >::~list() { node* it = cur; node* next = cur->get_next(); cur = next; - destroy(it); + destroy(it->get_value()); x0_allocator.deallocate(it); } } - template < typename T, typename Alloc > -typename list< T, Alloc >::node* list< T, Alloc >::erase(node* node) { +typename list< T, Alloc >::node* list< T, Alloc >::do_erase(node* node) { typename list< T, Alloc >::node* result = node->get_next(); if (node == x4_start) { - x4_start = result; + x4_start = node->get_next(); } node->get_prev()->set_next(node->get_next()); node->get_next()->set_prev(node->get_prev()); - destroy(node); + destroy(node->get_value()); x0_allocator.deallocate(node); x14_count--; return result; diff --git a/include/rstl/map.hpp b/include/rstl/map.hpp index 34a4d07..49fa8ad 100644 --- a/include/rstl/map.hpp +++ b/include/rstl/map.hpp @@ -21,6 +21,8 @@ class map { typedef typename rep_type::iterator iterator; typedef typename rep_type::const_iterator const_iterator; + ~map() {} + iterator insert(const value_type& item) { return inner.insert(item); } const_iterator begin() const { return inner.begin(); } @@ -31,7 +33,7 @@ class map { void erase(iterator it) { inner.erase(it); } - rep_type& get_inner() { return inner; } // hack for CWeaponMgr inlining depth + rep_type& get_inner() { return inner; } // hack for CWeaponMgr inlining depth private: rep_type inner; }; diff --git a/include/rstl/optional_object.hpp b/include/rstl/optional_object.hpp index 1eed041..87ff43b 100644 --- a/include/rstl/optional_object.hpp +++ b/include/rstl/optional_object.hpp @@ -19,34 +19,29 @@ class optional_object { construct< T >(m_data, other.data()); } } - ~optional_object() { - // clear(); - // Makes ~CScriptHudMemo match - if (m_valid) { - rstl::destroy(get_ptr()); - } - } + ~optional_object() { clear(); } optional_object& operator=(const optional_object& other) { - if (this != &other) { - if (other.m_valid) { - assign(other.data()); - } else { - clear(); - } + if (this == &other) { + return *this; + } + if (other.m_valid) { + assign(other.data()); + } else { + clear(); } return *this; } - optional_object& operator=(const T& item); /* { + optional_object& operator=(const T& item) { assign(item); return *this; - }*/ + } T& data() { return *get_ptr(); } const T& data() const { return *get_ptr(); } T* get_ptr() { return reinterpret_cast< T* >(m_data); } const T* get_ptr() const { return reinterpret_cast< const T* >(m_data); } - bool valid() const { return m_valid; } + const bool valid() const { return m_valid; } operator bool() const { return m_valid; } // replace with valid()? void clear() { if (m_valid) { @@ -74,13 +69,6 @@ class optional_object { } } }; - -template < typename T > -optional_object< T >& optional_object< T >::operator=(const T& item) { - assign(item); - return *this; -} - } // namespace rstl #endif // _RSTL_OPTIONAL_OBJECT diff --git a/include/rstl/pair.hpp b/include/rstl/pair.hpp index f1a22d2..cfe7361 100644 --- a/include/rstl/pair.hpp +++ b/include/rstl/pair.hpp @@ -3,14 +3,18 @@ #include "types.h" +class CInputStream; namespace rstl { template < typename L, typename R > class pair { public: pair() {} pair(const L& first, const R& second) : first(first), second(second) {} + pair(CInputStream& in); - bool operator==(const pair& other) const { return first == other.first && second == other.second; } + bool operator==(const pair& other) const { + return first == other.first && second == other.second; + } L first; R second; @@ -28,7 +32,6 @@ struct select1st< pair< K, V > > { const K& operator()(const pair< K, V >& it) const { return it.first; } }; - } // namespace rstl #endif // _RSTL_PAIR diff --git a/include/rstl/pointer_iterator.hpp b/include/rstl/pointer_iterator.hpp index e77cac7..2f33360 100644 --- a/include/rstl/pointer_iterator.hpp +++ b/include/rstl/pointer_iterator.hpp @@ -12,7 +12,7 @@ namespace rstl { template < typename T, typename Vec, typename Alloc > class const_pointer_iterator { public: - typedef ptrdiff_t difference_type; + typedef long difference_type; typedef random_access_iterator_tag iterator_category; typedef T value_type; @@ -37,12 +37,10 @@ class const_pointer_iterator { return *this; } const_pointer_iterator operator+(int v) const { - const_pointer_iterator it = *this; - return it += v; + return const_pointer_iterator(this->current + v); } const_pointer_iterator operator-(int v) const { - const_pointer_iterator it = *this; - return it -= v; + return const_pointer_iterator(this->current - v); } difference_type operator-(const const_pointer_iterator& other) const { return this->current - other.current; @@ -77,9 +75,8 @@ class pointer_iterator : public const_pointer_iterator< T, Vec, Alloc > { typedef typename base::iterator_category iterator_category; typedef typename base::value_type value_type; - pointer_iterator() : const_pointer_iterator< T, Vec, Alloc >(nullptr) {} - pointer_iterator(T* begin) : const_pointer_iterator< T, Vec, Alloc >(begin) {} - void operator=(const T& other) { rstl::construct(this->current, other); } + pointer_iterator() : base(nullptr) {} + pointer_iterator(T* begin) : base(begin) {} T& operator*() { return *this->current; } // TODO map says const, but breaks CScriptMazeNode::GenerateObjects T* operator->() { return this->current; } @@ -87,9 +84,7 @@ class pointer_iterator : public const_pointer_iterator< T, Vec, Alloc > { ++this->current; return *this; } - pointer_iterator operator++(int) { - return *this += 1; - } + pointer_iterator operator++(int) { return *this += 1; } pointer_iterator& operator--() { --this->current; return *this; @@ -103,14 +98,8 @@ class pointer_iterator : public const_pointer_iterator< T, Vec, Alloc > { this->current -= v; return *this; } - pointer_iterator operator+(int v) const { - pointer_iterator it = *this; - return it += v; - } - pointer_iterator operator-(int v) const { - pointer_iterator it = *this; - return it -= v; - } + pointer_iterator operator+(int v) const { return pointer_iterator(this->current + v); } + pointer_iterator operator-(int v) const { return pointer_iterator(this->current - v); } // HACK: non-const operator- is required to match vector::insert difference_type operator-(const pointer_iterator& other) { return this->current - other.current; } }; @@ -121,7 +110,7 @@ struct const_counting_iterator { int count; const_counting_iterator(const T* ptr, int count) : ptr(ptr), count(count) {} - + const_counting_iterator& operator++() { ++this->count; return *this; @@ -129,12 +118,12 @@ struct const_counting_iterator { }; template < typename It > -inline typename It::difference_type __distance(It first, It last, random_access_iterator_tag) { +typename It::difference_type __distance(It first, It last, random_access_iterator_tag) { return last - first; } template < typename It, typename S > -inline void __advance(It& it, S count, random_access_iterator_tag) { +void __advance(It& it, S count, random_access_iterator_tag) { it += count; } @@ -142,13 +131,13 @@ template < typename T > struct iterator_traits {}; template < typename T > -struct iterator_traits { +struct iterator_traits< T* > { typedef T value_type; }; template < typename T, typename Vec, typename Alloc > -struct iterator_traits< pointer_iterator > { - typedef typename pointer_iterator::value_type value_type; +struct iterator_traits< pointer_iterator< T, Vec, Alloc > > { + typedef typename pointer_iterator< T, Vec, Alloc >::value_type value_type; }; } // namespace rstl diff --git a/include/rstl/prereserved_vector.hpp b/include/rstl/prereserved_vector.hpp new file mode 100644 index 0000000..9402e6f --- /dev/null +++ b/include/rstl/prereserved_vector.hpp @@ -0,0 +1,25 @@ +#ifndef _RSTL_PRERESERVED_VECTOR +#define _RSTL_PRERESERVED_VECTOR + +#include + +namespace rstl { +template < typename T > +class prereserved_vector { +public: + prereserved_vector() : mData(nullptr), mSize(0) {} + + uint size() const { return mSize; } + void set_size(uint size) { mSize = size; } + void set_data(T* data) { mData = data; } + + T& operator[](uint idx) { return mData[idx]; } + const T& operator[](uint idx) const { return mData[idx]; } + +private: + T* mData; + uint mSize; +}; +}; // namespace rstl + +#endif // _RSTL_PRERESERVED_VECTOR diff --git a/include/rstl/rc_ptr.hpp b/include/rstl/rc_ptr.hpp index 707d79f..5c7c228 100644 --- a/include/rstl/rc_ptr.hpp +++ b/include/rstl/rc_ptr.hpp @@ -2,6 +2,7 @@ #define _RSTL_RC_PTR #include "types.h" +#include "rstl/rmemory_allocator.hpp" namespace rstl { class CRefData { @@ -25,7 +26,7 @@ template < typename T > class rc_ptr { public: rc_ptr() : x0_refData(&CRefData::sNull) { x0_refData->AddRef(); } - rc_ptr(const T* ptr) : x0_refData(new CRefData(ptr)) {} + rc_ptr(const T* ptr) : x0_refData(rs_new CRefData(ptr)) {} rc_ptr(const rc_ptr& other) : x0_refData(other.x0_refData) { x0_refData->AddRef(); } ~rc_ptr() { ReleaseData(); } T* GetPtr() const { return static_cast< T* >(x0_refData->GetPtr()); } diff --git a/include/rstl/red_black_tree.hpp b/include/rstl/red_black_tree.hpp index a355cf7..d19b0ee 100644 --- a/include/rstl/red_black_tree.hpp +++ b/include/rstl/red_black_tree.hpp @@ -107,7 +107,7 @@ class red_black_tree { }; red_black_tree() : x0_(0), x1_(0), x4_count(0) {} - ~red_black_tree() { clear(); } + ~red_black_tree() { destroy(); } iterator insert_into(node* n, const P& item); iterator insert(const P& item) { return insert_into(x8_header.get_root(), item); } @@ -228,6 +228,8 @@ class red_black_tree { node* rebalance_for_erase(node* n) { return static_cast< node* >(rbtree_rebalance_for_erase(&x8_header, n)); } + + void destroy() { clear(); } }; static bool kUnknownValueNewRoot = true; diff --git a/include/rstl/reserved_vector.hpp b/include/rstl/reserved_vector.hpp index 8bf62b9..bbe0bcd 100644 --- a/include/rstl/reserved_vector.hpp +++ b/include/rstl/reserved_vector.hpp @@ -7,6 +7,7 @@ #include "rstl/pointer_iterator.hpp" class CInputStream; +class COutputStream; namespace rstl { template < typename T, int N > @@ -19,6 +20,7 @@ class reserved_vector { // typedef const_pointer_iterator< T, reserved_vector< T, N >, void > const_iterator; typedef T* iterator; typedef const T* const_iterator; + typedef T value_type; inline iterator begin() { return iterator(data()); } inline const_iterator begin() const { return const_iterator(data()); } @@ -42,8 +44,9 @@ class reserved_vector { return *this; } void clear() { + T* ptr = data(); for (int i = 0; i < x0_count; ++i) { - destroy(&data()[i]); + destroy(&ptr[i]); } x0_count = 0; } @@ -51,7 +54,7 @@ class reserved_vector { ~reserved_vector() { clear(); } void push_back(const T& in) { - construct(&data()[x0_count], in); + construct(data() + x0_count, in); ++x0_count; } @@ -67,28 +70,31 @@ class reserved_vector { inline int capacity() const { return N; } inline T& front() { return data()[0]; } inline const T& front() const { return data()[0]; } - inline T& back() { return data()[x0_count - 1]; } - inline const T& back() const { return data()[x0_count - 1]; } + inline T& back() { return at(x0_count - 1); } + inline const T& back() const { return at(x0_count - 1); } inline T& operator[](int idx) { return data()[idx]; } inline const T& operator[](int idx) const { return data()[idx]; } - void erase(iterator it) { - if (it < begin()) { - return; - } - if (it < end()) { + inline T& at(int idx) { return data()[idx]; } + inline const T& at(int idx) const { return data()[idx]; } + iterator erase(iterator it) { + if (it >= begin() && it < end()) { for (iterator j = it; j < end() - 1; ++j) { *j = *(j + 1); } --x0_count; + return it; } + return end(); } - void resize(int count, const T& item) { + void resize(int count, const T& item = T()) { if (size() < count) { uninitialized_fill_n(end(), count - size(), item); x0_count = count; } } + + void PutTo(COutputStream& out) const; }; template < typename T, int N > diff --git a/include/rstl/rmemory_allocator.hpp b/include/rstl/rmemory_allocator.hpp index 52b55cf..c42d4e6 100644 --- a/include/rstl/rmemory_allocator.hpp +++ b/include/rstl/rmemory_allocator.hpp @@ -9,25 +9,17 @@ namespace rstl { struct rmemory_allocator { rmemory_allocator() {} rmemory_allocator(const rmemory_allocator&) {} + template < typename T > static void allocate(T*& out, int count) { int size = count * sizeof(T); if (size == 0) { out = nullptr; } else { - out = reinterpret_cast< T* >(new uchar[size]); - } - } - // TODO: this fixes a regswap in vector::reserve - template < typename T > - static T* allocate2(int count) { - int size = count * sizeof(T); - if (size == 0) { - return nullptr; - } else { - return reinterpret_cast< T* >(new uchar[size]); + out = reinterpret_cast< T* >(rs_new uchar[size]); } } + template < typename T > static void deallocate(T* ptr) { if (ptr != nullptr) { diff --git a/include/rstl/single_ptr.hpp b/include/rstl/single_ptr.hpp index 0b3536b..cb44f7b 100644 --- a/include/rstl/single_ptr.hpp +++ b/include/rstl/single_ptr.hpp @@ -2,6 +2,7 @@ #define _RSTL_SINGLE_PTR #include "types.h" +#include namespace rstl { template < typename T > @@ -11,20 +12,31 @@ class single_ptr { public: single_ptr() : x0_ptr(nullptr) {} single_ptr(T* ptr) : x0_ptr(ptr) {} - ~single_ptr() { delete x0_ptr; } - T* get() const { return x0_ptr; } - // const T* get() const { return x0_ptr; } - T* operator->() { return x0_ptr; } - const T* operator->() const { return x0_ptr; } single_ptr(const single_ptr& other) : x0_ptr(other.x0_ptr) { other.x0_ptr = nullptr; } - single_ptr& operator=(T* ptr) { + ~single_ptr() { delete x0_ptr; } + single_ptr& operator=(single_ptr& other) { + if (&other == this) { + return *this; + } + delete x0_ptr; + x0_ptr = other.x0_ptr; + other.x0_ptr = nullptr; + return *this; + } + + single_ptr& operator=(T* const ptr) { delete x0_ptr; x0_ptr = ptr; return *this; } - bool null() const { return x0_ptr == nullptr; } + + T* get() const { return x0_ptr; } + // const T* get() const { return x0_ptr; } + T* operator->() const { return x0_ptr; } T& operator*() { return *x0_ptr; } const T& operator*() const { return *x0_ptr; } + + bool null() const { return x0_ptr == nullptr; } T* release() { T* ptr = x0_ptr; x0_ptr = nullptr; @@ -32,16 +44,15 @@ class single_ptr { } // This is certainly not real, but handy to force not-inline - single_ptr& Set(T* ptr); + single_ptr& reset(T* ptr); }; - template < typename T > -single_ptr< T >& single_ptr< T >::Set(T* ptr) { +single_ptr< T >& single_ptr< T >::reset(T* ptr) { return *this = ptr; } -typedef single_ptr< void > unk_singleptr; +typedef single_ptr< char > unk_singleptr; CHECK_SIZEOF(unk_singleptr, 0x4); } // namespace rstl diff --git a/include/rstl/string.hpp b/include/rstl/string.hpp index 3294f40..75bbb22 100644 --- a/include/rstl/string.hpp +++ b/include/rstl/string.hpp @@ -29,7 +29,7 @@ class basic_string { void internal_prepare_to_write(int len, bool); void internal_allocate(int size); // { - // x4_cow = reinterpret_cast(new uchar[size * sizeof(_CharTp) + + // x4_cow = reinterpret_cast(rs_new uchar[size * sizeof(_CharTp) + // 8]); x0_ptr = x4_cow->x8_data; x4_cow->x0_capacity = uint(size); // x4_cow->x4_refCount = 1; // } @@ -47,17 +47,16 @@ class basic_string { basic_string() : x0_ptr(&mNull), x4_cow(nullptr), x8_size(0) {} - basic_string(literal_t, const _CharTp* data); - // { - // x0_ptr = data; - // x4_cow = nullptr; + basic_string(literal_t, const _CharTp* data) { + x0_ptr = data; + x4_cow = nullptr; - // const _CharTp* it = data; - // while (*it) - // ++it; + const _CharTp* it = data; + while (*it) + ++it; - // x8_size = uint((it - data) / sizeof(_CharTp)); - // } + x8_size = static_cast< uint >(it - data); + } basic_string(const basic_string& str); // { @@ -139,10 +138,14 @@ bool basic_string< _CharTp, Traits, Alloc >::operator<(const basic_string& other typedef basic_string< wchar_t > wstring; typedef basic_string< char > string; -wstring wstring_l(const wchar_t* data); -// { -// return wstring(wstring::literal_t(), data); -// } +#ifdef __MWERKS__ +__declspec(weak) // TODO +#else +static +#endif +wstring wstring_l(const wchar_t* data) { + return wstring(wstring::literal_t(), data); +} string string_l(const char* data); // { diff --git a/include/rstl/vector.hpp b/include/rstl/vector.hpp index 5f33c73..22c222a 100644 --- a/include/rstl/vector.hpp +++ b/include/rstl/vector.hpp @@ -3,6 +3,7 @@ #include "types.h" +#include "rstl/iterator.hpp" #include "rstl/pointer_iterator.hpp" #include "rstl/rmemory_allocator.hpp" @@ -34,6 +35,7 @@ class vector { T* xc_items; public: + typedef Alloc allocator_type; typedef pointer_iterator< T, vector< T, Alloc >, Alloc > iterator; typedef const_pointer_iterator< T, vector< T, Alloc >, Alloc > const_iterator; typedef T value_type; @@ -42,53 +44,65 @@ class vector { const_iterator begin() const { return const_iterator(xc_items); } iterator end() { return iterator(xc_items + x4_count); } const_iterator end() const { return const_iterator(xc_items + x4_count); } - vector() : x4_count(0), x8_capacity(0), xc_items(NULL) {} + vector(const Alloc& alloc = Alloc()) + : x0_allocator(alloc), x4_count(0), x8_capacity(0), xc_items(nullptr) {} vector(int count) : x4_count(0), x8_capacity(0), xc_items(0) { reserve(count); } - vector(int count, const T& v) : x4_count(count), x8_capacity(count) { + vector(const int count, const T& v) : x4_count(count), x8_capacity(count) { x0_allocator.allocate(xc_items, x4_count); uninitialized_fill_n(xc_items, count, v); } vector(int count, const T& v, const Alloc& alloc); - vector(const vector& other); /* : x4_count(other.x4_count), x8_capacity(other.x8_capacity) { + vector(const vector& other) : x4_count(other.x4_count), x8_capacity(other.x8_capacity) { if (other.x4_count == 0 && other.x8_capacity == 0) { xc_items = nullptr; } else { x0_allocator.allocate(xc_items, x8_capacity); uninitialized_copy_n(other.xc_items, x4_count, xc_items); } - }*/ + } vector(CInputStream& in, const Alloc& alloc = Alloc()); - ~vector(); /* { + ~vector() { destroy(begin(), end()); x0_allocator.deallocate(xc_items); - }*/ + } + void resize(int size, const T& in = T()); void reserve(int size); - void resize(int size, const T& in); iterator insert(iterator it, const T& value); template < typename from_iterator > iterator insert(iterator it, from_iterator begin, from_iterator end); - iterator erase(iterator it); - iterator erase(iterator first, iterator last); + // iterator erase(iterator it); + // iterator erase(iterator first, iterator last); + + iterator erase(iterator it) { return erase(it, it + 1); } + + iterator erase(iterator first, iterator last) { + destroy(first, last); + + const int tmp = first - begin(); + + int newCount = tmp; + + for (iterator it = last, moved = begin() + tmp; it != end(); ++moved, ++newCount, ++it) { + construct(&*moved, *it); + } + x4_count = newCount; + + return first; + } void push_back(const T& in) { if (x4_count >= x8_capacity) { reserve(x8_capacity != 0 ? x8_capacity * 2 : 4); } - iterator out = begin() + x4_count; - out = in; + rstl::construct(xc_items + x4_count, in); ++x4_count; } - - // This is likely fake, but the reserve check is really missing - void push_back_unsafe(const T& in) { - iterator out = begin() + x4_count; - ++x4_count; - out = in; - } + + void pop_back(); vector& operator=(const vector& other); @@ -118,14 +132,10 @@ class vector { template < typename T, typename Alloc > void vector< T, Alloc >::resize(int size, const T& in) { - if (x4_count != size) { - if (size > x4_count) { - reserve(size); - uninitialized_fill_n(xc_items + x4_count, size - x4_count, in); - } else { - destroy(begin() + size, end()); - } - x4_count = size; + clear(); + reserve(size); + for (int i = 0; i < size; ++i) { + push_back(in); } } @@ -134,7 +144,8 @@ void vector< T, Alloc >::reserve(int newSize) { if (newSize <= x8_capacity) { return; } - T* newData = x0_allocator.template allocate2< T >(newSize); + T* newData; + x0_allocator.allocate(newData, newSize); uninitialized_copy(begin(), end(), newData); destroy(xc_items, xc_items + x4_count); x0_allocator.deallocate(xc_items); @@ -216,29 +227,28 @@ vector< T, Alloc >& vector< T, Alloc >::operator=(const vector< T, Alloc >& othe return *this; } -template < typename T, typename Alloc > -typename vector< T, Alloc >::iterator vector< T, Alloc >::erase(iterator it) { - return erase(it, it + 1); -} - -template < typename T, typename Alloc > -typename vector< T, Alloc >::iterator vector< T, Alloc >::erase(iterator first, iterator last) { - destroy(first, last); - iterator start = begin(); - int newCount = rstl::distance(first, start); - - iterator moved = start + newCount; - for (iterator it = last; it != end(); ++it) { - construct(&*moved, *it); - ++moved; - ++newCount; - } - x4_count = newCount; - - return first; -} +// template < typename T, typename Alloc > +// typename vector< T, Alloc >::iterator vector< T, Alloc >::erase(iterator it) { +// return erase(it, it + 1); +// } +// +// template < typename T, typename Alloc > +// typename vector< T, Alloc >::iterator vector< T, Alloc >::erase(iterator first, iterator last) { +// destroy(first, last); +// +// const int tmp = first - begin(); +// +// int newCount = tmp; +// +// for (iterator it = last, moved = begin() + tmp; it != end(); ++moved, ++newCount, ++it) { +// construct(&*moved, *it); +// } +// x4_count = newCount; +// +// return first; +// } -typedef vector< void > unk_vector; +typedef vector< int > unk_vector; CHECK_SIZEOF(unk_vector, 0x10) } // namespace rstl diff --git a/src/Kyoto/Alloc/CCallStackDolphin.cpp b/src/Kyoto/Alloc/CCallStackDolphin.cpp new file mode 100644 index 0000000..874052f --- /dev/null +++ b/src/Kyoto/Alloc/CCallStackDolphin.cpp @@ -0,0 +1,10 @@ +#include "Kyoto/Alloc/CCallStack.hpp" + +const char CCallStack::kUnknownType[] = "UnknownType\0"; + +CCallStack::CCallStack(uint lineNum, const char* fileAndLine, const char* type) +: x0_line(fileAndLine), x4_type(type) {} + +const char* CCallStack::GetFileAndLineText() const { return x0_line; } + +const char* CCallStack::GetTypeText() const { return x4_type; } diff --git a/src/Kyoto/Alloc/CCircularBuffer.cpp b/src/Kyoto/Alloc/CCircularBuffer.cpp new file mode 100644 index 0000000..9c3d8ea --- /dev/null +++ b/src/Kyoto/Alloc/CCircularBuffer.cpp @@ -0,0 +1,62 @@ +#include "Kyoto/Alloc/CCircularBuffer.hpp" + +CCircularBuffer::CCircularBuffer(void* buf, int len, CCircularBuffer::EOwnership ownership) +: x0_ptr(static_cast(buf)), x8_bufferLen(len), xc_(0), x10_nextFreeAddr(0), x14_(-1) { + if (ownership == kOS_NotOwned) { + x0_ptr.release(); + } +} + +bool CCircularBuffer::IsWrappedMemory(int offset, int len) { + if (x14_ > -1 && x14_ >= offset && x14_ < (offset + len)) { + return true; + } + + return false; +} + +void* CCircularBuffer::Alloc(int len) { + uchar* ret; + if ((x8_bufferLen - x10_nextFreeAddr) >= len && !IsWrappedMemory(x10_nextFreeAddr, len)) { + int offset = x10_nextFreeAddr; + uchar* ptr = (uchar*)x0_ptr.get(); + x10_nextFreeAddr = offset + len; + return ptr + offset; + } else if (xc_ >= len && !IsWrappedMemory(0, len)) { + uint r3 = xc_; + xc_ = 0; + x10_nextFreeAddr = len; + x14_ = r3; + return x0_ptr.get(); + } + + return nullptr; +} + +void CCircularBuffer::Free(void* ptr, int len) { + if (x14_ > -1) { + if (ptr == x0_ptr.get()) { + x14_ = -1; + xc_ = len; + } else { + x14_ += len; + } + } else { + xc_ += len; + } + + if (x14_ == -1 && xc_ == x10_nextFreeAddr) { + x10_nextFreeAddr = 0; + xc_ = 0; + } +} + +int CCircularBuffer::GetAllocatedAmount() const { + int tmp = x14_; + int res = x10_nextFreeAddr - xc_; + if (tmp != -1) { + res += x8_bufferLen - tmp; + } + + return res; +} diff --git a/src/Kyoto/Alloc/CGameAllocator.cpp b/src/Kyoto/Alloc/CGameAllocator.cpp new file mode 100644 index 0000000..b5fade2 --- /dev/null +++ b/src/Kyoto/Alloc/CGameAllocator.cpp @@ -0,0 +1,599 @@ +// #include "dolphin/os/OSArena.h" +#include "dolphin/types.h" +#include "stddef.h" +#include + +#include +#include +#include +#include +#include + +#include + +/* Here just to make sure the data section matches */ +static const char* string_NULL = ""; +static const char* string_SOURCE_MODULE_UNLOADED = ""; +static const char* string_ = ""; +static int gAllocatorTime = 0; + +template < typename U1, typename U2 > +static inline U1 T_round_up(U2 val, int align) { + return (val + (align - 1)) & ~(align - 1); +} + +CGameAllocator::SGameMemInfo* CGameAllocator::GetMemInfoFromBlockPtr(const void* ptr) const { + return (SGameMemInfo*)((uchar*)(ptr) - sizeof(SGameMemInfo)); +} + +CGameAllocator::CGameAllocator() +: x4_(0) +, x8_heapSize(0) +, xc_first(nullptr) +, x10_last(nullptr) +, x54_(0) +, x58_oomCallback(nullptr) +, x5c_oomTarget(nullptr) +, x60_smallAllocPool(nullptr) +, x64_smallAllocMainData(nullptr) +, x68_smallAllocBookKeeping(nullptr) +, x6c_(false) +, x70_(0) +, x74_mediumPool(nullptr) +, x80_(0) +, x84_(0) +, x88_(0) +, x8c_(0) +, x90_heapSize2(0) +, x94_(0) +, x98_(0) +, x9c_(0) +, xa0_(0) +, xa4_(0) +, xa8_(0) +, xac_(0) +, xb0_(0) +, xb4_physicalAddr(nullptr) +, xb8_fakeStatics(0) +, xbc_(0) {} + +CGameAllocator::~CGameAllocator() { + if (x74_mediumPool) { + x74_mediumPool->ClearPuddles(); + FreeNormalAllocation(x74_mediumPool); + x74_mediumPool = nullptr; + } +} + +bool CGameAllocator::Initialize(COsContext& ctx) { + x8_heapSize = ctx.GetBaseFreeRam(); + xc_first = static_cast< SGameMemInfo* >(OSAllocFromArenaLo(x8_heapSize, sizeof(SGameMemInfo))); + xb4_physicalAddr = (void*)((int)this->xc_first - ((uint)(xc_first)&0xf0000000)); + OSGetArenaLo(); + x10_last = &xc_first[-1] + x8_heapSize; + + *xc_first = SGameMemInfo(nullptr, x10_last, x10_last, x8_heapSize - sizeof(SGameMemInfo) * 2, + "MemHead", "MemHead"); + *x10_last = SGameMemInfo(xc_first, nullptr, nullptr, 0, "MemTail", "MemTail"); + for (uint i = 0; i < 16; i++) { + x14_bins[i] = nullptr; + } + + AddFreeEntryToFreeList(xc_first); + x80_ = 0; + x84_ = 0; + x8c_ = 0; + x90_heapSize2 = x8_heapSize; + x94_ = 0; + x98_ = 0; + x9c_ = 0; + xa0_ = 0; + xa4_ = 0; + xa8_ = 0; + x4_ = 1; + + x64_smallAllocMainData = Alloc(0xb0000, kHI_None, kSC_Unk1, kTP_Heap, + CCallStack(0xffffffff, "SmallAllocMainData ", " - Ignore")); + + x68_smallAllocBookKeeping = Alloc(0x16000, kHI_None, kSC_Unk1, kTP_Heap, + CCallStack(0xffffffff, "SmallAllocBookKeeping", " - Ignore")); + + x60_smallAllocPool = new (Alloc(0x20, kHI_None, kSC_Unk1, kTP_Heap, + CCallStack(0xffffffff, "SmallAllocClass ", " - Ignore"))) + CSmallAllocPool(0x2c000, x64_smallAllocMainData, x68_smallAllocBookKeeping); + + x74_mediumPool = + new (Alloc(0x1c, kHI_None, kSC_Unk1, kTP_Heap, + CCallStack(0xffffffff, "MediumAllocClass ", " - Ignore"))) CMediumAllocPool(); + + x78_ = Alloc(0x21000, kHI_None, kSC_Unk1, kTP_Heap, + CCallStack(0xffffffff, "MediumAllocMainData ", " - Ignore")); + x84_ -= 4; + xbc_ = 0xc6000; + return false; +} + +void CGameAllocator::Shutdown() { + ReleaseAll(); + x4_ = 0; + x54_ = 0; +} + +void* CGameAllocator::Alloc(size_t size, EHint hint, EScope scope, EType type, + const CCallStack& callstack) { + OSTick startTick = OSGetTick(); + + if (hint & kHI_RoundUpLen) { + size = T_round_up< size_t, size_t >(size, 32); + } + + bool bVar1 = size <= 56 && !(hint & (kHI_RoundUpLen | kHI_TopOfHeap)) && x60_smallAllocPool; + + if (bVar1 && x70_ > 0) { + bVar1 = false; + --x70_; + } + + if (bVar1) { + void* buf = x60_smallAllocPool->Alloc(size); + uint tmp = x60_smallAllocPool->GetAllocatedSize(); + if (xac_ < tmp) { + xac_ = tmp; + static int sLastSmallAllocSize = 0; + if (sLastSmallAllocSize + 128 < tmp) { + sLastSmallAllocSize = tmp; + } + } + + if (buf != nullptr) { + gAllocatorTime += (OSGetTick() - startTick); + return buf; + } + x70_ = 25; + x6c_ = true; + } + + if (x74_mediumPool && size <= 0x400 && !(hint & kHI_TopOfHeap)) { + void* buf = nullptr; + if (!x74_mediumPool->HasPuddles()) { + x74_mediumPool->AddPuddle(0x1000, x78_, 0); + x78_ = nullptr; + } + + buf = x74_mediumPool->Alloc(size); + + if (buf == nullptr) { + buf = Alloc(0x21000, kHI_None, kSC_Unk1, kTP_Heap, + CCallStack(-1, "MediumAllocMainData ", " - Ignore")); + x74_mediumPool->AddPuddle(0x1000, buf, 1); + buf = x74_mediumPool->Alloc(size); + } + + if (buf != nullptr) { + gAllocatorTime += OSGetTick() - startTick; + return buf; + } + + if (!x7c_) { + x74_mediumPool->GetTotalEntries(); + x74_mediumPool->GetNumAllocs(); + x74_mediumPool->GetNumBlocksAvailable(); + } + x7c_ = true; + } + + size_t roundedSize = T_round_up< size_t, size_t >(size, 32); + SGameMemInfo* info = nullptr; + + if (hint & kHI_TopOfHeap) { + info = FindFreeBlockFromTopOfHeap(roundedSize); + } else { + info = FindFreeBlock(roundedSize); + } + + if (info == nullptr) { + void* mediumBuf = nullptr; + if (x58_oomCallback) { + x58_oomCallback(x5c_oomTarget, size); + + static bool bTriedCallback = false; + if (!bTriedCallback) { + bTriedCallback = true; + mediumBuf = Alloc(size, hint, scope, type, callstack); + bTriedCallback = false; + } else { + return nullptr; + } + } + if (mediumBuf == nullptr) { + callstack.GetFileAndLineText(); + callstack.GetTypeText(); + DumpAllocations(); + return nullptr; + } + return mediumBuf; + } + + uint tmp = FixupAllocPtrs(info, size, roundedSize, hint, callstack); + if ((hint & kHI_TopOfHeap) != 0u && !info->IsAllocated()) { + info = info->GetNext(); + } + + UpdateAllocDebugStats(size, roundedSize, tmp); + gAllocatorTime += OSGetTick() - startTick; + return ++info; +} + +CGameAllocator::SGameMemInfo* CGameAllocator::FindFreeBlock(uint len) { + CGameAllocator::SGameMemInfo* ret = nullptr; + uint binIndex = GetFreeBinEntryForSize(len); + + CGameAllocator::SGameMemInfo* previous = NULL; + uint chosenBin = 0; + uint bestDelta = 0x10000000; + + while (binIndex < 16 && !ret) { + CGameAllocator::SGameMemInfo* fromBin = x14_bins[binIndex]; + CGameAllocator::SGameMemInfo* pSVar7 = NULL; + uint candidateDelta; + + while (true) { + CGameAllocator::SGameMemInfo* candidate = fromBin; + candidateDelta = bestDelta; + if (candidate == NULL) + break; + + if (!candidate->IsAllocated() && (candidate->GetLength() >= len)) { + candidateDelta = candidate->GetLength() - len; + if (candidateDelta < bestDelta && candidate->GetNext()) { + chosenBin = binIndex; + previous = pSVar7; + bestDelta = candidateDelta; + ret = candidate; + if (candidateDelta < 0x20) { + break; + } + } + } + fromBin = candidate->GetNextFree(); + pSVar7 = candidate; + } + binIndex += 1; + bestDelta = candidateDelta; + } + + if (ret) { + if (previous == NULL) { + x14_bins[chosenBin] = ret->GetNextFree(); + } else { + previous->SetNextFree(ret->GetNextFree()); + } + } + return ret; +} + +CGameAllocator::SGameMemInfo* CGameAllocator::FindFreeBlockFromTopOfHeap(uint size) { + SGameMemInfo* iter = x10_last; + SGameMemInfo* ret = nullptr; + + while (iter != nullptr) { + if (!iter->IsAllocated() && iter->GetLength() >= size) { + ret = iter; + break; + } + iter = iter->GetPrev(); + } + + RemoveFreeEntryFromFreeList(ret); + return ret; +} + +uint CGameAllocator::FixupAllocPtrs(SGameMemInfo* info, uint len, uint roundedLen, EHint hint, + const CCallStack& cs) { + + uint ret = 0; + if (info->GetLength() == roundedLen + sizeof(SGameMemInfo)) { + ret = sizeof(SGameMemInfo); + roundedLen += sizeof(SGameMemInfo); + } + + if (info->GetLength() == roundedLen) { + info->x8_fileAndLine = cs.GetFileAndLineText(); + info->xc_type = cs.GetTypeText(); + + } else { + SGameMemInfo* newPtr; + SGameMemInfo* newInfo; + + SGameMemInfo* infoNext = info->GetNext(); + if ((hint & kHI_TopOfHeap) == kHI_None) { + newInfo = (SGameMemInfo*)((char*)(info + 1) + roundedLen); + new (newInfo) SGameMemInfo(info, infoNext, info->GetNextFree(), + info->GetLength() - roundedLen - sizeof(SGameMemInfo), "", ""); + AddFreeEntryToFreeList(newInfo); + newPtr = info; + } else { + newInfo = (SGameMemInfo*)((char*)(infoNext) - (roundedLen + sizeof(SGameMemInfo))); + new (newInfo) SGameMemInfo(info, infoNext, nullptr, + info->GetLength(), "", ""); + info->SetLength(info->GetLength() - (roundedLen + sizeof(SGameMemInfo))); + AddFreeEntryToFreeList(info); + newPtr = newInfo; + } + newPtr->x8_fileAndLine = cs.GetFileAndLineText(); + newPtr->xc_type = cs.GetTypeText(); + ret = sizeof(SGameMemInfo); + + infoNext->SetPrev(newInfo); + infoNext = info->GetNext(); + info->SetNext(newInfo); + info = newPtr; + } + + uint uVar3 = 0; + if (hint & kHI_TopOfHeap) { + uVar3 = 2; + } + info->SetTopOfHeapAllocated(uVar3 != 0); // maybe? + info->SetLength(len); + return ret; +} + +void CGameAllocator::UpdateAllocDebugStats(uint len, uint roundedLen, uint offset) { + ++x84_; + ++x80_; + x88_ += len; + x8c_ += roundedLen + offset; + x90_heapSize2 -= roundedLen + offset; + + if (x84_ > x94_) { + x94_ = x84_; + } + + if (x8c_ > x98_) { + x98_ = x8c_; + } + + if (len < x9c_) { + x9c_ = len; + } + + if (len > xa0_) { + xa0_ = len; + } + xa4_ = (len + xa4_ * (x80_ - 1)) / x80_; + if (len > 56) { + return; + } + + ++xa8_; +} + +bool CGameAllocator::Free(const void* ptr) { + if (ptr == nullptr) { + return true; + } + + if (x60_smallAllocPool && x60_smallAllocPool->PtrWithinPool(ptr)) { + return x60_smallAllocPool->Free(ptr); + } + + if (x74_mediumPool) { + int tmp = x74_mediumPool->Free(ptr); + if (tmp != 1) { + return tmp > 0; + } + } + return FreeNormalAllocation(ptr); +} + +bool CGameAllocator::FreeNormalAllocation(const void* ptr) { + SGameMemInfo* info = GetMemInfoFromBlockPtr(ptr); + size_t infoLen = info->GetLength(); + SGameMemInfo* k = info->GetNext(); + size_t len = 0; + if (k) { + len = (size_t)k - (size_t)info - sizeof(SGameMemInfo); + } + info->SetLength(len); + + SGameMemInfo* prev = info->GetPrev(); + SGameMemInfo* next = info->GetNext(); + size_t newLen = 0; + + if (prev && !prev->IsAllocated()) { + RemoveFreeEntryFromFreeList(prev); + prev->SetNext(next); + if (next) { + next->SetPrev(prev); + } + newLen = sizeof(SGameMemInfo); + prev->SetLength(prev->GetLength() + sizeof(SGameMemInfo) + info->GetLength()); + } + + if (next) { + if (!next->IsAllocated()) { + if (next->GetNext()) { + RemoveFreeEntryFromFreeList(next); + info->SetNext(next->GetNext()); + if (info->GetNext()) { + info->GetNext()->SetPrev(info); + } + newLen += sizeof(SGameMemInfo); + info->SetLength(next->GetLength() + info->GetLength() + sizeof(SGameMemInfo)); + } + } + } + info->SetNotAllocated(); + AddFreeEntryToFreeList(info); + + x84_ -= 1; + x88_ -= infoLen; + x8c_ -= (len + newLen); + x90_heapSize2 += (len + newLen); + if (infoLen <= 0x39) { + xa8_ -= 1; + } + + return true; +}; + +void CGameAllocator::ReleaseAll() { + if (x74_mediumPool) { + x74_mediumPool->ClearPuddles(); + FreeNormalAllocation(x74_mediumPool); + x74_mediumPool = nullptr; + } + + SGameMemInfo* iter = xc_first; + while (iter != nullptr) { + SGameMemInfo* next = iter->GetNext(); + if (iter->IsAllocated()) { + FreeNormalAllocation(((uchar*)iter) + sizeof(SGameMemInfo)); + } + iter = next; + } + + xc_first = nullptr; + x10_last = nullptr; +}; + +void* CGameAllocator::AllocSecondary(size_t size, EHint hint, EScope scope, EType type, + const CCallStack& callstack) { + return Alloc(size, hint, scope, type, callstack); +}; + +bool CGameAllocator::FreeSecondary(const void* ptr) { return Free(ptr); }; + +void CGameAllocator::ReleaseAllSecondary(){}; + +void CGameAllocator::SetOutOfMemoryCallback(FOutOfMemoryCb cb, const void* target) { + x58_oomCallback = cb; + x5c_oomTarget = target; +}; + +IAllocator::SAllocInfo CGameAllocator::GetAllocInfo(const void* ptr) const { + SGameMemInfo* info = GetMemInfoFromBlockPtr(ptr); + + return SAllocInfo((const void*)info, info->GetLength(), info->IsAllocated(), false, + info->x8_fileAndLine, info->xc_type); +}; + +IAllocator::SMetrics CGameAllocator::GetMetrics() const { + uint mediumAllocTotalAllocated = + x74_mediumPool != nullptr ? x74_mediumPool->GetTotalEntries() * 32 : 0; + uint mediumAllocBlocksAvailable = + x74_mediumPool != nullptr ? x74_mediumPool->GetNumBlocksAvailable() : 0; + uint mediumAllocAllocatedSize = + x74_mediumPool != nullptr + ? x74_mediumPool->GetTotalEntries() - x74_mediumPool->GetNumBlocksAvailable() + : 0; + uint mediumAllocNumAllocs = x74_mediumPool != nullptr ? x74_mediumPool->GetNumAllocs() : 0; + SMetrics ret(x8_heapSize, x80_, x84_, x88_, x8c_, x90_heapSize2, x94_, x98_, x9c_, xa0_, xa4_, + x60_smallAllocPool != nullptr ? x60_smallAllocPool->GetNumAllocs() : 0, + x60_smallAllocPool != nullptr ? x60_smallAllocPool->GetAllocatedSize() : 0, + x60_smallAllocPool != nullptr ? x60_smallAllocPool->GetNumBlocksAvailable() : 0, + mediumAllocNumAllocs, mediumAllocAllocatedSize, mediumAllocBlocksAvailable, + x80_ - xb0_, (uintptr_t)xb4_physicalAddr, xbc_, mediumAllocTotalAllocated, + xb8_fakeStatics); + xb0_ = x80_; + return ret; +}; + +int CGameAllocator::EnumAllocations(FEnumAllocationsCb func, const void* ptr, bool b) const { + + int i = 0; + SGameMemInfo* iter = xc_first; + + while (iter != nullptr) { + if (!iter->IsPostGuardIntact()) { + return -1; + } + + if (!iter->IsPriorGuardIntact()) { + return -1; + } + + SGameMemInfo* next = iter->GetNext(); + SAllocInfo alloc((const void*)iter, iter->GetLength(), iter->IsAllocated(), false, + iter->x8_fileAndLine, iter->xc_type); + func(alloc, ptr); + ++i; + iter = next; + } + + return i; +}; + +uint CGameAllocator::GetFreeBinEntryForSize(uint size) { + uint maxLen = 0x20; + uint bin = 0; + + while (maxLen < 0x200000) { + if (size < maxLen) { + return bin; + } + + maxLen <<= 1; + ++bin; + } + + return 0xf; +} + +void CGameAllocator::AddFreeEntryToFreeList(SGameMemInfo* info) { + uint bin = GetFreeBinEntryForSize(info->GetLength()); + info->SetNextFree(x14_bins[bin]); + x14_bins[bin] = info; +} + +void CGameAllocator::RemoveFreeEntryFromFreeList(SGameMemInfo* memInfo) { + uint bin = GetFreeBinEntryForSize(memInfo->GetLength()); + SGameMemInfo* curBin = nullptr; + SGameMemInfo* binIt = x14_bins[bin]; + + while (binIt != nullptr) { + if (binIt == memInfo) { + if (curBin == nullptr) { + x14_bins[bin] = binIt->GetNextFree(); + } else { + curBin->SetNextFree(binIt->GetNextFree()); + } + return; + } + + curBin = binIt; + binIt = binIt->GetNextFree(); + } +} + +static inline bool DoWait(int v) { return (v % 4) == 0; } + +void CGameAllocator::DumpAllocations() const { + GetLargestFreeChunk(); + uint i = 0; + SGameMemInfo* iter = xc_first; + + while (iter != nullptr) { + ++i; + + if (DoWait(i)) { + CStopwatch::Wait(0.005f); + } + iter = iter->GetNext(); + } +} + +size_t CGameAllocator::GetLargestFreeChunk() const { + SGameMemInfo* iter = xc_first; + size_t ret = 0; + while (iter != nullptr) { + if (!iter->IsAllocated() && iter->GetLength() > ret) { + ret = iter->GetLength(); + } + iter = iter->GetNextFree(); + } + + return ret; +} +void CGameAllocator::OffsetFakeStatics(int offset) { xb8_fakeStatics += offset; } diff --git a/src/Kyoto/Alloc/CMediumAllocPool.cpp b/src/Kyoto/Alloc/CMediumAllocPool.cpp new file mode 100644 index 0000000..9655b07 --- /dev/null +++ b/src/Kyoto/Alloc/CMediumAllocPool.cpp @@ -0,0 +1,246 @@ +#include "Kyoto/Alloc/CMediumAllocPool.hpp" + +CMediumAllocPool* CMediumAllocPool::gMediumAllocPtr = nullptr; + +CMediumAllocPool::CMediumAllocPool() : x18_lastNodePrev(x0_list.begin()) { gMediumAllocPtr = this; } + +void CMediumAllocPool::ClearPuddles() { + x18_lastNodePrev = x0_list.end(); + x0_list.clear(); + gMediumAllocPtr = nullptr; +} + +bool CMediumAllocPool::HasPuddles() const { return x0_list.size() != 0; } + +void* CMediumAllocPool::Alloc(uint len) { + SMediumAllocPuddle* puddle = &*x18_lastNodePrev; + void* ret; + uint blockCount = 1; + if (len >= 32) { + blockCount = (len + 31) / 32; + } + + ret = puddle->FindFree(blockCount); + + if (ret == nullptr) { + for (rstl::list< SMediumAllocPuddle >::iterator it = x0_list.begin(); it != x0_list.end(); + ++it) { + if (it == x18_lastNodePrev) { + continue; + } + + ret = it->FindFree(blockCount); + if (ret != nullptr) { + x18_lastNodePrev = it; + break; + } + } + } + + return ret; +} + +int CMediumAllocPool::Free(const void* ptr) { + rstl::list< SMediumAllocPuddle >::node* node = x0_list.begin().get_node(); + for (; node != x0_list.end().get_node(); node = node->get_next()) { + SMediumAllocPuddle* puddle = node->get_value(); + if (puddle->GetPtrOffset(ptr) < puddle->GetNumEntries() * 32) { + puddle->Free(ptr); + if (node->get_value()->GetNumAllocs() == 0 && node->get_value()->CanErase()) { + if (x18_lastNodePrev == node) { + x18_lastNodePrev = x0_list.begin().get_node(); + } + + x0_list.erase(node); + } + + return 2; + } + } + return 1; +} + +uint CMediumAllocPool::GetNumAllocs() { + uint ret = 0; + for (rstl::list< SMediumAllocPuddle >::iterator it = x0_list.begin(); it != x0_list.end(); ++it) { + ret += it->GetNumAllocs(); + } + + return ret; +} +uint CMediumAllocPool::GetTotalEntries() { + uint ret = 0; + for (rstl::list< SMediumAllocPuddle >::iterator it = x0_list.begin(); it != x0_list.end(); ++it) { + ret += it->GetNumEntries(); + } + + return ret; +} + +uint CMediumAllocPool::GetNumBlocksAvailable() { + uint ret = 0; + for (rstl::list< SMediumAllocPuddle >::iterator it = x0_list.begin(); it != x0_list.end(); ++it) { + ret += it->GetNumBlocks(); + } + + return ret; +} + +#pragma inline_max_size(250) +void CMediumAllocPool::AddPuddle(uint len, void* data, const bool unk) { + x0_list.push_back(SMediumAllocPuddle(len, data, unk)); + x18_lastNodePrev = x0_list.end(); + --x18_lastNodePrev; +} + +SMediumAllocPuddle::SMediumAllocPuddle(const uint numBlocks, void* data, const bool canErase) +: x0_mainData(static_cast< uchar* >(data)) +, x8_bookKeeping(static_cast< uchar* >(data) + numBlocks * 32) +, xc_cachedBookKeepingAddr(nullptr) +, x10_unused(-1) +, x14_numBlocks(numBlocks) +, x18_numAllocs(0) +, x1c_numEntries(numBlocks) +, x20_canErase(canErase) { + SMediumAllocPuddle::InitBookKeeping(x8_bookKeeping, numBlocks); +} + +SMediumAllocPuddle::~SMediumAllocPuddle() {} + +void* SMediumAllocPuddle::FindFree(uint blockCount) { + void* bookKeepingptr; + uchar* entryPtr; + void* ret; + + entryPtr = (uchar*)FindFreeEntry(blockCount); + if (entryPtr == NULL) { + return NULL; + } + + bookKeepingptr = x8_bookKeeping; + ret = x0_mainData.get(); + entryPtr[0] = (uchar)blockCount; + ret = (void*)((uchar*)ret + ((uchar*)entryPtr - (uchar*)bookKeepingptr) * 0x20); + entryPtr[blockCount - 1] = blockCount; + x14_numBlocks -= blockCount; + x18_numAllocs++; + return ret; +} + +void* SMediumAllocPuddle::FindFreeEntry(uint numBlocks) { + if (GetNumBlocks() >= numBlocks) { + uchar* cachedBookPtr = xc_cachedBookKeepingAddr; + uchar* bookPtr = x8_bookKeeping; + + if (cachedBookPtr == nullptr) { + cachedBookPtr = bookPtr; + } + + uchar* ptr2 = bookPtr + GetNumEntries(); + uchar* ptr1 = cachedBookPtr; + do { + + if ((*ptr1 & 0x80) == 0 || ptr1 == ptr2) { + if (ptr1 == ptr2) { + ptr1 = bookPtr; + } else { + ptr1 += *ptr1; + } + } else { + uint offset = GetBlockOffset(ptr1, ptr2); + + if (offset >= numBlocks) { + if ((ushort)(offset - numBlocks)) { + SMediumAllocPuddle::InitBookKeeping(ptr1 + numBlocks, offset - numBlocks); + } + + xc_cachedBookKeepingAddr = ptr1; + return ptr1; + } + + ptr1 += offset; + + if (ptr1 == cachedBookPtr) { + break; + } + + if (ptr1 == ptr2) { + ptr1 = bookPtr; + } + } + } while (ptr1 != cachedBookPtr); + } + return nullptr; +} + +void SMediumAllocPuddle::Free(const void* ptr) { + uint blockOffset = ((uint)ptr - (uint)x0_mainData.get()) / 32; + uint blockCount = x8_bookKeeping[blockOffset]; + bool isCached = false; + x14_numBlocks += blockCount; + --x18_numAllocs; + + uchar* bookKeepingStart = x8_bookKeeping; + uchar* cachedBookKeep = bookKeepingStart + blockOffset; + uchar* block = bookKeepingStart + blockOffset; + uchar* bookKeepingPtr = block; + uchar* bookKeepingEndPtr = block + GetNumEntries(); + if (cachedBookKeep == block) { + isCached = true; + } + + if (block > bookKeepingStart && block[-1] & 0x80) { + if (!(block[-1] & 0x60)) { + blockOffset = (block[-2] + (block[-1] & 0x7f) * 256); + } else if ((block[-1] & 0x60) == 0x60ul) { + blockOffset = 3; + } else { + blockOffset = __cntlzw(0x40 - (block[-1] & 0x60)); + blockOffset = (blockOffset >> 5); + blockOffset++; + } + + bookKeepingPtr = block - (ushort)blockOffset; + blockOffset = blockCount + blockOffset; + } + + uchar* ptr1 = block + blockCount; + if (ptr1 < bookKeepingEndPtr && (ptr1[0] & 0x80) > 0) { + blockOffset += GetBlockOffset(ptr1, bookKeepingEndPtr); + } + + InitBookKeeping(bookKeepingPtr, blockOffset); + if (!isCached) { + return; + } + if (bookKeepingPtr == bookKeepingStart) { + xc_cachedBookKeepingAddr = nullptr; + } else { + xc_cachedBookKeepingAddr = bookKeepingPtr - bookKeepingPtr[-1]; + } +} + +ushort SMediumAllocPuddle::GetBlockOffset(const void* ptr1, const void* ptr2) { + unsigned char tmp = (uchar*)ptr2 - (uchar*)ptr1 > 1 ? ((uchar*)ptr1)[1] : 0; + + ushort x = tmp + (*(uchar*)(ptr1) & 0x7f) * 0x100; + if ((x & 0x6000) == 0) { + return x; + } + return (x & 0x6000u) == 0x6000u ? 3 : (((x & 0x6000u) != 0x4000) ? 0 : 1) + 1; +} + +void SMediumAllocPuddle::InitBookKeeping(uchar* bookKeepingPtr, ushort blockCount) { + if (blockCount < 4) { + const uchar tmp = (blockCount == 3 ? 96 : blockCount == 2 ? 64 : 32) | 0x80; + bookKeepingPtr[0] = tmp; + if (blockCount > 1) { + bookKeepingPtr[blockCount - 1] = tmp; + } + } else { + bookKeepingPtr[0] = (blockCount >> 8) | 0x80; + bookKeepingPtr[1] = blockCount; + bookKeepingPtr[blockCount - 2] = blockCount; + bookKeepingPtr[blockCount - 1] = (blockCount >> 8) | 0x80; + } +} diff --git a/src/Kyoto/Alloc/CMemory.cpp b/src/Kyoto/Alloc/CMemory.cpp new file mode 100644 index 0000000..459e818 --- /dev/null +++ b/src/Kyoto/Alloc/CMemory.cpp @@ -0,0 +1,90 @@ +#include "Kyoto/Alloc/CMemory.hpp" +#include "Kyoto/Alloc/CMemorySys.hpp" + +#include "Kyoto/Alloc/CCallStack.hpp" +#include "Kyoto/Alloc/CGameAllocator.hpp" +#include "Kyoto/Basics/RAssertDolphin.hpp" + +#include "dolphin/os.h" + +static CGameAllocator gGameAllocator; +IAllocator* CMemory::mpAllocator = &gGameAllocator; +bool CMemory::mInitialized; +uint gLeakCount = 0; +uint gLeakBytes = 0; + +CMemorySys::CMemorySys(COsContext& ctx, IAllocator& allocator) { + CMemory::Startup(ctx); + CMemory::SetAllocator(ctx, allocator); +} + +CMemorySys::~CMemorySys() { CMemory::Shutdown(); } + +IAllocator& CMemorySys::GetGameAllocator() { return gGameAllocator; } + +void CMemory::Startup(COsContext& ctx) { mInitialized = mpAllocator->Initialize(ctx); } + +void CMemory::SetAllocator(COsContext& ctx, IAllocator& allocator) { + if (mpAllocator != &allocator) { + if (mpAllocator != nullptr) { + mpAllocator->ReleaseAll(); + } + mpAllocator = &allocator; + mpAllocator->Initialize(ctx); + } +} + +static bool cmemory_enum_alloc_cb(const IAllocator::SAllocInfo& info, const void* ptr) { + if (info.x8_isAllocated && info.x9_ == 0) { + ++gLeakCount; + gLeakBytes += info.x4_len; + } + return true; +} + +void CMemory::Shutdown() { + CMemory::mInitialized = false; + + if (mpAllocator->GetMetrics().x8_ != 0) { + gLeakCount = 0; + gLeakBytes = 0; + mpAllocator->EnumAllocations((IAllocator::FEnumAllocationsCb)cmemory_enum_alloc_cb, nullptr, + false); + } + mpAllocator->Shutdown(); +} + +void* CMemory::Alloc(size_t len, IAllocator::EHint hint, IAllocator::EScope scope, + IAllocator::EType type, const CCallStack& callstack) { + volatile bool enabled = OSDisableInterrupts(); + void* ret = mpAllocator->Alloc(len, hint, scope, type, callstack); + if (ret == nullptr) { + rs_debugger_printf("Alloc failed - Size: %d", len); + } + + OSRestoreInterrupts(enabled); + return ret; +} + +void CMemory::Free(const void* ptr) { + volatile bool enabled = OSDisableInterrupts(); + if (ptr != nullptr) { + mpAllocator->Free(ptr); + } + OSRestoreInterrupts(enabled); +} + +void CMemory::SetOutOfMemoryCallback(IAllocator::FOutOfMemoryCb cb, const void* context) { + mpAllocator->SetOutOfMemoryCallback(cb, context); +} + +void CMemory::OffsetFakeStatics(int offset) { mpAllocator->OffsetFakeStatics(offset); } + +void* operator new(size_t sz, const char* fileAndLine, const char* type) { + return CMemory::Alloc(sz, IAllocator::kHI_None, IAllocator::kSC_Unk1, IAllocator::kTP_Heap, + CCallStack(-1, fileAndLine, type)); +} +void* operator new[](size_t sz, const char* fileAndLine, const char* type) { + return CMemory::Alloc(sz, IAllocator::kHI_None, IAllocator::kSC_Unk1, IAllocator::kTP_Array, + CCallStack(-1, fileAndLine, type)); +} diff --git a/src/Kyoto/Alloc/CSmallAllocPool.cpp b/src/Kyoto/Alloc/CSmallAllocPool.cpp new file mode 100644 index 0000000..bc3e8a4 --- /dev/null +++ b/src/Kyoto/Alloc/CSmallAllocPool.cpp @@ -0,0 +1,120 @@ +#include "Kyoto/Alloc/CSmallAllocPool.hpp" +#include + +CSmallAllocPool::CSmallAllocPool(uint len, void* mainData, void* bookKeeping) +: x0_mainData(mainData) +, x4_bookKeeping(bookKeeping) +, x8_numBlocks(len) +, xc_cachedBookKeepingOffset(NULL) +, x10_(-1) +, x14_(-1) +, x18_numBlocksAvailable(len) +, x1c_numAllocs(0) { + memset(bookKeeping, 0, len / 2); +} + +void* CSmallAllocPool::FindFree(int len) { + uchar* bookKeepingPtr; + int size = (int)len / 2; + if (xc_cachedBookKeepingOffset == nullptr) { + xc_cachedBookKeepingOffset = x4_bookKeeping; + } + uchar* curKeepingOffset = static_cast< uchar* >(xc_cachedBookKeepingOffset); + bookKeepingPtr = static_cast< uchar* >(x4_bookKeeping); + uchar* bookKeepingEndPtr = bookKeepingPtr + ((uint)x8_numBlocks >> 1); + uchar* curKeepingIter = curKeepingOffset; + while (true) { + uchar* iter; + if (static_cast< uchar* >(curKeepingIter)[0] != 0 || curKeepingIter == bookKeepingEndPtr) { + if (curKeepingIter == bookKeepingEndPtr) { + curKeepingIter = bookKeepingPtr; + } else { + int tmp = static_cast< uchar* >(curKeepingIter)[0]; + int reg = tmp >> 4; + curKeepingIter += (reg / 2); + } + } else { + uchar* tempIter = curKeepingIter + size; + iter = curKeepingIter + 1; + while (iter != curKeepingOffset && iter != bookKeepingEndPtr && iter != tempIter) { + if (static_cast< uchar* >(iter)[0] == 0) { + iter++; + } else { + break; + } + } + + if (iter == curKeepingIter + size) { + if (iter == bookKeepingEndPtr) { + xc_cachedBookKeepingOffset = bookKeepingPtr; + } else { + xc_cachedBookKeepingOffset = curKeepingIter; + } + return curKeepingIter; + } + + if (iter == curKeepingOffset) { + return nullptr; + } + if (iter == bookKeepingEndPtr) { + curKeepingIter = bookKeepingPtr; + } else { + curKeepingIter = iter; + } + } + if (curKeepingIter == curKeepingOffset) { + return nullptr; + } + }; +} + +void* CSmallAllocPool::Alloc(uint size) { + uint len = size >= 4 ? len = (size + 3) / 4 : 1; + + if ((len & 1) != 0) { + len += 1; + } + + uchar* freePtr = static_cast< uchar* >(FindFree(len)); + if (freePtr == nullptr) { + return nullptr; + } + + int sub = len - 2; + uchar* bufPtr = GetPtrFromIndex(freePtr - static_cast< uchar* >(x4_bookKeeping)); + *static_cast< uchar* >(freePtr) = (len << 4) | 0xf; + int blockSize = sub / 2; + uchar* freePtrIter = freePtr + 1; + while (blockSize--) { + *freePtrIter = 0xff; + ++freePtrIter; + } + + x18_numBlocksAvailable -= len; + ++x1c_numAllocs; + + return bufPtr; +} + +bool CSmallAllocPool::Free(const void* arg0) { + int temp_r8 = GetIndexFromPtr(arg0); + int mask = (temp_r8 & 1) ? 0 : 4; + size_t temp_r9 = (size_t)temp_r8 / 2; + long temp_r4_2 = GetEntryValue(temp_r9); + temp_r4_2 = (temp_r4_2 >> mask) & 0xF; + x18_numBlocksAvailable += temp_r4_2; + int var_r5 = temp_r4_2; + x1c_numAllocs -= 1; + x14_ = temp_r8; + if ((size_t)temp_r8 == (size_t)x10_) { + x10_ = -1; + } + + uchar* var_r3 = ((uchar*)x4_bookKeeping) + temp_r9; + while (var_r5 != 0) { + *var_r3 = 0; + var_r5 -= 2; + ++var_r3; + } + return 1; +} diff --git a/src/Kyoto/Alloc/IAllocator.cpp b/src/Kyoto/Alloc/IAllocator.cpp new file mode 100644 index 0000000..d165b82 --- /dev/null +++ b/src/Kyoto/Alloc/IAllocator.cpp @@ -0,0 +1,36 @@ +#include "Kyoto/Alloc/IAllocator.hpp" + +#include "Kyoto/Alloc/CMemory.hpp" +#include "Kyoto/Basics/COsContext.hpp" + +IAllocator::SMetrics::SMetrics(uint heapSize, uint unk1, uint unk2, uint unk3, uint unk4, + uint heapSize2, uint unk5, uint unk6, uint unk7, uint unk8, + uint unk9, uint smallAllocNumAllocs, uint smallAllocAllocatedSize, + uint smallAllocRemainingSize, uint mediumAllocNumAllocs, + uint mediumAllocAllocatedSize, uint mediumAllocBlocksAvailable, + uint unk10, uint unk11, uint unk12, uint mediumAllocTotalAllocated, + uint fakeStatics) +: x0_heapSize(heapSize) +, x4_(unk1) +, x8_(unk2) +, xc_(unk3) +, x10_(unk4) +, x14_heapSize2(heapSize2) +, x18_(unk5) +, x1c_(unk6) +, x20_(unk7) +, x24_(unk8) +, x28_(unk9) +, x2c_smallNumAllocs(smallAllocNumAllocs) +, x30_smallAllocatedSize(smallAllocAllocatedSize) +, x34_smallRemainingSize(smallAllocRemainingSize) +, x38_mediumNumAllocs(mediumAllocNumAllocs) +, x3c_mediumAllocatedSize(mediumAllocAllocatedSize) +, x40_mediumBlocksAvailable(mediumAllocBlocksAvailable) +, x44_(unk10) +, x48_(unk11) +, x4c_(unk12) +, x50_mediumTotalAllocated(mediumAllocTotalAllocated) +, x54_fakeStatics(fakeStatics) {} + +IAllocator::~IAllocator() {} diff --git a/src/Kyoto/rstl/RstlExtras.cpp b/src/Kyoto/rstl/RstlExtras.cpp new file mode 100644 index 0000000..0fbe8b3 --- /dev/null +++ b/src/Kyoto/rstl/RstlExtras.cpp @@ -0,0 +1,135 @@ +#include "Kyoto/Alloc/CMemory.hpp" +#include "rstl/StringExtras.hpp" +#include "rstl/math.hpp" +#include "rstl/rc_ptr.hpp" + +#include "Kyoto/Basics/CCast.hpp" +#include "Kyoto/Streams/CInputStream.hpp" + +namespace rstl { +CRefData CRefData::sNull(nullptr, 0x1000000 - 1); +} + +int CStringExtras::IndexOfSubstring(const rstl::string& left, const rstl::string& right) { + int rightSize = right.size(); + if (rightSize == 0) { + return 0; + } + int leftSize = left.size(); + if (leftSize == 0) { + return -1; + } + + for (int i = 0; i < (leftSize - rightSize) + 1; ++i) { + int j = 0; + for (; j < rightSize; ++j) { + if (ConvertToUpperCase(right.at(i)) != ConvertToUpperCase(left.at(i + j))) { + break; + } + } + if (j == rightSize) { + return i; + } + } + return -1; +} + +int CStringExtras::CompareCaseInsensitive(const rstl::string& left, const rstl::string& right) { + int left_size = left.size(); + int right_size = right.size(); + int max_size = rstl::min_val(left_size, right_size); + + for (int idx = 0; idx < max_size; ++idx) { + if (ConvertToUpperCase(left.at(idx)) < ConvertToUpperCase(right.at(idx))) { + return -1; + } + + if (ConvertToUpperCase(left.at(idx)) > ConvertToUpperCase(right.at(idx))) { + return 1; + } + } + if (left_size < right_size) { + return -1; + } else if (left_size > right_size) { + return 1; + } else { + return 0; + } +} + +char CStringExtras::ConvertToUpperCase(char c) { + if (c >= CCast::ToChar('a') && c <= CCast::ToChar('z')) { + return (c - CCast::ToChar(' ')) & 0xFF; + } + + return c; +} + +rstl::string CStringExtras::CreateFromInteger(int v) { + int iVar3 = ((v >> 31) ^ v) - (v >> 31); + int iVar4 = 0; + uchar tmp[24]; + if (v == 0) { + return rstl::string_l("0"); + } + + uchar* ptr = &tmp[0]; + while (iVar3 > 0) { + ++iVar4; + int iVar1 = iVar3 / 10 + (iVar3 >> 31); + *ptr = iVar3 + (((iVar1 - (iVar1 >> 31)) * 10) + '0'); + ++ptr; + iVar3 = iVar1 - (iVar1 >> 31); + } + + rstl::string ret; + if (v < 0) { + ret.append("-"); + } + + for (int i = 0; i < iVar4; ++i) { + ret.append(1, tmp[iVar4 - i]); + } + + return ret; +} + +rstl::string CStringExtras::ConvertToANSI(const rstl::wstring& str) { + rstl::string ret; + ret.reserve(str.size() + 1); + + for (int i = 0; i < (int)str.size(); ++i) { + ret.assign(ret + (char)(str.at(i))); + } + return ret; +} +rstl::wstring CStringExtras::ConvertToUNICODE(const rstl::string& str) { + rstl::wstring ret; + ret.reserve(str.size() + 1); + + for (int i = 0; i < (int)str.size(); ++i) { + ret.append(1, (wchar_t)str.at(i)); + } + return ret; +} + +rstl::string CStringExtras::ReadString(CInputStream& in) { + rstl::string ret; + int strLen = in.ReadInt32(); + ret.reserve(strLen); + while (strLen > 0) { + int len = strLen > 512u ? 512 : strLen; + char tmp[512]; + in.ReadBytes(tmp, len); + ret.append(tmp, len); + strLen -= len; + } + + return ret; +} + +rstl::vector< rstl::string > CStringExtras::TokenizeString(const rstl::string& string, + const char* delims, int expectedSize) { + rstl::vector< rstl::string > ret; + ret.reserve(expectedSize); +} diff --git a/src/Kyoto/rstl/rstl_map.cpp b/src/Kyoto/rstl/rstl_map.cpp new file mode 100644 index 0000000..15d2350 --- /dev/null +++ b/src/Kyoto/rstl/rstl_map.cpp @@ -0,0 +1,342 @@ +#include "rstl/red_black_tree.hpp" + +namespace rstl { + +struct _node { + _node* mLeft; + _node* mRight; + _node* mParent; + node_color mColor; +}; + +struct _header { + _node* mLeftmost; + _node* mRightmost; + _node* mRootNode; +}; + +void rbtree_rotate_left(void* header_void, void* node_void) { + _header* header = static_cast< _header* >(header_void); + _node* node = static_cast< _node* >(node_void); + + _node* parent = node->mParent; + _node* right = node->mRight; + _node* l = right->mLeft; + + if (parent == nullptr) { + header->mRootNode = right; + right->mParent = nullptr; + } else { + if (parent->mLeft == node) { + parent->mLeft = right; + } else { + parent->mRight = right; + } + right->mParent = node->mParent; + } + node->mParent = right; + right->mLeft = node; + if (l) { + l->mParent = node; + } + node->mRight = l; +} + +void rbtree_rotate_right(void* header_void, void* node_void) { + _header* header = static_cast< _header* >(header_void); + _node* node = static_cast< _node* >(node_void); + + _node* parent = node->mParent; + _node* left = node->mLeft; + _node* r = left->mRight; + + if (parent == nullptr) { + header->mRootNode = left; + left->mParent = nullptr; + } else { + if (node == parent->mLeft) { + parent->mLeft = left; + } else { + parent->mRight = left; + } + left->mParent = node->mParent; + } + node->mParent = left; + left->mRight = node; + if (r) { + r->mParent = node; + } + node->mLeft = r; +} + +void rbtree_rebalance(void* header_void, void* node_void) { + _node* node = static_cast< _node* >(node_void); + _header* header = static_cast< _header* >(header_void); + + while (node->mParent != nullptr && node->mParent->mColor == kNC_Black) { + _node* p = node->mParent->mParent->mLeft; + if (node->mParent == p) { + p = node->mParent->mParent->mRight; + if ((p != nullptr && p->mColor == kNC_Black)) { + node->mParent->mColor = kNC_Red; + p->mColor = kNC_Red; + node->mParent->mParent->mColor = kNC_Black; + node = node->mParent->mParent; + + } else { + if (node == node->mParent->mRight) { + node = node->mParent; + rbtree_rotate_left(header, node); + } + node->mParent->mColor = kNC_Red; + node->mParent->mParent->mColor = kNC_Black; + rbtree_rotate_right(header, node->mParent->mParent); + } + } else if (p != nullptr && p->mColor == kNC_Black) { + node->mParent->mColor = kNC_Red; + p->mColor = kNC_Red; + node->mParent->mParent->mColor = kNC_Black; + node = node->mParent->mParent; + + } else { + if (node == node->mParent->mLeft) { + node = node->mParent; + rbtree_rotate_right(header, node); + } + node->mParent->mColor = kNC_Red; + node->mParent->mParent->mColor = kNC_Black; + rbtree_rotate_left(header, node->mParent->mParent); + } + } + header->mRootNode->mColor = kNC_Red; +} + +void* rbtree_rebalance_for_erase(void* header_void, void* node_void) { + _header* header = static_cast< _header* >(header_void); + _node* node = static_cast< _node* >(node_void); + + _node* replacement; + _node* successor = node; + _node* parent; + + if (node->mLeft == nullptr) { + replacement = node->mRight; + } else { + _node* tmp = node->mRight; + if (tmp == nullptr) { + replacement = tmp; + } else { + do { + successor = tmp; + tmp = successor->mLeft; + } while (successor->mLeft != nullptr); + replacement = successor->mRight; + } + } + + if (successor != node) { + node->mLeft->mParent = successor; + successor->mLeft = node->mLeft; + + parent = successor; + if (successor != node->mRight) { + parent = successor->mParent; + if (replacement != nullptr) { + replacement->mParent = successor->mParent; + } + successor->mParent->mLeft = replacement; + successor->mRight = node->mRight; + node->mRight->mParent = successor; + } + + if (header->mRootNode == node) { + header->mRootNode = successor; + } else { + if (node->mParent->mLeft == node) { + node->mParent->mLeft = successor; + } else { + node->mParent->mRight = successor; + } + } + + successor->mParent = node->mParent; + node_color c = successor->mColor; + successor->mColor = node->mColor; + node->mColor = c; + successor = node; + + } else { + parent = successor->mParent; + if (replacement != nullptr) { + replacement->mParent = parent; + } + if (header->mRootNode == node) { + header->mRootNode = replacement; + } else { + if (node->mParent->mLeft == node) { + node->mParent->mLeft = replacement; + } else { + node->mParent->mRight = replacement; + } + } + + if (header->mLeftmost == node) { + if (node->mRight == nullptr) { + header->mLeftmost = node->mParent; + } else { + _node* iter = replacement; + if (replacement == nullptr) { + header->mLeftmost = nullptr; + } else { + _node* newLeftmost; + do { + newLeftmost = iter; + iter = newLeftmost->mLeft; + } while (newLeftmost->mLeft != nullptr); + header->mLeftmost = newLeftmost; + } + } + } + + if (header->mRightmost == node) { + if (node->mLeft == nullptr) { + header->mRightmost = node->mParent; + } else { + _node* iter = replacement; + if (replacement == nullptr) { + header->mRightmost = nullptr; + } else { + _node* newRightmost; + do { + newRightmost = iter; + iter = newRightmost->mRight; + } while (newRightmost->mRight != nullptr); + header->mRightmost = newRightmost; + } + } + } + } + + if (successor->mColor != kNC_Black) { + _node* currentParent; + _node* siblingChild; + _node* sibling; + + while (true) { + currentParent = parent; + if (replacement == header->mRootNode || (replacement && replacement->mColor != kNC_Red)) { + break; + } + sibling = currentParent->mLeft; + if (replacement == sibling) { + // Replacement is left child, sibling is on the right + sibling = currentParent->mRight; + if (sibling->mColor == kNC_Black) { + sibling->mColor = kNC_Red; + currentParent->mColor = kNC_Black; + rbtree_rotate_left(header, currentParent); + sibling = currentParent->mRight; + } + siblingChild = sibling->mLeft; + if (((siblingChild != nullptr) && (siblingChild->mColor != kNC_Red)) || + ((sibling->mRight != nullptr && (sibling->mRight->mColor != kNC_Red)))) { + if ((sibling->mRight == nullptr) || (sibling->mRight->mColor == kNC_Red)) { + if (siblingChild != nullptr) { + siblingChild->mColor = kNC_Red; + } + sibling->mColor = kNC_Black; + rbtree_rotate_right(header, sibling); + sibling = currentParent->mRight; + } + sibling->mColor = currentParent->mColor; + currentParent->mColor = kNC_Red; + if (sibling->mRight != nullptr) { + sibling->mRight->mColor = kNC_Red; + } + rbtree_rotate_left(header, currentParent); + break; + } + sibling->mColor = kNC_Black; + parent = currentParent->mParent; + replacement = currentParent; + } else { + // Replacement is right child, sibling is on the left + if (sibling->mColor == kNC_Black) { + sibling->mColor = kNC_Red; + currentParent->mColor = kNC_Black; + rbtree_rotate_right(header, currentParent); + sibling = currentParent->mLeft; + } + siblingChild = sibling->mRight; + if ((siblingChild && siblingChild->mColor != kNC_Red) || + (sibling->mLeft && sibling->mLeft->mColor != kNC_Red)) { + + if (!sibling->mLeft || sibling->mLeft->mColor == kNC_Red) { + if (siblingChild) { + siblingChild->mColor = kNC_Red; + } + sibling->mColor = kNC_Black; + rbtree_rotate_left(header, sibling); + sibling = currentParent->mLeft; + } + sibling->mColor = currentParent->mColor; + currentParent->mColor = kNC_Red; + if (sibling->mLeft != nullptr) { + sibling->mLeft->mColor = kNC_Red; + } + rbtree_rotate_right(header, currentParent); + break; + } + sibling->mColor = kNC_Black; + parent = currentParent->mParent; + replacement = currentParent; + } + } + if (replacement != nullptr) { + replacement->mColor = kNC_Red; + } + } + + return successor; +} + +void* rbtree_traverse_forward(const void* header_void, void* node_void) { + const _header* header = static_cast< const _header* >(header_void); + _node* node = static_cast< _node* >(node_void); + + if (node == nullptr) { + return header->mLeftmost; + } + _node* right = node->mRight; + if ((right == nullptr) && (node->mParent == nullptr)) { + return nullptr; + } + if ((right == nullptr) && (node->mParent->mLeft == node)) { + return node->mParent; + } + + if (right != nullptr) { + _node* result = right; + goto enter_middle; + do { + result = right; + enter_middle: + right = result->mLeft; + } while (right != nullptr); + return result; + } + + _node* parent = nullptr; + goto enter_final; + do { + node = parent; + enter_final: + parent = node->mParent; + if (!parent) + break; + } while (parent->mRight == node); + + return parent != nullptr ? parent : nullptr; +} + +} // namespace rstl diff --git a/src/MetroidPrime/CRuleSet.cpp b/src/MetroidPrime/CRuleSet.cpp index 33b76ad..e63b9e0 100644 --- a/src/MetroidPrime/CRuleSet.cpp +++ b/src/MetroidPrime/CRuleSet.cpp @@ -13,7 +13,7 @@ CRuleSet::CRuleSet(CInputStream& input) { int ruleCount = input.ReadInt8(); m_rules.reserve(ruleCount); for (int i = 0; i < ruleCount; ++i) { - m_rules.push_back_unsafe(CRuleSetRule(input)); + m_rules.push_back(CRuleSetRule(input)); } } @@ -27,7 +27,7 @@ CRuleSetRule::CRuleSetRule(CInputStream& input) { int actionCount = input.ReadInt8(); m_actions.reserve(actionCount); for (int i = 0; i < actionCount; ++i) { - m_actions.push_back_unsafe(CRuleAction(input)); + m_actions.push_back(CRuleAction(input)); } } @@ -38,7 +38,7 @@ CRuleAction::CRuleAction(CInputStream& input) : m_id(input.ReadInt32()) { int propCount = input.ReadInt8(); m_properties.reserve(propCount); for (int i = 0; i < propCount; ++i) { - m_properties.push_back_unsafe(CRuleValue(3, input)); + m_properties.push_back(CRuleValue(3, input)); } }