-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathallocator.cc
More file actions
114 lines (97 loc) · 3.08 KB
/
Copy pathallocator.cc
File metadata and controls
114 lines (97 loc) · 3.08 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
#include <bit>
#include <coroutine>
#include <cstdint>
#include <cstring>
#include <iostream>
import pollcoro;
template<std::size_t BlockSize, std::size_t BlockCount>
class bitmap_allocator {
alignas(std::max_align_t) std::byte data_[BlockSize * BlockCount];
static constexpr size_t BitmapSize = (BlockCount + 63) / 64;
uint64_t bitmap_[BitmapSize] = {};
public:
bool owns(const void* ptr) const noexcept {
auto* p = static_cast<const std::byte*>(ptr);
return p >= data_ && p < data_ + sizeof(data_);
}
void* allocate() {
for (size_t i = 0; i < BitmapSize; ++i) {
if (bitmap_[i] != ~0ULL) { // has at least one free bit
int bit = std::countr_one(bitmap_[i]);
size_t index = i * 64 + bit;
if (index >= BlockCount)
throw std::bad_alloc();
bitmap_[i] |= (1ULL << bit);
return data_ + index * BlockSize;
}
}
throw std::bad_alloc();
}
void deallocate(void* ptr) noexcept {
size_t index = (static_cast<std::byte*>(ptr) - data_) / BlockSize;
bitmap_[index / 64] &= ~(1ULL << (index % 64));
}
size_t allocated_count() const noexcept {
size_t count = 0;
for (size_t i = 0; i < BitmapSize; ++i) {
count += std::popcount(bitmap_[i]);
}
return count;
}
size_t allocated_bytes() const noexcept {
return allocated_count() * BlockSize;
}
};
template<size_t N>
class slab_allocator {
bitmap_allocator<128, N / 128> small_;
bitmap_allocator<512, N / 512> medium_;
bitmap_allocator<1024, N / 1024> large_;
public:
void* allocate(size_t size) {
std::cout << "slab_allocator::allocate " << size << std::endl;
if (size <= 128)
return small_.allocate();
if (size <= 512)
return medium_.allocate();
if (size <= 1024)
return large_.allocate();
throw std::bad_alloc();
}
void deallocate(void* ptr) noexcept {
if (small_.owns(ptr))
return small_.deallocate(ptr);
if (medium_.owns(ptr))
return medium_.deallocate(ptr);
if (large_.owns(ptr))
return large_.deallocate(ptr);
}
size_t allocated_bytes() const noexcept {
return small_.allocated_bytes() + medium_.allocated_bytes() + large_.allocated_bytes();
}
size_t allocated_count() const noexcept {
return small_.allocated_count() + medium_.allocated_count() + large_.allocated_count();
}
};
pollcoro::task<> test2() {
int a[100];
co_return;
}
pollcoro::task<> yield() {
co_await test2();
co_await pollcoro::yield();
}
pollcoro::task<> test() {
auto alloc = slab_allocator<10240>();
co_await pollcoro::allocate_in(alloc, yield);
co_await yield();
}
pollcoro::task<> square() {
for (int i = 0; i < 1000; ++i) {
co_await pollcoro::allocate_in(pollcoro::default_allocator, yield);
}
}
int main() {
auto result = pollcoro::block_on(pollcoro::wait_all(test(), square()));
return 0;
}