libutil++  1.9.3
 All Classes Functions Variables
cedarpp.h
1 // cedar -- C++ implementation of Efficiently-updatable Double ARray trie
2 // $Id: cedarpp.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 <climits>
11 #include <cassert>
12 
13 #ifdef HAVE_CONFIG_H
14 #include "config.h"
15 #endif
16 
17 #ifdef SUPPRESS_CEDAR_ASSERT /* Complains when used through the wrapper */
18 #define STATIC_ASSERT(e, msg)
19 #else
20 #define STATIC_ASSERT(e, msg) typedef char msg[(e) ? 1 : -1]
21 #endif
22 
23 namespace cedar {
24  // typedefs
25 #if LONG_BIT == 64
26  typedef unsigned long npos_t; // possibly compatible with size_t
27 #else
28  typedef unsigned long long npos_t;
29 #endif
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; // must be divisible by 256
36  // dynamic double array
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>
43  class da {
44  public:
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 {
48  value_type value;
49  size_t length; // prefix length
50  };
51  struct result_triple_type { // for predict ()
52  value_type value;
53  size_t length; // suffix length
54  npos_t id; // node id of value
55  };
56  struct node {
57  union { int base; value_type value; }; // negative means prev empty index
58  int check; // negative means next empty index
59  node (const int base_ = 0, const int check_ = 0)
60  : base (base_), check (check_) {}
61  };
62  struct ninfo { // x1.5 update speed; +.25 % memory (8n -> 10n)
63  uchar sibling; // right sibling (= 0 if not exist)
64  uchar child; // first child
65  ninfo () : sibling (0), child (0) {}
66  };
67  struct block { // a block w/ 256 elements
68  int prev; // prev block; 3 bytes
69  int next; // next block; 3 bytes
70  short num; // # empty elements; 0 - 256
71  short reject; // minimum # branching failed to locate; soft limit
72  int trial; // # trial
73  int ehead; // first empty item
74  block () : prev (0), next (0), num (256), reject (257), trial (0), ehead (0) {}
75  };
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
79  );
80  _initialize ();
81  }
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 {
89  size_t i = 0;
90  for (int to = 0; to < _size; ++to)
91  if (_array[to].check >= 0) ++i;
92  return i;
93  }
94  size_t nonzero_length () const {
95  size_t i (0), j (0);
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; }
100  }
101  return i + j * (1 + sizeof (value_type));
102  }
103  size_t num_keys () const {
104  size_t i = 0;
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;
108  }
109  return i;
110  }
111  // interfance
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;
118  size_t pos = 0;
119  b.i = _find (key, from, pos, len);
120  if (b.i == CEDAR_NO_PATH) b.i = CEDAR_NO_VALUE;
121  T result;
122  _set_result (&result, b.x, len, from);
123  return result;
124  }
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 {
130  size_t num = 0;
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);
137  ++num;
138  }
139  return num;
140  }
141  // predict key from double array
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);
154  ++num;
155  }
156  return num;
157  }
158  void suffix (char* key, size_t len, npos_t to) const {
159  key[len] = '\0';
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);
165  }
166  while (len--) {
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);
170  }
171  }
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);
177  return b.x;
178  }
179  struct empty_callback { void operator () (const int, const int) {} }; // dummy empty function
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) {
188  if (! len && ! from)
189  _err (__FILE__, __LINE__, "failed to insert zero-length key\n");
190 #ifndef USE_FAST_LOAD
191  if (! _ninfo || ! _block) restore ();
192 #endif
193  npos_t offset = from >> 32;
194  if (! offset) { // node on trie
195  for (const uchar* const key_ = reinterpret_cast <const uchar*> (key);
196  _array[from].base >= 0; ++pos) {
197  if (pos == len)
198  { const int to = _follow (from, 0, cf); return _array[to].value += val; }
199  from = static_cast <size_t> (_follow (from, key_[pos], cf));
200  }
201  offset = static_cast <npos_t> (-_array[from].base);
202  }
203  if (offset >= sizeof (int)) { // go to _tail
204  const size_t pos_orig = pos;
205  char* const tail = &_tail[offset] - pos;
206  while (pos < len && key[pos] == tail[pos]) ++pos;
207  //
208  if (pos == len && tail[pos] == '\0') { // found exact key
209  if (const npos_t moved = pos - pos_orig) { // search end on tail
210  from &= TAIL_OFFSET_MASK;
211  from |= (offset + moved) << 32;
212  }
213  return *reinterpret_cast <value_type*> (&tail[len + 1]) += val;
214  }
215  // otherwise, insert the common prefix in tail if any
216  if (from >> 32) {
217  from &= TAIL_OFFSET_MASK; // reset to update tail offset
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));
222  ++offset_;
223  // this shows intricacy in debugging updatable double array trie
224  if (NUM_TRACKING_NODES) // keep the traversed node (on tail) updated
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);
228  }
229  }
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;
234  if (tail[pos]) { // remember to move offset to existing tail
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); // keep record
238  }
239  moved += offset;
240  for (npos_t i = offset; i <= moved; i += 1 + sizeof (value_type)) {
241  if (_quota0 == ++*_length0) {
242 #ifdef USE_EXACT_FIT
243  _quota0 += *_length0 >= MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE : *_length0;
244 #else
245  _quota0 += _quota0;
246 #endif
247  _realloc_array (_tail0, _quota0, *_length0);
248  }
249  _tail0[*_length0] = static_cast <int> (i);
250  }
251  if (pos == len || tail[pos] == '\0') {
252  const int to = _follow (from, 0, cf);
253  if (pos == len) return _array[to].value += val; // set value on tail
254  _array[to].value += *reinterpret_cast <value_type*> (&tail[pos + 1]);
255  }
256  from = static_cast <size_t> (_follow (from, static_cast <uchar> (key[pos]), cf));
257  ++pos;
258  }
259  const int needed = static_cast <int> (len - pos + 1 + sizeof (value_type));
260  if (pos == len && *_length0) { // reuse
261  const int offset0 = _tail0[*_length0];
262  _tail[offset0] = '\0';
263  _array[from].base = -offset0;
264  --*_length0;
265  return *reinterpret_cast <value_type*> (&_tail[offset0 + 1]) = val;
266  }
267  if (_quota < *_length + needed) {
268 #ifdef USE_EXACT_FIT
269  _quota += needed > *_length || needed > MAX_ALLOC_SIZE ? needed :
270  (*_length >= MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE : *_length);
271 #else
272  _quota += _quota >= needed ? _quota : needed;
273 #endif
274  _realloc_array (_tail, _quota, *_length);
275  }
276  _array[from].base = -*_length;
277  const size_t pos_orig = pos;
278  char* const tail = &_tail[*_length] - pos;
279  if (pos < len) {
280  do tail[pos] = key[pos]; while (++pos < len);
281  from |= (static_cast <npos_t> (*_length) + (len - pos_orig)) << 32;
282  }
283  *_length += needed;
284  return *reinterpret_cast <value_type*> (&tail[len + 1]) += val;
285  }
286  // easy-going erase () without compression
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) {
289  size_t pos = 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; // leave tail as is
293  bool flag = _array[from].base < 0; // have sibling
294  int e = flag ? static_cast <int> (from) : _array[from].base ^ 0;
295  from = _array[e].check;
296  do {
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));
300  _push_enode (e);
301  e = static_cast <int> (from);
302  from = static_cast <size_t> (_array[from].check);
303  } while (! flag);
304  return 0;
305  }
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));
309  return 0;
310  }
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);
315  npos_t from = 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);
319  else
320  _err (__FILE__, __LINE__, "dump() needs array of length = num_keys()\n");
321  }
322  void shrink_tail () {
323  union { char* tail; int* length; } t;
324  const size_t length_
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));
339  }
340  }
341  std::free (_tail);
342  _tail = t.tail;
343  _realloc_array (_tail, *_length, *_length);
344  _quota = *_length;
345  _realloc_array (_tail0, 1);
346  _quota0 = 1;
347  }
348  int save (const char* fn, const char* mode, const bool shrink) {
349  if (shrink) shrink_tail ();
350  return save (fn, mode);
351  }
352  int save (const char* fn, const char* mode = "wb") const {
353  // _test ();
354  FILE* fp = std::fopen (fn, mode);
355  if (! fp) return -1;
356  std::fwrite (_tail, sizeof (char), static_cast <size_t> (*_length), fp);
357  std::fwrite (_array, sizeof (node), static_cast <size_t> (_size), fp);
358  std::fclose (fp);
359 #ifdef USE_FAST_LOAD
360  const char* const info
361  = std::strcat (std::strcpy (new char[std::strlen (fn) + 5], fn), ".sbl");
362  fp = std::fopen (info, mode);
363  delete [] info; // resolve memory leak
364  if (! fp) return -1;
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);
370  std::fclose (fp);
371 #endif
372  return 0;
373  }
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);
377  if (! fp) return -1;
378  // get size
379  if (! size_) {
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;
383  }
384  if (size_ <= offset) return -1;
385  if (std::fseek (fp, static_cast <long> (offset), SEEK_SET) != 0) return -1;
386  int len = 0;
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;
390  // set array
391  clear (false);
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)));
396 #ifdef USE_FAST_LOAD
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)
400 #else
401  if (! _array || ! _tail || ! _tail0)
402 #endif
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))
407  return -1;
408  std::fclose (fp);
409  _size = static_cast <int> (size_);
410  *_length0 = 0;
411 #ifdef USE_FAST_LOAD
412  const char* const info
413  = std::strcat (std::strcpy (new char[std::strlen (fn) + 5], fn), ".sbl");
414  fp = std::fopen (info, mode);
415  delete [] info; // resolve memory leak
416  if (! fp) return -1;
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))
422  return -1;
423  std::fclose (fp);
424  _capacity = _size;
425  _quota = *_length;
426  _quota0 = 1;
427 #endif
428  return 0;
429  }
430 #ifndef USE_FAST_LOAD
431  void restore () { // restore information to update
432  if (! _block) _restore_block ();
433  if (! _ninfo) _restore_ninfo ();
434  _capacity = _size;
435  _quota = *_length;
436  _quota0 = 1;
437  }
438 #endif
439  void set_array (void* p, size_t size_ = 0) { // ad-hoc
440  clear (false);
441  if (size_)
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));
446  _no_delete = true;
447  }
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 ();
458  _no_delete = false;
459  }
460  // return the first child for a tree rooted by a given node
461  int begin (npos_t& from, size_t& len) {
462 #ifndef USE_FAST_LOAD
463  if (! _ninfo) _restore_ninfo ();
464 #endif
465  int base = from >> 32 ? - static_cast <int> (from >> 32) : _array[from].base;
466  if (base >= 0) { // on trie
467  uchar c = _ninfo[from].child;
468  if (! from && ! (c = _ninfo[base ^ c].sibling)) // bug fix
469  return CEDAR_NO_PATH; // no entry
470  for (; c && base >= 0; ++len) {
471  from = static_cast <size_t> (base) ^ c;
472  base = _array[from].base;
473  c = _ninfo[from].child;
474  }
475  if (base >= 0) return _array[base ^ c].base;
476  }
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;
480  len += len_;
481  return *reinterpret_cast <int*> (&_tail[-base] + len_ + 1);
482  }
483  // return the next child if any
484  int next (npos_t& from, size_t& len, const npos_t root = 0) {
485  uchar c = 0;
486  if (const int offset = static_cast <int> (from >> 32)) { // on tail
487  if (root >> 32) return CEDAR_NO_PATH;
488  from &= TAIL_OFFSET_MASK;
489  len -= static_cast <size_t> (offset - (-_array[from].base));
490  } else
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);
495  }
496  if (! c) return CEDAR_NO_PATH;
497  return begin (from = static_cast <size_t> (_array[from].base) ^ c, ++len);
498  }
499  npos_t tracking_node[NUM_TRACKING_NODES + 1];
500  private:
501  // currently disabled; implement these if you need
502  da (const da&);
503  da& operator= (const da&);
504  node* _array;
505  union { char* _tail; int* _length; };
506  union { int* _tail0; int* _length0; };
507  ninfo* _ninfo;
508  block* _block;
509  int _bheadF; // first block of Full; 0
510  int _bheadC; // first block of Closed; 0 if no Closed
511  int _bheadO; // first block of Open; 0 if no Open
512  int _capacity;
513  int _size;
514  int _quota;
515  int _quota0;
516  int _no_delete;
517  short _reject[257];
518  //
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));
524  if (! tmp)
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;
529  }
530  void _initialize () { // initilize the first special block
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;
540  _block[0].ehead = 1; // bug fix for erase
541  _quota = *_length = static_cast <int> (sizeof (int));
542  _quota0 = 1;
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;
545  }
546  // follow/create edge
547  template <typename T>
548  int _follow (npos_t& from, const uchar& label, T& cf) {
549  int to = 0;
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);
556  return to;
557  }
558  // find key from double array
559  int _find (const char* key, npos_t& from, size_t& pos, const size_t len) const {
560  npos_t offset = from >> 32;
561  if (! offset) { // node on trie
562  for (const uchar* const key_ = reinterpret_cast <const uchar*> (key);
563  _array[from].base >= 0; ) {
564  if (pos == len) {
565  const node& n = _array[_array[from].base ^ 0];
566  if (n.check != static_cast <int> (from)) return CEDAR_NO_VALUE;
567  return n.base;
568  }
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;
571  ++pos;
572  from = to;
573  }
574  offset = static_cast <npos_t> (-_array[from].base);
575  }
576  // switch to _tail to match suffix
577  const size_t pos_orig = pos; // start position in reading _tail
578  const char* const tail = &_tail[offset] - pos;
579  if (pos < len) {
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;
584  }
585  if (pos < len) return CEDAR_NO_PATH; // input > tail, input != tail
586  }
587  if (tail[pos]) return CEDAR_NO_VALUE; // input < tail
588  return *reinterpret_cast <const int*> (&tail[len + 1]);
589  }
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; // skip empty node
596  const int base = _array[from].base;
597  if (const uchar label = static_cast <uchar> (base ^ to)) // skip leaf
598  _push_sibling (static_cast <size_t> (from), base, label,
599  ! from || _ninfo[from].child || _array[base ^ 0].check == from);
600  }
601  }
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) { // register blocks to full
606  block& b = _block[bi];
607  b.num = 0;
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);
612  }
613  }
614 #endif
615  void _set_result (result_type* x, value_type r, size_t = 0, npos_t = 0) const
616  { *x = r; }
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) {
622  if (last) { // last one poped; Closed or Open
623  head_in = 0;
624  } else {
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;
629  }
630  }
631  void _push_block (const int bi, int& head_out, const bool empty) {
632  block& b = _block[bi];
633  if (empty) { // the destination is empty
634  head_out = b.prev = b.next = bi;
635  } else { // use most recently pushed
636  int& tail_out = _block[head_out].prev;
637  b.prev = tail_out;
638  b.next = head_out;
639  head_out = tail_out = _block[tail_out].next = bi;
640  }
641  }
642  int _add_block () {
643  if (_size == _capacity) { // allocate memory if needed
644 #ifdef USE_EXACT_FIT
645  _capacity += _size >= MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE : _size;
646 #else
647  _capacity += _capacity;
648 #endif
649  _realloc_array (_array, _capacity, _capacity);
650  _realloc_array (_ninfo, _capacity, _size);
651  _realloc_array (_block, _capacity >> 8, _size >> 8);
652  }
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); // append to block Open
659  _size += 256;
660  return (_size >> 8) - 1;
661  }
662  // transfer block from one start w/ head_in to one start w/ head_out
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);
666  }
667  // pop empty node from block; never transfer the special block (bi = 0)
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;
671  node& n = _array[e];
672  block& b = _block[bi];
673  if (--b.num == 0) {
674  if (bi) _transfer_block (bi, _bheadC, _bheadF); // Closed to Full
675  } else { // release empty node from empty ring
676  _array[-n.base].check = n.check;
677  _array[-n.check].base = n.base;
678  if (e == b.ehead) b.ehead = -n.check; // set ehead
679  if (bi && b.num == 1 && b.trial != MAX_TRIAL) // Open to Closed
680  _transfer_block (bi, _bheadO, _bheadC);
681  }
682  // initialize the released node
683  if (label) n.base = -1; else n.value = value_type (0);
684  n.check = from;
685  if (base < 0) _array[from].base = e ^ label;
686  return e;
687  }
688  // push empty node into empty ring
689  void _push_enode (const int e) {
690  const int bi = e >> 8;
691  block& b = _block[bi];
692  if (++b.num == 1) { // Full to Closed
693  b.ehead = e;
694  _array[e] = node (-e, -e);
695  if (bi) _transfer_block (bi, _bheadF, _bheadC); // Full to Closed
696  } else {
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) { // Closed to Open
702  if (bi) _transfer_block (bi, _bheadC, _bheadO);
703  }
704  b.trial = 0;
705  }
706  if (b.reject < _reject[b.num]) b.reject = _reject[b.num];
707  _ninfo[e] = ninfo (); // reset ninfo; no child, no sibling
708  }
709  // push label to from's child
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;
715  }
716  // pop label from from's child
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;
721  }
722  // check whether to replace branching w/ the newly added node
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;
725  while (c_n && c_p);
726  return c_p;
727  }
728  // enumerate (equal to or more than one) child nodes
729  uchar* _set_child (uchar* p, const int base, uchar c, const int label = -1) {
730  --p;
731  if (! c) { *++p = c; c = _ninfo[base ^ c].sibling; } // 0: terminal
732  if (ORDERED)
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; }
736  return p;
737  }
738  // explore new block to settle down
739  int _find_place () {
740  if (_bheadC) return _block[_bheadC].ehead;
741  if (_bheadO) return _block[_bheadO].ehead;
742  return _add_block () << 8;
743  }
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);
748  while (1) { // set candidate block
749  block& b = _block[bi];
750  if (b.num >= nc && nc < b.reject) // explore configuration
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; // no conflict
755  if ((e = -_array[e].check) == b.ehead) break;
756  }
757  b.reject = nc;
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);
761  if (bi == bz) break;
762  bi = bi_;
763  }
764  }
765  return _add_block () << 8;
766  }
767  // resolve conflict on base_n ^ label_n = base_p ^ label_p
768  template <typename T>
769  int _resolve (npos_t& from_n, const int base_n, const uchar label_n, T& cf) {
770  // examine siblings of conflicted nodes
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;
774  const bool flag // whether to replace siblings of newly added
775  = _consult (base_n, base_p, _ninfo[from_n].child, _ninfo[from_p].child);
776  uchar child[256];
777  uchar* const first = &child[0];
778  uchar* const last =
779  flag ? _set_child (first, base_n, _ninfo[from_n].child, label_n)
780  : _set_child (first, base_p, _ninfo[from_p].child);
781  const int base =
782  (first == last ? _find_place () : _find_place (first, last)) ^ *first;
783  // replace & modify empty list
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; // new child
787  _array[from].base = base; // new base
788  for (const uchar* p = first; p <= last; ++p) { // to_ => to
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; // skip newcomer (no child)
793  cf (to_, to);
794  node& n = _array[to];
795  node& n_ = _array[to_];
796  if ((n.base = n_.base) > 0 && *p) { // copy base; bug fix
797  uchar c = _ninfo[to].child = _ninfo[to_].child;
798  do _array[n.base ^ c].check = to; // adjust grand son's check
799  while ((c = _ninfo[n.base ^ c].sibling));
800  }
801  if (! flag && to_ == static_cast <int> (from_n)) // parent node moved
802  from_n = static_cast <size_t> (to); // bug fix
803  if (! flag && to_ == to_pn) { // the address is immediately used
804  _push_sibling (from_n, to_pn ^ label_n, label_n);
805  _ninfo[to_].child = 0; // remember to reset child
806  if (label_n) n_.base = -1; else n_.value = value_type (0);
807  n_.check = static_cast <int> (from_n);
808  } else
809  _push_enode (to_);
810  if (NUM_TRACKING_NODES) // keep the traversed node updated
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);
815  }
816  }
817  }
818  return flag ? base ^ label_n : to_pn;
819  }
820  // test the validity of double array for debug
821  void _test (const npos_t from = 0) const {
822  const int base = _array[from].base;
823  if (base < 0) { // validate tail offset
824  assert (*_length >= static_cast <int> (-base + 1 + sizeof (value_type)));
825  return;
826  }
827  uchar c = _ninfo[from].child;
828  do {
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));
832  }
833  };
834 }
835 #endif