#ifndef NEW_INL_H_ #error "Direct inclusion of this file is not allowed, include new.h" // For the sake of sane code completion. #include "new.h" #endif #include namespace NYT { //////////////////////////////////////////////////////////////////////////////// struct TRefCountedCookieHolder { #ifdef YT_ENABLE_REF_COUNTED_TRACKING TRefCountedTypeCookie Cookie = NullRefCountedTypeCookie; void InitializeTracking(TRefCountedTypeCookie cookie) { YT_ASSERT(Cookie == NullRefCountedTypeCookie); Cookie = cookie; TRefCountedTrackerFacade::AllocateInstance(Cookie); } ~TRefCountedCookieHolder() { if (Cookie != NullRefCountedTypeCookie) { TRefCountedTrackerFacade::FreeInstance(Cookie); } } #endif }; template struct TRefCountedWrapper final : public T , public TRefTracked { template explicit TRefCountedWrapper(TArgs&&... args) : T(std::forward(args)...) { } ~TRefCountedWrapper() = default; void DestroyRefCounted() override { T::DestroyRefCountedImpl(this); } }; template class TRefCountedWrapperWithDeleter final : public T , public TRefTracked { public: template explicit TRefCountedWrapperWithDeleter(const TDeleter& deleter, TArgs&&... args) : T(std::forward(args)...) , Deleter_(deleter) { } ~TRefCountedWrapperWithDeleter() = default; void DestroyRefCounted() override { Deleter_(this); } private: TDeleter Deleter_; }; template struct TRefCountedWrapperWithCookie final : public T , public TRefCountedCookieHolder { template explicit TRefCountedWrapperWithCookie(TArgs&&... args) : T(std::forward(args)...) { } ~TRefCountedWrapperWithCookie() = default; void DestroyRefCounted() override { T::DestroyRefCountedImpl(this); } }; namespace NDetail { Y_FORCE_INLINE void* AllignedMalloc(size_t size, size_t allignment) { #ifdef _win_ return ::_aligned_malloc(size, allignment); #else void* ptr = nullptr; ::posix_memalign(&ptr, allignment, size); return ptr; #endif } template Y_FORCE_INLINE void CustomInitialize(Args... args) { Y_UNUSED(args...); } template Y_FORCE_INLINE auto CustomInitialize(T* ptr) -> decltype(&T::InitializeRefCounted, void()) { ptr->InitializeRefCounted(); } template Y_FORCE_INLINE T* NewEpilogue(void* ptr, As&& ... args) { try { auto* instance = static_cast(ptr); new (instance) T(std::forward(args)...); CustomInitialize(instance); return instance; } catch (const std::exception& ex) { // Do not forget to free the memory. TFreeMemory::Do(ptr); throw; } } template > struct TConstructHelper { static constexpr size_t RefCounterSpace = (sizeof(TRefCounter) + alignof(T) - 1) & ~(alignof(T) - 1); static constexpr size_t RefCounterOffset = RefCounterSpace - sizeof(TRefCounter); static constexpr size_t Size = RefCounterSpace + sizeof(T); static constexpr size_t Alignment = alignof(T); template Y_FORCE_INLINE static T* Construct(void* ptr, As&&... args) { auto* refCounter = reinterpret_cast(static_cast(ptr) + RefCounterOffset); new (refCounter) TRefCounter(); auto* object = reinterpret_cast(refCounter + 1); if constexpr (std::is_constructible_v) { new(object) T(std::forward(args)...); } else { new(object) T{std::forward(args)...}; } CustomInitialize(object); return object; } }; template struct TConstructHelper { static constexpr size_t Size = sizeof(TRefCountedWrapper); static constexpr size_t Alignment = alignof(TRefCountedWrapper); template Y_FORCE_INLINE static TRefCountedWrapper* Construct(void* ptr, As&&... args) { using TDerived = TRefCountedWrapper; auto* object = new(static_cast(ptr)) TDerived(std::forward(args)...); CustomInitialize(object); return object; } }; template Y_FORCE_INLINE TIntrusivePtr SafeConstruct(void* ptr, As&&... args) { try { auto* instance = TConstructHelper::Construct(ptr, std::forward(args)...); return TIntrusivePtr(instance, false); } catch (const std::exception& ex) { // Do not forget to free the memory. TFreeMemory::Do(ptr); throw; } } template void* AllocateConstSizeAligned() { if (Alignment <= 16) { return NYTAlloc::AllocateConstSize(); } else { return AllignedMalloc(Size, Alignment); } } } // namespace NDetail //////////////////////////////////////////////////////////////////////////////// template Y_FORCE_INLINE TIntrusivePtr New( As&&... args) { void* ptr = NDetail::AllocateConstSizeAligned< NDetail::TConstructHelper::Size, NDetail::TConstructHelper::Alignment>(); return NDetail::SafeConstruct(ptr, std::forward(args)...); } template Y_FORCE_INLINE TIntrusivePtr New( typename T::TAllocator* allocator, As&&... args) { auto* ptr = allocator->Allocate(NDetail::TConstructHelper::Size); if (!ptr) { return nullptr; } return NDetail::SafeConstruct(ptr, std::forward(args)...); } //////////////////////////////////////////////////////////////////////////////// template Y_FORCE_INLINE TIntrusivePtr NewWithExtraSpace( size_t extraSpaceSize, As&&... args) { auto totalSize = NYT::NDetail::TConstructHelper::Size + extraSpaceSize; void* ptr = nullptr; if (NYT::NDetail::TConstructHelper::Alignment <= 16) { ptr = NYTAlloc::Allocate(totalSize); } else { ptr = NYT::NDetail::AllignedMalloc(totalSize, NYT::NDetail::TConstructHelper::Alignment); } return NYT::NDetail::SafeConstruct(ptr, std::forward(args)...); } template Y_FORCE_INLINE TIntrusivePtr NewWithExtraSpace( typename T::TAllocator* allocator, size_t extraSpaceSize, As&&... args) { auto totalSize = NYT::NDetail::TConstructHelper::Size + extraSpaceSize; auto* ptr = allocator->Allocate(totalSize); if (!ptr) { return nullptr; } return NYT::NDetail::SafeConstruct(ptr, std::forward(args)...); } //////////////////////////////////////////////////////////////////////////////// // Support for polymorphic only template Y_FORCE_INLINE TIntrusivePtr NewWithDelete(const TDeleter& deleter, As&&... args) { using TWrapper = TRefCountedWrapperWithDeleter; void* ptr = NDetail::AllocateConstSizeAligned(); auto* instance = NDetail::NewEpilogue( ptr, deleter, std::forward(args)...); return TIntrusivePtr(instance, false); } //////////////////////////////////////////////////////////////////////////////// template Y_FORCE_INLINE TIntrusivePtr NewWithLocation( const TSourceLocation& location, As&&... args) { using TWrapper = TRefCountedWrapperWithCookie; void* ptr = NDetail::AllocateConstSizeAligned(); auto* instance = NDetail::NewEpilogue(ptr, std::forward(args)...); #ifdef YT_ENABLE_REF_COUNTED_TRACKING instance->InitializeTracking(GetRefCountedTypeCookieWithLocation(location)); #else Y_UNUSED(location); #endif return TIntrusivePtr(instance, false); } //////////////////////////////////////////////////////////////////////////////// template const void* TWithExtraSpace::GetExtraSpacePtr() const { return static_cast(this) + 1; } template void* TWithExtraSpace::GetExtraSpacePtr() { return static_cast(this) + 1; } //////////////////////////////////////////////////////////////////////////////// } // namespace NYT