amorph.h

Go to the documentation of this file.
00001 #ifndef AMORPH_CLASS
00002 #define AMORPH_CLASS
00003 
00004 /*****************************************************************************\
00005 *                                                                             *
00006 *  Name   : amorph                                                            *
00007 *  Author : Chris Koeritz                                                     *
00008 *                                                                             *
00009 *******************************************************************************
00010 * Copyright (c) 1989-$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 "object_packers.h"
00019 
00020 #include <basis/astring.h>
00021 #include <basis/functions.h>
00022 #include <basis/contracts.h>
00023 #include <basis/guards.h>
00024 
00026 
00055 namespace structures {
00056 
00057 template <class contents>
00058 class amorph : private basis::array<contents *>
00059 {
00060 public:
00061   amorph(int elements = 0);
00063 
00064   ~amorph();
00065 
00066   int elements() const { return this->length(); }
00068 
00069   int valid_fields() const { return _fields_used; }
00071 
00073   void adjust(int new_max);
00075 
00079   void reset(int new_maximum = 0);
00081 
00082   basis::outcome put(int field, const contents *data);
00084 
00090   basis::outcome append(const contents *data);
00092 
00095   basis::outcome operator += (const contents *data) { return append(data); }
00097 
00099 
00101   const contents *get(int field) const;
00103 
00105   contents *borrow(int field);
00106 
00108   const contents *operator [] (int field) const { return get(field); }
00110   contents *operator [] (int field) { return borrow(field); }
00111 
00112   contents *acquire(int field);
00114 
00121   basis::outcome clear(int field);
00123 
00127   void clear_all();
00129 
00130   basis::outcome zap(int start, int end);
00132 
00140   basis::outcome insert(int position, int lines_to_add);
00142 
00146   int find_empty(basis::outcome &o) const;
00148 
00150   const contents *next_valid(int &field) const;
00152 
00156   int find(const contents *to_locate, basis::outcome &o);
00158 
00163   void swap_contents(amorph<contents> &other);
00165 
00168 private:
00169   int _fields_used;  
00170 
00171   void check_fields(const char *where) const;
00173 
00175   void set_nil(int start, int end);
00176     // Puts NIL in the indices between start and end.
00180   // not to be used: amorphs should not be copied because it is intended that
00181   // they support storing heavyweight objects that either have no copy
00182   // constructors or have high-cost copy constructors.
00183   amorph(const amorph &to_copy) {}  
00184   amorph &operator = (const amorph &to_copy) { return *this; }
00186 };
00187 
00189 
00190 // these extensions are phrased as macros to avoid including the headers
00191 // necessary for compiling them.  to use them, just put the macro name in
00192 // the file where the template is needed.
00193 
00195 
00197 
00198 template <class contents>
00199 void amorph_assign(amorph<contents> &to_assign,
00200     const amorph<contents> &to_copy);
00201 
00203 
00205 
00211 template <class contents>
00212 void amorph_pack(basis::byte_array &packed_form, const amorph<contents> &to_pack);
00213 
00215 template <class contents>
00216 bool amorph_unpack(basis::byte_array &packed_form, amorph<contents> &to_unpack);
00217 
00219 template <class contents>
00220 int amorph_packed_size(const amorph<contents> &to_pack);
00221 
00222 // implementation for longer methods...
00223 
00224 //#define DEBUG_AMORPH
00225   // uncomment to enable more testing, as well as complaints on errors.
00226 
00227 #undef static_class_name
00228 #define static_class_name() "amorph"
00229   // used in bounds_halt macro.
00230 
00231 #undef AMO_ALERT
00232 #ifdef DEBUG_AMORPH
00233   #include <basis/astring.h>
00234   #define AMO_ALERT(a, b, c) basis::throw_error(basis::astring(a), basis::astring(func), basis::astring(b) + " -- " + c)
00235   #define CHECK_FIELDS check_fields(func)
00236 #else
00237   #define AMO_ALERT(a1, a2, a3) {}
00238   #define CHECK_FIELDS { if (!func) {} }
00239 #endif
00240 
00242 
00243 template <class contents>
00244 amorph<contents>::amorph(int elements)
00245 : basis::array<contents *>(elements, NIL, basis::array<contents *>::SIMPLE_COPY
00246       | basis::array<contents *>::EXPONE | basis::array<contents *>::FLUSH_INVISIBLE),
00247   _fields_used(0)
00248 {
00249   FUNCDEF("constructor");
00250   set_nil(0, elements - 1);
00251   CHECK_FIELDS;
00252 }
00253 
00254 template <class contents>
00255 amorph<contents>::~amorph()
00256 {
00257   FUNCDEF("destructor");
00258   CHECK_FIELDS;
00259   clear_all();
00260 }
00261 
00262 template <class contents>
00263 void amorph<contents>::set_nil(int start, int end)
00264 {
00265   for (int i = start; i <= end; i++)
00266     basis::array<contents *>::put(i, (contents *)NIL);
00267 }
00268 
00269 template <class contents>
00270 void amorph<contents>::check_fields(const char *where) const
00271 {
00272   FUNCDEF("check_fields");
00273   int counter = 0;
00274   for (int i = 0; i < elements(); i++)
00275     if (basis::array<contents *>::get(i)) counter++;
00276   if (_fields_used != counter) {
00277     AMO_ALERT("amorph", basis::a_sprintf("check_fields for %s", where),
00278         "error in _fields_used count");
00279   }
00280 }
00281 
00282 template <class contents>
00283 void amorph<contents>::reset(int new_maximum)
00284 {
00285   FUNCDEF("reset");
00286   CHECK_FIELDS;
00287   adjust(new_maximum);
00288   clear_all();
00289 }
00290 
00291 template <class contents>
00292 void amorph<contents>::clear_all()
00293 {
00294   FUNCDEF("clear_all");
00295   CHECK_FIELDS;
00296   for (int i = 0; i < elements(); i++) clear(i);
00297 }
00298 
00299 template <class contents>
00300 basis::outcome amorph<contents>::append(const contents *data)
00301 {
00302   FUNCDEF("append");
00303   CHECK_FIELDS;
00304   adjust(elements() + 1);
00305   return put(elements() - 1, (contents *)data);
00306 }
00307 
00308 template <class contents>
00309 const contents *amorph<contents>::get(int field) const
00310 {
00311   FUNCDEF("get");
00312   CHECK_FIELDS;
00313   bounds_return(field, 0, elements() - 1, NIL);
00314   return basis::array<contents *>::observe()[field];
00315 }
00316 
00317 template <class contents>
00318 void amorph<contents>::adjust(int new_maximum)
00319 {
00320   FUNCDEF("adjust");
00321   CHECK_FIELDS;
00322   if (new_maximum < 0) return;  // bad input here.
00323   int old_max = elements();
00324   if (new_maximum == old_max) return;  // nothing to do.
00325   if (new_maximum < old_max) {
00326     // removes the elements beyond the new size of the amorph.
00327     zap(new_maximum, old_max - 1);
00328     // we're done tuning it.
00329     return;
00330   }
00331 
00332   // we get to here if we need more space than we used to.
00333   int new_fields = new_maximum - old_max;
00334 
00335   basis::array<contents *>::insert(old_max, new_fields);
00336   for (int i = old_max; i < new_maximum; i++) {
00337     basis::array<contents *>::put(i, NIL);
00338   }
00339 }
00340 
00341 template <class contents>
00342 basis::outcome amorph<contents>::insert(int position, int lines_to_add)
00343 {
00344   FUNCDEF("insert");
00345   CHECK_FIELDS;
00346   bounds_return(position, 0, elements(), basis::common::OUT_OF_RANGE);
00347   basis::outcome o = basis::array<contents *>::insert(position, lines_to_add);
00348   if (o != basis::common::OKAY) return basis::common::OUT_OF_RANGE;
00349   set_nil(position, position + lines_to_add - 1);
00350   return basis::common::OKAY;
00351 }
00352 
00353 template <class contents>
00354 basis::outcome amorph<contents>::zap(int start_index, int end_index)
00355 {
00356   FUNCDEF("zap");
00357   CHECK_FIELDS;
00358   bounds_return(start_index, 0, elements() - 1, basis::common::OUT_OF_RANGE);
00359   bounds_return(end_index, 0, elements() - 1, basis::common::OUT_OF_RANGE);
00360   if (end_index < start_index) return basis::common::OKAY;
00361   for (int i = start_index; i <= end_index;  i++) clear(i);
00362   basis::outcome o = basis::array<contents *>::zap(start_index, end_index);
00363   return (o == basis::common::OKAY? basis::common::OKAY : basis::common::OUT_OF_RANGE);
00364 }
00365 
00366 template <class contents>
00367 basis::outcome amorph<contents>::put(int field, const contents *data)
00368 {
00369   FUNCDEF("put");
00370   CHECK_FIELDS;
00371   bounds_return(field, 0, elements() - 1, basis::common::OUT_OF_RANGE);
00372   contents *to_whack = acquire(field);
00373   WHACK(to_whack);
00374   if (data) {
00375     basis::array<contents *>::access()[field] = (contents *)data;
00376     _fields_used++; 
00377   }
00378   return basis::common::OKAY;
00379 }
00380 
00381 template <class contents>
00382 int amorph<contents>::find_empty(basis::outcome &o) const
00383 {
00384   FUNCDEF("find_empty");
00385   CHECK_FIELDS;
00386   if (_fields_used == elements()) { o = basis::common::IS_FULL; return 0; }
00387   for (int i = 0; i < elements(); i++)
00388     if (!basis::array<contents *>::get(i)) { o = basis::common::OKAY; return i; }
00389   AMO_ALERT("amorph", "empty", "_fields_used is incorrect");
00390   return basis::common::IS_FULL;
00391 }
00392 
00393 template <class contents>
00394 const contents *amorph<contents>::next_valid(int &field) const
00395 {
00396   FUNCDEF("next_valid");
00397   CHECK_FIELDS;
00398   bounds_return(field, 0, elements() - 1, NIL);
00399   for (int i = field; i < elements(); i++)
00400     if (basis::array<contents *>::get(i)) {
00401       field = i;
00402       return basis::array<contents *>::get(i);
00403     }
00404   return NIL;
00405 }
00406 
00407 template <class contents>
00408 basis::outcome amorph<contents>::clear(int field)
00409 {
00410   FUNCDEF("clear");
00411   CHECK_FIELDS;
00412   return this->put(field, NIL);
00413 }
00414 
00415 template <class contents>
00416 contents *amorph<contents>::acquire(int field)
00417 {
00418   FUNCDEF("acquire");
00419   CHECK_FIELDS;
00420   contents *to_return = borrow(field);
00421   if (to_return) {
00422     _fields_used--;
00423     basis::array<contents *>::access()[field] = NIL;
00424   }
00425   return to_return;
00426 }
00427 
00428 template <class contents>
00429 int amorph<contents>::find(const contents *to_locate, basis::outcome &o)
00430 {
00431   FUNCDEF("find");
00432   CHECK_FIELDS;
00433   if (!_fields_used) { o = basis::common::NOT_FOUND; return 0; }
00434   for (int i = 0; i < elements(); i++) {
00435     if (basis::array<contents *>::get(i) == to_locate) {
00436       o = basis::common::OKAY;
00437       return i; 
00438     }
00439   }
00440   o = basis::common::NOT_FOUND;
00441   return 0;
00442 }
00443 
00444 template <class contents>
00445 contents *amorph<contents>::borrow(int field)
00446 {
00447   FUNCDEF("borrow");
00448   CHECK_FIELDS;
00449   bounds_return(field, 0, elements() - 1, NIL);
00450   return basis::array<contents *>::access()[field];
00451 }
00452 
00453 template <class contents>
00454 void amorph<contents>::swap_contents(amorph<contents> &other)
00455 {
00456   FUNCDEF("swap_contents");
00457   CHECK_FIELDS;
00458   int hold_fields = _fields_used;
00459   _fields_used = other._fields_used;
00460   other._fields_used = hold_fields;
00461   this->basis::array<contents *>::swap_contents(other);
00462 }
00463 
00464 template <class contents>
00465 int amorph_packed_size(const amorph<contents> &to_pack)
00466 {
00467   int parts_size = 0;
00468   for (int i = 0; i < to_pack.elements(); i++) {
00469     const contents *current = to_pack.get(i);
00470     if (current) parts_size += current->packed_size();
00471   }
00472   return PACKED_SIZE_INT32 + parts_size;
00473 }
00474 
00475 template <class contents>
00476 void amorph_pack(basis::byte_array &packed_form, const amorph<contents> &to_pack)
00477 {
00478   structures::attach(packed_form, to_pack.elements());
00479   for (int i = 0; i < to_pack.elements(); i++) {
00480     const contents *current = to_pack.get(i);
00481     if (current) current->pack(packed_form);
00482   }
00483 }
00484 
00485 template <class contents>
00486 bool amorph_unpack(basis::byte_array &packed_form, amorph<contents> &to_unpack)
00487 {
00488   to_unpack.reset();
00489   int elem = 0;
00490   if (!structures::detach(packed_form, elem)) return false;
00491   for (int i = 0; i < elem; i++) {
00492     contents *to_add = new contents;
00493     if (!to_add->unpack(packed_form)) { delete to_add; return false; }
00494     to_unpack.append(to_add);
00495   }
00496   return true;
00497 }
00498 
00499 template <class contents>
00500 void amorph_assign(amorph<contents> &to_assign,
00501     const amorph<contents> &to_copy)
00502 {
00503   if (&to_assign == &to_copy) return;
00504   to_assign.clear_all();
00505   if (to_assign.elements() != to_copy.elements()) {
00506     to_assign.zap(0, to_assign.elements() - 1);
00507     to_assign.insert(0, to_copy.elements());
00508   }
00509   for (int i = 0; i < to_assign.elements(); i++) {
00510     if (to_copy.get(i)) to_assign.put(i, new contents(*to_copy.get(i)));
00511     else to_assign.put(i, (contents *)NIL);
00512   }
00513 }
00514 
00515 #undef static_class_name
00516 
00517 } //namespace.
00518 
00519 #endif
00520 
Generated on Sat Jan 28 04:22:24 2012 for hoople2 project by  doxygen 1.6.3