packable_tree.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "packable_tree.h"
00016
00017 #include <basis/astring.h>
00018 #include <basis/byte_array.h>
00019 #include <basis/guards.h>
00020 #include <structures/object_packers.h>
00021 #include <structures/stack.h>
00022
00023 using namespace basis;
00024 using namespace structures;
00025
00026
00027
00028
00029 #undef LOG
00030 #ifdef DEBUG_PACKABLE_TREE
00031 #include <stdio.h>
00032 #define LOG(to_print) printf("%s\n", astring(to_print).s());
00033 #else
00034 #define LOG(s) { if (!!s) {} }
00035 #endif
00036
00037 namespace nodes {
00038
00039
00040
00041
00042
00043
00044 enum tree_commands { BRANCHES_FOLLOW, ATTACH_BRANCHES, FINISH };
00045
00047
00048 packable_tree_factory::~packable_tree_factory() {}
00049
00051
00053 struct tree_command_unit : public virtual packable
00054 {
00055 tree_commands command;
00056 int number;
00057 int size;
00058
00059 virtual ~tree_command_unit() {}
00060
00061 virtual int packed_size() const { return 3 * PACKED_SIZE_INT32; }
00062
00063 virtual void pack(byte_array &packed_form) const {
00064 attach(packed_form, int(command));
00065 attach(packed_form, number);
00066 attach(packed_form, size);
00067 }
00068
00069 virtual bool unpack(byte_array &packed_form) {
00070 int cmd;
00071 if (!detach(packed_form, cmd)) return false;
00072 command = (tree_commands)cmd;
00073 if (!detach(packed_form, number)) return false;
00074 if (!detach(packed_form, size)) return false;
00075 return true;
00076 }
00077 };
00078
00080
00081 packable_tree::packable_tree() : tree() {}
00082
00083 void packable_tree::calcit(int &size_accumulator, const packable_tree *current_node)
00084 {
00085 LOG(a_sprintf("calcing node %x", current_node));
00086 FUNCDEF("calcit");
00087 if (!current_node) throw_error(static_class_name(), func, "current node is nil");
00088 tree_command_unit temp;
00089 size_accumulator += current_node->packed_size() + temp.packed_size();
00090 LOG(a_sprintf("len A %d", size_accumulator));
00091 }
00092
00093 void packable_tree::packit(byte_array &packed_form, const packable_tree *current_node)
00094 {
00095 LOG(a_sprintf("packing node %x", current_node));
00096 LOG(a_sprintf("size A %d", packed_form.length()));
00097 FUNCDEF("packit");
00098 if (!current_node) throw_error(static_class_name(), func, "current node is nil");
00099
00100 byte_array temp_store;
00101
00102 int guess = current_node->packed_size();
00103
00104 current_node->pack(temp_store);
00105
00106 if (temp_store.length() != guess)
00107 throw_error(current_node->class_name(), func, "failure calculating size");
00108
00109 tree_command_unit command;
00110 command.size = temp_store.length();
00111
00112 if (current_node->branches() == 0) {
00113 command.command = BRANCHES_FOLLOW;
00114
00115 command.number = 1;
00116 } else {
00117 command.command = ATTACH_BRANCHES;
00118 command.number = current_node->branches();
00119 }
00120
00121 command.pack(packed_form);
00122 LOG(a_sprintf("size B %d", packed_form.length()));
00123 packed_form += temp_store;
00124 LOG(a_sprintf("size C %d", packed_form.length()));
00125 }
00126
00127 int packable_tree::recursive_packed_size() const
00128 {
00129 packable_tree *curr = NIL;
00130 int accum = 0;
00131 for (iterator zip2 = start(postfix); (curr = (packable_tree *)zip2.next()); )
00132 calcit(accum, curr);
00133 tree_command_unit end_command;
00134 accum += end_command.packed_size();
00135 return accum;
00136 }
00137
00138 void packable_tree::recursive_pack(byte_array &packed_form) const
00139 {
00140 packable_tree *curr = NIL;
00141 for (iterator zip2 = start(postfix); (curr = (packable_tree *)zip2.next()); )
00142 packit(packed_form, curr);
00143
00144 tree_command_unit end_command;
00145 end_command.number = 1;
00146 end_command.command = FINISH;
00147 end_command.size = 0;
00148
00149 end_command.pack(packed_form);
00150 }
00151
00152 packable_tree *packable_tree::recursive_unpack(byte_array &packed_form,
00153 packable_tree_factory &creator)
00154 {
00155 stack<packable_tree *> accumulated_trees(0);
00156 tree_command_unit cmd;
00157
00158 if (!cmd.unpack(packed_form)) {
00159
00160 return false;
00161 }
00162
00163 packable_tree *new_branch = NIL;
00164 bool failure = false;
00165
00166
00167
00168 while (cmd.command != FINISH) {
00169 new_branch = creator.create();
00170
00171 new_branch->unpack(packed_form);
00172
00173 if (cmd.command == ATTACH_BRANCHES) {
00174 if (cmd.number > accumulated_trees.size()) {
00175
00176 failure = true;
00177 break;
00178 }
00179 for (int i = cmd.number; i > 0; i--) {
00180 packable_tree *to_add = (packable_tree *)accumulated_trees
00181 [accumulated_trees.size()-i];
00182 new_branch->attach(to_add);
00183 }
00184 packable_tree *junk;
00185 for (int j = 0; j < cmd.number; j++)
00186 accumulated_trees.acquire_pop(junk);
00187 accumulated_trees.push(new_branch);
00188 } else if (cmd.command == BRANCHES_FOLLOW) {
00189 accumulated_trees.push(new_branch);
00190 } else {
00191
00192 failure = true;
00193 break;
00194 }
00195 if (!cmd.unpack(packed_form)) {
00196
00197 failure = true;
00198 break;
00199 }
00200 }
00201
00202 if (accumulated_trees.size() != 1) {
00203
00204 failure = true;
00205 } else if (!failure) {
00206 packable_tree *junk;
00207 accumulated_trees.acquire_pop(junk);
00208 }
00209
00210
00211 if (failure) {
00212 while (true) {
00213 packable_tree *to_whack;
00214 outcome ret = accumulated_trees.acquire_pop(to_whack);
00215 if (ret == common::IS_EMPTY) break;
00216 if (to_whack != new_branch)
00217 WHACK(to_whack);
00218 }
00219 WHACK(new_branch);
00220 }
00221
00222 return new_branch;
00223 }
00224
00225 }
00226