#ifndef SEAD_HEAPMGR_H_ #define SEAD_HEAPMGR_H_ #include #include #include #include #include namespace sead { class HeapMgr { public: HeapMgr(); virtual ~HeapMgr() {} void initialize(ulong); void initializeImpl_(void); void initialize(sead::Arena *); Heap* getCurrentHeap() const; Heap* findContainHeap(const void* ptr) const; static bool isContainedInAnyHeap(const void* ptr); static HeapMgr* instance() { return sInstancePtr; } static s32 getRootHeapNum(); // { return sRootHeaps.size(); } Heap *findHeapByName(sead::SafeStringBase const&,int) const; Heap* findHeapByName_(sead::Heap*, sead::SafeStringBase const&, int*); // TODO: these should be private static HeapMgr sInstance; static HeapMgr* sInstancePtr; using RootHeaps = FixedPtrArray; using IndependentHeaps = FixedPtrArray; // private: friend class ScopedCurrentHeapSetter; /// Set the current heap to the specified heap and returns the previous "current heap". sead::Heap* setCurrentHeap_(sead::Heap* heap); static Arena sDefaultArena; static RootHeaps sRootHeaps; static IndependentHeaps sIndependentHeaps; static CriticalSection sHeapTreeLockCS; void* mAllocFailedCallback; // IAllocFailedCallback* = IDelegate1* }; /// Sets the "current heap" to the specified heap and restores the previous "current heap" /// when this goes out of scope. class ScopedCurrentHeapSetter { public: explicit ScopedCurrentHeapSetter(sead::Heap* heap) { if (heap) setPreviousHeap_(HeapMgr::instance()->setCurrentHeap_(heap)); else setPreviousHeapToNone_(); } ~ScopedCurrentHeapSetter() { if (hasPreviousHeap_()) HeapMgr::instance()->setCurrentHeap_(getPreviousHeap_()); } protected: /// @warning Only call this if hasPreviousHeap returns true. Heap* getPreviousHeap_() const { return reinterpret_cast(mPreviousHeap); } void setPreviousHeap_(Heap* heap) { mPreviousHeap = reinterpret_cast(heap); } void setPreviousHeapToNone_() { mPreviousHeap = 1; } bool hasPreviousHeap_() const { // XXX: We cannot just do `mPreviousHeap != 1` because that results in different codegen. // The cast smells like implementation defined behavior, but 1 should not be a valid // pointer on any platform that we support. In practice, this will work correctly. return reinterpret_cast(mPreviousHeap) != reinterpret_cast(1); } uintptr_t mPreviousHeap; }; class FindContainHeapCache { public: FindContainHeapCache(); bool tryRemoveHeap(Heap* heap); // getHeap and setHeap probably exist too Atomic mHeap; }; } // namespace sead #endif // SEAD_HEAPMGR_H_