libutil++  1.9.3
 All Classes Functions Variables
cedar.h
1 // cedar -- C++ implementation of Efficiently-updatable Double ARray trie
2 // $Id: cedar.h 1617 2016-01-19 06:39:10Z sella $
3 // Copyright (c) 2009-2014 Naoki Yoshinaga <ynaga@tkl.iis.u-tokyo.ac.jp>
4 #ifndef CEDAR_H
5 #define CEDAR_H
6 
7 #include <cstdio>
8 #include <cstdlib>
9 #include <cstring>
10 #include <cassert>
11 
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif
15 
16 #ifdef SUPPRESS_CEDAR_ASSERT /* Complains when used through the wrapper */
17 #define STATIC_ASSERT(e, msg)
18 #else
19 #define STATIC_ASSERT(e, msg) typedef char msg[(e) ? 1 : -1]
20 #endif
21 
22 namespace cedar {
23  // typedefs
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; // must be divisible by 256
28  // dynamic double array
29  template <typename value_type,
30  const int NO_VALUE = NaN <value_type>::N1,
31  const int NO_PATH = NaN <value_type>::N2,
32  const bool ORDERED = true,
33  const int MAX_TRIAL = 1,
34  const size_t NUM_TRACKING_NODES = 0>
35  class da {
36  public:
37  enum error_code { CEDAR_NO_VALUE = NO_VALUE, CEDAR_NO_PATH = NO_PATH, CEDAR_VALUE_LIMIT = 2147483647 };
38  typedef value_type result_type;
40  value_type value;
41  size_t length; // prefix length
42  };
43  struct result_triple_type { // for predict ()
44  value_type value;
45  size_t length; // suffix length
46  size_t id; // node id of value
47  };
48  struct node {
49  union { int base_; value_type value; }; // negative means prev empty index
50  int check; // negative means next empty index
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); } // ~ in two's complement system
55 #else
56  int base () const { return base_; }
57 #endif
58  };
59  struct ninfo { // x1.5 update speed; +.25 % memory (8n -> 10n)
60  uchar sibling; // right sibling (= 0 if not exist)
61  uchar child; // first child
62  ninfo () : sibling (0), child (0) {}
63  };
64  struct block { // a block w/ 256 elements
65  int prev; // prev block; 3 bytes
66  int next; // next block; 3 bytes
67  short num; // # empty elements; 0 - 256
68  short reject; // minimum # branching failed to locate; soft limit
69  int trial; // # trial
70  int ehead; // first empty item
71  block () : prev (0), next (0), num (256), reject (257), trial (0), ehead (0) {}
72  };
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
76  );
77  _initialize ();
78  }
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 {
85  size_t i = 0;
86  for (int to = 0; to < _size; ++to)
87  if (_array[to].check >= 0) ++i;
88  return i;
89  }
90  size_t num_keys () const {
91  size_t i = 0;
92  for (int to = 0; to < _size; ++to)
93 #ifdef USE_REDUCED_TRIE
94  if (_array[to].check >= 0 && _array[to].value >= 0) ++i;
95 #else
96  if (_array[to].check >= 0 && _array[_array[to].check].base () == to) ++i;
97 #endif
98  return i;
99  }
100  // interfance
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;
107  size_t pos = 0;
108  b.i = _find (key, from, pos, len);
109  if (b.i == CEDAR_NO_PATH) b.i = CEDAR_NO_VALUE;
110  T result;
111  _set_result (&result, b.x, len, from);
112  return result;
113  }
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 {
119  size_t num = 0;
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);
126  ++num;
127  }
128  return num;
129  }
130  // predict key from double array
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;
139  size_t root = from;
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);
142  ++num;
143  }
144  return num;
145  }
146  void suffix (char* key, size_t len, size_t to) const {
147  key[len] = '\0';
148  while (len--) {
149  const int from = _array[to].check;
150  key[len]
151  = static_cast <char> (_array[from].base () ^ static_cast <int> (to));
152  to = static_cast <size_t> (from);
153  }
154  }
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);
160  return b.x;
161  }
162  struct empty_callback { void operator () (const int, const int) {} }; // dummy empty function
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) {
171  if (! len && ! from)
172  _err (__FILE__, __LINE__, "failed to insert zero-length key\n");
173 #ifndef USE_FAST_LOAD
174  if (! _ninfo || ! _block) restore ();
175 #endif
176  for (const uchar* const key_ = reinterpret_cast <const uchar*> (key);
177  pos < len; ++pos) {
178 #ifdef USE_REDUCED_TRIE
179  const value_type val_ = _array[from].value;
180  if (val_ >= 0 && val_ != CEDAR_VALUE_LIMIT) // always new; correct this!
181  { const int to = _follow (from, 0, cf); _array[to].value = val_; }
182 #endif
183  from = static_cast <size_t> (_follow (from, key_[pos], cf));
184  }
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;
188 #else
189  const int to = _follow (from, 0, cf);
190 #endif
191  return _array[to].value += val;
192  }
193  // easy-going erase () without compression
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) {
196  size_t pos = 0;
197  const int i = _find (key, from, pos, len);
198  if (i == CEDAR_NO_PATH || i == CEDAR_NO_VALUE) return -1;
199  erase (from);
200  return 0;
201  }
202  void erase (size_t from) {
203  // _test ();
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);
207 #else
208  int e = _array[from].base () ^ 0;
209 #endif
210  bool flag = false; // have sibling
211  do {
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));
215  _push_enode (e);
216  e = static_cast <int> (from);
217  from = static_cast <size_t> (_array[from].check);
218  } while (! flag);
219  }
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));
223  return 0;
224  }
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);
232  else
233  _err (__FILE__, __LINE__, "dump() needs array of length = num_keys()\n");
234  }
235  int save (const char* fn, const char* mode = "wb") const {
236  // _test ();
237  FILE* fp = std::fopen (fn, mode);
238  if (! fp) return -1;
239  std::fwrite (_array, sizeof (node), static_cast <size_t> (_size), fp);
240  std::fclose (fp);
241 #ifdef USE_FAST_LOAD
242  const char* const info
243  = std::strcat (std::strcpy (new char[std::strlen (fn) + 5], fn), ".sbl");
244  fp = std::fopen (info, mode);
245  delete [] info; // resolve memory leak
246  if (! fp) return -1;
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);
252  std::fclose (fp);
253 #endif
254  return 0;
255  }
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);
259  if (! fp) return -1;
260  // get size
261  if (! size_) {
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;
265  }
266  if (size_ <= offset) return -1;
267  // set array
268  clear (false);
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_));
272 #ifdef USE_FAST_LOAD
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)
276 #else
277  if (! _array)
278 #endif
279  _err (__FILE__, __LINE__, "memory allocation failed\n");
280  if (size_ != std::fread (_array, sizeof (node), size_, fp)) return -1;
281  std::fclose (fp);
282  _size = static_cast <int> (size_);
283 #ifdef USE_FAST_LOAD
284  const char* const info
285  = std::strcat (std::strcpy (new char[std::strlen (fn) + 5], fn), ".sbl");
286  fp = std::fopen (info, mode);
287  delete [] info; // resolve memory leak
288  if (! fp) return -1;
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)
294  return -1;
295  std::fclose (fp);
296  _capacity = _size;
297 #endif
298  return 0;
299  }
300 #ifndef USE_FAST_LOAD
301  void restore () { // restore information to update
302  if (! _block) _restore_block ();
303  if (! _ninfo) _restore_ninfo ();
304  _capacity = _size;
305  }
306 #endif
307  void set_array (void* p, size_t size_ = 0) { // ad-hoc
308  clear (false);
309  _array = static_cast <node*> (p);
310  _size = static_cast <int> (size_);
311  _no_delete = true;
312  }
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 ();
320  _no_delete = false;
321  }
322  // return the first child for a tree rooted by a given node
323  int begin (size_t& from, size_t& len) {
324 #ifndef USE_FAST_LOAD
325  if (! _ninfo) _restore_ninfo ();
326 #endif
327  int base = _array[from].base ();
328  uchar c = _ninfo[from].child;
329  if (! from && ! (c = _ninfo[base ^ c].sibling)) // bug fix
330  return CEDAR_NO_PATH; // no entry
331  for (; c; ++len) {
332  from = static_cast <size_t> (_array[from].base ()) ^ c;
333  c = _ninfo[from].child;
334  }
335 #ifdef USE_REDUCED_TRIE
336  if (_array[from].value >= 0) return _array[from].value;
337 #endif
338  return _array[_array[from].base () ^ c].base_;
339  }
340  // return the next child if any
341  int next (size_t& from, size_t& len, const size_t root = 0) {
342  uchar c = 0;
343 #ifdef USE_REDUCED_TRIE
344  if (_array[from].value < 0)
345 #endif
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);
350  }
351  return c ?
352  begin (from = static_cast <size_t> (_array[from].base ()) ^ c, ++len) :
353  CEDAR_NO_PATH;
354  }
355  // test the validity of double array for debug
356  void test (const size_t from = 0) const {
357  const int base = _array[from].base ();
358  uchar c = _ninfo[from].child;
359  do {
360  if (from) assert (_array[base ^ c].check == static_cast <int> (from));
361  if (c && _array[base ^ c].value < 0) // correct this
362  test (static_cast <size_t> (base ^ c));
363  } while ((c = _ninfo[base ^ c].sibling));
364  }
365  size_t tracking_node[NUM_TRACKING_NODES + 1];
366  private:
367  // currently disabled; implement these if you need
368  da (const da&);
369  da& operator= (const da&);
370  node* _array;
371  ninfo* _ninfo;
372  block* _block;
373  int _bheadF; // first block of Full; 0
374  int _bheadC; // first block of Closed; 0 if no Closed
375  int _bheadO; // first block of Open; 0 if no Open
376  int _capacity;
377  int _size;
378  int _no_delete;
379  short _reject[257];
380  //
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));
386  if (! tmp)
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;
391  }
392  void _initialize () { // initilize the first special block
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);
398 #else
399  _array[0] = node (0, -1);
400 #endif
401  for (int i = 1; i < 256; ++i)
402  _array[i] = node (i == 1 ? -255 : - (i - 1), i == 255 ? -1 : - (i + 1));
403  _block[0].ehead = 1; // bug fix for erase
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;
407  }
408  // follow/create edge
409  template <typename T>
410  int _follow (size_t& from, const uchar& label, T& cf) {
411  int to = 0;
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);
418  return to;
419  }
420  // find key from double array
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);
423  pos < len; ) { // follow link
424 #ifdef USE_REDUCED_TRIE
425  if (_array[from].value >= 0) break;
426 #endif
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;
429  ++pos;
430  from = to;
431  }
432 #ifdef USE_REDUCED_TRIE
433  if (_array[from].value >= 0) // get value from leaf
434  return pos == len ? _array[from].value : CEDAR_NO_PATH; // only allow integer key
435 #endif
436  const node n = _array[_array[from].base () ^ 0];
437  if (n.check != static_cast <int> (from)) return CEDAR_NO_VALUE;
438  return n.base_;
439  }
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; // skip empty node
446  const int base = _array[from].base ();
447  if (const uchar label = static_cast <uchar> (base ^ to)) // skip leaf
448  _push_sibling (static_cast <size_t> (from), base, label,
449  ! from || _ninfo[from].child || _array[base ^ 0].check == from);
450  }
451  }
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) { // register blocks to full
456  block& b = _block[bi];
457  b.num = 0;
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);
462  }
463  }
464 #endif
465  void _set_result (result_type* x, value_type r, size_t = 0, size_t = 0) const
466  { *x = r; }
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) {
472  if (last) { // last one poped; Closed or Open
473  head_in = 0;
474  } else {
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;
479  }
480  }
481  void _push_block (const int bi, int& head_out, const bool empty) {
482  block& b = _block[bi];
483  if (empty) { // the destination is empty
484  head_out = b.prev = b.next = bi;
485  } else { // use most recently pushed
486  int& tail_out = _block[head_out].prev;
487  b.prev = tail_out;
488  b.next = head_out;
489  head_out = tail_out = _block[tail_out].next = bi;
490  }
491  }
492  int _add_block () {
493  if (_size == _capacity) { // allocate memory if needed
494 #ifdef USE_EXACT_FIT
495  _capacity += _size >= MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE : _size;
496 #else
497  _capacity += _capacity;
498 #endif
499  _realloc_array (_array, _capacity, _capacity);
500  _realloc_array (_ninfo, _capacity, _size);
501  _realloc_array (_block, _capacity >> 8, _size >> 8);
502  }
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); // append to block Open
509  _size += 256;
510  return (_size >> 8) - 1;
511  }
512  // transfer block from one start w/ head_in to one start w/ head_out
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);
516  }
517  // pop empty node from block; never transfer the special block (bi = 0)
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;
521  node& n = _array[e];
522  block& b = _block[bi];
523  if (--b.num == 0) {
524  if (bi) _transfer_block (bi, _bheadC, _bheadF); // Closed to Full
525  } else { // release empty node from empty ring
526  _array[-n.base_].check = n.check;
527  _array[-n.check].base_ = n.base_;
528  if (e == b.ehead) b.ehead = -n.check; // set ehead
529  if (bi && b.num == 1 && b.trial != MAX_TRIAL) // Open to Closed
530  _transfer_block (bi, _bheadO, _bheadC);
531  }
532  // initialize the released node
533 #ifdef USE_REDUCED_TRIE
534  n.value = CEDAR_VALUE_LIMIT; n.check = from;
535  if (base < 0) _array[from].base_ = - (e ^ label) - 1;
536 #else
537  if (label) n.base_ = -1; else n.value = value_type (0); n.check = from;
538  if (base < 0) _array[from].base_ = e ^ label;
539 #endif
540  return e;
541  }
542  // push empty node into empty ring
543  void _push_enode (const int e) {
544  const int bi = e >> 8;
545  block& b = _block[bi];
546  if (++b.num == 1) { // Full to Closed
547  b.ehead = e;
548  _array[e] = node (-e, -e);
549  if (bi) _transfer_block (bi, _bheadF, _bheadC); // Full to Closed
550  } else {
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) // Closed to Open
556  if (bi) _transfer_block (bi, _bheadC, _bheadO);
557  b.trial = 0;
558  }
559  if (b.reject < _reject[b.num]) b.reject = _reject[b.num];
560  _ninfo[e] = ninfo (); // reset ninfo; no child, no sibling
561  }
562  // push label to from's child
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;
568  }
569  // pop label from from's child
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;
574  }
575  // check whether to replace branching w/ the newly added node
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;
578  while (c_n && c_p);
579  return c_p;
580  }
581  // enumerate (equal to or more than one) child nodes
582  uchar* _set_child (uchar* p, const int base, uchar c, const int label = -1) {
583  --p;
584  if (! c) { *++p = c; c = _ninfo[base ^ c].sibling; } // 0: terminal
585  if (ORDERED)
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; }
589  return p;
590  }
591  // explore new block to settle down
592  int _find_place () {
593  if (_bheadC) return _block[_bheadC].ehead;
594  if (_bheadO) return _block[_bheadO].ehead;
595  return _add_block () << 8;
596  }
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);
601  while (1) { // set candidate block
602  block& b = _block[bi];
603  if (b.num >= nc && nc < b.reject) // explore configuration
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; // no conflict
608  if ((e = -_array[e].check) == b.ehead) break;
609  }
610  b.reject = nc;
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);
614  if (bi == bz) break;
615  bi = bi_;
616  };
617  }
618  return _add_block () << 8;
619  }
620  // resolve conflict on base_n ^ label_n = base_p ^ label_p
621  template <typename T>
622  int _resolve (size_t& from_n, const int base_n, const uchar label_n, T& cf) {
623  // examine siblings of conflicted nodes
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 ();
627  const bool flag // whether to replace siblings of newly added
628  = _consult (base_n, base_p, _ninfo[from_n].child, _ninfo[from_p].child);
629  uchar child[256];
630  uchar* const first = &child[0];
631  uchar* const last =
632  flag ? _set_child (first, base_n, _ninfo[from_n].child, label_n)
633  : _set_child (first, base_p, _ninfo[from_p].child);
634  const int base =
635  (first == last ? _find_place () : _find_place (first, last)) ^ *first;
636  // replace & modify empty list
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; // new child
640 #ifdef USE_REDUCED_TRIE
641  _array[from].base_ = -base - 1; // new base
642 #else
643  _array[from].base_ = base; // new base
644 #endif
645  for (const uchar* p = first; p <= last; ++p) { // to_ => to
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; // skip newcomer (no child)
650  cf (to_, to); // user-defined callback function to handle moved nodes
651  node& n = _array[to];
652  node& n_ = _array[to_];
653 #ifdef USE_REDUCED_TRIE
654  if ((n.base_ = n_.base_) < 0 && *p) // copy base; bug fix
655 #else
656  if ((n.base_ = n_.base_) > 0 && *p) // copy base; bug fix
657 #endif
658  {
659  uchar c = _ninfo[to].child = _ninfo[to_].child;
660  do _array[n.base () ^ c].check = to; // adjust grand son's check
661  while ((c = _ninfo[n.base () ^ c].sibling));
662  }
663  if (! flag && to_ == static_cast <int> (from_n)) // parent node moved
664  from_n = static_cast <size_t> (to); // bug fix
665  if (! flag && to_ == to_pn) { // the address is immediately used
666  _push_sibling (from_n, to_pn ^ label_n, label_n);
667  _ninfo[to_].child = 0; // remember to reset child
668 #ifdef USE_REDUCED_TRIE
669  n_.value = CEDAR_VALUE_LIMIT;
670 #else
671  if (label_n) n_.base_ = -1; else n_.value = value_type (0);
672 #endif
673  n_.check = static_cast <int> (from_n);
674  } else
675  _push_enode (to_);
676  if (NUM_TRACKING_NODES) // keep the traversed node updated
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; }
680  }
681  return flag ? base ^ label_n : to_pn;
682  }
683  };
684 }
685 #endif