00001 #ifndef PACKABLE_TREE_IMPLEMENTATION_FILE
00002 #define PACKABLE_TREE_IMPLEMENTATION_FILE
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
00033
00034
00035
00036
00037 enum tree_commands { BRANCHES_FOLLOW, ATTACH_BRANCHES, FINISH };
00038
00040
00041 packable_tree_factory::~packable_tree_factory() {}
00042
00044
00045
00046
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
00070
00071
00073
00075
00076 packable_tree::packable_tree()
00077 : tree()
00078 {}
00079
00080 packable_tree::~packable_tree()
00081 {
00082
00083 }
00084
00085 void packable_tree::packit(byte_array &packed_form,
00086 const packable_tree *current_node)
00087 {
00088 if (!current_node) {
00089
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
00098 if (current_node->branches() == 0) {
00099 command.command = BRANCHES_FOLLOW;
00100
00101 command.number = 1;
00102 } else {
00103 command.command = ATTACH_BRANCHES;
00104 command.number = current_node->branches();
00105 }
00106
00107 command.pack(packed_form);
00108 packed_form += temp_store;
00109
00110 }
00111
00112 void packable_tree::recursive_pack(byte_array &packed_form) const
00113 {
00116
00117
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
00133 end_command.pack(packed_form);
00134 }
00135
00136
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);
00142 tree_command_unit cmd;
00143
00144 if (!cmd.unpack(packed_form)) {
00145
00146 return false;
00147 }
00148
00149 packable_tree *new_branch = NIL;
00150 bool failure = false;
00151
00152
00153
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
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
00178 failure = true;
00179 break;
00180 }
00181 if (!cmd.unpack(packed_form)) {
00182
00183 failure = true;
00184 break;
00185 }
00186 }
00187
00188 if (accumulated_trees.size() != 1) {
00189
00190 failure = true;
00191 } else if (!failure) {
00192 packable_tree *junk;
00193 accumulated_trees.acquire_pop(junk);
00194 }
00195
00196
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 }
00212
00213
00214 #endif //PACKABLE_TREE_IMPLEMENTATION_FILE
00215