-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathallocator.h
More file actions
310 lines (239 loc) · 9 KB
/
Copy pathallocator.h
File metadata and controls
310 lines (239 loc) · 9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
//
// Created by oem on 23.05.18.
//
#pragma once
#include <type_traits>
#include <memory>
#include <stack>
#include <list>
#include <vector>
#include <iostream>
namespace kkk
{
template<typename T>
struct FixedAllocator {
public:
FixedAllocator();
~FixedAllocator();
using element_type = T;
using void_pointer = void*;
using size_type = std::size_t;
void_pointer allocate();
void deallocate(void_pointer);
private:
size_type size_block;
size_type num_block;
struct block {
struct block *prev = nullptr, *next = nullptr;
};
using stack_pool = void**;
stack_pool pools;
size_type size_pool;
size_type max_size_pool;
using block_pointer = struct block*;
block_pointer head_free_blocks;
block_pointer head_allocated_blocks;
void add_pool();
void pop_front(block_pointer& head) {
head = head->next;
if (head != nullptr) {
head->prev = nullptr;
}
}
void push_front(block_pointer& head, block_pointer& block) {
block->prev = nullptr;
block->next = head;
if (head != nullptr) {
head->prev = block;
}
head = block;
}
void delete_block(block_pointer& head, block_pointer& block) {
block_pointer next = block->next;
block_pointer prev = block->prev;
if (next != nullptr) {
next->prev = prev;
}
if (prev == nullptr) {
head = nullptr;
} else {
prev->next = next;
}
}
size_type size_(block_pointer head) {
size_type s = 0;
for (;head != nullptr; head = head->next) { ++s; }
return s;
}
};
template <typename T>
FixedAllocator<T>::FixedAllocator()
{
size_block = sizeof(T) + sizeof(block);
num_block = 65550;
head_free_blocks = nullptr;
head_allocated_blocks = nullptr;
max_size_pool = 50;
size_pool = 0;
pools = new void*[max_size_pool];
}
template <typename T>
void FixedAllocator<T>::add_pool() {
void_pointer pool = ::operator new(num_block * size_block);
if (pool == nullptr || size_pool == max_size_pool) {
throw std::bad_alloc();
}
pools[size_pool++] = (pool);
for (size_type i = 0; i < num_block; ++i) {
auto block = reinterpret_cast<block_pointer>(static_cast<char*>(pool) + i * size_block);
this->push_front(head_free_blocks, block);
}
// std::cout << "Log: add pool " << std::endl
// << "count pool:" << pools.size() << std::endl
// << " num free block " << this->size_(head_free_blocks) << std::endl;
}
template <typename T>
FixedAllocator<T>::~FixedAllocator() {
// std::cout << "Log: delete " << std::endl
// << "count pool:" << pools.size() << std::endl
// << " num free block " << this->size_(head_free_blocks) << std::endl
// << " num allocated block " << this->size_(head_allocated_blocks) << std::endl;
for (int i = 0; i < size_pool; ++i) {
auto pool = static_cast<void_pointer>(pools[i]);
::operator delete(pool);
}
if (head_allocated_blocks != nullptr) {
throw std::exception();
}
}
template <typename T>
typename FixedAllocator<T>::void_pointer FixedAllocator<T>::allocate() {
if (head_free_blocks == nullptr) {
this->add_pool();
}
block_pointer block = head_free_blocks;
pop_front(head_free_blocks);
push_front(head_allocated_blocks, block);
// std::cout << "Log: allocate " << std::endl
// << " num free block " << this->size_(head_free_blocks) << std::endl
// << " num allocated block " << this->size_(head_allocated_blocks) << std::endl;
return static_cast<void_pointer>(reinterpret_cast<char*>(block) + sizeof(FixedAllocator<T>::block));
}
template <typename T>
void FixedAllocator<T>::deallocate(void_pointer p) {
auto block = reinterpret_cast<block_pointer>(static_cast<char*>(p) - sizeof(FixedAllocator<T>::block));
delete_block(head_allocated_blocks, block);
push_front(head_free_blocks, block);
// std::cout << "Log: deallocate " << std::endl
// << " num free block " << this->size_(head_free_blocks) << std::endl
// << " num allocated block " << this->size_(head_allocated_blocks) << std::endl;
}
template <typename T>
class Allocator
{
private:
static FixedAllocator<T> allocator_policy;
public:
using value_type = T;
using pointer = T*;
using size_type = std::size_t;
template <class U> struct rebind { using other = Allocator<U>; };
constexpr Allocator() noexcept = default;
constexpr Allocator( const Allocator& other ) noexcept {}
template <class U>
constexpr Allocator(const Allocator<U>& other) noexcept {}
Allocator &operator=(const Allocator&) = delete;
~Allocator() = default;
[[nodiscard]] pointer allocate(size_type n) {
if (n == 1) {
return static_cast<pointer>(Allocator<T>::allocator_policy.allocate());
}
// return reinterpret_cast<pointer>(::operator new(sizeof (T)));
throw std::bad_alloc();
}
void deallocate(pointer p, size_type n) {
if (n == 1) {
Allocator<T>::allocator_policy.deallocate(p);
return;
}
// ::operator delete(p);
throw std::bad_alloc();
}
template <typename U, typename ...Args>
void construct(U* p, Args &&...args) {
new (p) U(std::forward<Args>(args)...);
};
template <typename U>
void destroy(U* p) {
p->~U();
}
size_type max_size() const {
return std::numeric_limits<size_type>::max() / sizeof(T);
}
};
template <typename T> FixedAllocator<T> Allocator<T>::allocator_policy;
template< class T1, class T2 >
bool operator==(const Allocator<T1>& lhs, const Allocator<T2>& rhs ) {
return true;
};
template <class T1, class OtherAllocator>
bool operator==(const Allocator<T1>& lhs, const OtherAllocator& rhs) {
return false;
};
template <class T1, class T2>
bool operator!=(const Allocator<T1>& lhs, const Allocator<T2>& rhs) {
return !(lhs == rhs);
};
} // kkk
template <typename T>
struct std::allocator_traits<kkk::Allocator<T>> {
using allocator_type = typename kkk::Allocator<T>;
using value_type = typename kkk::Allocator<T>::value_type;
using pointer = typename kkk::Allocator<T>::pointer;
using const_pointer = typename std::pointer_traits<pointer>::template rebind<const value_type>;
using void_pointer = typename std::pointer_traits<pointer>::template rebind<void>;
using const_void_pointer = typename std::pointer_traits<pointer>::template rebind<const void>;
using difference_type = typename std::pointer_traits<pointer>::difference_type;
using size_type = typename std::make_unsigned<difference_type>::type;
using propagate_on_container_copy_assignment = std::false_type;
// true if the allocator of type A needs to be copied when the container that uses it is copy-assigned.
// Note that if the allocators of the source and the target containers do not compare equal, copy assignment has
// to deallocate the target's memory using the old allocator and then allocate it using the new allocator before
// copying the elements (and the allocator).
using propagate_on_container_move_assignment = std::false_type;
// true if the allocator of type A needs to be moved when the container that uses it is move-assigned.
// If this member is false and the allocators of the source and the target containers do not compare equal,
// move assignment cannot take ownership of the source memory and must move-assign or move-construct the
// elements individually, resizing its own memory as needed.
using propagate_on_container_swap = std::false_type;
// true if the allocators of type A need to be swapped when two containers that
// use them are swapped. If this member is false and the allocators of the two containers
// do not compare equal, the behavior of container swap is undefined.
using is_always_equal = std::false_type;
template <class U> using rebind_alloc = kkk::Allocator<U>;
template <class U> using rebind_traits = std::allocator_traits<rebind_alloc<U>>;
[[nodiscard]] static pointer allocate(allocator_type& a, size_type n ) {
return a.allocate(n);
}
[[nodiscard]] static pointer allocate(allocator_type& a, size_type n,
const_void_pointer hint) {
return a.allocate(n);
}
static void deallocate (allocator_type &a, pointer p, size_type n) {
a.deallocate(p, n);
}
template<typename U , typename... Args>
static void construct(allocator_type &a, U* p, Args &&...args) {
a.construct(p, std::forward<Args>(args)...);
};
template <typename U>
static void destroy(allocator_type &a, U* p) {
a.destroy(p);
}
static size_type max_size (const allocator_type &a) {
return a.max_size();
}
static allocator_type select_on_container_copy_construction (const allocator_type &rhs) {
return allocator_type(rhs);
}
};