forked from 1ykos/patchmap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
hashed_array_tree.hpp
346 lines (344 loc) · 12.3 KB
/
hashed_array_tree.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
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
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
#ifndef HASHED_ARRAY_TREE_H
#define HASHED_ARRAY_TREE_H
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <stdexcept>
#include <boost/container/allocator.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <typeinfo>
#include <exception>
#include <memory>
#include <utility>
#include "wmath_forward.hpp"
#include "wmath_bits.hpp"
#include "wmath_hash.hpp"
#include "wmath_math.hpp"
namespace wmath{
template<
typename T,
class alloc = std::allocator<T>
>
class hashed_array_tree{
public:
typedef typename alloc::size_type size_type;
typedef alloc allocator_type;
private:
size_type n = 0;
T** data = nullptr;
allocator_type allocator;
size_type log2rootsize_n;
size_type static constexpr log2rootsize(const size_type& n) {
return (digits<size_type>()-clz(n)+1)/2;
}
size_type static constexpr rootsize(const size_type& n) {
return n?(size_type(1)<<((digits<size_type>()-clz(n)+1)/2)):0;
}
size_type static constexpr rootsize_from_log2(
const size_type& log2rootsize_n){
return size_type(1)<<log2rootsize_n;
}
tuple<size_type,size_type> constexpr resolve(
const size_type& i,
const size_type& n,
const size_type& log2rootsize_n
) const {
assert(n);
assert(i<n);
const size_type m = (size_type(1)<<log2rootsize_n)-1;
return {i>>log2rootsize_n,i&m};
}
tuple<size_type,size_type> constexpr resolve(
const size_type& i,
const size_type& n) const {
const size_type log2roosize_n = log2rootsize(n);
return resolve(i,n,log2rootsize_n);
}
public:
~hashed_array_tree() {
if (data!=nullptr) {
for (size_type i=0;i!=rootsize(n);++i) {
allocator.deallocate(data[i],rootsize(n));
}
delete[] data;
}
}
inline const T& operator[](const size_type& i) const {
const auto r = resolve(i,n,log2rootsize_n);
//cerr << i << " " << n << " " << get<0>(r) << " " << get<1>(r) << endl;
assert(data!=nullptr);
assert(get<0>(r)<rootsize(n));
assert(data[get<0>(r)]!=nullptr);
assert(get<1>(r)<rootsize(n));
return data[get<0>(r)][get<1>(r)];
}
inline T& operator[](const size_type& i) {
const auto r = resolve(i,n,log2rootsize_n);
//cerr << i << " " << n << " " << get<0>(r) << " " << get<1>(r) << endl;
assert(data!=nullptr);
assert(get<0>(r)<rootsize(n));
assert(data[get<0>(r)]!=nullptr);
assert(get<1>(r)<rootsize(n));
return data[get<0>(r)][get<1>(r)];
}
template<bool is_const>
class const_noconst_iterator {
friend class hashed_array_tree;
private:
typename conditional<is_const,const T**,T**>::type data;
size_type position;
const size_type log2rootsize;
public:
typedef typename alloc::difference_type difference_type;
typedef typename alloc::value_type value_type;
typedef typename
conditional<is_const,
const typename alloc::reference,
typename alloc::reference
>::type
reference;
typedef typename
conditional<is_const,
const typename alloc::pointer,
typename alloc::pointer
>::type
pointer;
typedef std::random_access_iterator_tag iterator_category;
const_noconst_iterator(
typename conditional<is_const,
const hashed_array_tree*,
hashed_array_tree*
>::type tree
)
:data(tree->data),
position(0),
log2rootsize(hashed_array_tree::log2rootsize(tree->n))
{}
const_noconst_iterator(
typename conditional<is_const,
const hashed_array_tree*,
hashed_array_tree*
>::type tree,
const size_type& i
)
:data(tree->data),
position(i),
log2rootsize(hashed_array_tree::log2rootsize(tree->n))
{}
template<bool is_const_other>
bool operator==(
const const_noconst_iterator<is_const_other>& o) const {
if (position!=o.position) return false;
if (data!=o.data) return false;
return true;
}
template<bool is_const_other>
bool operator!=(
const const_noconst_iterator<is_const_other>& o) const {
return !((*this)==o);
}
template<bool is_const_other>
bool operator< (
const const_noconst_iterator<is_const_other>& o) const {
if (position < o.position) return true;
else return false;
}
template<bool is_const_other>
bool operator> (
const const_noconst_iterator<is_const_other>& o) const {
if (position > o.position) return true;
else return false;
}
template<bool is_const_other>
bool operator<=(
const const_noconst_iterator<is_const_other>& o) const {
if (position <=o.position) return true;
else return false;
}
template<bool is_const_other>
bool operator>=(
const const_noconst_iterator<is_const_other>& o) const {
if (position >=o.position) return true;
else return false;
}
const_noconst_iterator<is_const>& operator++(){ // prefix
++position;
return *this;
}
const_noconst_iterator<is_const> operator++(int){ // postfix
iterator pre(*this);
operator++();
return pre;
}
const_noconst_iterator<is_const>& operator--(){ // prefix
--position;
return *this;
}
const_noconst_iterator<is_const> operator--(int){ // postfix
iterator pre(*this);
operator--();
return pre;
}
const_noconst_iterator<is_const>& operator+=(const size_type& n){
position+=n;
return *this;
}
const_noconst_iterator<is_const> operator+(const size_type& n) const {
return (const_noconst_iterator<is_const>(*this)+=n);
}
friend const_noconst_iterator<is_const> operator+(
const size_type& n,
const const_noconst_iterator<is_const>& it){
return (const_noconst_iterator<is_const>(it)+=n);
}
const_noconst_iterator<is_const>& operator-=(const size_type& n){
position-=n;
return *this;
}
const_noconst_iterator<is_const> operator-(const size_type& n) const{
return (const_noconst_iterator<is_const>(*this)-=n);
}
reference operator*() {
const size_type m = (size_type(1)<<log2rootsize)-1;
return data[position>>log2rootsize][position&m];
}
pointer operator->() {
const size_type m = (size_type(1)<<log2rootsize)-1;
return data[position>>log2rootsize]+(position&m);
}
reference operator*() const {
const size_type m = (size_type(1)<<log2rootsize)-1;
return data[position>>log2rootsize][position&m];
}
pointer operator->() const {
const size_type m = (size_type(1)<<log2rootsize)-1;
return data[position>>log2rootsize]+(position&m);
}
};
typedef const_noconst_iterator<false> iterator;
typedef const_noconst_iterator<true> const_iterator;
iterator begin(){
return iterator(this);
}
const_iterator begin() const {
return const_iterator(this);
}
const_iterator cbegin() const {
return const_iterator(this);
}
iterator end() {
return iterator(this,n);
}
const_iterator end() const {
return const_iterator(this,n);
}
const_iterator cend() const {
return const_iterator(this,n);
}
size_type constexpr max_size() const {
return numeric_limits<size_type>::max();
}
const size_type size() const {
return n;
}
size_type constexpr static next_size(const size_type& n) {
return (1+(n-1)/rootsize(n))*rootsize(n);
}
void inline resize(const size_type& m) {
//cerr << "resize hashed_array_tree from " << n << " to " << m << endl;
if (m==n) return;
const size_type rootsize_n = rootsize_from_log2(log2rootsize_n);
const size_type log2rootsize_m = log2rootsize(m);
const size_type rootsize_m = rootsize(m);
if (m==0) {
for (size_type i=0;i!=rootsize_n;++i){
allocator.deallocate(data[i],rootsize_n);
}
delete[] data;
data = nullptr;
n = m;
log2rootsize_n = log2rootsize(n);
return;
}
//cout << rootsize_n << " " << rootsize_m << endl;
if (rootsize_m!=rootsize_n) {
//cerr << "new index needed" << endl;
T** new_data = new T*[rootsize_m];
//cout << "first new[]" << endl;
//cout << "new rootsize = " << rootsize_m << endl;
for (size_type i=0;i!=rootsize_m;++i) new_data[i] = nullptr;
size_type old_leaf = 0;
size_type old_leafposition = 0;
size_type new_leaf = 0;
size_type new_leafposition = 0;
for (size_type i=0;;++i) {
if (new_leafposition == 0) {
new_data[new_leaf] = allocator.allocate(rootsize_m);
//cout << "new leaf" << endl;
}
if (i==min(m,n)) break;
//cerr << "copying values" << endl;
new_data[new_leaf][new_leafposition] =
std::move(data[old_leaf][old_leafposition]);
if (i+1==min(m,n)) break;
if (++new_leafposition==rootsize_m) {
++new_leaf;
new_leafposition = 0;
}
if (++old_leafposition==rootsize_n) {
allocator.deallocate(data[old_leaf],rootsize_n);
++old_leaf;
old_leafposition = 0;
}
}
//cout << new_leaf << " " << (((m-1)>>log2rootsize_m)+1) << endl;
for (++new_leaf;
new_leaf!=(((m-1)>>log2rootsize_m)+1);
++new_leaf) {
new_data[new_leaf] = allocator.allocate(rootsize_m);
//cout << "new leaf" << endl;
}
//cout << "this were supposed to be all the leaves" << endl;
if (data!=nullptr) {
for (;old_leaf!=(((n-1)>>log2rootsize_n)+1);++old_leaf) {
allocator.deallocate(data[old_leaf],rootsize_n);
}
delete[] data;
}
data = new_data;
n = m;
log2rootsize_n = log2rootsize(n);
//cout << "I think I am done oO " << endl;
} else {
//cout << "only new leaves needed" << endl;
if (m>n) {
//cout << ((n-1)>>log2rootsize_n)+1 << " "
// << ((m-1)>>log2rootsize_n)+1 << endl;
for (size_type i = n?((n-1)>>log2rootsize_n)+1:0;
i!=(m?((m-1)>>log2rootsize_n)+1:0);
++i) {
//cout << i << " " << rootsize_n << endl;
assert(i<rootsize_n);
data[i] = allocator.allocate(rootsize_n);
}
} else {
for (size_type i = m?((m-1)>>log2rootsize_n)+1:0;
i!=(n?((n-1)>>log2rootsize_n)+1:0);
++i) {
assert(i<rootsize_n);
allocator.deallocate(data[i],rootsize_n);
}
}
n = m;
log2rootsize_n = log2rootsize(n);
}
}
};
}
#endif // HASHED_ARRAY_TREE_H