Skip to content

Commit

Permalink
Improve allocator and UniquePtr to support arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
maximegmd committed Jan 23, 2021
1 parent b9467c2 commit fe0cd35
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 10 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ build/
.xmake
.vscode
vs20*
vsxmake*
88 changes: 81 additions & 7 deletions Code/core/include/Allocator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ namespace TiltedPhoques
virtual void Free(void* apData) noexcept = 0;
[[nodiscard]] virtual size_t Size(void* apData) noexcept = 0;

using TArraySizePrefix = size_t;

template<class T>
[[nodiscard]] T* New() noexcept
{
Expand All @@ -45,7 +47,28 @@ namespace TiltedPhoques
return nullptr;
}

template<class T, class... Args>
template<class T, std::enable_if_t<std::is_array_v<T>>* = nullptr>
[[nodiscard]] auto New(TArraySizePrefix aCount) noexcept
{
using TUnderlyingType = std::remove_all_extents_t<T>;

static_assert(alignof(T) <= alignof(details::default_align_t));

const auto pData = static_cast<uint8_t*>(Allocate(sizeof(TUnderlyingType) * aCount + sizeof(TArraySizePrefix)));
*reinterpret_cast<TArraySizePrefix*>(pData) = aCount;

auto pArray = reinterpret_cast<TUnderlyingType*>(pData + sizeof(TArraySizePrefix));

if (pData)
{
for (auto i = 0; i < aCount; ++i)
new (&pArray[i]) TUnderlyingType();
}

return pArray;
}

template<class T, std::enable_if_t<!std::is_array_v<T>>* = nullptr, class... Args>
[[nodiscard]] T* New(Args&&... args) noexcept
{
static_assert(alignof(T) <= alignof(details::default_align_t));
Expand All @@ -59,7 +82,28 @@ namespace TiltedPhoques
return nullptr;
}

template<class T>
template<class T, std::enable_if_t<std::is_array_v<T>>* = nullptr, class... Args>
[[nodiscard]] auto New(TArraySizePrefix aCount, Args&&... args) noexcept
{
using TUnderlyingType = std::remove_all_extents_t<T>;

static_assert(alignof(T) <= alignof(details::default_align_t));

const auto pData = static_cast<uint8_t*>(Allocate(sizeof(TUnderlyingType) * aCount + sizeof(TArraySizePrefix)));
*reinterpret_cast<TArraySizePrefix*>(pData) = aCount;

auto pArray = reinterpret_cast<TUnderlyingType*>(pData + sizeof(TArraySizePrefix));

if (pData)
{
for(auto i = 0; i < aCount; ++i)
new (&pArray[i]) TUnderlyingType(std::forward<Args>(args)...);
}

return pArray;
}

template<class T, std::enable_if_t<!std::is_array_v<T>>* = nullptr>
void Delete(T* apData) noexcept
{
if (apData == nullptr)
Expand All @@ -69,6 +113,23 @@ namespace TiltedPhoques
Free(apData);
}

template<class T, std::enable_if_t<std::is_array_v<T>>* = nullptr>
void Delete(T apData) noexcept
{
if (apData == nullptr)
return;

using TUnderlyingType = std::remove_all_extents_t<T>;

auto* pSize = reinterpret_cast<TArraySizePrefix*>(reinterpret_cast<uint8_t*>(apData) - 8);
for(auto i = 0ull; i < *pSize; ++i)
{
apData[i].~TUnderlyingType();
}

Free(pSize);
}

static void Push(Allocator* apAllocator) noexcept;
static void Push(Allocator& aAllocator) noexcept;
static Allocator* Pop() noexcept;
Expand All @@ -95,24 +156,24 @@ namespace TiltedPhoques
};

template<class T>
[[nodiscard]] T* New() noexcept
[[nodiscard]] auto New() noexcept
{
if constexpr (details::has_allocator<T>)
if constexpr (details::has_allocator<std::remove_all_extents_t<T>>)
return Allocator::Get()->New<T>();
else
return Allocator::GetDefault()->New<T>();
}

