carb/Memory.h
File members: carb/Memory.h
// Copyright (c) 2021-2024, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//
#pragma once
#include "Defines.h"
#include "Types.h"
#include "cpp/Bit.h"
#include "detail/DeferredLoad.h"
#if CARB_REQUIRE_LINKED
CARB_DYNAMICLINK void* carbReallocate(void* p, size_t size, size_t align);
#else
CARB_DYNAMICLINK void* carbReallocate(void* p, size_t size, size_t align) CARB_ATTRIBUTE(weak);
#endif
namespace carb
{
namespace detail
{
CARB_DETAIL_DEFINE_DEFERRED_LOAD(getCarbReallocate, carbReallocate, (void* (*)(void*, size_t, size_t)));
} // namespace detail
inline void* allocate(size_t size, size_t align = 0) noexcept
{
if (auto impl = detail::getCarbReallocate())
return impl(nullptr, size, align);
else
return nullptr;
}
inline void deallocate(void* p) noexcept
{
if (p)
{
if (auto impl = detail::getCarbReallocate())
impl(p, 0, 0);
}
}
inline void* reallocate(void* p, size_t size, size_t align = 0) noexcept
{
if (auto impl = detail::getCarbReallocate())
return impl(p, size, align);
else
return p;
}
template <class T, class Align = std::integral_constant<size_t, 0>>
class Allocator
{
public:
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using void_pointer = void*;
using const_void_pointer = const void*;
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
static_assert(!Align::value || ::carb::cpp::has_single_bit(Align::value), "Must be a power of two");
constexpr static size_t alignment = Align::value;
template <class U>
struct rebind
{
using other = Allocator<U, Align>;
};
constexpr Allocator() noexcept = default;
constexpr Allocator(const Allocator&) noexcept = default;
constexpr Allocator& operator=(const Allocator&) noexcept = default;
template <class U, class UAlign>
constexpr Allocator(const Allocator<U, UAlign>& other) noexcept
{
CARB_UNUSED(other);
}
template <class U, class UAlign>
constexpr Allocator& operator=(const Allocator<U, UAlign>& other) noexcept
{
CARB_UNUSED(other);
return *this;
}
~Allocator() = default;
CARB_NODISCARD constexpr bool operator==(const Allocator& other) const noexcept
{
CARB_UNUSED(other);
return true;
}
CARB_NODISCARD constexpr bool operator!=(const Allocator& other) const noexcept
{
CARB_UNUSED(other);
return false;
}
CARB_NODISCARD pointer allocate(size_type n = 1)
{
auto align = ::carb_max(+alignment, alignof(T));
auto p = ::carb::allocate(sizeof(T) * n, align);
#if CARB_EXCEPTIONS_ENABLED
if (!p)
{
throw std::bad_alloc();
}
#endif
return pointer(p);
}
CARB_NODISCARD pointer allocate(size_type n, const_void_pointer p)
{
return p ? pointer(p) : allocate(n);
}
void deallocate(pointer p, size_type n) noexcept /*strengthened*/
{
CARB_UNUSED(n);
::carb::deallocate(p);
}
CARB_NODISCARD size_type max_size() const noexcept
{
return size_type(-1);
}
template <class X, class... Args>
void construct(X* const p, Args&&... args)
{
::new (const_cast<void*>(static_cast<const volatile void*>(p))) X(std::forward<Args>(args)...);
}
template <class X>
void destroy(X* const p)
{
p->~X();
}
};
template <size_t Align = 0>
class UseCarbAllocatorAligned
{
public:
constexpr static size_t alignment = Align;
void* operator new(std::size_t count)
{
return carb::allocate(count, alignment);
}
void* operator new[](std::size_t count)
{
return carb::allocate(count, alignment);
}
void operator delete(void* ptr)
{
carb::deallocate(ptr);
}
void operator delete[](void* ptr)
{
carb::deallocate(ptr);
}
#if CARB_HAS_CPP17
void* operator new(std::size_t count, std::align_val_t al)
{
return carb::allocate(count, ::carb_max(alignment, size_t(al)));
}
void* operator new[](std::size_t count, std::align_val_t al)
{
return carb::allocate(count, ::carb_max(alignment, size_t(al)));
}
void operator delete(void* ptr, std::align_val_t al)
{
CARB_UNUSED(al);
carb::deallocate(ptr);
}
void operator delete[](void* ptr, std::align_val_t al)
{
CARB_UNUSED(al);
carb::deallocate(ptr);
}
#endif
};
template <class T>
class Deleter
{
public:
void operator()(T* p) noexcept
{
p->~T();
carb::deallocate(p);
}
};
using UseCarbAllocator = UseCarbAllocatorAligned<>;
} // namespace carb