00001 #ifndef BIT_TRIE_HH
00002 #define BIT_TRIE_HH
00003
00004 #include "bit/algo.hh"
00005 #include "bit/CompressedArray.hh"
00006
00007 namespace bit {
00008
00037 template <class Array>
00038 class Trie {
00039
00040 public:
00041
00043 class Iterator {
00044 public:
00045
00048
00050 Iterator()
00051 : m_trie(NULL)
00052 {
00053 }
00054
00059 Iterator(const Trie<Array> &trie)
00060 : m_trie(&trie)
00061 {
00062 }
00063
00069 Iterator(const Iterator &it, unsigned int length)
00070 : m_trie(it.m_trie)
00071 {
00072 if (length > it.length())
00073 length = it.length();
00074 m_symbol_stack.resize(length);
00075 m_child_limit_stack.resize(length);
00076 for (size_t i = 0; i < length; i++) {
00077 m_symbol_stack[i] = it.m_symbol_stack[i];
00078 m_child_limit_stack[i] = it.m_child_limit_stack[i];
00079 }
00080 }
00081
00083
00084
00085
00088
00093 unsigned int length() const
00094 {
00095 return m_symbol_stack.size();
00096 }
00097
00102 u32 symbol_index(unsigned int level) const
00103 {
00104 if (level >= length())
00105 throw bit::out_of_range(
00106 "bit::Trie::Iterator::symbol_index() level out of range");
00107 assert(!m_symbol_stack.empty());
00108 return m_symbol_stack[level];
00109 }
00110
00115 u32 symbol_index() const
00116 {
00117 if (is_root())
00118 throw bit::out_of_range(
00119 "bit::Trie::Iterator::symbol_index() called at root node");
00120 return symbol_index(length() - 1);
00121 }
00122
00128 u32 child_limit_index(unsigned int level) const
00129 {
00130 if (level >= length())
00131 throw bit::out_of_range(
00132 "bit::Trie::Iterator::child_limit_index() level out of range");
00133 assert(!m_child_limit_stack.empty());
00134 return m_child_limit_stack[level];
00135 }
00136
00142 u32 child_limit_index() const
00143 {
00144 if (is_root())
00145 throw bit::out_of_range(
00146 "bit::Trie::Iterator::child_limit_index() called at root node");
00147 return child_limit_index(length() - 1);
00148 }
00149
00154 u32 symbol(unsigned int level) const
00155 {
00156 u32 index = symbol_index(level);
00157 return m_trie->symbol_array(level).get(index);
00158 }
00159
00164 u32 symbol() const
00165 {
00166 if (is_root())
00167 throw bit::out_of_range(
00168 "bit::Trie::Iterator::symbol() called at root node");
00169 u32 index = symbol_index(length() - 1);
00170 return m_trie->symbol_array(length() - 1).get(index);
00171 }
00172
00174 std::vector<u32> symbol_vec() const
00175 {
00176 std::vector<u32> vec(length());
00177 for (unsigned int l = 0; l < length(); l++)
00178 vec[l] = symbol(l);
00179 return vec;
00180 }
00181
00188 u32 child_limit(unsigned int level) const
00189 {
00190 u32 index = child_limit_index(level);
00191 if (index == max_u32)
00192 throw bit::invalid_call(
00193 "bit::Trie::child_limit() leaf-node in separated array");
00194
00195 const Array &array = m_trie->child_limit_array(level);
00196 if (array.num_elems() == 0)
00197 return 0;
00198 if (index >= array.num_elems())
00199 return array.get(array.num_elems() - 1);
00200 return m_trie->child_limit_array(level).get(index);
00201 }
00202
00207 u32 child_limit() const
00208 {
00209 if (is_root())
00210 return m_trie->num_nodes(0);
00211 return child_limit(length() - 1);
00212 }
00213
00221 u32 first_child(unsigned int level) const
00222 {
00223 u32 index = child_limit_index(level);
00224 if (index == 0)
00225 return 0;
00226 if (index == max_u32)
00227 throw bit::invalid_call(
00228 "bit::Trie::child_limit() leaf-node in separated array");
00229 const Array &array = m_trie->child_limit_array(level);
00230 if (index > array.num_elems())
00231 return array.get(array.num_elems() - 1);
00232 return array.get(index - 1);
00233 }
00234
00239 u32 first_child() const
00240 {
00241 if (is_root())
00242 return 0;
00243 return first_child(length() - 1);
00244 }
00245
00250 u32 first_sibling(unsigned int level) const
00251 {
00252 if (level >= length())
00253 throw bit::out_of_range(
00254 "bit::Trie::first_sibling(): level out of range");
00255 if (level == 0)
00256 return 0;
00257 return first_child(level - 1);
00258 }
00259
00264 u32 first_sibling() const
00265 {
00266 if (is_root())
00267 throw bit::out_of_range(
00268 "bit::Trie::first_sibling(): called for root");
00269 return first_sibling(length() - 1);
00270 }
00271
00276 u32 sibling_limit(unsigned int level) const
00277 {
00278 if (level >= length())
00279 throw bit::out_of_range(
00280 "bit::Trie::sibling_limit(): level out of range");
00281 if (level == 0)
00282 return m_trie->num_nodes(0);
00283 return child_limit(level - 1);
00284 }
00285
00290 u32 sibling_limit() const
00291 {
00292 if (is_root())
00293 throw bit::out_of_range(
00294 "bit::Trie::sibling_limit() called for root");
00295 return sibling_limit(length() - 1);
00296 }
00297
00299 bool is_root() const
00300 {
00301 return length() == 0;
00302 }
00303
00305 bool is_separated_leaf() const
00306 {
00307 return (!is_root() && m_child_limit_stack.back() == max_u32);
00308 }
00309
00312 u32 num_children(unsigned int level) const
00313 {
00314 if (is_separated_leaf())
00315 return 0;
00316
00317 u32 child_limit = this->child_limit(level);
00318 if (child_limit == 0)
00319 return 0;
00320 return child_limit - first_child(level);
00321 }
00322
00324 u32 num_children() const
00325 {
00326 if (is_root())
00327 return m_trie->num_nodes(0);
00328 return num_children(length() - 1);
00329 }
00330
00332
00333
00334
00337
00341 Iterator parent() const
00342 {
00343 Iterator it(*this);
00344 if (!it.goto_parent())
00345 throw bit::invalid_call("Trie::Iterator::parent() failed");
00346 return it;
00347 }
00348
00350 void goto_root()
00351 {
00352 m_symbol_stack.clear();
00353 m_child_limit_stack.clear();
00354 }
00355
00359 bool goto_parent()
00360 {
00361 if (is_root())
00362 return false;
00363 m_symbol_stack.pop_back();
00364 m_child_limit_stack.pop_back();
00365 return true;
00366 }
00367
00371 bool goto_first_child()
00372 {
00373 if (is_separated_leaf())
00374 return false;
00375
00376 u32 child_limit = this->child_limit();
00377 if (child_limit == 0)
00378 return false;
00379 u32 first_child = this->first_child();
00380 assert(first_child <= child_limit);
00381 if (first_child == child_limit)
00382 return false;
00383
00384 m_symbol_stack.push_back(first_child);
00385 m_child_limit_stack.push_back(
00386 m_trie->compute_non_leaf_index(length() - 1, first_child));
00387 return true;
00388 }
00389
00394 bool goto_next_sibling()
00395 {
00396 if (is_root())
00397 throw bit::out_of_range(
00398 "bit::Trie::Iterator::goto_next_sibling() called for root");
00399 u32 limit = sibling_limit();
00400 assert(limit > 0);
00401 assert(m_symbol_stack.back() < limit);
00402 if (m_symbol_stack.back() == limit - 1)
00403 return false;
00404 m_symbol_stack.back()++;
00405 m_child_limit_stack.back() =
00406 m_trie->compute_non_leaf_index(length() - 1, m_symbol_stack.back());
00407 return true;
00408 }
00409
00414 bool goto_child(u32 symbol)
00415 {
00416 if (is_separated_leaf())
00417 return false;
00418
00419 u32 limit = child_limit();
00420 if (limit == 0)
00421 return false;
00422 u32 first = first_child();
00423 assert(first <= limit);
00424 if (first == limit)
00425 return false;
00426
00427 const Array &array = m_trie->symbol_array(length());
00428 u64 index = binary_search(array, symbol, first, limit);
00429 if (index == limit)
00430 return false;
00431 m_symbol_stack.push_back(index);
00432 m_child_limit_stack.push_back(
00433 m_trie->compute_non_leaf_index(length() - 1, index));
00434 return true;
00435 }
00436
00440 bool goto_next_depth_first()
00441 {
00442 if (goto_first_child())
00443 return true;
00444
00445 while (1) {
00446 if (goto_next_sibling())
00447 return true;
00448 bool ret = goto_parent();
00449 assert(ret);
00450 if (is_root())
00451 return false;
00452 }
00453 }
00454
00459 bool goto_leaf()
00460 {
00461 bool did_move = false;
00462 while (goto_first_child())
00463 did_move = true;
00464 return did_move;
00465 }
00466
00474 bool goto_next_depth_first_post()
00475 {
00476 if (is_root())
00477 return goto_leaf();
00478
00479 if (goto_next_sibling()) {
00480 goto_leaf();
00481 return true;
00482 }
00483
00484 goto_parent();
00485 if (is_root())
00486 return false;
00487 return true;
00488 }
00489
00497 bool goto_next_on_level(unsigned int level)
00498 {
00499 Iterator it(*this);
00500
00501 while (it.length() > level + 1)
00502 it.goto_parent();
00503
00504 if (it.length() == level + 1) {
00505 if (it.goto_next_sibling())
00506 goto ok;
00507 while (1) {
00508 it.goto_parent();
00509 if (it.is_root())
00510 return false;
00511 if (it.goto_next_sibling())
00512 break;
00513 }
00514 }
00515
00516 while (it.goto_next_depth_first())
00517 if (it.length() == level + 1)
00518 goto ok;
00519
00520 return false;
00521
00522 ok:
00523 *this = it;
00524 return true;
00525 }
00526
00532 void goto_backoff_full()
00533 {
00534 if (is_root())
00535 throw bit::invalid_call(
00536 "bit::Trie::Iterator::goto_backoff_full() called at root");
00537
00538 std::vector<u32> vec(symbol_vec());
00539 while (!vec.empty()) {
00540 vec.erase(vec.begin());
00541 Iterator it(*m_trie);
00542 bool failed = false;
00543 for (size_t i = 0; i < vec.size(); i++) {
00544 if (!it.goto_child(vec[i])) {
00545 failed = true;
00546 break;
00547 }
00548 }
00549 if (!failed) {
00550 *this = it;
00551 break;
00552 }
00553 }
00554 }
00555
00564 bool goto_backoff_once()
00565 {
00566 if (is_root())
00567 throw bit::invalid_call(
00568 "bit::Trie::Iterator::goto_backoff_once() called at root");
00569
00570 std::vector<u32> vec(symbol_vec());
00571 vec.erase(vec.begin());
00572 Iterator it(*m_trie);
00573 for (size_t i = 0; i < vec.size(); i++)
00574 if (!it.goto_child(vec[i]))
00575 return false;
00576 *this = it;
00577 return true;
00578 }
00579
00581
00582
00583
00586
00588 bool operator==(const Iterator it)
00589 {
00590 return m_symbol_stack == it.m_symbol_stack;
00591 }
00592
00594 bool operator!=(const Iterator it)
00595 {
00596 return m_symbol_stack != it.m_symbol_stack;
00597 }
00598
00600
00601 private:
00602
00604 const Trie<Array> *m_trie;
00605
00608 std::vector<u32> m_symbol_stack;
00609
00613 std::vector<u32> m_child_limit_stack;
00614
00615 friend class Trie;
00616
00617 };
00618
00619 public:
00620
00624 void reserve_levels(unsigned int num_levels)
00625 {
00626 m_symbol_arrays.reserve(num_levels);
00627 m_pointer_arrays.reserve(num_levels);
00628 m_child_limit_arrays.reserve(num_levels);
00629 }
00630
00633 u32 num_nodes(unsigned int level) const
00634 {
00635 if (level >= m_symbol_arrays.size())
00636 return 0;
00637 return m_symbol_arrays.at(level).num_elems();
00638 }
00639
00645 u64 size() const {
00646 u64 ret = 0;
00647 for (size_t a = 0; a < m_symbol_arrays.size(); a++)
00648 ret += m_symbol_arrays[a].compressed_size();
00649 for (size_t a = 0; a < m_child_limit_arrays.size(); a++)
00650 ret += m_child_limit_arrays[a].compressed_size();
00651 for (size_t a = 0; a < m_pointer_arrays.size(); a++)
00652 ret += m_pointer_arrays[a].compressed_size();
00653 return ret;
00654 }
00655
00659 const Array &symbol_array(unsigned int level) const
00660 {
00661 return m_symbol_arrays.at(level);
00662 }
00663
00667 const Array &child_limit_array(unsigned int level) const
00668 {
00669 return m_child_limit_arrays.at(level);
00670 }
00671
00675 const Array &pointer_array(unsigned int level) const
00676 {
00677 return m_pointer_arrays.at(level);
00678 }
00679
00680
00695 Iterator insert(Iterator it, u32 symbol)
00696 {
00697 if (it.goto_child(symbol))
00698 return it;
00699 return insert_new(it, symbol);
00700 }
00701
00712 template <class T>
00713 Iterator insert(const std::vector<T> &vec)
00714 {
00715 if (vec.empty())
00716 throw bit::invalid_argument(
00717 "bit::Trie::insert_new(): trying to add an empty string");
00718
00719 Iterator it(*this);
00720 for (size_t i = 0; i < vec.size() - 1; i++)
00721 if (!it.goto_child(vec[i]))
00722 throw bit::invalid_argument("bit::Trie::insert(): prefix not found");
00723
00724 if (it.goto_child(vec.back()))
00725 return it;
00726 return insert_new(it, vec.back());
00727 }
00728
00743 Iterator insert_new(Iterator it, u32 symbol)
00744 {
00745 unsigned int len = it.length();
00746 if (len > m_symbol_arrays.size())
00747 throw bit::invalid_argument(
00748 "bit::Trie::insert_new(): too long iterator argument");
00749
00750 if (it.goto_child(symbol))
00751 throw bit::invalid_argument("bit::Trie::insert_new(): duplicate");
00752
00753
00754
00755 assert(m_symbol_arrays.size() == m_child_limit_arrays.size());
00756 if (len == m_symbol_arrays.size()) {
00757 Array empty_array;
00758
00759 if (m_symbol_arrays.size() == m_symbol_arrays.capacity())
00760 fprintf(stderr, "DEBUG WARNING: growing array vectors!\n");
00761
00762 m_symbol_arrays.push_back(empty_array);
00763 m_child_limit_arrays.push_back(empty_array);
00764 m_pointer_arrays.push_back(empty_array);
00765 }
00766 Array &tgt_symbol_array = m_symbol_arrays.at(len);
00767 int tgt_symbol_index = tgt_symbol_array.num_elems();
00768 tgt_symbol_array.set_grow_widen(tgt_symbol_index, symbol);
00769
00770
00771
00772
00773 if (len > 0) {
00774 Array &src_child_limit_array = m_child_limit_arrays.at(len - 1);
00775 u32 limit = it.child_limit_index();
00776
00777 for (u32 i = src_child_limit_array.num_elems(); i < limit; i++)
00778 src_child_limit_array.set_grow_widen(i, tgt_symbol_index);
00779 src_child_limit_array.set_grow_widen(limit, tgt_symbol_index + 1);
00780 }
00781
00782
00783
00784 Iterator tgt_it(it);
00785 tgt_it.m_symbol_stack.push_back(tgt_symbol_index);
00786 tgt_it.m_child_limit_stack.push_back(
00787 compute_non_leaf_index(tgt_it.length() - 1, tgt_symbol_index));
00788
00789 assert(m_symbol_arrays.size() == m_child_limit_arrays.size());
00790 assert(m_symbol_arrays.size() == m_pointer_arrays.size());
00791
00792 return tgt_it;
00793 }
00794
00806 template <class T>
00807 Iterator insert_new(const std::vector<T> &vec)
00808 {
00809 if (vec.empty())
00810 throw bit::invalid_argument(
00811 "bit::Trie::insert_new(): trying to add an empty string");
00812
00813 Iterator it(*this);
00814 for (size_t i = 0; i < vec.size() - 1; i++)
00815 if (!it.goto_child(vec[i]))
00816 throw bit::invalid_argument("bit::Trie::insert(): prefix not found");
00817 return insert_new(it, vec.back());
00818 }
00819
00825 template <class T>
00826 Iterator find(const std::vector<T> &vec) const
00827 {
00828 if (vec.empty())
00829 throw bit::invalid_argument(
00830 "bit::Trie::Iterator::find() called at root");
00831 Iterator it(*this);
00832 for (size_t i = 0; i < vec.size(); i++)
00833 if (!it.goto_child(vec[i]))
00834 return Iterator();
00835 return it;
00836 }
00837
00844 void compress(unsigned int level)
00845 {
00846 if (level >= m_child_limit_arrays.size())
00847 throw bit::out_of_range("bit::Trie::compress() level out of bounds");
00848 m_child_limit_arrays.at(level).recursive_optimal_compress();
00849 m_pointer_arrays.at(level).recursive_optimal_compress();
00850 }
00851
00853 void compress()
00854 {
00855 for (size_t l = 0; l < m_child_limit_arrays.size(); l++) {
00856 m_child_limit_arrays.at(l).recursive_optimal_compress();
00857 m_pointer_arrays.at(l).recursive_optimal_compress();
00858 }
00859 }
00860
00866 void uncompress(unsigned int level)
00867 {
00868 if (level >= m_child_limit_arrays.size())
00869 throw bit::out_of_range("bit::Trie::compress() level out of bounds");
00870 m_child_limit_arrays.at(level).uncompress();
00871 m_pointer_arrays.at(level).uncompress();
00872 }
00873
00876 void uncompress()
00877 {
00878 for (size_t l = 0; l < m_child_limit_arrays.size(); l++) {
00879 m_child_limit_arrays.at(l).uncompress();
00880 m_pointer_arrays.at(l).uncompress();
00881 }
00882 }
00883
00890 bool is_separated(unsigned int level)
00891 {
00892 if (level + 1 >= m_pointer_arrays.size())
00893 throw bit::out_of_range(
00894 "bit::Trie::separate_leafs() level out of range");
00895 return pointer_array(level).num_elems() > 0;
00896 }
00897
00915 void separate_leafs(unsigned int level)
00916 {
00917 if (level + 1 >= m_pointer_arrays.size())
00918 throw bit::out_of_range(
00919 "bit::Trie::separate_leafs() level out of range");
00920
00921 Array &pointer_array = m_pointer_arrays.at(level);
00922 Array &limit_array = m_child_limit_arrays.at(level);
00923 Array new_limit_array;
00924
00925 if (pointer_array.num_elems() != 0)
00926 throw bit::invalid_call(
00927 "bit::Trie::separate_leafs() already separated");
00928
00929 u64 tgt = 0;
00930 u64 prev_limit = 0;
00931 for (u64 src = 0; src < limit_array.num_elems(); src++) {
00932 u32 limit = limit_array.get(src);
00933 if (limit > prev_limit) {
00934 new_limit_array.set_grow_widen(tgt, limit);
00935 tgt++;
00936 }
00937 pointer_array.set_grow_widen(src, tgt);
00938 prev_limit = limit;
00939 }
00940 limit_array = new_limit_array;
00941 }
00942
00950 void unseparate_leafs(unsigned int level)
00951 {
00952 if (level + 1 >= m_pointer_arrays.size())
00953 throw bit::out_of_range(
00954 "bit::Trie::separate_leafs() level out of range");
00955
00956 CompressedArray &pointer_array = m_pointer_arrays.at(level);
00957 CompressedArray &limit_array = m_child_limit_arrays.at(level);
00958
00959 if (pointer_array.num_elems() == 0)
00960 return;
00961
00962 CompressedArray new_limit_array;
00963 u32 limit = 0;
00964 u32 prev_index = 0;
00965 for (u64 i = 0; i < pointer_array.num_elems(); i++) {
00966 u32 index = pointer_array.get(i);
00967 if (index > prev_index) {
00968 limit = limit_array.get(index - 1);
00969 prev_index = index;
00970 }
00971 new_limit_array.set_grow_widen(i, limit);
00972 }
00973 limit_array = new_limit_array;
00974 pointer_array = CompressedArray();
00975 }
00976
00978 std::string debug_child_limit_arrays_str() const
00979 {
00980 std::string ret;
00981 for (size_t a = 0; a < m_child_limit_arrays.size(); a++) {
00982 ret.append(str::fmt(256, "===== %d =====\n", a));
00983 const Array &array = m_child_limit_arrays.at(a);
00984 ret.append(array.debug_str());
00985 }
00986 return ret;
00987 }
00988
00990 std::string debug_str() const
00991 {
00992 std::string ret;
00993 for (size_t a = 0; a < m_child_limit_arrays.size(); a++) {
00994 ret.append(str::fmt(256, "===== %d =====\n", a));
00995 const Array &symbol_array = m_symbol_arrays.at(a);
00996 const Array &limit_array = m_child_limit_arrays.at(a);
00997 const Array &pointer_array = m_pointer_arrays.at(a);
00998 for (u64 i = 0; i < symbol_array.num_elems(); i++) {
00999 ret.append(str::fmt(64, "%d:\t%d\t", (int)i, symbol_array.get(i)));
01000 if (i < pointer_array.num_elems())
01001 ret.append(str::fmt(64, "%d", pointer_array.get(i)));
01002 else
01003 ret.append("-");
01004 ret.append("\t");
01005 if (i < limit_array.num_elems())
01006 ret.append(str::fmt(64, "%d", limit_array.get(i)));
01007 ret.append("\n");
01008 }
01009 }
01010 return ret;
01011 }
01012
01017 void write(FILE *file) const
01018 {
01019 fputs("TRIE1:", file);
01020 fprintf(file, "%d:%d:%d:",
01021 (int)m_symbol_arrays.size(),
01022 (int)m_child_limit_arrays.size(),
01023 (int)m_pointer_arrays.size());
01024 if (ferror(file))
01025 throw bit::io_error(std::string("bit::Trie::write() failed: ") +
01026 strerror(errno));
01027 try {
01028 for (size_t i = 0; i < m_symbol_arrays.size(); i++)
01029 m_symbol_arrays[i].write(file);
01030 for (size_t i = 0; i < m_child_limit_arrays.size(); i++)
01031 m_child_limit_arrays[i].write(file);
01032 for (size_t i = 0; i < m_pointer_arrays.size(); i++)
01033 m_pointer_arrays[i].write(file);
01034 }
01035 catch (bit::io_error &e) {
01036 throw bit::io_error(std::string("bit::Trie::write() failed: ") +
01037 e.what());
01038 }
01039 }
01040
01047 void read(FILE *file)
01048 {
01049 int symbol_levels;
01050 int child_limit_levels;
01051 int pointer_levels;
01052 int version;
01053 int ret = fscanf(file, "TRIE%d:%d:%d:%d:", &version,
01054 &symbol_levels, &child_limit_levels, &pointer_levels);
01055 if (ret != 4 || version != 1)
01056 throw bit::io_error(
01057 "bit::Trie::read() error while reading header");
01058
01059 try {
01060 m_symbol_arrays.resize(symbol_levels);
01061 m_child_limit_arrays.resize(child_limit_levels);
01062 m_pointer_arrays.resize(pointer_levels);
01063
01064 for (size_t a = 0; a < m_symbol_arrays.size(); a++)
01065 m_symbol_arrays[a].read(file);
01066 for (size_t a = 0; a < m_child_limit_arrays.size(); a++)
01067 m_child_limit_arrays[a].read(file);
01068 for (size_t a = 0; a < m_pointer_arrays.size(); a++)
01069 m_pointer_arrays[a].read(file);
01070 }
01071 catch (bit::io_error &e) {
01072 throw bit::io_error(
01073 std::string("bit::CompressedArray::read() read failed") + e.what());
01074 }
01075 }
01076
01077 private:
01078
01087 u32 compute_non_leaf_index(unsigned int level, u32 symbol_index) const
01088 {
01089 assert(symbol_index < symbol_array(level).num_elems());
01090 const Array &pointer_array = this->pointer_array(level);
01091
01092
01093
01094 if (pointer_array.num_elems() == 0)
01095 return symbol_index;
01096
01097
01098
01099 if (symbol_index >= pointer_array.num_elems())
01100 return max_u32;
01101
01102 u64 index = pointer_array.get(symbol_index);
01103 if (index == 0)
01104 return max_u32;
01105
01106 u64 prev_index = 0;
01107 if (symbol_index > 0)
01108 prev_index = pointer_array.get(symbol_index - 1);
01109 if (index == prev_index)
01110 return max_u32;
01111
01112 return index - 1;
01113 }
01114
01115
01116 private:
01117
01119 std::vector<Array> m_symbol_arrays;
01120
01122 std::vector<Array> m_child_limit_arrays;
01123
01136 std::vector<Array> m_pointer_arrays;
01137
01138 };
01139
01140 };
01141
01142 #endif