blob: 7e75ac23e5dc354458f2c9ec3a7610307b3fad90 (
plain)
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
|
#pragma once
#include <cassert>
#include <type_traits>
#include "pal.h"
static constexpr size_t kBytesPerCommit = pal::kPageSize;
size_t GetCommittedBytes(size_t used_bytes) {
return ((used_bytes + kBytesPerCommit - 1) / kBytesPerCommit) * kBytesPerCommit;
}
struct Arena {
char* base = nullptr;
size_t cap = 0;
size_t len = 0;
Arena() = delete;
Arena(const Arena&) = delete;
Arena(Arena&& other) {
base = other.base;
cap = other.cap;
len = other.len;
other.base = nullptr;
other.cap = 0;
other.len = 0;
}
explicit Arena(size_t max_len) {
assert(max_len != 0);
cap = GetCommittedBytes(max_len);
len = 0;
void* buf = pal::MemReserve(cap);
if (buf == nullptr) {
throw std::bad_alloc();
}
base = static_cast<char*>(buf);
}
~Arena() {
if (base != nullptr) {
pal::MemFree(base, cap);
}
}
bool Grow(size_t additional_len) {
assert(len+additional_len <= cap);
size_t old_committed = GetCommittedBytes(len);
size_t new_committed = GetCommittedBytes(len+additional_len);
size_t delta = new_committed - old_committed;
if (delta == 0) {
len += additional_len;
return true;
}
if (!pal::MemCommit(base + old_committed, delta)) {
return false;
}
len += additional_len;
return true;
}
};
template <typename T>
class DynArray {
Arena arena;
public:
// Redundant, but useful as documentation.
DynArray() = delete;
DynArray(const DynArray<T>& other) = delete;
DynArray(DynArray&& other) = default;
explicit DynArray(size_t max_len)
: arena(max_len * sizeof(T)) {}
// Support for range loops.
T* begin() {
return reinterpret_cast<T*>(arena.base);
}
T* end() {
return reinterpret_cast<T*>(arena.base + arena.len);
}
bool Append(T v) {
auto* dst = end();
if (!arena.Grow(sizeof(T))) {
return false;
}
new (dst) T(std::move(v));
return true;
}
size_t Len() const {
return arena.len / sizeof(T);
}
T& operator[](size_t i) {
assert(i < Len());
return begin()[i];
}
~DynArray() {
if (!std::is_trivially_destructible_v<T>) {
for (auto* p = begin(); p != end(); p++) {
p->~T();
}
}
}
};
|