tree.cpp

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