array.h

Go to the documentation of this file.
00001 #ifndef ARRAY_CLASS
00002 #define ARRAY_CLASS
00003 
00004 /*****************************************************************************\
00005 *                                                                             *
00006 *  Name   : array                                                             *
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 "common_outcomes.h"
00019 #include "definitions.h"
00020 #include "enhance_cpp.h"
00021 #include "functions.h"
00022 #include "guards.h"
00023 #include "outcome.h"
00024 
00025 #define DEBUG_ARRAY
00026   // uncomment for the noisier debugging version.
00027 
00028 namespace basis {
00029 
00031 
00050 template <class contents>
00051 class array : public virtual root_object
00052 {
00053 public:
00055   enum specialc_flags {
00056     NO_SPECIAL_MODES = 0x0,  
00057     SIMPLE_COPY = 0x1,  
00058     EXPONENTIAL_GROWTH = 0x2,  
00059     EXPONE = EXPONENTIAL_GROWTH,  
00060     FLUSH_INVISIBLE = 0x4  
00061   };
00062 
00063   DEFINE_CLASS_NAME("array");
00064 
00065   enum how_to_copy { NEW_AT_END, NEW_AT_BEGINNING, DONT_COPY }; 
00067 
00077   array(int number = 0, const contents *init = NIL,
00078           int flags = EXPONENTIAL_GROWTH | FLUSH_INVISIBLE);
00080 
00095   array(const array<contents> &copy_from);
00097 
00098   virtual ~array();  
00099 
00100   void reset(int number = 0, const contents *initial_contents = NIL);
00102     /*< If "initial_contents" is not NIL, then it must contain an array of
00103     "contents" with at least "number" objects in it.  If it is NIL, then
00104     the size of the array is changed but the contents are not.  note that
00105     any pre-existing elements that were previously out of range might still
00106     have their prior contents; the newly available elements are not necessarily
00107     "blank".  thus, before using them, ensure you store appropriate elements
00108     in those positions. */
00109 
00110   array &operator = (const array<contents> &copy_from);
00112 
00113   int length() const { return c_active_length; }
00115 
00116   int last() const { return c_active_length - 1; }
00118 
00119   int flags() const { return c_flags; }
00121 
00122   bool exponential() const { return c_flags & EXPONENTIAL_GROWTH; }
00124 
00125   bool simple() const { return c_flags & SIMPLE_COPY; }
00127 
00128   const contents &get(int index) const;
00130 
00132   contents &use(int index);
00134 
00135   const contents &operator [] (int index) const { return get(index); }
00137   contents &operator [] (int index) { return use(index); }
00139 
00140   outcome put(int index, const contents &to_put);
00142 
00144   array concatenation(const array &to_concatenate) const;
00146   array concatenation(const contents &to_concatenate) const;
00148 
00149   array &concatenate(const array &to_concatenate);
00151   array &concatenate(const contents &to_concatenate);
00153   array &concatenate(const contents *to_concatenate, int length);
00155 
00157   array operator + (const array &to_cat) const
00158           { return concatenation(to_cat); }
00160   array operator + (const contents &to_concatenate) const
00161           { return concatenation(to_concatenate); }
00163   array &operator += (const array &to_concatenate)
00164           { return concatenate(to_concatenate); }
00166   array &operator += (const contents &to_concatenate)
00167           { return concatenate(to_concatenate); }
00169 
00170   const contents *observe() const { return c_offset; }
00172 
00174   contents *access() { return c_offset; }
00176 
00177   void swap_contents(array<contents> &other);
00179 
00182   void snarf(array &new_contents);
00184 
00187   array subarray(int start, int end) const;
00189 
00193   outcome insert(int index, int new_indices);
00195 
00196   outcome overwrite(int index, const array &write_with, int count = -1);
00198 
00204   outcome stuff(int length, contents *to_stuff) const;
00206 
00209   outcome resize(int new_size, how_to_copy way = NEW_AT_END);
00211 
00222   outcome zap(int start, int end);
00224 
00228   outcome shrink();
00230 
00231   outcome retrain(int new_size, const contents *to_copy);
00233 
00234   enum shift_directions { TO_LEFT, TO_RIGHT };
00236 
00237   void shift_data(shift_directions where);
00239 
00242   // These are gritty internal information methods and should not be used
00243   // except by appropriately careful code.
00244   int internal_real_length() const { return c_real_length; }
00246   int internal_offset() const { return int(c_offset - c_mem_block); }
00248   const contents *internal_block_start() const { return c_mem_block; }
00250   contents *internal_block_start() { return c_mem_block; }
00252   contents * const *internal_offset_mem() const { return &c_offset; }
00254 
00255 private:
00256   int c_active_length; 
00257   int c_real_length;  // the real number of objects that can be stored.
00258   contents *c_mem_block;  
00259   contents *c_offset;  
00260   int c_flags;  
00261 
00262   outcome allocator_reset(int initial_elements, int blocking);
00264 
00267 };
00268 
00270 
00272 class int_array : public array<int>
00273 {
00274 public:
00275   int_array(int number = 0, const int *initial_contents = 0)
00276       : root_object(),
00277         array<int>(number, initial_contents, SIMPLE_COPY | EXPONE) {}
00279 
00282 };
00283 
00285 
00287 class double_array : public array<double>
00288 {
00289 public:
00290   double_array(int len = 0, double *data = NIL)
00291       : root_object(),
00292         array<double>(len, data, SIMPLE_COPY | EXPONE) {}
00293   double_array(const array<double> &to_copy) : array<double>(to_copy) {}
00294 };
00295 
00297 
00298 // implementation code, much longer methods below...
00299 
00300 // GOALS:
00301 //
00302 // 1) provide a slightly smarter allocation method for C arrays and other
00303 //    contiguous-storage container classes with better speed and reduced memory
00304 //    fragmentation through pre-allocation.  this can reduce memory thrashing
00305 //    when doing appends and inserts that can be granted with previously
00306 //    allocated, but unused, space.
00307 // 2) clean-up bounds failure cases in functions that return a reference by
00308 //    always having at least one bogus element in the array for returns.  this
00309 //    really just requires that we never allow our hidden real length of the
00310 //    array to be zero.
00311 
00312 template <class contents>
00313 array<contents>::array(int num, const contents *init, int flags)
00314 : root_object(), c_active_length(0), c_real_length(0), c_mem_block(NIL), c_offset(NIL), c_flags(flags)
00315 {
00316   if (c_flags > 7) {
00317 #ifdef DEBUG_ARRAY
00318     throw "error: array::constructor: error in parameters!  still passing a block size?";
00319 #endif
00320     c_flags = EXPONE | FLUSH_INVISIBLE;
00321       // drop simple copy, since the caller doesn't know what they're doing.
00322   }
00323 
00324   allocator_reset(num, 1);  // get some space.
00325   retrain(num, init);  // plug in their contents.
00326 }
00327 
00328 template <class contents>
00329 array<contents>::array(const array<contents> &cf)
00330 : root_object(), c_active_length(0), c_real_length(0), c_mem_block(NIL), c_offset(NIL), c_flags(cf.c_flags)
00331 {
00332   allocator_reset(cf.c_active_length, 1);  // get some space.
00333   operator = (cf);  // assignment operator does the rest.
00334 }
00335 
00336 template <class contents>
00337 array<contents>::~array()
00338 {
00339   c_offset = NIL;
00340   if (c_mem_block) delete [] c_mem_block;
00341   c_mem_block = NIL;
00342   c_active_length = 0;
00343   c_real_length = 0;
00344 }
00345 
00346 template <class contents>
00347 void array<contents>::reset(int num, const contents *init)
00348 { retrain(num, init); }
00349 
00350 template <class contents>
00351 array<contents> &array<contents>::operator =(const array &cf)
00352 {
00353   if (this == &cf) return *this;
00354   c_flags = cf.c_flags;  // copy the flags coming in from the other object.
00355   // prepare the array for retraining...
00356   c_offset = c_mem_block;  // slide the offset back to the start.
00357   c_active_length = 0;  // the length gets reset also.
00358   retrain(cf.c_active_length, cf.observe());
00359   return *this;
00360 }
00361 
00362 template <class contents>
00363 contents &array<contents>::use(int index)
00364 {
00365   bounds_return(index, 0, this->last(), bogonic<contents>());
00366   return this->access()[index];
00367 }
00368 
00369 template <class contents>
00370 const contents &array<contents>::get(int index) const
00371 {
00372   bounds_return(index, 0, this->last(), bogonic<contents>());
00373   return this->observe()[index];
00374 }
00375 
00376 template <class contents>
00377 array<contents> &array<contents>::concatenate(const array &s1)
00378 {
00379   // check whether there's anything to concatenate.
00380   if (!s1.length()) return *this;
00381   if (this == &s1) {
00382     // make sure they don't concatenate this array to itself.
00383     return concatenate(array<contents>(*this)); 
00384   }
00385   int old_len = this->length();
00386   resize(this->length() + s1.length(), NEW_AT_END);
00387   overwrite(old_len, s1);
00388   return *this;
00389 }
00390 
00391 template <class contents>
00392 array<contents> &array<contents>::concatenate(const contents &to_concatenate)
00393 {
00394   resize(this->length() + 1, NEW_AT_END);
00395   if (!this->simple())
00396     this->access()[this->last()] = to_concatenate;
00397   else
00398     memcpy(&(this->access()[this->last()]), &to_concatenate, sizeof(contents));
00399   return *this;
00400 }
00401 
00402 template <class contents>
00403 array<contents> &array<contents>::concatenate(const contents *to_concatenate,
00404     int length)
00405 {
00406   if (!length) return *this;  // nothing to do.
00407   const int old_len = this->length();
00408   resize(this->length() + length, NEW_AT_END);
00409   if (!this->simple())
00410     for (int i = 0; i < length; i++)
00411       this->access()[old_len + i] = to_concatenate[i];
00412   else
00413     memcpy(&(this->access()[old_len]), to_concatenate,
00414         length * sizeof(contents));
00415   return *this;
00416 }
00417 
00418 template <class contents>
00419 array<contents> array<contents>::concatenation(const array &s1) const
00420 {
00421   // tailor the return array to the new size needed.
00422   array<contents> to_return(this->length() + s1.length(), NIL, s1.c_flags);
00423   to_return.overwrite(0, *this);  // put the first part into the new array.
00424   to_return.overwrite(this->length(), s1);  // add the second segment.
00425   return to_return;
00426 }
00427 
00428 template <class contents>
00429 array<contents> array<contents>::concatenation(const contents &s1) const
00430 {
00431   array<contents> to_return(this->length() + 1, NIL, c_flags);
00432   to_return.overwrite(0, *this);
00433   if (!this->simple())
00434     to_return.access()[to_return.last()] = s1;
00435   else
00436     memcpy(&(to_return.access()[to_return.last()]), &s1, sizeof(contents));
00437   return to_return;
00438 }
00439 
00440 template <class contents>
00441 array<contents> array<contents>::subarray(int start, int end) const
00442 {
00443   bounds_return(start, 0, this->last(), array<contents>(0, NIL, c_flags));
00444   bounds_return(end, 0, this->last(), array<contents>(0, NIL, c_flags));
00445   if (start > end) return array<contents>(0, NIL, c_flags);
00446   return array<contents>(end - start + 1, &(this->observe()[start]), c_flags);
00447 }
00448 
00449 template <class contents>
00450 void array<contents>::swap_contents(array &other)
00451 {
00452   if (this == &other) return;  // already swapped then, i suppose.
00453   swap_values(this->c_active_length, other.c_active_length);
00454   swap_values(this->c_real_length, other.c_real_length);
00455   swap_values(this->c_offset, other.c_offset);
00456   swap_values(this->c_mem_block, other.c_mem_block);
00457   swap_values(this->c_flags, other.c_flags);
00458 }
00459 
00460 template <class contents>
00461 outcome array<contents>::shrink()
00462 {
00463   if (!c_mem_block) return common::OUT_OF_MEMORY;
00464   if (c_active_length == c_real_length) return common::OKAY;  // already just right.
00465   array new_holder(*this);
00466     // create a copy of this object that is just the size needed.
00467   swap_contents(new_holder);
00468     // swap this object with the copy, leaving the enlarged version behind
00469     // for destruction.
00470   return common::OKAY;
00471 }
00472 
00473 template <class contents>
00474 outcome array<contents>::stuff(int lengthx, contents *to_stuff) const
00475 {
00476   if (!lengthx || !this->length()) return common::OKAY;
00477   int copy_len = minimum(lengthx, this->length());
00478   if (!this->simple()) {
00479     for (int i = 0; i < copy_len; i++)
00480       to_stuff[i] = this->observe()[i];
00481   } else {
00482     memcpy(to_stuff, this->observe(), copy_len * sizeof(contents));
00483   }
00484   return common::OKAY;
00485 }
00486 
00487 template <class contents>
00488 outcome array<contents>::overwrite(int position,
00489     const array<contents> &write_with, int count)
00490 {
00491   if (!count) return common::OKAY;
00492   if ( (this == &write_with) || !this->length() || !write_with.length())
00493     return common::BAD_INPUT;
00494   bounds_return(position, 0, this->last(), common::OUT_OF_RANGE);
00495   if ( negative(count) || (count > write_with.length()) )
00496     count = write_with.length();
00497   if (position > this->length() - count)
00498     count = this->length() - position;
00499   if (!this->simple()) {
00500     for (int i = position; i < position + count; i++)
00501       this->access()[i] = write_with.observe()[i - position];
00502   } else {
00503     memcpy(&(this->access()[position]), write_with.observe(), 
00504         count * sizeof(contents));
00505   }
00506   return common::OKAY;
00507 }
00508 
00509 template <class contents>
00510 outcome array<contents>::allocator_reset(int initial, int blocking)
00511 {
00512 //  FUNCDEF("allocator_reset")
00513   if (blocking < 1) {
00514 #ifdef DEBUG_ARRAY
00515     throw "error: array::allocator_reset: has bad block size";
00516 #endif
00517     blocking = 1;
00518   }
00519   if (initial < 0) initial = 0;  // no antimatter arrays.
00520   if (c_mem_block) {
00521     // remove old contents.
00522     delete [] c_mem_block;
00523     c_mem_block = NIL;
00524     c_offset = NIL;
00525   }
00526   c_active_length = initial;  // reset the length to the reporting size.
00527   c_real_length = initial + blocking;  // compute the real length.
00528   if (c_real_length) {
00529     c_mem_block = new contents[c_real_length];
00530     if (!c_mem_block) {
00531       // this is an odd situation; memory allocation didn't blow out an
00532       // exception, but the memory block is empty.  let's consider that
00533       // a fatal error; we can't issue empty objects.
00534       throw common::OUT_OF_MEMORY;
00535     }
00536     c_offset = c_mem_block;  // reset offset to start of array.
00537   }
00538   return common::OKAY;
00539 }
00540 
00541 template <class contents>
00542 void array<contents>::shift_data(shift_directions where)
00543 {
00544   if (where == TO_LEFT) {
00545     // we want to end up with the data jammed up against the left edge.  thus
00546     // we need the offset to be zero bytes from start.
00547     if (c_offset == c_mem_block)
00548       return;  // offset already at start, we're done.
00549     // well, we need to move the data.
00550     if (simple()) {
00551       memmove(c_mem_block, c_offset, c_active_length * sizeof(contents));
00552     } else {
00553       for (contents *ptr = c_offset; ptr < c_offset + c_active_length; ptr++)
00554         c_mem_block[ptr - c_offset] = *ptr;
00555     }
00556     c_offset = c_mem_block;  // we've ensured that this is correct.
00557     if (c_flags & FLUSH_INVISIBLE) {
00558       // we need to clean up what might have had contents previously.
00559 //      for (contents *p = c_mem_block + c_active_length; p < c_mem_block + c_real_length; p++)
00560 //        *p = contents();
00561     }
00562   } else {
00563     // we want to move the data to the right, so the offset should be the
00564     // difference between the real length and the length.
00565     if (c_offset == c_mem_block + c_real_length - c_active_length)
00566       return;  // the offset is already the right size.
00567     if (simple()) {
00568       memmove(&c_mem_block[c_real_length - c_active_length], c_offset, c_active_length * sizeof(contents));
00569     } else {
00570       for (int i = c_real_length - 1; i >= c_real_length - c_active_length; i--)
00571         c_mem_block[i] = c_offset[i - c_real_length + c_active_length];
00572     }
00573     c_offset = c_mem_block + c_real_length - c_active_length;  // we've now ensured this.
00574     if (c_flags & FLUSH_INVISIBLE) {
00575       // we need to clean up the space on the left where old contents might be.
00576 //      for (contents *p = c_mem_block; p < c_offset; p++)
00577 //        *p = contents();
00578     }
00579   }
00580 }
00581 
00582 template <class contents>
00583 outcome array<contents>::resize(int new_size, how_to_copy way)
00584 {
00586   if (new_size < 0) new_size = 0;  // we stifle this.
00587   if (new_size == c_active_length) {
00588     // nothing much to do.
00589     return common::OKAY;
00590   }
00591   // okay, now we at least know that the sizes are different.  we save all the
00592   // old information about the array prior to this resizing.
00593   contents *old_s = c_mem_block;  // save the old contents...
00594   const int old_len = c_active_length;  // and length.
00595   contents *old_off = c_offset;  // and offset.
00596   bool delete_old = false;  // if true, old memory is whacked once it's copied.
00597 
00598 //hmmm: wasn't there a nice realization that we could bail out early in
00599 //      the case where the size is already suffcient?  there seems to be
00600 //      an extraneous copy case here.
00601 //      also it would be nice to have better, more descriptive names for the
00602 //      variables here since they are not lending themselves to understanding
00603 //      the algorithm.
00604 
00605   // we check whether there's easily enough space in the array already.
00606   // if not, then we have some more decisions to make.
00607   if (c_real_length - (old_off - old_s) < new_size) {
00608     // well, there's not enough space with the current space and offset.
00609     if (c_real_length < new_size) {
00610       // there's really not enough space overall, no fooling.  we now will
00611       // create a new block.
00612       c_mem_block = NIL;  // zero out the pointer so reset doesn't delete it.
00613       delete_old = true;
00614       int blocking = 1;
00615       if (exponential()) blocking = new_size + 1;
00616       outcome ret = allocator_reset(new_size, blocking);
00617       if (ret != common::OKAY) {
00618         // failure, but don't forget to whack the old glob.
00619 #ifdef DEBUG_ARRAY
00620         throw "error: array::resize: saw array reset failure";
00621 #endif
00622         delete [] old_s;
00623         return ret;
00624       }
00625       // fall out to the copying phase, now that we have some fresh memory.
00626     } else {
00627       // there is enough space if we shift some things around.
00628       const int size_difference = new_size - c_active_length;
00629         // we compute how much space has to be found in the array somewhere
00630         // to support the new larger size.
00631       if (way == DONT_COPY) {
00632         // simplest case; just reset the offset appropriately so the new_size
00633         // will fit.
00634         c_offset = c_mem_block;
00635         c_active_length = new_size;
00636       } else if (way == NEW_AT_BEGINNING) {
00637         // if the new space is at the beginning, there are two cases.  either
00638         // the new size can be accomodated by the current position of the
00639         // data or the data must be shifted to the right.
00640         if (c_offset - c_mem_block < size_difference) {
00641           // we need to shift the data over to the right since the offset isn't
00642           // big enough for the size increase.
00643           shift_data(TO_RIGHT);  // resets the offset appropriately.
00644         }
00645         // now we know that the amount of space prior to the real data
00646         // is sufficient to hold what new space is needed.  we just need to
00647         // shift the offset back somewhat.
00648         c_offset -= size_difference;
00649         c_active_length = new_size;
00650       } else {
00651         // better only be three ways to do this; we're now assuming the new
00652         // space should be at the end (NEW_AT_END).
00653         // now that we're here, we know there will be enough space if we shift
00654         // the block to the left, but we DO NEED to do this.  if we didn't need
00655         // to shift the data, then we would find that:
00656         //     c_real_length - old_off >= new_size
00657         // which is disallowed by the guardian conditional around this area.
00658         shift_data(TO_LEFT);  // resets the offset for us.
00659         c_active_length = new_size;
00660       }
00661       // we have ensured that we had enough space and we have already shifted
00662       // the data around appropriately.  we no longer need to enter the next
00663       // block where we would copy data around if we had to.  it has become
00664       // primarily for cases where either we have to copy data because we
00665       // have new storage to fill or where we are shrinking the array.
00666       return common::OKAY;
00667     }
00668   }
00669 
00670   // the blob of code below is offset invariant.  by the time we reach here,
00671   // the array should be big enough and the offset should be okay.
00672   c_active_length = new_size;  // set length to the new reporting size.
00673   if (way != DONT_COPY) {
00674     int where = 0;  // offset for storing into new array.
00675     bool do_copy = false;  // if true, then we need to move the data around.
00676     contents *loopc_offset_old = old_off;  // offset into original object.
00677     // we should only have to copy the memory in one other case besides our
00678     // inhabiting new memory--when we are asked to resize with the new stuff
00679     // at the beginning of the array.  if the new space is at the end, we're
00680     // already looking proper, but if the new stuff is at the beginning, we
00681     // need to shift existing stuff downwards.
00682     if (way == NEW_AT_BEGINNING) {
00683       where = new_size - old_len;  // move up existing junk.
00684       if (where) do_copy = true;  // do copy, since it's not immobile.
00685       if (where < 0) {
00686         // array shrank; we need to do the loop differently for starting
00687         // from the beginning.  we skip to the point in the array that our
00688         // suffix needs to start at.
00689         loopc_offset_old -= where;
00690         where = 0;  // reset where so we don't have negative offsets.
00691       }
00692     }
00693     const int size_now = minimum(old_len, c_active_length);
00694     if (delete_old || do_copy) {
00695       contents *offset_in_new = c_offset + where;
00696       contents *posn_in_old = loopc_offset_old;
00697       if (simple()) {
00698         // memmove should take care of intersections.
00699         memmove(offset_in_new, posn_in_old, size_now * sizeof(contents));
00700       } else {
00701         // we need to do the copies using the object's assignment operator.
00702         if (new_size >= old_len) {
00703           for (int i = size_now - 1; i >= 0; i--)
00704             offset_in_new[i] = posn_in_old[i];
00705         } else {
00706           for (int i = 0; i < size_now; i++)
00707             offset_in_new[i] = posn_in_old[i];
00708         }
00709       }
00710 
00711       // we only want to flush the obscured elements when we aren't already
00712       // inhabiting new space.
00713       if ( (c_flags & FLUSH_INVISIBLE) && !delete_old) {
00714         // clear out the space that just went out of scope.  we only do this
00715         // for the flushing mode and when we aren't starting from a fresh
00716         // pointer (i.e., delete_old isn't true).
00717         if (new_size < old_len) {
00718 //          for (contents *p = posn_in_old; p < offset_in_new; p++)
00719 //            *p = contents();
00720         }
00721       }
00722     }
00723   }
00724   if (delete_old) delete [] old_s;
00725   return common::OKAY;
00726 }
00727 
00728 template <class contents>
00729 outcome array<contents>::retrain(int new_len, const contents *to_set)
00730 {
00732   if (new_len < 0) new_len = 0;  // stifle that bad length.
00733 #ifdef DEBUG_ARRAY
00734   if (to_set && (c_mem_block >= to_set) && (c_mem_block < to_set + new_len) ) {
00735     throw "error: array::retrain: ranges overlap in retrain!";
00736   }
00737 #endif
00738   outcome ret = resize(new_len, DONT_COPY);
00739   if (ret != common::OKAY) return ret;
00740 #ifdef DEBUG_ARRAY
00741   if (new_len != c_active_length) {
00742     throw "error: array resize set the wrong length";
00743   }
00744 #endif
00745   if (to_set) {
00746     if (simple()) 
00747       memcpy(c_offset, to_set, c_active_length * sizeof(contents));
00748     else
00749       for (int i = 0; i < c_active_length; i++)
00750         c_offset[i] = to_set[i];
00751   } else {
00752     if (c_flags & FLUSH_INVISIBLE) {
00753       // no contents provided, so stuff the space with blanks.
00754 //      for (int i = 0; i < c_active_length; i++) c_offset[i] = contents();
00755     }
00756   }
00757   if (c_flags & FLUSH_INVISIBLE) {
00758 //    for (contents *ptr = c_mem_block; ptr < c_offset; ptr++)
00759 //      *ptr = contents();
00760 //    for (contents *ptr = c_offset + c_active_length; ptr < c_mem_block + c_real_length; ptr++)
00761 //      *ptr = contents();
00762   }
00763   return common::OKAY;
00764 }
00765 
00766 template <class contents>
00767 outcome array<contents>::zap(int position1, int position2)
00768 {
00769   if (position1 > position2) return common::OKAY;
00770   bounds_return(position1, 0, c_active_length - 1, common::OUT_OF_RANGE);
00771   bounds_return(position2, 0, c_active_length - 1, common::OUT_OF_RANGE);
00772   if (!position1) {
00773     // if they're whacking from the beginning, we just reset the offset.
00774     c_offset += position2 + 1;
00775     c_active_length -= position2 + 1;
00776     return common::OKAY;
00777   }
00778   const int difference = position2 - position1 + 1;
00779   // copy from just above position2 down into position1.
00780   if (simple()) {
00781     if (c_active_length - difference - position1 > 0)
00782       memmove(&c_offset[position1], &c_offset[position1 + difference],
00783           (c_active_length - difference - position1) * sizeof(contents));
00784   } else {
00785     for (int i = position1; i < c_active_length - difference; i++)
00786       c_offset[i] = c_offset[i + difference];
00787   }
00788 
00789   outcome ret = resize(c_active_length - difference, NEW_AT_END);
00790     // chop down to new size.
00791 #ifdef DEBUG_ARRAY
00792   if (ret != common::OKAY) {
00793     throw "error: array::zap: resize failure";
00794     return ret;
00795   }
00796 #endif
00797   return ret;
00798 }
00799 
00800 template <class contents>
00801 outcome array<contents>::insert(int position, int elem_to_add)
00802 {
00803   if (position < 0) return common::OUT_OF_RANGE;
00804   if (position > this->length())
00805     position = this->length();
00806   if (elem_to_add < 0) return common::OUT_OF_RANGE;
00807   how_to_copy how = NEW_AT_END;
00808   if (position == 0) how = NEW_AT_BEGINNING;
00809   resize(this->length() + elem_to_add, how);
00810 
00811   // if the insert wasn't at the front, we have to copy stuff into the new
00812   // locations.
00813   if (how == NEW_AT_END) {
00814     const contents simple_default_object = contents();
00815     if (!this->simple()) {
00816       for (int i = this->last(); i >= position + elem_to_add; i--)
00817         this->access()[i] = this->observe()[i - elem_to_add];
00818       for (int j = position; j < position + elem_to_add; j++)
00819         this->access()[j] = simple_default_object;
00820     } else {
00821       memmove(&(this->access()[position + elem_to_add]),
00822           &(this->observe()[position]), (this->length() - position
00823           - elem_to_add) * sizeof(contents));
00824       for (int j = position; j < position + elem_to_add; j++)
00825         memcpy(&this->access()[j], &simple_default_object, sizeof(contents));
00826     }
00827   }
00828   return common::OKAY;
00829 }
00830 
00831 template <class contents>
00832 outcome array<contents>::put(int index, const contents &to_put)
00833 {
00834   bounds_return(index, 0, this->last(), common::OUT_OF_RANGE);
00835   if (!this->simple())
00836     this->access()[index] = to_put;
00837   else
00838     memcpy(&(this->access()[index]), &to_put, sizeof(contents));
00839   return common::OKAY;
00840 }
00841 
00842 template <class contents>
00843 void array<contents>::snarf(array<contents> &new_contents)
00844 {
00845   if (this == &new_contents) return;  // no blasting own feet off.
00846   reset();  // trash our current storage.
00847   swap_contents(new_contents);
00848 }
00849 
00850 /*
00852 class char_star_array : public array<char *>
00853 {
00854 public:
00855   char_star_array() : array<char *>(0, NIL, SIMPLE_COPY | EXPONE
00856       | FLUSH_INVISIBLE) {}
00857   ~char_star_array() {
00858     // clean up all the memory we're holding.
00859     for (int i = 0; i < length(); i++) {
00860       delete [] (use(i));
00861     }
00862   }
00863 };
00864 */
00865 
00866 } //namespace
00867 
00868 #undef static_class_name
00869 
00870 #endif
00871 
Generated on Sat Jan 28 04:22:10 2012 for hoople2 project by  doxygen 1.6.3