packable_tree.cpp

Go to the documentation of this file.
00001 #ifndef PACKABLE_TREE_IMPLEMENTATION_FILE
00002 #define PACKABLE_TREE_IMPLEMENTATION_FILE
00003 
00004 /*****************************************************************************\
00005 *                                                                             *
00006 *  Name   : packable_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 // Implementation Details:
00019 //
00020 // packit: called to pack each node of the tree and add it to the store.
00021 
00022 #include "packable_tree.h"
00023 
00024 #include <basis/byte_array.h>
00025 #include <basis/guards.h>
00026 #include <data_struct/stack.cpp>
00027 
00028 using namespace basis;
00029 
00030 namespace nodes {
00031 
00032 // tree commands are used to tell the unpacker what to do with the blobs
00033 // it finds.  BRANCHES_FOLLOW indicates that there are a few branches stored
00034 // at the next few contiguous memory positions.  ATTACH_BRANCHES means that
00035 // the next branch should be the parent of some number of previous branches.
00036 // FINISH means that the tree is done being stored (or reconstructed).
00037 enum tree_commands { BRANCHES_FOLLOW, ATTACH_BRANCHES, FINISH };
00038 
00040 
00041 packable_tree_factory::~packable_tree_factory() {}
00042 
00044 
00045 // the TCU stores a command, the number of branches held, and the size of
00046 // the contents?
00047 struct tree_command_unit : public packable
00048 {
00049   tree_commands command;
00050   int number;
00051   int size;
00052 
00053   virtual void pack(byte_array &packed_form) const {
00054     attach(packed_form, int(command));
00055     attach(packed_form, number);
00056     attach(packed_form, size);
00057   }
00058 
00059   virtual bool unpack(byte_array &packed_form) {
00060     int cmd;
00061     if (!detach(packed_form, cmd)) return false;
00062     command = (tree_commands)cmd;
00063     if (!detach(packed_form, number)) return false;
00064     if (!detach(packed_form, size)) return false;
00065     return true;
00066   }
00067 };
00068 
00069 // pack_purposes: tells packit whether to add the bit of memory onto the end
00070 // of the current_place_to_stuff or whether to merely add the size of the bit
00071 // onto the accumulated_size.
00073 
00075 
00076 packable_tree::packable_tree()
00077 : tree()
00078 {}
00079 
00080 packable_tree::~packable_tree()
00081 {
00082 //let tree's destructor deal with it.
00083 }
00084 
00085 void packable_tree::packit(byte_array &packed_form,
00086     const packable_tree *current_node)
00087 {
00088   if (!current_node) {
00089 //complain.
00090     return;
00091   }
00092 
00093   byte_array temp_store;
00094   current_node->pack(temp_store);
00095   tree_command_unit command;
00096   command.size = temp_store.length();
00097 //hmmm: do we still need a packed size?
00098   if (current_node->branches() == 0) {
00099     command.command = BRANCHES_FOLLOW;
00100     // the branches following are always just one branch.
00101     command.number = 1;
00102   } else {
00103     command.command = ATTACH_BRANCHES;
00104     command.number = current_node->branches();
00105   }
00106   // stuff the command unit.
00107   command.pack(packed_form);
00108   packed_form += temp_store;
00109 // not packed, just added.
00110 }
00111 
00112 void packable_tree::recursive_pack(byte_array &packed_form) const
00113 {
00116 
00117   // end command is added in.
00121 
00123 
00124   packable_tree *curr = NIL;
00125   for (iterator zip2 = start(postfix); (curr = (packable_tree *)zip2.next()); )
00126     packit(packed_form, curr);
00127 
00128   tree_command_unit end_command;
00129   end_command.number = 1;
00130   end_command.command = FINISH;
00131   end_command.size = 0;
00132   // end command is stored at end.
00133   end_command.pack(packed_form);
00134 }
00135 
00136 //memory leaks here !  wherever return without clearing "new_branch".
00137 
00138 packable_tree *packable_tree::recursive_unpack(byte_array &packed_form,
00139     packable_tree_factory &creator)
00140 {
00141   stack<packable_tree *> accumulated_trees(0);  // unbounded.
00142   tree_command_unit cmd;
00143   // get the first command out of the package.
00144   if (!cmd.unpack(packed_form)) {
00145 //complain.
00146     return false;
00147   }
00148 
00149   packable_tree *new_branch = NIL;
00150   bool failure = false;  // set to true if errors occurred.
00151 
00152   // the packed tree is traversed by grabbing a command and then doing what
00153   // it says as far as pulling in children or adding a new branch.
00154   while (cmd.command != FINISH) {
00155     new_branch = creator.create();
00156 
00157     new_branch->unpack(packed_form);
00158 
00159     if (cmd.command == ATTACH_BRANCHES) {
00160       if (cmd.number > accumulated_trees.size()) {
00161 //log instead: "badly formed packed tree"
00162         failure = true;
00163         break;
00164       }
00165       for (int i = cmd.number; i > 0; i--) {
00166         packable_tree *to_add = (packable_tree *)accumulated_trees
00167             [accumulated_trees.size()-i];
00168         new_branch->attach(to_add);
00169       }
00170       packable_tree *junk;
00171       for (int j = 0; j < cmd.number; j++)
00172         accumulated_trees.acquire_pop(junk);
00173       accumulated_trees.push(new_branch);
00174     } else if (cmd.command == BRANCHES_FOLLOW) {
00175       accumulated_trees.push(new_branch);
00176     } else {
00177 //log instead: "invalid command in packed tree"
00178       failure = true;
00179       break;
00180     }
00181     if (!cmd.unpack(packed_form)) {
00182 //complain.
00183       failure = true;
00184       break;
00185     }
00186   }
00187 
00188   if (accumulated_trees.size() != 1) {
00189 //log instead: "not all branches were claimed"
00190     failure = true;
00191   } else if (!failure) {
00192     packable_tree *junk;
00193     accumulated_trees.acquire_pop(junk);
00194   }
00195 
00196   // clean up the allocated objects if we saw a failure.
00197   if (failure) {
00198     while (true) {
00199       packable_tree *to_whack;
00200       outcome ret = accumulated_trees.acquire_pop(to_whack);
00201       if (ret == common::IS_EMPTY) break;
00202       if (to_whack != new_branch)
00203         WHACK(to_whack);
00204     }
00205     WHACK(new_branch);
00206   }
00207 
00208   return new_branch;
00209 }
00210 
00211 }  // namespace.
00212 
00213 
00214 #endif //PACKABLE_TREE_IMPLEMENTATION_FILE
00215 

Generated on Fri Nov 28 04:29:17 2008 for HOOPLE Libraries by  doxygen 1.5.1