symbol_tree.cpp

Go to the documentation of this file.
00001 #ifndef SYMBOL_TREE_IMPLEMENTATION_FILE
00002 #define SYMBOL_TREE_IMPLEMENTATION_FILE
00003 
00004 /*****************************************************************************\
00005 *                                                                             *
00006 *  Name   : symbol_tree                                                       *
00007 *  Author : Chris Koeritz                                                     *
00008 *                                                                             *
00009 *******************************************************************************
00010 * Copyright (c) 1992-$now By Author.  This program is free software; you can  *
00011 * redistribute it and/or modify it under the terms of the GNU General Public  *
00012 * License as published by the Free Software Foundation; either version 2 of   *
00013 * the License or (at your option) any later version.  This is online at:      *
00014 *     http://www.fsf.org/copyleft/gpl.html                                    *
00015 * Please send any updates to: fred@gruntose.com                               *
00016 \*****************************************************************************/
00017 
00018 // NOTES:
00019 //
00020 //   + Redesigned in April 2003 to shed legacy gunk from bad older version.
00021 
00022 #include "symbol_tree.h"
00023 
00024 #include <basis/function.h>
00025 #include <data_struct/symbol_table.cpp>
00026 #include <textual/string_manipulation.h>
00027 
00028 //#define DEBUG_SYMBOL_TREE
00029   // uncomment for totally noisy version.
00030 
00031 #undef LOG
00032 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger(), s)
00033 
00034 namespace nodes {
00035 
00036 class symbol_tree_associations : public symbol_table<symbol_tree *>
00037 {
00038 public:
00039   symbol_tree_associations(int max_bits)
00040       :  symbol_table<symbol_tree *>(max_bits) {}
00041 };
00042 
00044 
00045 symbol_tree::symbol_tree(const istring &node_name, int max_bits)
00046 : tree(),
00047   _associations(new symbol_tree_associations(max_bits)),
00048   _name(new istring(node_name))
00049 {
00050 }
00051 
00052 symbol_tree::~symbol_tree()
00053 {
00054   WHACK(_name);
00055   WHACK(_associations);
00056 }
00057 
00058 int symbol_tree::children() const { return _associations->symbols(); }
00059 
00060 const istring &symbol_tree::name() const { return *_name; }
00061 
00062 int symbol_tree::max_bits() const { return _associations->max_bits(); }
00063 
00064 void symbol_tree::rehash(int max_bits) { _associations->rehash(max_bits); }
00065 
00066 void symbol_tree::hash_appropriately(int max_per_bucket)
00067 { _associations->hash_appropriately(max_per_bucket); }
00068 
00069 bool symbol_tree::add(symbol_tree *to_add)
00070 {
00071   FUNCDEF("add");
00072 #ifdef DEBUG_SYMBOL_TREE
00073   LOG(istring("adding node for ") + to_add->name());
00074 #endif
00075   attach(to_add);  // add to tree.
00076   _associations->add(to_add->name(), to_add);  // add to associations.
00077   return true;
00078 }
00079 
00080 outcome symbol_tree::prune(tree *to_zap_in)
00081 {
00082   FUNCDEF("prune");
00083   symbol_tree *to_zap = dynamic_cast<symbol_tree *>(to_zap_in);
00084   if (!to_zap)
00085     non_continuable_error(static_class_name(), func, "wrong type of node in prune");
00086 #ifdef DEBUG_SYMBOL_TREE
00087   LOG(istring("zapping node for ") + to_zap->name());
00088 #endif
00089   int found = which(to_zap);  // find the node in the tree.
00090   if (negative(found)) return common::NOT_FOUND;  // not found.
00091 #ifdef DEBUG_SYMBOL_TREE
00092   int kids = _associations->symbols();
00093 #endif
00094   _associations->whack(to_zap->name());  // remove from associations.
00095 #ifdef DEBUG_SYMBOL_TREE
00096   if (kids - 1 != _associations->symbols())
00097     deadly_error(static_class_name(), func, "failed to crop kid in symtab");
00098 #endif
00099   tree::prune(to_zap);  // remove from tree.
00100   return common::OKAY;
00101 }
00102 
00103 symbol_tree *symbol_tree::branch(int index) const
00104 { return dynamic_cast<symbol_tree *>(tree::branch(index)); }
00105 
00106 // implementation snagged from basis/shell_sort.
00107 void symbol_tree::sort()
00108 {
00109   int n = branches();
00110   symbol_tree *temp;
00111   int gap, i, j;
00112   for (gap = n / 2; gap > 0; gap /= 2) {
00113     for (i = gap; i < n; i++) {
00114       for (j = i - gap; j >= 0 && branch(j)->name() > branch(j + gap)->name();
00115           j = j - gap) {
00116         // swap the elements that are disordered.
00117         temp = branch(j + gap);
00118         prune_index(j + gap);
00119         insert(j, temp);
00120         temp = branch(j + 1);
00121         prune_index(j + 1);
00122         insert(j + gap, temp);
00123       }
00124     }
00125   }
00126 }
00127 
00128 symbol_tree *symbol_tree::find(const istring &to_find, find_methods how,
00129     string_comparator_function *comp)
00130 {
00131   FUNCDEF("find");
00132   if (comp == NIL) comp = istring_comparator;
00133 #ifdef DEBUG_SYMBOL_TREE
00134   LOG(istring("finding node called ") + to_find);
00135 #endif
00136   // ensure that we compare the current node.
00137   if (comp(name(), to_find)) return this;
00138 
00139   // perform the upward recursion first, since it's pretty simple.
00140   if (how == recurse_upward) {
00141     symbol_tree *our_parent = dynamic_cast<symbol_tree *>(parent());
00142     if (!our_parent) return NIL;  // done recursing.
00143     return our_parent->find(to_find, how, comp);
00144   }
00145 
00146   // see if our branches match the search term.
00147   symbol_tree **found = _associations->find(to_find, comp);
00148 #ifdef DEBUG_SYMBOL_TREE
00149   if (!found) LOG(to_find + " was not found.")
00150   else LOG(to_find + " was found successfully.");
00151 #endif
00152   if (!found) {
00153     if (how == recurse_downward) {
00154       // see if we can't find that name in a sub-node.
00155       symbol_tree *answer = NIL;
00156       for (int i = 0; i < branches(); i++) {
00157         // we will try each branch in turn and see if it has a child named
00158         // appropriately.
00159         symbol_tree *curr = dynamic_cast<symbol_tree *>(branch(i));
00160 #ifdef DEBUG_SYMBOL_TREE
00161         LOG(istring("recursing to ") + curr->name());
00162 #endif
00163         if (curr)
00164           answer = curr->find(to_find, how, comp);
00165         if (answer)
00166           return answer;
00167       }
00168     }
00169     return NIL;
00170   }
00171   return *found;
00172 }
00173 
00174 //hmmm: is this useful elsewhere?
00175 istring hier_prefix(int depth, int kids)
00176 {
00177   istring indent = string_manipulation::indentation( (depth - 1) * 2);
00178   if (!depth) return "";
00179   else if (!kids) return indent + "|--";
00180   else return indent + "+--";
00181 }
00182 
00183 istring symbol_tree::text_form() const
00184 {
00185   FUNCDEF("text_form");
00186   istring to_return;
00187 
00188   tree::iterator ted = start(prefix);
00189     // create our iterator to do a prefix traversal.
00190 
00191   tree *curr = (tree *)ted.next();
00192 
00193 //hmmm: this cast assumes that the tree only contains trees.  for more
00194 //      safety, we might want a dynamic cast here also.
00195   while (curr) {
00196     // we have a good directory to show.
00197     symbol_tree *curr_cast = dynamic_cast<symbol_tree *>(curr);
00198     if (!curr_cast) {
00199       // something very bad with that...
00200 #ifdef DEBUG_SYMBOL_TREE
00201       LOG("logic error: unknown type in symbol tree.");
00202 #endif
00203       ted.next();
00204       continue;
00205     }
00206     istring name_to_log = curr_cast->name();
00207     if (!ted.size()) name_to_log = "";
00208 #ifdef DEBUG_SYMBOL_TREE
00209     LOG(isprintf("depth %d kids %d name %s", ted.size(), curr_cast->branches(),
00210         name_to_log.s()));
00211 #endif
00212     to_return += hier_prefix(curr->depth(), curr_cast->branches());
00213     to_return += name_to_log;
00214     to_return += log_base::platform_ending();
00215 
00216     curr = (tree *)ted.next();
00217   }
00218 
00219   return to_return;
00220 }
00221 
00222 } // namespace.
00223 
00224 
00225 #endif //SYMBOL_TREE_IMPLEMENTATION_FILE
00226 

Generated on Fri Nov 21 04:29:51 2008 for HOOPLE Libraries by  doxygen 1.5.1