16 #ifdef SUPPRESS_CEDAR_ASSERT
17 #define STATIC_ASSERT(e, msg)
19 #define STATIC_ASSERT(e, msg) typedef char msg[(e) ? 1 : -1]
24 typedef unsigned char uchar;
25 template <
typename T>
struct NaN {
enum { N1 = -1, N2 = -2 }; };
26 template <>
struct NaN <float> {
enum { N1 = 0x7f800001, N2 = 0x7f800002 }; };
27 static const int MAX_ALLOC_SIZE = 1 << 16;
29 template <
typename value_type,
32 const bool ORDERED =
true,
33 const int MAX_TRIAL = 1,
34 const size_t NUM_TRACKING_NODES = 0>
37 enum error_code { CEDAR_NO_VALUE = NO_VALUE, CEDAR_NO_PATH = NO_PATH, CEDAR_VALUE_LIMIT = 2147483647 };
38 typedef value_type result_type;
49 union {
int base_; value_type value; };
51 node (
const int base__ = 0,
const int check_ = 0)
52 : base_ (base__), check (check_) {}
53 #ifdef USE_REDUCED_TRIE
54 int base ()
const {
return - (base_ + 1); }
56 int base ()
const {
return base_; }
62 ninfo () : sibling (0), child (0) {}
71 block () : prev (0), next (0), num (256), reject (257), trial (0), ehead (0) {}
73 da () : tracking_node (), _array (0), _ninfo (0), _block (0), _bheadF (0), _bheadC (0), _bheadO (0), _capacity (0), _size (0), _no_delete (false), _reject () {
74 STATIC_ASSERT(
sizeof (value_type) <=
sizeof (
int),
75 value_type_is_not_supported___maintain_a_value_array_by_yourself_and_store_its_index
79 ~
da () { clear (
false); }
80 size_t capacity ()
const {
return static_cast <
size_t> (_capacity); }
81 size_t size ()
const {
return static_cast <
size_t> (_size); }
82 size_t total_size ()
const {
return sizeof (node) * _size; }
83 size_t unit_size ()
const {
return sizeof (node); }
84 size_t nonzero_size ()
const {
86 for (
int to = 0; to < _size; ++to)
87 if (_array[to].check >= 0) ++i;
90 size_t num_keys ()
const {
92 for (
int to = 0; to < _size; ++to)
93 #ifdef USE_REDUCED_TRIE
94 if (_array[to].check >= 0 && _array[to].value >= 0) ++i;
96 if (_array[to].check >= 0 && _array[_array[to].check].base () == to) ++i;
101 template <
typename T>
102 T exactMatchSearch (
const char* key)
const
103 {
return exactMatchSearch <T> (key, std::strlen (key)); }
104 template <
typename T>
105 T exactMatchSearch (
const char* key,
size_t len,
size_t from = 0)
const {
106 union {
int i; value_type x; } b;
108 b.i = _find (key, from, pos, len);
109 if (b.i == CEDAR_NO_PATH) b.i = CEDAR_NO_VALUE;
111 _set_result (&result, b.x, len, from);
114 template <
typename T>
115 size_t commonPrefixSearch (
const char* key, T* result,
size_t result_len)
const
116 {
return commonPrefixSearch (key, result, result_len, std::strlen (key)); }
117 template <
typename T>
118 size_t commonPrefixSearch (
const char* key, T* result,
size_t result_len,
size_t len,
size_t from = 0)
const {
120 for (
size_t pos = 0; pos < len; ) {
121 union {
int i; value_type x; } b;
122 b.i = _find (key, from, pos, pos + 1);
123 if (b.i == CEDAR_NO_VALUE)
continue;
124 if (b.i == CEDAR_NO_PATH)
return num;
125 if (num < result_len) _set_result (&result[num], b.x, pos, from);
131 template <
typename T>
132 size_t commonPrefixPredict (
const char* key, T* result,
size_t result_len)
133 {
return commonPrefixPredict (key, result, result_len, std::strlen (key)); }
134 template <
typename T>
135 size_t commonPrefixPredict (
const char* key, T* result,
size_t result_len,
size_t len,
size_t from = 0) {
136 size_t num (0), pos (0), p (0);
137 if (_find (key, from, pos, len) == CEDAR_NO_PATH)
return 0;
138 union {
int i; value_type x; } b;
140 for (b.i = begin (from, p); b.i != CEDAR_NO_PATH; b.i = next (from, p, root)) {
141 if (num < result_len) _set_result (&result[num], b.x, p, from);
146 void suffix (
char* key,
size_t len,
size_t to)
const {
149 const int from = _array[to].check;
151 = static_cast <
char> (_array[from].base () ^ static_cast <
int> (to));
152 to = static_cast <
size_t> (from);
155 value_type traverse (
const char* key,
size_t& from,
size_t& pos)
const
156 {
return traverse (key, from, pos, std::strlen (key)); }
157 value_type traverse (
const char* key,
size_t& from,
size_t& pos,
size_t len)
const {
158 union {
int i; value_type x; } b;
159 b.i = _find (key, from, pos, len);
163 value_type& update (
const char* key)
164 {
return update (key, std::strlen (key)); }
165 value_type& update (
const char* key,
size_t len, value_type val = value_type (0))
166 {
size_t from (0), pos (0);
return update (key, from, pos, len, val); }
167 value_type& update (
const char* key,
size_t& from,
size_t& pos,
size_t len, value_type val = value_type (0))
168 { empty_callback cf;
return update (key, from, pos, len, val, cf); }
169 template <
typename T>
170 value_type& update (
const char* key,
size_t& from,
size_t& pos,
size_t len, value_type val, T& cf) {
172 _err (__FILE__, __LINE__,
"failed to insert zero-length key\n");
173 #ifndef USE_FAST_LOAD
174 if (! _ninfo || ! _block) restore ();
176 for (
const uchar*
const key_ = reinterpret_cast <const uchar*> (key);
178 #ifdef USE_REDUCED_TRIE
179 const value_type val_ = _array[from].value;
180 if (val_ >= 0 && val_ != CEDAR_VALUE_LIMIT)
181 {
const int to = _follow (from, 0, cf); _array[to].value = val_; }
183 from = static_cast <
size_t> (_follow (from, key_[pos], cf));
185 #ifdef USE_REDUCED_TRIE
186 const int to = _array[from].value >= 0 ? static_cast <
int> (from) : _follow (from, 0, cf);
187 if (_array[to].value == CEDAR_VALUE_LIMIT) _array[to].value = 0;
189 const int to = _follow (from, 0, cf);
191 return _array[to].value += val;
194 int erase (
const char* key) {
return erase (key, std::strlen (key)); }
195 int erase (
const char* key,
size_t len,
size_t from = 0) {
197 const int i = _find (key, from, pos, len);
198 if (i == CEDAR_NO_PATH || i == CEDAR_NO_VALUE)
return -1;
202 void erase (
size_t from) {
204 #ifdef USE_REDUCED_TRIE
205 int e = _array[from].value >= 0 ? static_cast <
int> (from) : _array[from].base () ^ 0;
206 from = static_cast <
size_t> (_array[e].check);
208 int e = _array[from].base () ^ 0;
212 const node& n = _array[from];
213 flag = _ninfo[n.base () ^ _ninfo[from].child].sibling;
214 if (flag) _pop_sibling (from, n.base (), static_cast <uchar> (n.base () ^ e));
216 e = static_cast <
int> (from);
217 from = static_cast <
size_t> (_array[from].check);
220 int build (
size_t num,
const char** key,
const size_t* len = 0,
const value_type* val = 0) {
221 for (
size_t i = 0; i < num; ++i)
222 update (key[i], len ? len[i] : std::strlen (key[i]), val ? val[i] : value_type (i));
225 template <
typename T>
226 void dump (T* result,
const size_t result_len) {
227 union {
int i; value_type x; } b;
228 size_t num (0), from (0), p (0);
229 for (b.i = begin (from, p); b.i != CEDAR_NO_PATH; b.i = next (from, p))
230 if (num < result_len)
231 _set_result (&result[num++], b.x, p, from);
233 _err (__FILE__, __LINE__,
"dump() needs array of length = num_keys()\n");
235 int save (
const char* fn,
const char* mode =
"wb")
const {
237 FILE* fp = std::fopen (fn, mode);
239 std::fwrite (_array,
sizeof (node), static_cast <size_t> (_size), fp);
242 const char*
const info
243 = std::strcat (std::strcpy (
new char[std::strlen (fn) + 5], fn),
".sbl");
244 fp = std::fopen (info, mode);
247 std::fwrite (&_bheadF,
sizeof (
int), 1, fp);
248 std::fwrite (&_bheadC,
sizeof (
int), 1, fp);
249 std::fwrite (&_bheadO,
sizeof (
int), 1, fp);
250 std::fwrite (_ninfo,
sizeof (ninfo), static_cast <size_t> (_size), fp);
251 std::fwrite (_block,
sizeof (block), static_cast <size_t> (_size >> 8), fp);
256 int open (
const char* fn,
const char* mode =
"rb",
257 const size_t offset = 0,
size_t size_ = 0) {
258 FILE* fp = std::fopen (fn, mode);
262 if (std::fseek (fp, 0, SEEK_END) != 0)
return -1;
263 size_ = static_cast <
size_t> (std::ftell (fp));
264 if (std::fseek (fp, 0, SEEK_SET) != 0)
return -1;
266 if (size_ <= offset)
return -1;
269 size_ = (size_ - offset) /
sizeof (node);
270 if (std::fseek (fp, static_cast <long> (offset), SEEK_SET) != 0)
return -1;
271 _array = static_cast <node*> (std::malloc (
sizeof (node) * size_));
273 _ninfo = static_cast <ninfo*> (std::malloc (
sizeof (ninfo) * size_));
274 _block = static_cast <block*> (std::malloc (
sizeof (block) * size_));
275 if (! _array || ! _ninfo || ! _block)
279 _err (__FILE__, __LINE__,
"memory allocation failed\n");
280 if (size_ != std::fread (_array,
sizeof (node), size_, fp))
return -1;
282 _size = static_cast <
int> (size_);
284 const char*
const info
285 = std::strcat (std::strcpy (
new char[std::strlen (fn) + 5], fn),
".sbl");
286 fp = std::fopen (info, mode);
289 std::fread (&_bheadF,
sizeof (
int), 1, fp);
290 std::fread (&_bheadC,
sizeof (
int), 1, fp);
291 std::fread (&_bheadO,
sizeof (
int), 1, fp);
292 if (size_ != std::fread (_ninfo,
sizeof (ninfo), size_, fp) ||
293 size_ != std::fread (_block,
sizeof (block), size_ >> 8, fp) << 8)
300 #ifndef USE_FAST_LOAD
302 if (! _block) _restore_block ();
303 if (! _ninfo) _restore_ninfo ();
307 void set_array (
void* p,
size_t size_ = 0) {
309 _array = static_cast <node*> (p);
310 _size = static_cast <
int> (size_);
313 const void* array ()
const {
return _array; }
314 void clear (
const bool reuse =
true) {
315 if (_array && ! _no_delete) std::free (_array); _array = 0;
316 if (_ninfo) std::free (_ninfo); _ninfo = 0;
317 if (_block) std::free (_block); _block = 0;
318 _bheadF = _bheadC = _bheadO = _capacity = _size = 0;
319 if (reuse) _initialize ();
323 int begin (
size_t& from,
size_t& len) {
324 #ifndef USE_FAST_LOAD
325 if (! _ninfo) _restore_ninfo ();
327 int base = _array[from].base ();
328 uchar c = _ninfo[from].child;
329 if (! from && ! (c = _ninfo[base ^ c].sibling))
330 return CEDAR_NO_PATH;
332 from = static_cast <
size_t> (_array[from].base ()) ^ c;
333 c = _ninfo[from].child;
335 #ifdef USE_REDUCED_TRIE
336 if (_array[from].value >= 0)
return _array[from].value;
338 return _array[_array[from].base () ^ c].base_;
341 int next (
size_t& from,
size_t& len,
const size_t root = 0) {
343 #ifdef USE_REDUCED_TRIE
344 if (_array[from].value < 0)
346 c = _ninfo[_array[from].base () ^ 0].sibling;
347 for (; ! c && from != root; --len) {
348 c = _ninfo[from].sibling;
349 from = static_cast <
size_t> (_array[from].check);
352 begin (from = static_cast <size_t> (_array[from].base ()) ^ c, ++len) :
356 void test (
const size_t from = 0)
const {
357 const int base = _array[from].base ();
358 uchar c = _ninfo[from].child;
360 if (from) assert (_array[base ^ c].check == static_cast <int> (from));
361 if (c && _array[base ^ c].value < 0)
362 test (static_cast <size_t> (base ^ c));
363 }
while ((c = _ninfo[base ^ c].sibling));
365 size_t tracking_node[NUM_TRACKING_NODES + 1];
369 da& operator= (
const da&);
381 static void _err (
const char* fn,
const int ln,
const char* msg)
382 { std::fprintf (stderr,
"cedar: %s [%d]: %s", fn, ln, msg); std::exit (1); }
383 template <
typename T>
384 static void _realloc_array (T*& p,
const int size_n,
const int size_p = 0) {
385 void* tmp = std::realloc (p,
sizeof (T) * static_cast <size_t> (size_n));
387 std::free (p), _err (__FILE__, __LINE__,
"memory reallocation failed\n");
388 p = static_cast <T*> (tmp);
389 static const T T0 = T ();
390 for (T* q (p + size_p), *
const r (p + size_n); q != r; ++q) *q = T0;
392 void _initialize () {
393 _realloc_array (_array, 256, 256);
394 _realloc_array (_ninfo, 256);
395 _realloc_array (_block, 1);
396 #ifdef USE_REDUCED_TRIE
397 _array[0] = node (-1, -1);
399 _array[0] = node (0, -1);
401 for (
int i = 1; i < 256; ++i)
402 _array[i] = node (i == 1 ? -255 : - (i - 1), i == 255 ? -1 : - (i + 1));
404 _capacity = _size = 256;
405 for (
size_t i = 0 ; i <= NUM_TRACKING_NODES; ++i) tracking_node[i] = 0;
406 for (
short i = 0; i <= 256; ++i) _reject[i] = i + 1;
409 template <
typename T>
410 int _follow (
size_t& from,
const uchar& label, T& cf) {
412 const int base = _array[from].base ();
413 if (base < 0 || _array[to = base ^ label].check < 0) {
414 to = _pop_enode (base, label, static_cast <int> (from));
415 _push_sibling (from, to ^ label, label, base >= 0);
416 }
else if (_array[to].check != static_cast <int> (from))
417 to = _resolve (from, base, label, cf);
421 int _find (
const char* key,
size_t& from,
size_t& pos,
const size_t len)
const {
422 for (
const uchar*
const key_ = reinterpret_cast <const uchar*> (key);
424 #ifdef USE_REDUCED_TRIE
425 if (_array[from].value >= 0)
break;
427 size_t to = static_cast <
size_t> (_array[from].base ()); to ^= key_[pos];
428 if (_array[to].check != static_cast <int> (from))
return CEDAR_NO_PATH;
432 #ifdef USE_REDUCED_TRIE
433 if (_array[from].value >= 0)
434 return pos == len ? _array[from].value : CEDAR_NO_PATH;
436 const node n = _array[_array[from].base () ^ 0];
437 if (n.check != static_cast <int> (from))
return CEDAR_NO_VALUE;
440 #ifndef USE_FAST_LOAD
441 void _restore_ninfo () {
442 _realloc_array (_ninfo, _size);
443 for (
int to = 0; to < _size; ++to) {
444 const int from = _array[to].check;
445 if (from < 0)
continue;
446 const int base = _array[from].base ();
447 if (
const uchar label = static_cast <uchar> (base ^ to))
448 _push_sibling (static_cast <size_t> (from), base, label,
449 ! from || _ninfo[from].child || _array[base ^ 0].check == from);
452 void _restore_block () {
453 _realloc_array (_block, _size >> 8);
454 _bheadF = _bheadC = _bheadO = 0;
455 for (
int bi (0), e (0); e < _size; ++bi) {
456 block& b = _block[bi];
458 for (; e < (bi << 8) + 256; ++e)
459 if (_array[e].check < 0 && ++b.num == 1) b.ehead = e;
460 int& head_out = b.num == 1 ? _bheadC : (b.num == 0 ? _bheadF : _bheadO);
461 _push_block (bi, head_out, ! head_out && b.num);
465 void _set_result (result_type* x, value_type r,
size_t = 0,
size_t = 0)
const
467 void _set_result (result_pair_type* x, value_type r,
size_t l,
size_t = 0)
const
468 { x->value = r; x->length = l; }
469 void _set_result (result_triple_type* x, value_type r,
size_t l,
size_t from)
const
470 { x->value = r; x->length = l; x->id = from; }
471 void _pop_block (
const int bi,
int& head_in,
const bool last) {
475 const block& b = _block[bi];
476 _block[b.prev].next = b.next;
477 _block[b.next].prev = b.prev;
478 if (bi == head_in) head_in = b.next;
481 void _push_block (
const int bi,
int& head_out,
const bool empty) {
482 block& b = _block[bi];
484 head_out = b.prev = b.next = bi;
486 int& tail_out = _block[head_out].prev;
489 head_out = tail_out = _block[tail_out].next = bi;
493 if (_size == _capacity) {
495 _capacity += _size >= MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE : _size;
497 _capacity += _capacity;
499 _realloc_array (_array, _capacity, _capacity);
500 _realloc_array (_ninfo, _capacity, _size);
501 _realloc_array (_block, _capacity >> 8, _size >> 8);
503 _block[_size >> 8].ehead = _size;
504 _array[_size] = node (- (_size + 255), - (_size + 1));
505 for (
int i = _size + 1; i < _size + 255; ++i)
506 _array[i] = node (-(i - 1), -(i + 1));
507 _array[_size + 255] = node (- (_size + 254), -_size);
508 _push_block (_size >> 8, _bheadO, ! _bheadO);
510 return (_size >> 8) - 1;
513 void _transfer_block (
const int bi,
int& head_in,
int& head_out) {
514 _pop_block (bi, head_in, bi == _block[bi].next);
515 _push_block (bi, head_out, ! head_out && _block[bi].num);
518 int _pop_enode (
const int base,
const uchar label,
const int from) {
519 const int e = base < 0 ? _find_place () : base ^ label;
520 const int bi = e >> 8;
522 block& b = _block[bi];
524 if (bi) _transfer_block (bi, _bheadC, _bheadF);
526 _array[-n.base_].check = n.check;
527 _array[-n.check].base_ = n.base_;
528 if (e == b.ehead) b.ehead = -n.check;
529 if (bi && b.num == 1 && b.trial != MAX_TRIAL)
530 _transfer_block (bi, _bheadO, _bheadC);
533 #ifdef USE_REDUCED_TRIE
534 n.value = CEDAR_VALUE_LIMIT; n.check = from;
535 if (base < 0) _array[from].base_ = - (e ^ label) - 1;
537 if (label) n.base_ = -1;
else n.value = value_type (0); n.check = from;
538 if (base < 0) _array[from].base_ = e ^ label;
543 void _push_enode (
const int e) {
544 const int bi = e >> 8;
545 block& b = _block[bi];
548 _array[e] = node (-e, -e);
549 if (bi) _transfer_block (bi, _bheadF, _bheadC);
551 const int prev = b.ehead;
552 const int next = -_array[prev].check;
553 _array[e] = node (-prev, -next);
554 _array[prev].check = _array[next].base_ = -e;
555 if (b.num == 2 || b.trial == MAX_TRIAL)
556 if (bi) _transfer_block (bi, _bheadC, _bheadO);
559 if (b.reject < _reject[b.num]) b.reject = _reject[b.num];
560 _ninfo[e] = ninfo ();
563 void _push_sibling (
const size_t from,
const int base,
const uchar label,
const bool flag =
true) {
564 uchar* c = &_ninfo[from].child;
565 if (flag && (ORDERED ? label > *c : ! *c))
566 do c = &_ninfo[base ^ *c].sibling;
while (ORDERED && *c && *c < label);
567 _ninfo[base ^ label].sibling = *c, *c = label;
570 void _pop_sibling (
const size_t from,
const int base,
const uchar label) {
571 uchar* c = &_ninfo[from].child;
572 while (*c != label) c = &_ninfo[base ^ *c].sibling;
573 *c = _ninfo[base ^ label].sibling;
576 bool _consult (
const int base_n,
const int base_p, uchar c_n, uchar c_p)
const {
577 do c_n = _ninfo[base_n ^ c_n].sibling, c_p = _ninfo[base_p ^ c_p].sibling;
582 uchar* _set_child (uchar* p,
const int base, uchar c,
const int label = -1) {
584 if (! c) { *++p = c; c = _ninfo[base ^ c].sibling; }
586 while (c && c < label) { *++p = c; c = _ninfo[base ^ c].sibling; }
587 if (label != -1) *++p = static_cast <uchar> (label);
588 while (c) { *++p = c; c = _ninfo[base ^ c].sibling; }
593 if (_bheadC)
return _block[_bheadC].ehead;
594 if (_bheadO)
return _block[_bheadO].ehead;
595 return _add_block () << 8;
597 int _find_place (
const uchar*
const first,
const uchar*
const last) {
598 if (
int bi = _bheadO) {
599 const int bz = _block[_bheadO].prev;
600 const short nc = static_cast <
short> (last - first + 1);
602 block& b = _block[bi];
603 if (b.num >= nc && nc < b.reject)
604 for (
int e = b.ehead;;) {
605 const int base = e ^ *first;
606 for (
const uchar* p = first; _array[base ^ *++p].check < 0; )
607 if (p == last)
return b.ehead = e;
608 if ((e = -_array[e].check) == b.ehead)
break;
611 if (b.reject < _reject[b.num]) _reject[b.num] = b.reject;
612 const int bi_ = b.next;
613 if (++b.trial == MAX_TRIAL) _transfer_block (bi, _bheadO, _bheadC);
618 return _add_block () << 8;
621 template <
typename T>
622 int _resolve (
size_t& from_n,
const int base_n,
const uchar label_n, T& cf) {
624 const int to_pn = base_n ^ label_n;
625 const int from_p = _array[to_pn].check;
626 const int base_p = _array[from_p].base ();
628 = _consult (base_n, base_p, _ninfo[from_n].child, _ninfo[from_p].child);
630 uchar*
const first = &child[0];
632 flag ? _set_child (first, base_n, _ninfo[from_n].child, label_n)
633 : _set_child (first, base_p, _ninfo[from_p].child);
635 (first == last ? _find_place () : _find_place (first, last)) ^ *first;
637 const int from = flag ? static_cast <
int> (from_n) : from_p;
638 const int base_ = flag ? base_n : base_p;
639 if (flag && *first == label_n) _ninfo[from].child = label_n;
640 #ifdef USE_REDUCED_TRIE
641 _array[from].base_ = -base - 1;
643 _array[from].base_ = base;
645 for (
const uchar* p = first; p <= last; ++p) {
646 const int to = _pop_enode (base, *p, from);
647 const int to_ = base_ ^ *p;
648 _ninfo[to].sibling = (p == last ? 0 : *(p + 1));
649 if (flag && to_ == to_pn)
continue;
651 node& n = _array[to];
652 node& n_ = _array[to_];
653 #ifdef USE_REDUCED_TRIE
654 if ((n.base_ = n_.base_) < 0 && *p)
656 if ((n.base_ = n_.base_) > 0 && *p)
659 uchar c = _ninfo[to].child = _ninfo[to_].child;
660 do _array[n.base () ^ c].check = to;
661 while ((c = _ninfo[n.base () ^ c].sibling));
663 if (! flag && to_ == static_cast <int> (from_n))
664 from_n = static_cast <size_t> (to);
665 if (! flag && to_ == to_pn) {
666 _push_sibling (from_n, to_pn ^ label_n, label_n);
667 _ninfo[to_].child = 0;
668 #ifdef USE_REDUCED_TRIE
669 n_.value = CEDAR_VALUE_LIMIT;
671 if (label_n) n_.base_ = -1;
else n_.value = value_type (0);
673 n_.check = static_cast <
int> (from_n);
676 if (NUM_TRACKING_NODES)
677 for (
size_t j = 0; tracking_node[j] != 0; ++j)
678 if (tracking_node[j] == static_cast <size_t> (to_))
679 { tracking_node[j] = static_cast <
size_t> (to);
break; }
681 return flag ? base ^ label_n : to_pn;