#pragma once class CPUThread; namespace vm { template class page_alloc_t { u32 m_addr; void dealloc() { if (m_addr) { vm::dealloc_verbose_nothrow(m_addr); } } public: page_alloc_t() : m_addr(0) { } page_alloc_t(vm::memory_location_t location, u32 count = 1) : m_addr(vm::alloc(sizeof32(T) * count, location, std::max(alignof32(T), 4096))) { } page_alloc_t(const page_alloc_t&) = delete; page_alloc_t(page_alloc_t&& other) : m_addr(other.m_addr) { other.m_addr = 0; } ~page_alloc_t() { this->dealloc(); } page_alloc_t& operator =(const page_alloc_t&) = delete; page_alloc_t& operator =(page_alloc_t&& other) { std::swap(m_addr, other.m_addr); return *this; } u32 get_addr() const { return m_addr; } }; template class stack_alloc_t { u32 m_addr; u32 m_old_pos; // TODO: use the stack to save it? CPUThread& m_thread; public: stack_alloc_t() = delete; stack_alloc_t(CPUThread& thread, u32 count = 1) : m_addr(vm::stack_push(thread, sizeof32(T) * count, alignof32(T), m_old_pos)) , m_thread(thread) { } ~stack_alloc_t() noexcept(false) // allow exceptions { if (!std::uncaught_exception()) // don't call during stack unwinding (it's pointless anyway) { vm::stack_pop(m_thread, m_addr, m_old_pos); } } stack_alloc_t(const stack_alloc_t&) = delete; stack_alloc_t(stack_alloc_t&&) = delete; stack_alloc_t& operator =(const stack_alloc_t&) = delete; stack_alloc_t& operator =(stack_alloc_t&&) = delete; u32 get_addr() const { return m_addr; } }; template class A> class _var_base final : public _ptr_base, private A { using _ptr_base::m_addr; using allocation = A; public: template, Args...>::value>> _var_base(Args&&... args) : allocation(std::forward(args)...) { m_addr = allocation::get_addr(); } }; template class A = vm::stack_alloc_t> using varl = _var_base, A>; template class A = vm::stack_alloc_t> using varb = _var_base, A>; namespace ps3 { template class A = vm::stack_alloc_t> using var = varb; } namespace psv { template class A = vm::stack_alloc_t> using var = varl; } }