template<class T, class... Args>
[[nodiscard]] T* New(Args&&... args) noexcept
[[nodiscard]] auto New(Args&&... args) noexcept
{
if constexpr (details::has_allocator<T>)
if constexpr (details::has_allocator<std::remove_all_extents_t<T>>)
return Allocator::Get()->New<T>(std::forward<Args>(args)...);
else
return Allocator::GetDefault()->New<T>(std::forward<Args>(args)...);
}

template<class T>
template<class T, std::enable_if_t<!std::is_array_v<T>>* = nullptr>
void Delete(T* apEntry) noexcept
{
if constexpr (details::has_allocator<T>)
Expand All @@ -124,4 +185,17 @@ namespace TiltedPhoques
Allocator::GetDefault()->Delete(apEntry);
}
}

template<class T, std::enable_if_t<std::is_array_v<T>>* = nullptr>
void Delete(T apEntry) noexcept
{
if constexpr (details::has_allocator<std::remove_all_extents_t<T>>)
{
apEntry->GetAllocator()->Delete<T>(apEntry);
}
else
{
Allocator::GetDefault()->Delete<T>(apEntry);
}
}
}
19 changes: 16 additions & 3 deletions Code/core/include/Stl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,19 @@

namespace TiltedPhoques
{
namespace details
{
template<class T>
struct UniqueDeleter
{
void operator()(std::conditional_t<std::is_array_v<T>, T, T*> apData)
{
TiltedPhoques::Delete<T>(apData);
}
};
}


template<class T>
using Vector = std::vector<T, StlAllocator<T>>;

Expand All @@ -32,7 +45,7 @@ namespace TiltedPhoques
using Queue = std::queue<T, Deque<T>>;

template<class T>
using UniquePtr = std::unique_ptr<T, decltype(&Delete<T>)>;
using UniquePtr = std::unique_ptr<T, details::UniqueDeleter<T>>;

template<class T>
using SharedPtr = std::shared_ptr<T>;
Expand All @@ -45,13 +58,13 @@ namespace TiltedPhoques
{
auto pPtr = aPtr.release();

return UniquePtr<T>(reinterpret_cast<T*>(pPtr), &Delete<T>);
return UniquePtr<T>(reinterpret_cast<T*>(pPtr));
}

template<typename T, typename... Args>
auto MakeUnique(Args&& ... args)
{
return UniquePtr<T>(New<T>(std::forward<Args>(args)...), &Delete<T>);
return UniquePtr<T>(New<T>(std::forward<Args>(args)...));
}

template<typename T, typename... Args>
Expand Down
17 changes: 17 additions & 0 deletions Code/tests/src/core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,23 @@ TEST_CASE("Allocators allocate memory", "[core.allocators]")
allocator.Free(pData);
}
}

GIVEN("A default allocator")
{
WHEN("Allocating an array")
{
auto* pArray = New<uint8_t[]>(10);
pArray[0] = 4;

Delete<uint8_t[]>(pArray);
}

WHEN("Creating a UniquePtr containing an array")
{
UniquePtr<uint8_t[]> pArr = MakeUnique<uint8_t[]>(10, 2);
REQUIRE(pArr[0] == 2);
}
}
}

TEST_CASE("Making sure allocator stacks work corrently", "[core.allocator.stack]")
Expand Down
11 changes: 11 additions & 0 deletions xmake.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@ set_languages("cxx17")
add_requires("mimalloc", {config = {rltgenrandom = true }})
add_requires("catch2")

add_rules("mode.debug","mode.releasedbg", "mode.release")
add_rules("plugin.vsxmake.autoupdate")

if is_mode("release") then
add_ldflags("/LTCG", "/OPT:REF")
add_cxflags("/Ot", "/GL", "/Ob2", "/Oi", "/GS-")
add_defines("NDEBUG")

set_optimize("fastest")
end

target("TiltedCore")
set_kind("static")
add_files("Code/core/src/*.cpp")
Expand Down

0 comments on commit fe0cd35

Please sign in to comment.