ArenaMemoryResource.cpp pma/resources/ArenaMemoryResource.h pma/ScopedPtr.h pma/TypeDefs.h cassert cmath cstddef cstdint pma::ArenaMemoryResource::Impl pma::ArenaMemoryResource::Impl::Arena pma //CopyrightEpicGames,Inc.AllRightsReserved. #include"pma/resources/ArenaMemoryResource.h" #include"pma/ScopedPtr.h" #include"pma/TypeDefs.h" #include<cassert> #include<cmath> #include<cstddef> #include<cstdint> namespacepma{ inlinestd::uintptr_talignAddress(std::uintptr_taddress,std::size_talignment){ conststd::size_tmask=alignment-1ul; assert((alignment&mask)==0ul); return(address+mask)&~mask; } template<typenameT> inlineT*alignPointer(T*ptr,std::size_talignment){ conststd::uintptr_taddress=reinterpret_cast<std::uintptr_t>(ptr); conststd::uintptr_taligned=alignAddress(address,alignment); returnreinterpret_cast<T*>(aligned); } classArenaMemoryResource::Impl{ public: staticImpl*create(std::size_tinitialSize_,std::size_tregionSize_,floatgrowthFactor_,MemoryResource*upstream_){ PolyAllocator<Impl>alloc{upstream_}; returnalloc.newObject(initialSize_,regionSize_,growthFactor_,upstream_); } staticvoiddestroy(Impl*instance){ PolyAllocator<Impl>alloc{instance->upstream}; alloc.deleteObject(instance); } Impl(std::size_tinitialSize_,std::size_tregionSize_,floatgrowthFactor_,MemoryResource*upstream_): arenas{upstream_}, regionSize{regionSize_}, growthFactor{growthFactor_}, upstream{upstream_}, ptr{nullptr}{ assert(upstream!=nullptr); allocateArena(initialSize_); } ~Impl(){ for(autoit=arenas.rbegin();it!=arenas.rend();++it){ upstream->deallocate(it->memory,it->size,alignof(std::max_align_t)); } arenas.clear(); } Impl(constImpl&)=delete; Impl&operator=(constImpl&)=delete; Impl(Impl&&)=delete; Impl&operator=(Impl&&)=delete; void*allocate(std::size_tsize,std::size_talignment){ autopAligned=alignPointer(ptr,alignment); //Iftheold(current)pointerequalsthealignedpointer,itwasalready //adheringtothegivenalignmentrequirement. constautoalignmentCorrection=static_cast<std::size_t>(static_cast<char*>(pAligned)-static_cast<char*>(ptr)); constautoneededSize=size+alignmentCorrection; //Checkifcurrentarenahasenoughfreespace assert(!arenas.empty()); constauto&currentArena=arenas.back(); if((static_cast<char*>(ptr)+neededSize)>(static_cast<char*>(currentArena.memory)+currentArena.size)){ //Notenoughspaceincurrentarena,allocateanadditionalone(honoringgrowthfactor), //unlessthisisthefirstadditionalregionthat'sneeded,inwhichcaseit'ssizewill //beexactly`regionSize` constboolisFirstAdditional=(arenas.size()==1ul); conststd::size_tnewArenaSize= (isFirstAdditional?regionSize:static_cast<std::size_t>(std::lroundf(static_cast<float>(currentArena.size) *growthFactor))); allocateArena(newArenaSize); //Retryallocationrelyingonnewlyallocatedarena returnallocate(size,alignment); } ptr=static_cast<void*>(static_cast<char*>(ptr)+neededSize); returnpAligned; } MemoryResource*getUpstreamMemoryResource()const{ returnupstream; } private: voidallocateArena(std::size_tsize){ if(!arenas.empty()&&(arenas.back().memory==ptr)){ //Noallocationhappenedinthearenawhatsoever,andthefirstallocationwas //immediatelylargerthanthearena'ssize,thusit'sanunusedarena,andshould //bediscardedimmediately. autounusedArena=arenas.back(); arenas.pop_back(); upstream->deallocate(unusedArena.memory,unusedArena.size,alignof(std::max_align_t)); } arenas.push_back({upstream->allocate(size,alignof(std::max_align_t)),size}); ptr=arenas.back().memory; } private: structArena{ void*memory; std::size_tsize; }; pma::List<Arena>arenas; std::size_tregionSize; floatgrowthFactor; MemoryResource*upstream; void*ptr; }; ArenaMemoryResource::ArenaMemoryResource(std::size_tinitialSize, std::size_tregionSize, floatgrowthFactor, MemoryResource*upstream): pImpl{makeScoped<Impl,FactoryCreate,FactoryDestroy>(initialSize,regionSize,growthFactor,upstream)}{ } ArenaMemoryResource::ArenaMemoryResource(std::size_tregionSize,floatgrowthFactor,MemoryResource*upstream): ArenaMemoryResource{regionSize,regionSize,growthFactor,upstream}{ } ArenaMemoryResource::ArenaMemoryResource(std::size_tregionSize,MemoryResource*upstream): ArenaMemoryResource{regionSize,regionSize,1.0f,upstream}{ } ArenaMemoryResource::~ArenaMemoryResource()=default; ArenaMemoryResource::ArenaMemoryResource(ArenaMemoryResource&&)=default; ArenaMemoryResource&ArenaMemoryResource::operator=(ArenaMemoryResource&&)=default; void*ArenaMemoryResource::allocate(std::size_tsize,std::size_talignment){ returnpImpl->allocate(size,alignment); } voidArenaMemoryResource::deallocate(void*/*unused*/,std::size_t/*unused*/,std::size_t/*unused*/){ //No-op } MemoryResource*ArenaMemoryResource::getUpstreamMemoryResource()const{ returnpImpl->getUpstreamMemoryResource(); } }//namespacepma