-
Notifications
You must be signed in to change notification settings - Fork 0
/
allocator.h
152 lines (121 loc) · 4.08 KB
/
allocator.h
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
#ifndef allocator_def
#define allocator_def
#include <memory>
namespace moya_alloc {
template <class T, std::size_t grow_size = 1024>
class mem_pool {
struct node {
node *next;
};
class buffer {
static const std::size_t block_size = sizeof(T) > sizeof(node) ? sizeof(T) : sizeof(node);
uint8_t data[block_size * grow_size];
public:
buffer *const next;
buffer(buffer *next) :
next(next) {
}
T *get_block(std::size_t index) {
return reinterpret_cast<T *>(&data[block_size * index]);
}
};
node *first_free_block = nullptr;
buffer *first_buffer = nullptr;
std::size_t buffered_blocks = grow_size;
public:
mem_pool() = default;
mem_pool(mem_pool &&memory_pool) = delete;
mem_pool(const mem_pool &memory_pool) = delete;
mem_pool operator =(mem_pool &&memory_pool) = delete;
mem_pool operator =(const mem_pool &memory_pool) = delete;
~mem_pool() {
while (first_buffer) {
buffer *buffer = first_buffer;
first_buffer = buffer->next;
delete buffer;
}
}
T *allocate() {
if (first_free_block) {
node *block = first_free_block;
first_free_block = block->next;
return reinterpret_cast<T *>(block);
}
if (buffered_blocks >= grow_size) {
first_buffer = new buffer(first_buffer);
buffered_blocks = 0;
}
return first_buffer->get_block(buffered_blocks++);
}
void deallocate(T *pointer)
{
node *block = reinterpret_cast<node *>(pointer);
block->next = first_free_block;
first_free_block = block;
}
};
template <class T, std::size_t grow_size = 1024>
class allocator : private mem_pool<T, grow_size> {
#ifdef _WIN32
allocator *copy_allocator = nullptr;
std::allocator<T> *rebind_allocator = nullptr;
#endif
public:
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef T *pointer;
typedef const T *const_pointer;
typedef T &reference;
typedef const T &const_reference;
typedef T value_type;
template <class U>
struct rebind {
typedef allocator<U, grow_size> other;
};
#ifdef _WIN32
allocator() = default;
allocator(allocator &allocator) :
copy_allocator(&allocator) {
}
template <class U>
allocator(const allocator<U, grow_size> &other) {
if (!std::is_same<T, U>::value)
rebind_allocator = new std::allocator<T>();
}
~allocator() {
delete rebind_allocator;
}
#endif
pointer allocate(size_type n, const void *hint = 0) {
#ifdef _WIN32
if (copy_allocator)
return copy_allocator->allocate(n, hint);
if (rebind_allocator)
return rebind_allocator->allocate(n, hint);
#endif
if (n != 1 || hint)
throw std::bad_alloc();
return mem_pool<T, grow_size>::allocate();
}
void deallocate(pointer p, size_type n) {
#ifdef _WIN32
if (copy_allocator) {
copy_allocator->deallocate(p, n);
return;
}
if (rebind_allocator) {
rebind_allocator->deallocate(p, n);
return;
}
#endif
mem_pool<T, grow_size>::deallocate(p);
}
void construct(pointer p, const_reference val) {
new (p) T(val);
}
void destroy(pointer p) {
p->~T();
}
};
}
#endif