-
Notifications
You must be signed in to change notification settings - Fork 0
/
amt.hpp
164 lines (118 loc) · 4.5 KB
/
amt.hpp
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
#ifndef AMT_HPP
#define AMT_HPP
#include "sparse_array.hpp"
struct base {
std::shared_ptr<void> storage;
template<class T>
base(std::shared_ptr<T> storage): storage(std::move(storage)) { }
base() { }
};
template<class T, std::size_t level, std::size_t B, std::size_t L>
struct node: base {
static_assert(level > 0, "level error");
using child_node = node<T, level - 1, B, L>;
using children_type = sparse::base<child_node>;
using single_type = sparse::derived<child_node, 1>;
static constexpr std::size_t children_size = 1ul << B;
static constexpr std::size_t capacity = 1ul << (L + B * level);
static constexpr std::size_t shift = L + B * (level - 1);
static constexpr std::size_t mask = (1ul << (shift + 1)) - 1;
const children_type* children() const {
return reinterpret_cast<const children_type*>(storage.get());
};
static std::shared_ptr<children_type> make_children(std::size_t index,
const T& value) {
return split(index, [&](std::size_t sub, std::size_t rest) {
return std::make_shared<single_type>(1ul << sub, child_node(rest, value));
});
}
node(std::size_t index, const T& value):
base(make_children(index, value)) { }
node(std::shared_ptr<children_type> children={}): base(std::move(children)) {}
template<class Func>
static auto split(std::size_t index, const Func& func) {
const std::size_t sub = index >> shift;
const std::size_t rest = index & mask;
return func(sub, rest);
}
const T& get(std::size_t index) const {
return split(index, [&](std::size_t sub, std::size_t rest) {
assert(children()->contains(sub));
return children()->get(sub).get(rest);
});
}
node set(std::size_t index, const T& value) const {
return split(index, [&](std::size_t sub, std::size_t rest) -> node {
if(children()->contains(sub)) {
return children()->set(sub, children()->get(sub).set(rest, value));
} else {
return children()->set(sub, child_node(rest, value));
}
});
}
using raise_type = node<T, level + 1, B, L>;
raise_type raise() const {
return children() ? raise_type{0, *this} : raise_type{};
}
};
template<class T, std::size_t B, std::size_t L>
struct node<T, 0, B, L>: base {
using children_type = sparse::base<T>;
using single_type = sparse::derived<T, 1>;
static constexpr std::size_t children_size = 1ul << L;
static constexpr std::size_t capacity = children_size;
const children_type* children() const {
return reinterpret_cast<const children_type*>(storage.get());
};
node(std::size_t index, const T& value):
base(std::make_shared<single_type>(1ul << index, value)) { }
node(std::shared_ptr<children_type> children={}): base(std::move(children)) { }
const T& get(std::size_t index) const {
assert(index < children_size);
assert(children()->contains(index));
return children()->get(index);
}
node set(std::size_t index, const T& value) const {
assert(index < children_size);
return {children()->set(index, value)};
}
};
template<class T, std::size_t B, std::size_t L>
class array {
std::size_t level;
base data;
// TODO compute from B, L
static constexpr std::size_t max_level = 8;
template<class Ret, std::size_t ... Ms, class Func>
Ret visit(std::index_sequence<Ms...>, const Func& func) const {
using thunk_type = Ret (*)(const base&, const Func& func);
static const thunk_type table[] = {
[](const base& data, const Func& func) -> Ret {
return func(static_cast<const node<T, Ms, B, L>&>(data));
}...};
return table[level](data, func);
}
array(std::size_t level, const base data): level(level), data(data) { }
public:
array(): level(0) { }
const T& get(std::size_t index) const {
assert(data.storage);
return visit<const T&>(std::make_index_sequence<max_level>{},
[&](const auto& self) -> const T& {
return self.get(index);
});
}
array set(std::size_t index, const T& value) const {
return visit<array>(std::make_index_sequence<max_level>{}, [&](const auto& self) {
using node_type = typename std::decay<decltype(self)>::type;
if(index > node_type::capacity) {
throw std::runtime_error("derp");
} else if(self.children()) {
return array(level, self.set(index, value));
} else {
return array(level, node_type(index, value));
}
});
}
};
#endif