Skip to content

Commit

Permalink
Merge pull request #7 from KredeGC/reference-allocator
Browse files Browse the repository at this point in the history
Reference allocator
  • Loading branch information
KredeGC committed Dec 2, 2023
2 parents 28b2817 + 776f1fc commit d31cea3
Show file tree
Hide file tree
Showing 20 changed files with 358 additions and 16 deletions.
11 changes: 8 additions & 3 deletions .github/workflows/dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,18 @@ jobs:
with:
version: "5.0.0-beta1"
- name: Install GCC
if: matrix.machine.os == 'ubuntu-latest' && matrix.machine.toolset == 'gcc'
if: matrix.machine.toolset == 'gcc'
run: sudo apt-get update && sudo apt-get install -y gcc g++
- name: Clang libstdc++ image workaround
if: matrix.machine.toolset == 'clang'
uses: mjp41/workaround8649@7929373c0fe5caf844d8115adccef39e3b5362e7
with:
os: ${{ matrix.machine.os }}
- name: Install Clang & LLVM
if: matrix.machine.os == 'ubuntu-latest' && matrix.machine.toolset == 'clang'
if: matrix.machine.toolset == 'clang'
run: sudo apt-get update && sudo apt-get install -y clang llvm lld
- name: Install msbuild to PATH
if: matrix.machine.os == 'windows-latest' && matrix.machine.toolset == 'msc'
if: matrix.machine.toolset == 'msc'
uses: microsoft/setup-msbuild@v1.1
- name: Run premake
run: premake5 ${{ matrix.machine.action }} --toolset=${{ matrix.machine.toolset }} --dialect=C++20
Expand Down
11 changes: 8 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,18 @@ jobs:
with:
version: "5.0.0-beta1"
- name: Install GCC
if: matrix.machine.os == 'ubuntu-latest' && matrix.machine.toolset == 'gcc'
if: matrix.machine.toolset == 'gcc'
run: sudo apt update && sudo apt install -y gcc g++
- name: Install Clang & LLVM
if: matrix.machine.os == 'ubuntu-latest' && matrix.machine.toolset == 'clang'
if: matrix.machine.toolset == 'clang'
run: sudo apt update && sudo apt install -y clang llvm lld
- name: Clang libstdc++ image workaround
if: matrix.machine.toolset == 'clang'
uses: mjp41/workaround8649@7929373c0fe5caf844d8115adccef39e3b5362e7
with:
os: ${{ matrix.machine.os }}
- name: Install msbuild to PATH
if: matrix.machine.os == 'windows-latest' && matrix.machine.toolset == 'msc'
if: matrix.machine.toolset == 'msc'
uses: microsoft/setup-msbuild@v1.1
- name: Run premake
run: premake5 ${{ matrix.machine.action }} --toolset=${{ matrix.machine.toolset }} --dialect=${{ matrix.dialect }}
Expand Down
7 changes: 7 additions & 0 deletions include/ktl/allocators/linear_allocator_fwd.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "reference_fwd.h"
#include "shared_fwd.h"
#include "threaded_fwd.h"
#include "type_allocator_fwd.h"
Expand All @@ -18,6 +19,12 @@ namespace ktl
template<typename T, size_t Size>
using type_linear_allocator = type_allocator<T, linear_allocator<Size>>;

/**
* @brief Shorthand for a typed, weak-reference linear allocator
*/
template<typename T, size_t Size>
using type_reference_linear_allocator = type_allocator<T, reference<linear_allocator<Size>>>;

/**
* @brief Shorthand for a typed, ref-counted linear allocator
*/
Expand Down
124 changes: 124 additions & 0 deletions include/ktl/allocators/reference.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#pragma once

#include "../utility/aligned_malloc.h"
#include "../utility/alignment.h"
#include "../utility/empty_base.h"
#include "../utility/meta.h"
#include "reference_fwd.h"

#include <memory>
#include <type_traits>

