KTL
Loading...
Searching...
No Matches
freelist.h
Go to the documentation of this file.
1#pragma once
2
3#include "../utility/assert.h"
4#include "../utility/empty_base.h"
5#include "../utility/meta.h"
6#include "../utility/source_location.h"
7#include "freelist_fwd.h"
8#include "type_allocator.h"
9
10#include <cstddef>
11#include <memory>
12#include <type_traits>
13
14namespace ktl
15{
24 template<size_t Min, size_t Max, typename Alloc>
26 {
27 private:
28 static_assert(detail::has_no_value_type_v<Alloc>, "Building on top of typed allocators is not allowed. Use allocators without a type");
29 static_assert(Max >= sizeof(void*), "The freelist allocator requires a Max of at least the size of a pointer");
30
31 public:
33
34 private:
35 struct link
36 {
37 link* Next;
38 };
39
40 public:
41 template<typename A = Alloc>
43 noexcept(std::is_nothrow_default_constructible_v<A>) :
44 m_Alloc(),
45 m_Free(nullptr) {}
46
50 template<typename... Args,
51 typename = std::enable_if_t<
52 std::is_constructible_v<Alloc, Args...>>>
53 explicit freelist(Args&&... args)
54 noexcept(std::is_nothrow_constructible_v<Alloc, Args...>) :
55 m_Alloc(std::forward<Args>(args)...),
56 m_Free(nullptr) {}
57
58 freelist(const freelist&) = delete;
59
61 noexcept(std::is_nothrow_move_constructible_v<Alloc>) :
62 m_Alloc(std::move(other.m_Alloc)),
63 m_Free(other.m_Free)
64 {
65 // Moving raw allocators in use is undefined
66 KTL_ASSERT(m_Alloc == other.m_Alloc || other.m_Free == nullptr);
67
68 other.m_Free = nullptr;
69 }
70
72 {
73 release();
74 }
75
76 freelist& operator=(const freelist&) = delete;
77
79 noexcept(std::is_nothrow_move_assignable_v<Alloc>)
80 {
81 release();
82
83 m_Alloc = std::move(rhs.m_Alloc);
84 m_Free = rhs.m_Free;
85
86 // Moving raw allocators in use is undefined
87 KTL_ASSERT(m_Alloc == rhs.m_Alloc || rhs.m_Free == nullptr);
88
89 rhs.m_Free = nullptr;
90
91 return *this;
92 }
93
94 bool operator==(const freelist& rhs) const
96 {
97 return m_Alloc == rhs.m_Alloc && m_Free == rhs.m_Free;
98 }
99
100 bool operator!=(const freelist& rhs) const
102 {
103 return m_Alloc != rhs.m_Alloc || m_Free != rhs.m_Free;
104 }
105
106#pragma region Allocation
114 void* allocate(size_type n, const source_location source = KTL_SOURCE())
115 noexcept(detail::has_nothrow_allocate_v<Alloc>)
116 {
117 if (n > Min && n <= Max)
118 {
119 link* next = m_Free;
120 if (next)
121 {
122 m_Free = next->Next;
123 return std::launder(next);
124 }
125
126 return detail::allocate(m_Alloc, Max, source);
127 }
128
129 return nullptr;
130 }
131
138 void deallocate(void* p, size_type n)
140 {
141 KTL_ASSERT(p != nullptr);
142
143 if (n > Min && n <= Max && p)
144 {
145 link* next = std::launder(reinterpret_cast<link*>(p));
146 next->Next = m_Free;
147 m_Free = next;
148 }
149 }
150#pragma endregion
151
152#pragma region Construction
160 template<typename T, typename... Args>
161 typename std::enable_if<detail::has_construct_v<Alloc, T*, Args...>, void>::type
162 construct(T* p, Args&&... args)
163 noexcept(detail::has_nothrow_construct_v<Alloc, T*, Args...>)
164 {
165 m_Alloc.construct(p, std::forward<Args>(args)...);
166 }
167
173 template<typename T>
174 typename std::enable_if<detail::has_destroy_v<Alloc, T*>, void>::type
177 {
178 m_Alloc.destroy(p);
179 }
180#pragma endregion
181
182#pragma region Utility
188 template<typename A = Alloc>
189 typename std::enable_if<detail::has_max_size_v<A>, size_type>::type
190 max_size() const
191 noexcept(detail::has_nothrow_max_size_v<A>)
192 {
193 return m_Alloc.max_size();
194 }
195
202 template<typename A = Alloc>
203 typename std::enable_if<detail::has_owns_v<A>, bool>::type
204 owns(void* p) const
206 {
207 return m_Alloc.owns(p);
208 }
209#pragma endregion
210
215 Alloc& get_allocator() noexcept
216 {
217 return m_Alloc;
218 }
219
224 const Alloc& get_allocator() const noexcept
225 {
226 return m_Alloc;
227 }
228
229 private:
230 void release()
231 noexcept(detail::has_nothrow_deallocate_v<Alloc>)
232 {
233 link* next = m_Free;
234 while (next)
235 {
236 link* prev = next;
237 next = next->Next;
238 m_Alloc.deallocate(prev, Max);
239 }
240 }
241
242 private:
243 KTL_EMPTY_BASE Alloc m_Alloc;
244 link* m_Free;
245 };
246}
#define KTL_ASSERT(x)
Definition assert.h:17
An allocator which allocates using its underlying allocator. Only allocates if the requested size is ...
Definition freelist.h:26
freelist & operator=(const freelist &)=delete
std::enable_if< detail::has_max_size_v< A >, size_type >::type max_size() const noexcept(detail::has_nothrow_max_size_v< A >)
Returns the maximum size that an allocation can be.
Definition freelist.h:190
std::enable_if< detail::has_owns_v< A >, bool >::type owns(void *p) const noexcept(detail::has_nothrow_owns_v< A >)
Returns whether or not the allocator owns the given location in memory.
Definition freelist.h:204
void deallocate(void *p, size_type n) noexcept(detail::has_nothrow_deallocate_v< Alloc >)
Attempts to deallocate the memory at location p.
Definition freelist.h:138
std::enable_if< detail::has_destroy_v< Alloc, T * >, void >::type destroy(T *p) noexcept(detail::has_nothrow_destroy_v< Alloc, T * >)
Destructs an object of T at the given location.
Definition freelist.h:175
freelist() noexcept(std::is_nothrow_default_constructible_v< A >)
Definition freelist.h:42
freelist(freelist &&other) noexcept(std::is_nothrow_move_constructible_v< Alloc >)
Definition freelist.h:60
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... >)
Constructs an object of T with the given ...args at the given location.
Definition freelist.h:162
~freelist()
Definition freelist.h:71
bool operator==(const freelist &rhs) const noexcept(detail::has_nothrow_equal_v< Alloc >)
Definition freelist.h:94
freelist(const freelist &)=delete
freelist & operator=(freelist &&rhs) noexcept(std::is_nothrow_move_assignable_v< Alloc >)
Definition freelist.h:78
freelist(Args &&... args) noexcept(std::is_nothrow_constructible_v< Alloc, Args... >)
Constructor for forwarding any arguments to the underlying allocator.
Definition freelist.h:53
const Alloc & get_allocator() const noexcept
Returns a const reference to the underlying allocator.
Definition freelist.h:224
bool operator!=(const freelist &rhs) const noexcept(detail::has_nothrow_not_equal_v< Alloc >)
Definition freelist.h:100
Alloc & get_allocator() noexcept
Returns a reference to the underlying allocator.
Definition freelist.h:215
detail::get_size_type_t< Alloc > size_type
Definition freelist.h:32
void * allocate(size_type n, const source_location source=KTL_SOURCE()) noexcept(detail::has_nothrow_allocate_v< Alloc >)
Attempts to allocate a chunk of memory defined by n. Will use previous allocations that were meant to...
Definition freelist.h:114
#define KTL_EMPTY_BASE
Definition empty_base.h:6
typename get_size_type< Alloc, void >::type get_size_type_t
Definition meta.h:33
constexpr bool has_nothrow_construct_v
Definition meta.h:123
constexpr bool has_construct_v
Definition meta.h:53
void * allocate(Alloc &alloc, size_t n, const source_location source) noexcept(false)
Definition meta.h:161
constexpr bool has_no_value_type_v
Definition meta.h:17
Definition cascading.h:16
#define KTL_SOURCE()
Definition source_location.h:11
Definition source_location.h:19