17 #ifdef SUPPRESS_CEDAR_ASSERT
18 #define STATIC_ASSERT(e, msg)
20 #define STATIC_ASSERT(e, msg) typedef char msg[(e) ? 1 : -1]
26 typedef unsigned long npos_t;
28 typedef unsigned long long npos_t;
30 typedef unsigned char uchar;
31 static const npos_t TAIL_OFFSET_MASK = static_cast <npos_t> (0xffffffff);
32 static const npos_t NODE_INDEX_MASK = static_cast <npos_t> (0xffffffff) << 32;
33 template <
typename T>
struct NaN {
enum { N1 = -1, N2 = -2 }; };
34 template <>
struct NaN <float> {
enum { N1 = 0x7f800001, N2 = 0x7f800002 }; };
35 static const int MAX_ALLOC_SIZE = 1 << 16;
37 template <
typename value_type,
38 const int NO_VALUE = NaN <value_type>::N1,
39 const int NO_PATH = NaN <value_type>::N2,
40 const bool ORDERED =
true,
41 const int MAX_TRIAL = 1,
42 const size_t NUM_TRACKING_NODES = 0>
45 enum error_code { CEDAR_NO_VALUE = NO_VALUE, CEDAR_NO_PATH = NO_PATH };
46 typedef value_type result_type;
47 struct result_pair_type {
51 struct result_triple_type {
57 union {
int base; value_type value; };
59 node (
const int base_ = 0,
const int check_ = 0)
60 : base (base_), check (check_) {}
65 ninfo () : sibling (0), child (0) {}
74 block () : prev (0), next (0), num (256), reject (257), trial (0), ehead (0) {}
76 da () : tracking_node (), _array (0), _tail (0), _tail0 (0), _ninfo (0), _block (0), _bheadF (0), _bheadC (0), _bheadO (0), _capacity (0), _size (0), _quota (0), _quota0 (0), _no_delete (false), _reject () {
77 STATIC_ASSERT(
sizeof (value_type) <=
sizeof (
int),
78 value_type_is_not_supported___maintain_a_value_array_by_yourself_and_store_its_index_to_trie
82 ~da () { clear (
false); }
83 size_t capacity ()
const {
return static_cast <
size_t> (_capacity); }
84 size_t size ()
const {
return static_cast <
size_t> (_size); }
85 size_t length ()
const {
return static_cast <
size_t> (*_length); }
86 size_t total_size ()
const {
return sizeof (node) * _size; }
87 size_t unit_size ()
const {
return sizeof (node); }
88 size_t nonzero_size ()
const {
90 for (
int to = 0; to < _size; ++to)
91 if (_array[to].check >= 0) ++i;
94 size_t nonzero_length ()
const {
96 for (
int to = 0; to < _size; ++to) {
97 const node& n = _array[to];
98 if (n.check >= 0 && _array[n.check].base != to && n.base < 0)
99 { ++j;
for (
const char* p = &_tail[-n.base]; *p; ++p) ++i; }
101 return i + j * (1 +
sizeof (value_type));
103 size_t num_keys ()
const {
105 for (
int to = 0; to < _size; ++to) {
106 const node& n = _array[to];
107 if (n.check >= 0 && (_array[n.check].base == to || n.base < 0)) ++i;
112 template <
typename T>
113 T exactMatchSearch (
const char* key)
const
114 {
return exactMatchSearch <T> (key, std::strlen (key)); }
115 template <
typename T>
116 T exactMatchSearch (
const char* key,
size_t len, npos_t from = 0)
const {
117 union {
int i; value_type x; } b;
119 b.i = _find (key, from, pos, len);
120 if (b.i == CEDAR_NO_PATH) b.i = CEDAR_NO_VALUE;
122 _set_result (&result, b.x, len, from);
125 template <
typename T>
126 size_t commonPrefixSearch (
const char* key, T* result,
size_t result_len)
const
127 {
return commonPrefixSearch (key, result, result_len, std::strlen (key)); }
128 template <
typename T>
129 size_t commonPrefixSearch (
const char* key, T* result,
size_t result_len,
size_t len, npos_t from = 0)
const {
131 for (
size_t pos = 0; pos < len; ) {
132 union {
int i; value_type x; } b;
133 b.i = _find (key, from, pos, pos + 1);
134 if (b.i == CEDAR_NO_VALUE)
continue;
135 if (b.i == CEDAR_NO_PATH)
return num;
136 if (num < result_len) _set_result (&result[num], b.x, pos, from);
142 template <
typename T>
143 size_t commonPrefixPredict (
const char* key, T* result,
size_t result_len)
144 {
return commonPrefixPredict (key, result, result_len, std::strlen (key)); }
145 template <
typename T>
146 size_t commonPrefixPredict (
const char* key, T* result,
size_t result_len,
size_t len, npos_t from = 0) {
147 size_t num (0), pos (0), p (0);
148 if (_find (key, from, pos, len) == CEDAR_NO_PATH)
return 0;
149 union {
int i; value_type x; } b;
150 const npos_t root = from;
151 for (b.i = begin (from, p); b.i != CEDAR_NO_PATH; b.i = next (from, p, root)) {
152 if (num < result_len)
153 _set_result (&result[num], b.x, p, from);
158 void suffix (
char* key,
size_t len, npos_t to)
const {
160 if (
const int offset = static_cast <int> (to >> 32)) {
161 to &= TAIL_OFFSET_MASK;
162 size_t len_tail = std::strlen (&_tail[-_array[to].base]);
163 if (len > len_tail) len -= len_tail;
else len_tail = len, len = 0;
164 std::memcpy (&key[len], &_tail[static_cast <size_t> (offset) - len_tail], len_tail);
167 const int from = _array[to].check;
168 key[len] = static_cast <
char> (_array[from].base ^ static_cast <
int> (to));
169 to = static_cast <npos_t> (from);
172 value_type traverse (
const char* key, npos_t& from,
size_t& pos)
const
173 {
return traverse (key, from, pos, std::strlen (key)); }
174 value_type traverse (
const char* key, npos_t& from,
size_t& pos,
size_t len)
const {
175 union {
int i; value_type x; } b;
176 b.i = _find (key, from, pos, len);
179 struct empty_callback {
void operator () (
const int,
const int) {} };
180 value_type& update (
const char* key)
181 {
return update (key, std::strlen (key)); }
182 value_type& update (
const char* key,
size_t len, value_type val = value_type (0))
183 { npos_t from (0);
size_t pos (0);
return update (key, from, pos, len, val); }
184 value_type& update (
const char* key, npos_t& from,
size_t& pos,
size_t len, value_type val = value_type (0))
185 { empty_callback cf;
return update (key, from, pos, len, val, cf); }
186 template <
typename T>
187 value_type& update (
const char* key, npos_t& from,
size_t& pos,
size_t len, value_type val, T& cf) {
189 _err (__FILE__, __LINE__,
"failed to insert zero-length key\n");
190 #ifndef USE_FAST_LOAD
191 if (! _ninfo || ! _block) restore ();
193 npos_t offset = from >> 32;
195 for (
const uchar*
const key_ = reinterpret_cast <const uchar*> (key);
196 _array[from].base >= 0; ++pos) {
198 {
const int to = _follow (from, 0, cf);
return _array[to].value += val; }
199 from = static_cast <
size_t> (_follow (from, key_[pos], cf));
201 offset = static_cast <npos_t> (-_array[from].base);
203 if (offset >=
sizeof (
int)) {
204 const size_t pos_orig = pos;
205 char*
const tail = &_tail[offset] - pos;
206 while (pos < len && key[pos] == tail[pos]) ++pos;
208 if (pos == len && tail[pos] ==
'\0') {
209 if (
const npos_t moved = pos - pos_orig) {
210 from &= TAIL_OFFSET_MASK;
211 from |= (offset + moved) << 32;
213 return *reinterpret_cast <value_type*> (&tail[len + 1]) += val;
217 from &= TAIL_OFFSET_MASK;
218 for (npos_t offset_ = static_cast <npos_t> (-_array[from].base);
219 offset_ < offset; ) {
220 from = static_cast <
size_t>
221 (_follow (from, static_cast <uchar> (_tail[offset_]), cf));
224 if (NUM_TRACKING_NODES)
225 for (
size_t j = 0; tracking_node[j] != 0; ++j)
226 if (tracking_node[j] >> 32 == offset_)
227 tracking_node[j] = static_cast <npos_t> (from);
230 for (
size_t pos_ = pos_orig; pos_ < pos; ++pos_)
231 from = static_cast <size_t>
232 (_follow (from, static_cast <uchar> (key[pos_]), cf));
233 npos_t moved = pos - pos_orig;
235 const int to_ = _follow (from, static_cast <uchar> (tail[pos]), cf);
236 _array[to_].base = - static_cast <
int> (offset + ++moved);
237 moved -= 1 +
sizeof (value_type);
240 for (npos_t i = offset; i <= moved; i += 1 +
sizeof (value_type)) {
241 if (_quota0 == ++*_length0) {
243 _quota0 += *_length0 >= MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE : *_length0;
247 _realloc_array (_tail0, _quota0, *_length0);
249 _tail0[*_length0] = static_cast <
int> (i);
251 if (pos == len || tail[pos] ==
'\0') {
252 const int to = _follow (from, 0, cf);
253 if (pos == len)
return _array[to].value += val;
254 _array[to].value += *reinterpret_cast <value_type*> (&tail[pos + 1]);
256 from = static_cast <
size_t> (_follow (from, static_cast <uchar> (key[pos]), cf));
259 const int needed = static_cast <
int> (len - pos + 1 +
sizeof (value_type));
260 if (pos == len && *_length0) {
261 const int offset0 = _tail0[*_length0];
262 _tail[offset0] =
'\0';
263 _array[from].base = -offset0;
265 return *reinterpret_cast <value_type*> (&_tail[offset0 + 1]) = val;
267 if (_quota < *_length + needed) {
269 _quota += needed > *_length || needed > MAX_ALLOC_SIZE ? needed :
270 (*_length >= MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE : *_length);
272 _quota += _quota >= needed ? _quota : needed;
274 _realloc_array (_tail, _quota, *_length);
276 _array[from].base = -*_length;
277 const size_t pos_orig = pos;
278 char*
const tail = &_tail[*_length] - pos;
280 do tail[pos] = key[pos];
while (++pos < len);
281 from |= (static_cast <npos_t> (*_length) + (len - pos_orig)) << 32;
284 return *reinterpret_cast <value_type*> (&tail[len + 1]) += val;
287 int erase (
const char* key) {
return erase (key, std::strlen (key)); }
288 int erase (
const char* key,
size_t len, npos_t from = 0) {
290 const int i = _find (key, from, pos, len);
291 if (i == CEDAR_NO_PATH || i == CEDAR_NO_VALUE)
return -1;
292 if (from >> 32) from &= TAIL_OFFSET_MASK;
293 bool flag = _array[from].base < 0;
294 int e = flag ? static_cast <
int> (from) : _array[from].base ^ 0;
295 from = _array[e].check;
297 const node& n = _array[from];
298 flag = _ninfo[n.base ^ _ninfo[from].child].sibling;
299 if (flag) _pop_sibling (from, n.base, static_cast <uchar> (n.base ^ e));
301 e = static_cast <
int> (from);
302 from = static_cast <
size_t> (_array[from].check);
306 int build (
size_t num,
const char** key,
const size_t* len = 0,
const value_type* val = 0) {
307 for (
size_t i = 0; i < num; ++i)
308 update (key[i], len ? len[i] : std::strlen (key[i]), val ? val[i] : value_type (i));
311 template <
typename T>
312 void dump (T* result,
const size_t result_len) {
313 union {
int i; value_type x; } b;
314 size_t num (0), p (0);
316 for (b.i = begin (from, p); b.i != CEDAR_NO_PATH; b.i = next (from, p))
317 if (num < result_len)
318 _set_result (&result[num++], b.x, p, from);
320 _err (__FILE__, __LINE__,
"dump() needs array of length = num_keys()\n");
322 void shrink_tail () {
323 union {
char* tail;
int* length; } t;
325 = static_cast <
size_t> (*_length)
326 - static_cast <
size_t> (*_length0) * (1 +
sizeof (value_type));
327 t.tail = static_cast <
char*> (std::malloc (length_));
328 if (! t.tail) _err (__FILE__, __LINE__,
"memory allocation failed\n");
329 *t.length = static_cast <
int> (
sizeof (int));
330 for (
int to = 0; to < _size; ++to) {
331 node& n = _array[to];
332 if (n.check >= 0 && _array[n.check].base != to && n.base < 0) {
333 char*
const tail (&t.tail[*t.length]), *
const tail_ (&_tail[-n.base]);
334 n.base = - *t.length;
335 int i = 0;
do tail[i] = tail_[i];
while (tail[i++]);
336 *reinterpret_cast <value_type*> (&tail[i])
337 = *reinterpret_cast <const value_type*> (&tail_[i]);
338 *t.length += i + static_cast <
int> (
sizeof (value_type));
343 _realloc_array (_tail, *_length, *_length);
345 _realloc_array (_tail0, 1);
348 int save (
const char* fn,
const char* mode,
const bool shrink) {
349 if (shrink) shrink_tail ();
350 return save (fn, mode);
352 int save (
const char* fn,
const char* mode =
"wb")
const {
354 FILE* fp = std::fopen (fn, mode);
356 std::fwrite (_tail,
sizeof (
char), static_cast <size_t> (*_length), fp);
357 std::fwrite (_array,
sizeof (node), static_cast <size_t> (_size), fp);
360 const char*
const info
361 = std::strcat (std::strcpy (
new char[std::strlen (fn) + 5], fn),
".sbl");
362 fp = std::fopen (info, mode);
365 std::fwrite (&_bheadF,
sizeof (
int), 1, fp);
366 std::fwrite (&_bheadC,
sizeof (
int), 1, fp);
367 std::fwrite (&_bheadO,
sizeof (
int), 1, fp);
368 std::fwrite (_ninfo,
sizeof (ninfo), static_cast <size_t> (_size), fp);
369 std::fwrite (_block,
sizeof (block), static_cast <size_t> (_size >> 8), fp);
374 int open (
const char* fn,
const char* mode =
"rb",
375 const size_t offset = 0,
size_t size_ = 0) {
376 FILE* fp = std::fopen (fn, mode);
380 if (std::fseek (fp, 0, SEEK_END) != 0)
return -1;
381 size_ = static_cast <
size_t> (std::ftell (fp));
382 if (std::fseek (fp, 0, SEEK_SET) != 0)
return -1;
384 if (size_ <= offset)
return -1;
385 if (std::fseek (fp, static_cast <long> (offset), SEEK_SET) != 0)
return -1;
387 if (std::fread (&len,
sizeof (
int), 1, fp) != 1)
return -1;
388 const size_t length_ = static_cast <
size_t> (len);
389 if (size_ <= offset + length_)
return -1;
392 size_ = (size_ - offset - length_) /
sizeof (node);
393 _array = static_cast <node*> (std::malloc (
sizeof (node) * size_));
394 _tail = static_cast <
char*> (std::malloc (length_));
395 _tail0 = static_cast <
int*> (std::malloc (
sizeof (
int)));
397 _ninfo = static_cast <ninfo*> (std::malloc (
sizeof (ninfo) * size_));
398 _block = static_cast <block*> (std::malloc (
sizeof (block) * size_));
399 if (! _array || ! _tail || ! _tail0 || ! _ninfo || ! _block)
401 if (! _array || ! _tail || ! _tail0)
403 _err (__FILE__, __LINE__,
"memory allocation failed\n");
404 if (std::fseek (fp, static_cast <long> (offset), SEEK_SET) != 0)
return -1;
405 if (length_ != std::fread (_tail,
sizeof (
char), length_, fp) ||
406 size_ != std::fread (_array,
sizeof (node), size_, fp))
409 _size = static_cast <
int> (size_);
412 const char*
const info
413 = std::strcat (std::strcpy (
new char[std::strlen (fn) + 5], fn),
".sbl");
414 fp = std::fopen (info, mode);
417 std::fread (&_bheadF,
sizeof (
int), 1, fp);
418 std::fread (&_bheadC,
sizeof (
int), 1, fp);
419 std::fread (&_bheadO,
sizeof (
int), 1, fp);
420 if (size_ != std::fread (_ninfo,
sizeof (ninfo), size_, fp) ||
421 size_ >> 8 != std::fread (_block,
sizeof (block), size_ >> 8, fp))
430 #ifndef USE_FAST_LOAD
432 if (! _block) _restore_block ();
433 if (! _ninfo) _restore_ninfo ();
439 void set_array (
void* p,
size_t size_ = 0) {
442 size_ = size_ * unit_size () - static_cast <
size_t> (*static_cast <
int*> (p));
443 _tail = static_cast <
char*> (p);
444 _array = reinterpret_cast <node*> (_tail + *_length);
445 _size = static_cast <
int> (size_ / unit_size () + (size_ % unit_size () ? 1 : 0));
448 const void* array ()
const {
return _array; }
449 void clear (
const bool reuse =
true) {
450 if (_no_delete) _array = 0, _tail = 0;
451 if (_array) std::free (_array); _array = 0;
452 if (_tail) std::free (_tail); _tail = 0;
453 if (_tail0) std::free (_tail0); _tail0 = 0;
454 if (_ninfo) std::free (_ninfo); _ninfo = 0;
455 if (_block) std::free (_block); _block = 0;
456 _bheadF = _bheadC = _bheadO = _capacity = _size = _quota = _quota0 = 0;
457 if (reuse) _initialize ();
461 int begin (npos_t& from,
size_t& len) {
462 #ifndef USE_FAST_LOAD
463 if (! _ninfo) _restore_ninfo ();
465 int base = from >> 32 ? - static_cast <
int> (from >> 32) : _array[from].base;
467 uchar c = _ninfo[from].child;
468 if (! from && ! (c = _ninfo[base ^ c].sibling))
469 return CEDAR_NO_PATH;
470 for (; c && base >= 0; ++len) {
471 from = static_cast <
size_t> (base) ^ c;
472 base = _array[from].base;
473 c = _ninfo[from].child;
475 if (base >= 0)
return _array[base ^ c].base;
477 const size_t len_ = std::strlen (&_tail[-base]);
478 from &= TAIL_OFFSET_MASK;
479 from |= static_cast <npos_t> (static_cast <
size_t> (-base) + len_) << 32;
481 return *reinterpret_cast <
int*> (&_tail[-base] + len_ + 1);
484 int next (npos_t& from,
size_t& len,
const npos_t root = 0) {
486 if (
const int offset = static_cast <int> (from >> 32)) {
487 if (root >> 32)
return CEDAR_NO_PATH;
488 from &= TAIL_OFFSET_MASK;
489 len -= static_cast <
size_t> (offset - (-_array[from].base));
491 c = _ninfo[_array[from].base ^ 0].sibling;
492 for (; ! c && from != root; --len) {
493 c = _ninfo[from].sibling;
494 from = static_cast <
size_t> (_array[from].check);
496 if (! c)
return CEDAR_NO_PATH;
497 return begin (from = static_cast <size_t> (_array[from].base) ^ c, ++len);
499 npos_t tracking_node[NUM_TRACKING_NODES + 1];
503 da& operator= (
const da&);
505 union {
char* _tail;
int* _length; };
506 union {
int* _tail0;
int* _length0; };
519 static void _err (
const char* fn,
const int ln,
const char* msg)
520 { std::fprintf (stderr,
"cedar: %s [%d]: %s", fn, ln, msg); std::exit (1); }
521 template <
typename T>
522 static void _realloc_array (T*& p,
const int size_n,
const int size_p = 0) {
523 void* tmp = std::realloc (p,
sizeof (T) * static_cast <size_t> (size_n));
525 std::free (p), _err (__FILE__, __LINE__,
"memory reallocation failed\n");
526 p = static_cast <T*> (tmp);
527 static const T T0 = T ();
528 for (T* q (p + size_p), *
const r (p + size_n); q != r; ++q) *q = T0;
530 void _initialize () {
531 _realloc_array (_array, 256, 256);
532 _realloc_array (_tail,
sizeof (
int));
533 _realloc_array (_tail0, 1);
534 _realloc_array (_ninfo, 256);
535 _realloc_array (_block, 1);
536 _array[0] = node (0, -1);
537 for (
int i = 1; i < 256; ++i)
538 _array[i] = node (i == 1 ? -255 : - (i - 1), i == 255 ? -1 : - (i + 1));
539 _capacity = _size = 256;
541 _quota = *_length = static_cast <
int> (
sizeof (int));
543 for (
size_t i = 0 ; i <= NUM_TRACKING_NODES; ++i) tracking_node[i] = 0;
544 for (
short i = 0; i <= 256; ++i) _reject[i] = i + 1;
547 template <
typename T>
548 int _follow (npos_t& from,
const uchar& label, T& cf) {
550 const int base = _array[from].base;
551 if (base < 0 || _array[to = base ^ label].check < 0) {
552 to = _pop_enode (base, label, static_cast <int> (from));
553 _push_sibling (from, to ^ label, label, base >= 0);
554 }
else if (_array[to].check != static_cast <int> (from))
555 to = _resolve (from, base, label, cf);
559 int _find (
const char* key, npos_t& from,
size_t& pos,
const size_t len)
const {
560 npos_t offset = from >> 32;
562 for (
const uchar*
const key_ = reinterpret_cast <const uchar*> (key);
563 _array[from].base >= 0; ) {
565 const node& n = _array[_array[from].base ^ 0];
566 if (n.check != static_cast <int> (from))
return CEDAR_NO_VALUE;
569 size_t to = static_cast <
size_t> (_array[from].base); to ^= key_[pos];
570 if (_array[to].check != static_cast <int> (from))
return CEDAR_NO_PATH;
574 offset = static_cast <npos_t> (-_array[from].base);
577 const size_t pos_orig = pos;
578 const char*
const tail = &_tail[offset] - pos;
580 do if (key[pos] != tail[pos])
break;
while (++pos < len);
581 if (
const npos_t moved = pos - pos_orig) {
582 from &= TAIL_OFFSET_MASK;
583 from |= (offset + moved) << 32;
585 if (pos < len)
return CEDAR_NO_PATH;
587 if (tail[pos])
return CEDAR_NO_VALUE;
588 return *reinterpret_cast <
const int*> (&tail[len + 1]);
590 #ifndef USE_FAST_LOAD
591 void _restore_ninfo () {
592 _realloc_array (_ninfo, _size);
593 for (
int to = 0; to < _size; ++to) {
594 const int from = _array[to].check;
595 if (from < 0)
continue;
596 const int base = _array[from].base;
597 if (
const uchar label = static_cast <uchar> (base ^ to))
598 _push_sibling (static_cast <size_t> (from), base, label,
599 ! from || _ninfo[from].child || _array[base ^ 0].check == from);
602 void _restore_block () {
603 _realloc_array (_block, _size >> 8);
604 _bheadF = _bheadC = _bheadO = 0;
605 for (
int bi (0), e (0); e < _size; ++bi) {
606 block& b = _block[bi];
608 for (; e < (bi << 8) + 256; ++e)
609 if (_array[e].check < 0 && ++b.num == 1) b.ehead = e;
610 int& head_out = b.num == 1 ? _bheadC : (b.num == 0 ? _bheadF : _bheadO);
611 _push_block (bi, head_out, ! head_out && b.num);
615 void _set_result (result_type* x, value_type r,
size_t = 0, npos_t = 0)
const
617 void _set_result (result_pair_type* x, value_type r,
size_t l, npos_t = 0)
const
618 { x->value = r; x->length = l; }
619 void _set_result (result_triple_type* x, value_type r,
size_t l, npos_t from)
const
620 { x->value = r; x->length = l; x->id = from; }
621 void _pop_block (
const int bi,
int& head_in,
const bool last) {
625 const block& b = _block[bi];
626 _block[b.prev].next = b.next;
627 _block[b.next].prev = b.prev;
628 if (bi == head_in) head_in = b.next;
631 void _push_block (
const int bi,
int& head_out,
const bool empty) {
632 block& b = _block[bi];
634 head_out = b.prev = b.next = bi;
636 int& tail_out = _block[head_out].prev;
639 head_out = tail_out = _block[tail_out].next = bi;
643 if (_size == _capacity) {
645 _capacity += _size >= MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE : _size;
647 _capacity += _capacity;
649 _realloc_array (_array, _capacity, _capacity);
650 _realloc_array (_ninfo, _capacity, _size);
651 _realloc_array (_block, _capacity >> 8, _size >> 8);
653 _block[_size >> 8].ehead = _size;
654 _array[_size] = node (- (_size + 255), - (_size + 1));
655 for (
int i = _size + 1; i < _size + 255; ++i)
656 _array[i] = node (-(i - 1), -(i + 1));
657 _array[_size + 255] = node (- (_size + 254), -_size);
658 _push_block (_size >> 8, _bheadO, ! _bheadO);
660 return (_size >> 8) - 1;
663 void _transfer_block (
const int bi,
int& head_in,
int& head_out) {
664 _pop_block (bi, head_in, bi == _block[bi].next);
665 _push_block (bi, head_out, ! head_out && _block[bi].num);
668 int _pop_enode (
const int base,
const uchar label,
const int from) {
669 const int e = base < 0 ? _find_place () : base ^ label;
670 const int bi = e >> 8;
672 block& b = _block[bi];
674 if (bi) _transfer_block (bi, _bheadC, _bheadF);
676 _array[-n.base].check = n.check;
677 _array[-n.check].base = n.base;
678 if (e == b.ehead) b.ehead = -n.check;
679 if (bi && b.num == 1 && b.trial != MAX_TRIAL)
680 _transfer_block (bi, _bheadO, _bheadC);
683 if (label) n.base = -1;
else n.value = value_type (0);
685 if (base < 0) _array[from].base = e ^ label;
689 void _push_enode (
const int e) {
690 const int bi = e >> 8;
691 block& b = _block[bi];
694 _array[e] = node (-e, -e);
695 if (bi) _transfer_block (bi, _bheadF, _bheadC);
697 const int prev = b.ehead;
698 const int next = -_array[prev].check;
699 _array[e] = node (-prev, -next);
700 _array[prev].check = _array[next].base = -e;
701 if (b.num == 2 || b.trial == MAX_TRIAL) {
702 if (bi) _transfer_block (bi, _bheadC, _bheadO);
706 if (b.reject < _reject[b.num]) b.reject = _reject[b.num];
707 _ninfo[e] = ninfo ();
710 void _push_sibling (
const npos_t from,
const int base,
const uchar label,
const bool flag =
true) {
711 uchar* c = &_ninfo[from].child;
712 if (flag && (ORDERED ? label > *c : ! *c))
713 do c = &_ninfo[base ^ *c].sibling;
while (ORDERED && *c && *c < label);
714 _ninfo[base ^ label].sibling = *c, *c = label;
717 void _pop_sibling (
const npos_t from,
const int base,
const uchar label) {
718 uchar* c = &_ninfo[from].child;
719 while (*c != label) c = &_ninfo[base ^ *c].sibling;
720 *c = _ninfo[base ^ label].sibling;
723 bool _consult (
const int base_n,
const int base_p, uchar c_n, uchar c_p)
const {
724 do c_n = _ninfo[base_n ^ c_n].sibling, c_p = _ninfo[base_p ^ c_p].sibling;
729 uchar* _set_child (uchar* p,
const int base, uchar c,
const int label = -1) {
731 if (! c) { *++p = c; c = _ninfo[base ^ c].sibling; }
733 while (c && c < label) { *++p = c; c = _ninfo[base ^ c].sibling; }
734 if (label != -1) *++p = static_cast <uchar> (label);
735 while (c) { *++p = c; c = _ninfo[base ^ c].sibling; }
740 if (_bheadC)
return _block[_bheadC].ehead;
741 if (_bheadO)
return _block[_bheadO].ehead;
742 return _add_block () << 8;
744 int _find_place (
const uchar*
const first,
const uchar*
const last) {
745 if (
int bi = _bheadO) {
746 const int bz = _block[_bheadO].prev;
747 const short nc = static_cast <
short> (last - first + 1);
749 block& b = _block[bi];
750 if (b.num >= nc && nc < b.reject)
751 for (
int e = b.ehead;;) {
752 const int base = e ^ *first;
753 for (
const uchar* p = first; _array[base ^ *++p].check < 0; )
754 if (p == last)
return b.ehead = e;
755 if ((e = -_array[e].check) == b.ehead)
break;
758 if (b.reject < _reject[b.num]) _reject[b.num] = b.reject;
759 const int bi_ = b.next;
760 if (++b.trial == MAX_TRIAL) _transfer_block (bi, _bheadO, _bheadC);
765 return _add_block () << 8;
768 template <
typename T>
769 int _resolve (npos_t& from_n,
const int base_n,
const uchar label_n, T& cf) {
771 const int to_pn = base_n ^ label_n;
772 const int from_p = _array[to_pn].check;
773 const int base_p = _array[from_p].base;
775 = _consult (base_n, base_p, _ninfo[from_n].child, _ninfo[from_p].child);
777 uchar*
const first = &child[0];
779 flag ? _set_child (first, base_n, _ninfo[from_n].child, label_n)
780 : _set_child (first, base_p, _ninfo[from_p].child);
782 (first == last ? _find_place () : _find_place (first, last)) ^ *first;
784 const int from = flag ? static_cast <
int> (from_n) : from_p;
785 const int base_ = flag ? base_n : base_p;
786 if (flag && *first == label_n) _ninfo[from].child = label_n;
787 _array[from].base = base;
788 for (
const uchar* p = first; p <= last; ++p) {
789 const int to = _pop_enode (base, *p, from);
790 const int to_ = base_ ^ *p;
791 _ninfo[to].sibling = (p == last ? 0 : *(p + 1));
792 if (flag && to_ == to_pn)
continue;
794 node& n = _array[to];
795 node& n_ = _array[to_];
796 if ((n.base = n_.base) > 0 && *p) {
797 uchar c = _ninfo[to].child = _ninfo[to_].child;
798 do _array[n.base ^ c].check = to;
799 while ((c = _ninfo[n.base ^ c].sibling));
801 if (! flag && to_ == static_cast <int> (from_n))
802 from_n = static_cast <
size_t> (to);
803 if (! flag && to_ == to_pn) {
804 _push_sibling (from_n, to_pn ^ label_n, label_n);
805 _ninfo[to_].child = 0;
806 if (label_n) n_.base = -1;
else n_.value = value_type (0);
807 n_.check = static_cast <
int> (from_n);
810 if (NUM_TRACKING_NODES)
811 for (
size_t j = 0; tracking_node[j] != 0; ++j) {
812 if (static_cast <int> (tracking_node[j] & TAIL_OFFSET_MASK) == to_) {
813 tracking_node[j] &= NODE_INDEX_MASK;
814 tracking_node[j] |= static_cast <npos_t> (to);
818 return flag ? base ^ label_n : to_pn;
821 void _test (
const npos_t from = 0)
const {
822 const int base = _array[from].base;
824 assert (*_length >= static_cast <int> (-base + 1 +
sizeof (value_type)));
827 uchar c = _ninfo[from].child;
829 if (from) assert (_array[base ^ c].check == static_cast <int> (from));
830 if (c) _test (static_cast <npos_t> (base ^ c));
831 }
while ((c = _ninfo[base ^ c].sibling));