namespace ktl
{
template<typename Alloc>
class reference
{
private:
static_assert(detail::has_no_value_type_v<Alloc>, "Building on top of typed allocators is not allowed. Use allocators without a type");

public:
typedef typename detail::get_size_type_t<Alloc> size_type;

/**
* @brief Constructor for forwarding any arguments to the underlying allocator
*/
explicit reference(Alloc& alloc) noexcept:
m_Alloc(&alloc) {}

reference(const reference& other) noexcept :
m_Alloc(other.m_Alloc) {}

reference(reference&& other) noexcept :
m_Alloc(other.m_Alloc) {}

reference& operator=(const reference& rhs) noexcept
{
m_Alloc = rhs.m_Alloc;

return *this;
}

reference& operator=(reference&& rhs) noexcept
{
m_Alloc = rhs.m_Alloc;

return *this;
}

bool operator==(const reference& rhs) const
noexcept(detail::has_nothrow_equal_v<Alloc>)
{
return m_Alloc == rhs.m_Alloc && *m_Alloc == *rhs.m_Alloc;
}

bool operator!=(const reference& rhs) const
noexcept(detail::has_nothrow_not_equal_v<Alloc>)
{
return m_Alloc != rhs.m_Alloc || *m_Alloc != *rhs.m_Alloc;
}

#pragma region Allocation
void* allocate(size_t n)
noexcept(detail::has_nothrow_allocate_v<Alloc>)
{
return m_Alloc->allocate(n);
}

void deallocate(void* p, size_t n)
noexcept(detail::has_nothrow_deallocate_v<Alloc>)
{
m_Alloc->deallocate(p, n);
}
#pragma endregion

#pragma region Construction
template<typename T, typename... Args>
typename std::enable_if<detail::has_construct_v<Alloc, T*, Args...>, void>::type
construct(T* p, Args&&... args)
noexcept(detail::has_nothrow_construct_v<Alloc, T*, Args...>)
{
m_Alloc->construct(p, std::forward<Args>(args)...);
}

template<typename T>
typename std::enable_if<detail::has_destroy_v<Alloc, T*>, void>::type
destroy(T* p)
noexcept(detail::has_nothrow_destroy_v<Alloc, T*>)
{
m_Alloc->destroy(p);
}
#pragma endregion

#pragma region Utility
template<typename A = Alloc>
typename std::enable_if<detail::has_max_size_v<A>, size_type>::type
max_size() const
noexcept(detail::has_nothrow_max_size_v<A>)
{
return m_Alloc->max_size();
}

template<typename A = Alloc>
typename std::enable_if<detail::has_owns_v<A>, bool>::type
owns(void* p) const
noexcept(detail::has_nothrow_owns_v<A>)
{
return m_Alloc->owns(p);
}
#pragma endregion

Alloc& get_allocator() noexcept
{
return *m_Alloc;
}

const Alloc& get_allocator() const noexcept
{
return *m_Alloc;
}

private:
Alloc* m_Alloc;
};
}
10 changes: 10 additions & 0 deletions include/ktl/allocators/reference_fwd.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

#include <cstddef>

namespace ktl
{
// Wrapper class for making allocator ref-counted
template<typename Alloc>
class reference;
}
11 changes: 9 additions & 2 deletions include/ktl/allocators/segragator_fwd.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "reference_fwd.h"
#include "shared_fwd.h"
#include "threaded_fwd.h"
#include "type_allocator_fwd.h"
Expand Down Expand Up @@ -86,13 +87,19 @@ namespace ktl
using type_segragator_allocator = type_allocator<T, segragator<Threshold, P, F>>;

/**
* @brief Shorthand for a typed, ref-counted freelist allocator
* @brief Shorthand for a typed, weak-reference segragator allocator
*/
template<typename T, size_t Threshold, typename P, typename F>
using type_reference_segragator_allocator = type_allocator<T, reference<segragator<Threshold, P, F>>>;

/**
* @brief Shorthand for a typed, ref-counted segragator allocator
*/
template<typename T, size_t Threshold, typename P, typename F>
using type_shared_segragator_allocator = type_allocator<T, shared<segragator<Threshold, P, F>>>;

/**
* @brief Shorthand for a typed, thread-safe, ref-counted freelist allocator
* @brief Shorthand for a typed, thread-safe, ref-counted segragator allocator
*/
template<typename T, size_t Threshold, typename P, typename F>
using type_threaded_segragator_allocator = type_allocator<T, threaded<segragator<Threshold, P, F>>>;
Expand Down
3 changes: 2 additions & 1 deletion include/ktl/containers/packed_ptr_fwd.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#pragma once

#include <cstddef>
#include <type_traits>

namespace ktl
{
template<typename PtrT, size_t Bits, size_t Alignment = alignof(PtrT)>
template<typename PtrT, size_t Bits, size_t Alignment = alignof(std::remove_pointer_t<PtrT>)>
class packed_ptr;
}
1 change: 1 addition & 0 deletions include/ktl/ktl.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "allocators/mallocator.h"
#include "allocators/null_allocator.h"
#include "allocators/overflow.h"
#include "allocators/reference.h"
#include "allocators/segragator.h"
#include "allocators/shared.h"
#include "allocators/stack_allocator.h"
Expand Down
1 change: 1 addition & 0 deletions include/ktl/ktl_alloc_fwd.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "allocators/linear_allocator_fwd.h"
#include "allocators/mallocator_fwd.h"
#include "allocators/overflow_fwd.h"
#include "allocators/reference_fwd.h"
#include "allocators/segragator_fwd.h"
#include "allocators/shared_fwd.h"
#include "allocators/stack_allocator_fwd.h"
Expand Down
51 changes: 50 additions & 1 deletion src/shared/allocation_utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,57 @@

