00001 #ifndef ARRAY_IMPLEMENTATION
00002 #define ARRAY_IMPLEMENTATION
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "array.h"
00036 #include "function.h"
00037 #include "guards.h"
00038
00039 #include <stdio.h>
00040 #include <string.h>
00041
00042 #undef static_class_name
00043 #define static_class_name() "array"
00044
00045
00046
00047
00048
00049
00050 template <class contents>
00051 array<contents>::array(int num, const contents *init, u_short flags)
00052 : _active_length(0), _real_length(0), _mem_block(NIL), _offset(NIL), _flags(flags)
00053 {
00054 if (_flags > 7) {
00055 #ifdef DEBUG_ARRAY
00056 const char *error_msg = "array constructor: error in parameters! "
00057 "still passing a block size? flags is set to %d.";
00058 printf(error_msg, flags);
00059 fprintf(stderr, error_msg, flags);
00060 #ifdef ERRORS_ARE_FATAL
00061 fflush(0);
00062 CAUSE_BREAKPOINT;
00063 throw "deadly_error";
00064 #endif // errors are fatal.
00065 #endif // array debugging is turned on.
00066
00067 _flags = EXPONE | FLUSH_INVISIBLE;
00068
00069 }
00070
00071 allocator_reset(num, 1);
00072 retrain(num, init);
00073 }
00074
00075 template <class contents>
00076 array<contents>::array(const array<contents> &cf)
00077 : _active_length(0), _real_length(0), _mem_block(NIL), _offset(NIL), _flags(cf._flags)
00078 {
00079 allocator_reset(cf._active_length, 1);
00080 operator = (cf);
00081 }
00082
00083 template <class contents>
00084 array<contents>::~array()
00085 {
00086 _offset = NIL;
00087 if (_mem_block) delete [] _mem_block;
00088 _mem_block = NIL;
00089 _active_length = 0;
00090 _real_length = 0;
00091 }
00092
00093 template <class contents>
00094 void array<contents>::reset(int num, const contents *init)
00095 { retrain(num, init); }
00096
00097 template <class contents>
00098 array<contents> &array<contents>::operator =(const array &cf)
00099 {
00100 if (this == &cf) return *this;
00101 _flags = cf._flags;
00102
00103 _offset = _mem_block;
00104 _active_length = 0;
00105 retrain(cf._active_length, cf.observe());
00106 return *this;
00107 }
00108
00109 template <class contents>
00110 contents &array<contents>::use(int index)
00111 {
00112 FUNCDEF("use");
00113 bounds_halt(index, 0, this->last(), bogonic<contents>());
00114 return this->access()[index];
00115 }
00116
00117 template <class contents>
00118 const contents &array<contents>::get(int index) const
00119 {
00120 FUNCDEF("get");
00121 bounds_halt(index, 0, this->last(), bogonic<contents>());
00122 return this->observe()[index];
00123 }
00124
00125 template <class contents>
00126 array<contents> &array<contents>::concatenate(const array &s1)
00127 {
00128
00129 if (!s1.length()) return *this;
00130 if (this == &s1) {
00131
00132 return concatenate(array<contents>(*this));
00133 }
00134 int old_len = this->length();
00135 resize(this->length() + s1.length(), common::NEW_AT_END);
00136 overwrite(old_len, s1);
00137 return *this;
00138 }
00139
00140 template <class contents>
00141 array<contents> &array<contents>::concatenate(const contents &to_concatenate)
00142 {
00143 resize(this->length() + 1, common::NEW_AT_END);
00144 if (!this->simple())
00145 this->access()[this->last()] = to_concatenate;
00146 else
00147 memcpy(&(this->access()[this->last()]), &to_concatenate, sizeof(contents));
00148 return *this;
00149 }
00150
00151 template <class contents>
00152 array<contents> &array<contents>::concatenate(const contents *to_concatenate,
00153 int length)
00154 {
00155 if (!length) return *this;
00156 const int old_len = this->length();
00157 resize(this->length() + length, common::NEW_AT_END);
00158 if (!this->simple())
00159 for (int i = 0; i < length; i++)
00160 this->access()[old_len + i] = to_concatenate[i];
00161 else
00162 memcpy(&(this->access()[old_len]), to_concatenate,
00163 length * sizeof(contents));
00164 return *this;
00165 }
00166
00167 template <class contents>
00168 array<contents> array<contents>::concatenation(const array &s1) const
00169 {
00170
00171 array<contents> to_return(this->length() + s1.length(), NIL, s1._flags);
00172 to_return.overwrite(0, *this);
00173 to_return.overwrite(this->length(), s1);
00174 return to_return;
00175 }
00176
00177 template <class contents>
00178 array<contents> array<contents>::concatenation(const contents &s1) const
00179 {
00180 array<contents> to_return(this->length() + 1, NIL, _flags);
00181 to_return.overwrite(0, *this);
00182 if (!this->simple())
00183 to_return.access()[to_return.last()] = s1;
00184 else
00185 memcpy(&(to_return.access()[to_return.last()]), &s1, sizeof(contents));
00186 return to_return;
00187 }
00188
00189 template <class contents>
00190 array<contents> array<contents>::subarray(int start, int end) const
00191 {
00192 bounds_return(start, 0, this->last(), array<contents>(0, NIL, _flags));
00193 bounds_return(end, 0, this->last(), array<contents>(0, NIL, _flags));
00194 if (start > end) return array<contents>(0, NIL, _flags);
00195 return array<contents>(end - start + 1, &(this->observe()[start]), _flags);
00196 }
00197
00198 template <class contents>
00199 void array<contents>::swap_contents(array &other)
00200 {
00201 if (this == &other) return;
00202 swap_values(this->_active_length, other._active_length);
00203 swap_values(this->_real_length, other._real_length);
00204 swap_values(this->_offset, other._offset);
00205 swap_values(this->_mem_block, other._mem_block);
00206 swap_values(this->_flags, other._flags);
00207 }
00208
00209 template <class contents>
00210 outcome array<contents>::shrink()
00211 {
00212 if (!_mem_block) return common::OUT_OF_MEMORY;
00213 if (_active_length == _real_length) return common::OKAY;
00214 array new_holder(*this);
00215
00216 swap_contents(new_holder);
00217
00218
00219 return common::OKAY;
00220 }
00221
00222 template <class contents>
00223 outcome array<contents>::stuff(int lengthx, contents *to_stuff) const
00224 {
00225 if (!lengthx || !this->length()) return common::OKAY;
00226 int copy_len = minimum(lengthx, this->length());
00227 if (!this->simple()) {
00228 for (int i = 0; i < copy_len; i++)
00229 to_stuff[i] = this->observe()[i];
00230 } else {
00231 memcpy(to_stuff, this->observe(), copy_len * sizeof(contents));
00232 }
00233 return common::OKAY;
00234 }
00235
00236 template <class contents>
00237 outcome array<contents>::overwrite(int position,
00238 const array<contents> &write_with, int count)
00239 {
00240 FUNCDEF("overwrite");
00241 if (!count) return common::OKAY;
00242 if ( (this == &write_with) || !this->length() || !write_with.length())
00243 return common::BAD_INPUT;
00244 bounds_halt(position, 0, this->last(), common::OUT_OF_RANGE);
00245 if ( negative(count) || (count > write_with.length()) )
00246 count = write_with.length();
00247 if (position > this->length() - count)
00248 count = this->length() - position;
00249 if (!this->simple()) {
00250 for (int i = position; i < position + count; i++)
00251 this->access()[i] = write_with.observe()[i - position];
00252 } else {
00253 memcpy(&(this->access()[position]), write_with.observe(),
00254 count * sizeof(contents));
00255 }
00256 return common::OKAY;
00257 }
00258
00259 template <class contents>
00260 outcome array<contents>::allocator_reset(int initial, int blocking)
00261 {
00262 FUNCDEF("reset");
00263 if (blocking < 1) {
00264 #ifdef DEBUG_ARRAY
00265 continuable_error(static_class_name(), func, "bad block size");
00266 #endif
00267 blocking = 1;
00268 }
00269 if (initial < 0) initial = 0;
00270 if (_mem_block) {
00271
00272 delete [] _mem_block;
00273 _mem_block = NIL;
00274 _offset = NIL;
00275 }
00276 _active_length = initial;
00277 _real_length = initial + blocking;
00278 if (_real_length) {
00279 try {
00280 _mem_block = new contents[_real_length];
00281 if (!_mem_block) {
00282 out_of_memory_now(static_class_name(), func);
00283 return common::OUT_OF_MEMORY;
00284 }
00285 } catch (...) {
00286 _mem_block = NIL;
00287 out_of_memory_now(static_class_name(), func);
00288
00289 return common::OUT_OF_MEMORY;
00290 }
00291 _offset = _mem_block;
00292 }
00293 return common::OKAY;
00294 }
00295
00296 template <class contents>
00297 void array<contents>::shift_data(shift_directions where)
00298 {
00299 if (where == TO_LEFT) {
00300
00301
00302 if (_offset == _mem_block)
00303 return;
00304
00305 if (simple()) {
00306 memmove(_mem_block, _offset, _active_length * sizeof(contents));
00307 } else {
00308 for (contents *ptr = _offset; ptr < _offset + _active_length; ptr++)
00309 _mem_block[ptr - _offset] = *ptr;
00310 }
00311 _offset = _mem_block;
00312 if (_flags & FLUSH_INVISIBLE) {
00313
00314
00315
00316 }
00317 } else {
00318
00319
00320 if (_offset == _mem_block + _real_length - _active_length)
00321 return;
00322 if (simple()) {
00323 memmove(&_mem_block[_real_length - _active_length], _offset, _active_length * sizeof(contents));
00324 } else {
00325 for (int i = _real_length - 1; i >= _real_length - _active_length; i--)
00326 _mem_block[i] = _offset[i - _real_length + _active_length];
00327 }
00328 _offset = _mem_block + _real_length - _active_length;
00329 if (_flags & FLUSH_INVISIBLE) {
00330
00331
00332
00333 }
00334 }
00335 }
00336
00337 template <class contents>
00338 outcome array<contents>::resize(int new_size, common::how_to_copy way)
00339 {
00340 FUNCDEF("resize");
00341 if (new_size < 0) new_size = 0;
00342 if (new_size == _active_length) {
00343
00344 return common::OKAY;
00345 }
00346
00347
00348 contents *old_s = _mem_block;
00349 const int old_len = _active_length;
00350 contents *old_off = _offset;
00351 bool delete_old = false;
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362 if (_real_length - (old_off - old_s) < new_size) {
00363
00364 if (_real_length < new_size) {
00365
00366
00367 _mem_block = NIL;
00368 delete_old = true;
00369 int blocking = 1;
00370 if (exponential()) blocking = new_size + 1;
00371 outcome ret = allocator_reset(new_size, blocking);
00372 if (ret != common::OKAY) {
00373
00374 #ifdef DEBUG_ARRAY
00375 deadly_error(static_class_name(), "resize", "reset failure");
00376 #endif
00377 delete [] old_s;
00378 return ret;
00379 }
00380
00381 } else {
00382
00383 const int size_difference = new_size - _active_length;
00384
00385
00386 if (way == common::DONT_COPY) {
00387
00388
00389 _offset = _mem_block;
00390 _active_length = new_size;
00391 } else if (way == common::NEW_AT_BEGINNING) {
00392
00393
00394
00395 if (_offset - _mem_block < size_difference) {
00396
00397
00398 shift_data(TO_RIGHT);
00399 }
00400
00401
00402
00403 _offset -= size_difference;
00404 _active_length = new_size;
00405 } else {
00406
00407
00408
00409
00410
00411
00412
00413 shift_data(TO_LEFT);
00414 _active_length = new_size;
00415 }
00416
00417
00418
00419
00420
00421 return common::OKAY;
00422 }
00423 }
00424
00425
00426
00427 _active_length = new_size;
00428 if (way != common::DONT_COPY) {
00429 int where = 0;
00430 bool do_copy = false;
00431 contents *loop_offset_old = old_off;
00432
00433
00434
00435
00436
00437 if (way == common::NEW_AT_BEGINNING) {
00438 where = new_size - old_len;
00439 if (where) do_copy = true;
00440 if (where < 0) {
00441
00442
00443
00444 loop_offset_old -= where;
00445 where = 0;
00446 }
00447 }
00448 const int size_now = minimum(old_len, _active_length);
00449 if (delete_old || do_copy) {
00450 contents *offset_in_new = _offset + where;
00451 contents *posn_in_old = loop_offset_old;
00452 if (simple()) {
00453
00454 memmove(offset_in_new, posn_in_old, size_now * sizeof(contents));
00455 } else {
00456
00457 if (new_size >= old_len) {
00458 for (int i = size_now - 1; i >= 0; i--)
00459 offset_in_new[i] = posn_in_old[i];
00460 } else {
00461 for (int i = 0; i < size_now; i++)
00462 offset_in_new[i] = posn_in_old[i];
00463 }
00464 }
00465
00466
00467
00468 if ( (_flags & FLUSH_INVISIBLE) && !delete_old) {
00469
00470
00471
00472 if (new_size < old_len) {
00473
00474
00475 }
00476 }
00477 }
00478 }
00479 if (delete_old) delete [] old_s;
00480 return common::OKAY;
00481 }
00482
00483 template <class contents>
00484 outcome array<contents>::retrain(int new_len, const contents *to_set)
00485 {
00486 FUNCDEF("retrain");
00487 if (new_len < 0) new_len = 0;
00488 #ifdef DEBUG_ARRAY
00489 if ( (_mem_block >= to_set) && (_mem_block < to_set + new_len) )
00490 deadly_error(static_class_name(), func, "ranges overlap in retrain!");
00491 #endif
00492 outcome ret = resize(new_len, common::DONT_COPY);
00493 if (ret != common::OKAY) return ret;
00494 #ifdef DEBUG_ARRAY
00495 if (new_len != _active_length)
00496 continuable_error(static_class_name(), func, "resize set the wrong length");
00497 #endif
00498 if (to_set) {
00499 if (simple())
00500 memcpy(_offset, to_set, _active_length * sizeof(contents));
00501 else
00502 for (int i = 0; i < _active_length; i++)
00503 _offset[i] = to_set[i];
00504 } else {
00505 if (_flags & FLUSH_INVISIBLE) {
00506
00507
00508 }
00509 }
00510 if (_flags & FLUSH_INVISIBLE) {
00511
00512
00513
00514
00515 }
00516 return common::OKAY;
00517 }
00518
00519 template <class contents>
00520 outcome array<contents>::zap(int position1, int position2)
00521 {
00522 if (position1 > position2) return common::OKAY;
00523 bounds_return(position1, 0, _active_length - 1, common::OUT_OF_RANGE);
00524 bounds_return(position2, 0, _active_length - 1, common::OUT_OF_RANGE);
00525 if (!position1) {
00526
00527 _offset += position2 + 1;
00528 _active_length -= position2 + 1;
00529 return common::OKAY;
00530 }
00531 const int difference = position2 - position1 + 1;
00532
00533 if (simple()) {
00534 if (_active_length - difference - position1 > 0)
00535 memmove(&_offset[position1], &_offset[position1 + difference],
00536 (_active_length - difference - position1) * sizeof(contents));
00537 } else {
00538 for (int i = position1; i < _active_length - difference; i++)
00539 _offset[i] = _offset[i + difference];
00540 }
00541
00542 outcome ret = resize(_active_length - difference, common::NEW_AT_END);
00543
00544 #ifdef DEBUG_ARRAY
00545 if (ret != common::OKAY) {
00546 deadly_error(static_class_name(), "zap", "resize failure");
00547 return ret;
00548 }
00549 #endif
00550 return ret;
00551 }
00552
00553 template <class contents>
00554 outcome array<contents>::insert(int position, int elem_to_add)
00555 {
00556 if (position < 0) return common::OUT_OF_RANGE;
00557 if (position > this->length())
00558 position = this->length();
00559 if (elem_to_add < 0) return common::OUT_OF_RANGE;
00560 common::how_to_copy how = common::NEW_AT_END;
00561 if (position == 0) how = common::NEW_AT_BEGINNING;
00562 resize(this->length() + elem_to_add, how);
00563
00564
00565
00566 if (how == common::NEW_AT_END) {
00567 const contents simple_default_object = contents();
00568 if (!this->simple()) {
00569 for (int i = this->last(); i >= position + elem_to_add; i--)
00570 this->access()[i] = this->observe()[i - elem_to_add];
00571 for (int j = position; j < position + elem_to_add; j++)
00572 this->access()[j] = simple_default_object;
00573 } else {
00574 memmove(&(this->access()[position + elem_to_add]),
00575 &(this->observe()[position]), (this->length() - position
00576 - elem_to_add) * sizeof(contents));
00577 for (int j = position; j < position + elem_to_add; j++)
00578 memcpy(&this->access()[j], &simple_default_object, sizeof(contents));
00579 }
00580 }
00581 return common::OKAY;
00582 }
00583
00584 template <class contents>
00585 outcome array<contents>::put(int index, const contents &to_put)
00586 {
00587 FUNCDEF("put");
00588 bounds_halt(index, 0, this->last(), common::OUT_OF_RANGE);
00589 if (!this->simple())
00590 this->access()[index] = to_put;
00591 else
00592 memcpy(&(this->access()[index]), &to_put, sizeof(contents));
00593 return common::OKAY;
00594 }
00595
00596 template <class contents>
00597 void array<contents>::snarf(array<contents> &new_contents)
00598 {
00599 if (this == &new_contents) return;
00600 reset();
00601 swap_contents(new_contents);
00602 }
00603
00604 #undef static_class_name
00605
00606 #endif
00607