tree.cpp

Go to the documentation of this file.
00001 #ifndef TREE_IMPLEMENTATION_FILE
00002 #define TREE_IMPLEMENTATION_FILE
00003 
00004 /*****************************************************************************\
00005 *                                                                             *
00006 *  Name   : 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 #include "tree.h"
00019 
00020 #include <basis/function.h>
00021 #include <basis/guards.h>
00022 #include <basis/log_base.h>
00023 
00024 //#define DEBUG_TREE
00025   // uncomment if you want lots of debugging info.
00026 
00027 #undef LOG
00028 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger(), s)
00029 
00030 namespace nodes {
00031 
00032 const int BACKWARDS_BRANCH = 0;
00033   // BACKWARDS_BRANCH is the branch from this tree to its parent.  this is
00034   // steeped in the perspective that the root is the backwards direction (where
00035   // we came from, in a sense) and that the children of this node are the
00036   // forwards direction.
00037 
00039 
00040 // iterator methods:
00041 
00042 tree::iterator::iterator(const tree *initial, traversal_directions direction)
00043 : path(initial), _order(direction), _aim(AWAY_FROM_ROOT)
00044 {
00045 }
00046 
00047 tree::iterator::~iterator() { while (size()) pop(); }
00048 
00049 bool tree::iterator::next_node(tree *&to_return)
00050 {
00051   FUNCDEF("next_node");
00052   to_return = NIL;
00053 #ifdef DEBUG_TREE
00054   if ( (_order != to_branches)
00055       && (_order != reverse_branches) ) {
00056     if (_aim == AWAY_FROM_ROOT) LOG("going down")
00057     else LOG("going up");
00058   }
00059 #endif
00060   switch (_order) {
00061     case prefix: {
00062       if (_aim == AWAY_FROM_ROOT) {
00063         // going down means this is the first time we have seen the current top
00064         // node on the stack.
00065         to_return = (tree *)(*this)[size() - 1];
00066 #ifdef DEBUG_TREE
00067 //        LOG(isprintf("[%s] ", to_return->get_contents()->held().s());
00068         if (to_return->branches()) LOG("pushing 0")
00069         else LOG("switching direction");
00070 #endif
00071         if (to_return->branches())
00072           push(to_return->branch(0));
00073         else
00074           _aim = TOWARD_ROOT;
00075       } else {
00076         // going up means that we need to get rid of some things before we
00077         // start seeing new nodes again.
00078         if (size() == 1) return false;
00079           // the last node has been seen....
00080         tree *last = (tree *)pop();
00081         tree *current_tree = (tree *)current();
00082         int lastnum = current_tree->which(last);
00083 #ifdef DEBUG_TREE
00084         if (lastnum < current_tree->branches() - 1)
00085           LOG(isprintf("going down %d", lastnum+1))
00086         else LOG("still going up");
00087 #endif
00088         if (lastnum < current_tree->branches() - 1) {
00089           _aim = AWAY_FROM_ROOT;
00090           push(current_tree->branch(lastnum + 1));
00091         }  // else still going up.
00092       }
00093       break;
00094     }
00095     case infix: {
00096       if (_aim == AWAY_FROM_ROOT) {
00097         // going down means starting on the left branch.
00098         tree *temp = (tree *)current();
00099 #ifdef DEBUG_TREE
00100         if (temp->branches()) LOG("pushing 0")
00101         else LOG("switching direction");
00102 #endif
00103         if (temp->branches()) push(temp->branch(0));
00104         else {
00105           _aim = TOWARD_ROOT;
00106           to_return = (tree *)current();
00107 #ifdef DEBUG_TREE
00108 //          LOG(isprintf("[%s] ", to_return->get_contents()->held().s()));
00109 #endif
00110         }
00111       } else {
00112         // going up means that the left branch is done and we need to either
00113         // keep going up or go down the right branch.
00114         if (size() == 1) return false;
00115           // the last node has been seen....
00116         tree *last = (tree *)pop();
00117         tree *current_tree = (tree *)current();
00118         int lastnum = current_tree->which(last);
00119 #ifdef DEBUG_TREE
00120         if (lastnum < 1) LOG(isprintf("going down %d", lastnum+1))
00121         else LOG("still going up");
00122 #endif
00123         if (lastnum < 1) {
00124           _aim = AWAY_FROM_ROOT;
00125           to_return = (tree *)current();
00126 #ifdef DEBUG_TREE
00128 #endif
00129           push(current_tree->branch(lastnum + 1));
00130         }  // else still going up.
00131       }
00132       break;
00133     }
00134     case to_branches: {
00135       if (_aim == TOWARD_ROOT) return false;
00136       else {
00137         if (size() == 1) {
00138           tree *temp = (tree *)current();
00139           if (!temp->branches())
00140             _aim = TOWARD_ROOT;
00141           else
00142             push(temp->branch(0));
00143         } else {
00144           tree *last = (tree *)pop();
00145           tree *curr = (tree *)current();
00146           int lastnum = curr->which(last);
00147           if (lastnum < curr->branches() - 1)
00148             push(curr->branch(lastnum + 1));
00149           else _aim = TOWARD_ROOT;
00150           to_return = last;
00151         }
00152       }
00153       break;
00154     }
00155     case reverse_branches: {
00156       if (_aim == TOWARD_ROOT) return false;
00157       else {
00158         if (size() == 1) {
00159           tree *temp = (tree *)current();
00160           if (!temp->branches()) _aim = TOWARD_ROOT;
00161           else push(temp->branch(temp->branches() - 1));
00162         } else {
00163           tree *last = (tree *)pop();
00164           tree *curr = (tree *)current();
00165           int lastnum = curr->which(last);
00166           if (lastnum > 0) push(curr->branch(lastnum - 1));
00167           else _aim = TOWARD_ROOT;
00168           to_return = last;
00169         }
00170       }
00171       break;
00172     }
00173     default:   // intentional fall-through to postfix.
00174     case postfix: {
00175       if (_aim == AWAY_FROM_ROOT) {
00176         // going down means that the bottom is still being sought.
00177         tree *temp = (tree *)current();
00178 #ifdef DEBUG_TREE
00179         if (temp->branches()) LOG("pushing 0")
00180         else LOG("switching direction");
00181 #endif
00182         if (temp->branches()) push(temp->branch(0));
00183         else _aim = TOWARD_ROOT;
00184       } else {
00185         // going up means that all nodes below current have been hit.
00186         if (!size()) return false;  // the last node has been seen...
00187         else if (size() == 1) {
00188           to_return = (tree *)pop();
00189             // this is the last node.
00190           return true;
00191         }
00192         tree *last = (tree *)pop();
00193         to_return = last;
00194 #ifdef DEBUG_TREE
00196 #endif
00197         tree *current_tree = (tree *)current();
00198         int lastnum = current_tree->which(last);
00199 #ifdef DEBUG_TREE
00200         if (lastnum < current_tree->branches() - 1)
00201           LOG(isprintf("going down %d", lastnum+1))
00202         else LOG("still going up");
00203 #endif
00204         if (lastnum < current_tree->branches() - 1) {
00205           _aim = AWAY_FROM_ROOT;
00206           push(current_tree->branch(lastnum + 1));
00207         }  // else still going up.
00208       }
00209       break;
00210     }
00211   }
00212   return true;
00213     // it is assumed that termination conditions cause a return earlier on.
00214 }
00215 
00216 void tree::iterator::whack(tree *to_whack)
00217 {
00218   FUNCDEF("whack");
00219   if (!to_whack) return;  // that's a bad goof.
00220   if (size()) {
00221     if (to_whack == current()) {
00222       // we found that this is the one at the top right now.
00223       pop();
00224 #ifdef DEBUG_TREE
00225       LOG("found node in current top; removing it there.");
00226 #endif
00227     } else if (to_whack->parent() == current()) {
00228       // the parent is the current top.  make sure we don't mess up traversal.
00229 #ifdef DEBUG_TREE
00230       LOG("found node's parent as current top; don't know what to do.");
00231 #endif
00232     } else {
00233 #ifdef DEBUG_TREE
00234       LOG("found no match for either node to remove or parent in path.");
00235 #endif
00236     }
00237   }
00238   tree *parent = to_whack->parent();
00239   if (!parent) {
00240 #ifdef DEBUG_TREE
00241     LOG("no parent node for the one to whack!  would have whacked "
00242         "root of tree!");
00243 #endif
00244   } else {
00245     parent->prune(to_whack);
00246     WHACK(to_whack);
00247   }
00248 }
00249 
00250 tree *tree::iterator::next()
00251 {
00252   FUNCDEF("next");
00253   tree *to_return = NIL;
00254   bool found_tree = false;
00255   while (!found_tree) {
00256     bool still_running = next_node(to_return);
00257     if (to_return || !still_running) found_tree = true;
00258   }
00259   return to_return;
00260 }
00261 
00263 
00264 // tree methods:
00265 
00266 tree::tree()
00267 : node(1)
00268 { set_link(BACKWARDS_BRANCH, NIL); }
00269 
00270 tree::~tree()
00271 {
00272   // must at least unhook ourselves from the parent so we don't become a lost
00273   // cousin.
00274   tree *my_parent = parent();
00275   if (my_parent) my_parent->prune(this);
00276 
00277   // iterate over the child nodes and whack each individually.
00278   while (branches()) delete branch(0);
00279     // this relies on the child getting out of our branch list.
00280 }
00281 
00282 tree *tree::parent() const { return (tree *)get_link(BACKWARDS_BRANCH); }
00283 
00284 int tree::branches() const { return links() - 1; }
00285 
00286 tree *tree::branch(int branch_number) const
00287 {
00288   branch_number++;
00289   bounds_return(branch_number, 1, branches(), NIL);
00290   return (tree *)get_link(branch_number);
00291 }
00292 
00293 int tree::which(tree *branch_to_find) const
00294 { return node::which((node *)branch_to_find) - 1; }
00295 
00296 tree *tree::root() const
00297 {
00298   const tree *traveler = this;
00299   // keep looking at the backwards branch until it is a NIL.  the tree with
00300   // a NIL BACKWARDS_BRANCH is the root.  return that tree.
00301   while (traveler->get_link(BACKWARDS_BRANCH))
00302     traveler = (tree *)traveler->get_link(BACKWARDS_BRANCH);
00303   return const_cast<tree *>(traveler);
00304 }
00305 
00306 void tree::attach(tree *new_branch)
00307 {
00308   if (!new_branch) return;
00309   insert_link(links(), new_branch);
00310   new_branch->set_link(BACKWARDS_BRANCH, this);
00311 }
00312 
00313 void tree::insert(int branch_place, tree *new_branch)
00314 {
00315   branch_place++;
00316   insert_link(links(), NIL);
00317   if (branch_place >= links())
00318     branch_place = links() - 1;
00319   for (int i = links() - 1; i > branch_place; i--)
00320     set_link(i, get_link(i-1));
00321   set_link(branch_place, new_branch);
00322   new_branch->set_link(BACKWARDS_BRANCH, this);
00323 }
00324 
00325 outcome tree::prune(tree *branch_to_cut)
00326 {
00327   int branch_number = which(branch_to_cut);
00328   if (branch_number == common::NOT_FOUND) return common::NOT_FOUND;
00329   return prune_index(branch_number);
00330 }
00331 
00332 outcome tree::prune_index(int branch_to_cut)
00333 {
00334   branch_to_cut++;
00335   bounds_return(branch_to_cut, 1, branches(), common::NOT_FOUND);
00336   tree *that_branch = (tree *)get_link(branch_to_cut);
00337   that_branch->set_link(BACKWARDS_BRANCH, NIL);
00338   zap_link(branch_to_cut);
00339   return common::OKAY;
00340 }
00341 
00342 int tree::depth() const
00343 {
00344   tree *my_root = root();
00345   const tree *current_branch = this;
00346   int deep = 0;
00347   while (current_branch != my_root) {
00348     current_branch = current_branch->parent();
00349     deep++;
00350   }
00351   return deep;
00352 }
00353 
00354 //probably okay; we want to use this function rather than non-existent
00355 //node base function which isn't implemented yet.
00356 bool tree::generate_path(path &to_follow) const
00357 {
00358 if (to_follow.size()) {} 
00359 /*
00360   tree *traveller = this;
00361   path to_accumulate(root());
00362   while (traveller->parent() != NIL) {
00363 //    int branch_number = traveller->parent()->which(traveller);
00364 //    if (branch_number == BRANCH_NOT_FOUND) non_continuable_error
00365 //      (class_name(), "generate_path", "branch not found during path construction");
00366 //    chunk *to_stuff = new chunk
00367 //      (SELF_OWNED, (byte *)&branch_number, sizeof(int));
00368     to_accumulate.push(traveller);
00369     traveller = traveller->parent();
00370   }
00371   // the order of things on the stack needs to be reversed now.
00372 //  path to_return = new stack(*to_accumulate.invert());
00373 //  return to_return;
00374   to_accumulate.invert();
00375   return to_accumulate;
00376 */
00377 return false;//temp.
00378 }
00379 
00380 //hmmm: need text form!
00381 
00382 tree::iterator tree::start(traversal_directions direction) const
00383 { return iterator(this, direction); }
00384 
00385 }  // namespace.
00386 
00387 
00388 #endif //TREE_IMPLEMENTATION_FILE
00389 

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