namespace ktl::test
{
template<size_t... Is, typename Alloc>
void assert_raw_allocate_deallocate(Alloc& allocator)
{
constexpr size_t amount = sizeof...(Is);

size_t sizes[amount]{ Is... };
void* ptrs[amount]{ nullptr };

std::shuffle(sizes, sizes + amount, random_generator);

// Allocate all with random sizes
for (size_t i = 0; i < amount; i++)
{
void* valid_ptr = allocator.allocate(sizes[i]);
KTL_TEST_ASSERT(valid_ptr);
ptrs[i] = valid_ptr;
}

// Assert that they are all unique
for (size_t i = 1; i < amount; i++)
{
bool ptr_not_equal = ptrs[i - 1] != ptrs[i];
KTL_TEST_ASSERT(ptr_not_equal);
}

// Deallocate the first half
for (size_t i = 0; i < amount / 2; i++)
allocator.deallocate(ptrs[i], sizes[i]);

// Allocate the first half again
for (size_t i = 0; i < amount / 2; i++)
{
void* valid_ptr = allocator.allocate(sizes[i]);
KTL_TEST_ASSERT(valid_ptr);
ptrs[i] = valid_ptr;
}

// Assert that they are all still unique
for (size_t i = 1; i < amount; i++)
{
bool ptr_not_equal = ptrs[i - 1] != ptrs[i];
KTL_TEST_ASSERT(ptr_not_equal);
}

// Deallocate everything
for (size_t i = 0; i < amount; i++)
allocator.deallocate(ptrs[i], sizes[i]);
}

template<typename T, typename Alloc>
static T* assert_allocate(Alloc& alloc, const T& value)
T* assert_allocate(Alloc& alloc, const T& value)
{
T* ptr = std::allocator_traits<Alloc>::allocate(alloc, 1);

Expand Down
6 changes: 6 additions & 0 deletions src/test/cascading_allocator_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@

namespace ktl::test::cascading_allocator
{
KTL_ADD_TEST(test_cascading_linear_raw_allocate)
{
cascading<linear_allocator<32>> alloc;
assert_raw_allocate_deallocate<2, 4, 8, 16, 24, 32>(alloc);
}

KTL_ADD_TEST(test_cascading_linear_unordered_double)
{
type_cascading_allocator<double, linear_allocator<32>> alloc;
Expand Down
8 changes: 8 additions & 0 deletions src/test/fallback_allocator_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ namespace ktl::test::fallback_allocator
static_assert(!std::is_same_v<Alloc3, Alloc5>, "The allocator types shouldn't match");
}

KTL_ADD_TEST(test_cascading_linear_raw_allocate)
{
stack<16> primaryStack;
stack<4096> fallbackStack;
fallback<stack_allocator<16>, stack_allocator<4096>> alloc(primaryStack, fallbackStack);
assert_raw_allocate_deallocate<2, 4, 8, 16, 32, 64>(alloc);
}

KTL_ADD_TEST(test_fallback_stack_stack_unordered_double)
{
stack<16> primaryStack;
Expand Down
7 changes: 7 additions & 0 deletions src/test/freelist_allocator_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@

namespace ktl::test::freelist_allocator
{
KTL_ADD_TEST(test_freelist_stack_allocator_raw_allocate)
{
stack<4096> block;
freelist<0, 8, stack_allocator<4096>> alloc(block);
assert_raw_allocate_deallocate<1, 2, 4, 4, 8, 8>(alloc);
}

KTL_ADD_TEST(test_freelist_stack_allocator_unordered_double)
{
stack<4096> block;
Expand Down
6 changes: 6 additions & 0 deletions src/test/linear_allocator_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@

namespace ktl::test::linear_allocator
{
KTL_ADD_TEST(test_linear_raw_allocate)
{
ktl::linear_allocator<4096> alloc;
assert_raw_allocate_deallocate<2, 4, 8, 16, 32, 64>(alloc);
}

KTL_ADD_TEST(test_linear_allocator_unordered_double)
{
type_linear_allocator<double, 4096> alloc;
Expand Down
6 changes: 6 additions & 0 deletions src/test/mallocator_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@

namespace ktl::test::mallocator
{
KTL_ADD_TEST(test_mallocator_raw_allocate)
{
ktl::mallocator alloc;
assert_raw_allocate_deallocate<4, 8, 16, 32, 64, 128>(alloc);
}

KTL_ADD_TEST(test_mallocator_unordered_double)
{
type_mallocator<double> alloc;
Expand Down
Loading

0 comments on commit d31cea3

Please sign in to comment.