00001 #ifndef ARRAY_CLASS
00002 #define ARRAY_CLASS
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
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> ©_from);
00097
00098 virtual ~array();
00099
00100 void reset(int number = 0, const contents *initial_contents = NIL);
00102
00103
00104
00105
00106
00107
00108
00109
00110 array &operator = (const array<contents> ©_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
00243
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;
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
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
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
00322 }
00323
00324 allocator_reset(num, 1);
00325 retrain(num, init);
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);
00333 operator = (cf);
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;
00355
00356 c_offset = c_mem_block;
00357 c_active_length = 0;
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
00380 if (!s1.length()) return *this;
00381 if (this == &s1) {
00382
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;
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
00422 array<contents> to_return(this->length() + s1.length(), NIL, s1.c_flags);
00423 to_return.overwrite(0, *this);
00424 to_return.overwrite(this->length(), s1);
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;
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;
00465 array new_holder(*this);
00466
00467 swap_contents(new_holder);
00468
00469
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
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;
00520 if (c_mem_block) {
00521
00522 delete [] c_mem_block;
00523 c_mem_block = NIL;
00524 c_offset = NIL;
00525 }
00526 c_active_length = initial;
00527 c_real_length = initial + blocking;
00528 if (c_real_length) {
00529 c_mem_block = new contents[c_real_length];
00530 if (!c_mem_block) {
00531
00532
00533
00534 throw common::OUT_OF_MEMORY;
00535 }
00536 c_offset = c_mem_block;
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
00546
00547 if (c_offset == c_mem_block)
00548 return;
00549
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;
00557 if (c_flags & FLUSH_INVISIBLE) {
00558
00559
00560
00561 }
00562 } else {
00563
00564
00565 if (c_offset == c_mem_block + c_real_length - c_active_length)
00566 return;
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;
00574 if (c_flags & FLUSH_INVISIBLE) {
00575
00576
00577
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;
00587 if (new_size == c_active_length) {
00588
00589 return common::OKAY;
00590 }
00591
00592
00593 contents *old_s = c_mem_block;
00594 const int old_len = c_active_length;
00595 contents *old_off = c_offset;
00596 bool delete_old = false;
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607 if (c_real_length - (old_off - old_s) < new_size) {
00608
00609 if (c_real_length < new_size) {
00610
00611
00612 c_mem_block = NIL;
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
00619 #ifdef DEBUG_ARRAY
00620 throw "error: array::resize: saw array reset failure";
00621 #endif
00622 delete [] old_s;
00623 return ret;
00624 }
00625
00626 } else {
00627
00628 const int size_difference = new_size - c_active_length;
00629
00630
00631 if (way == DONT_COPY) {
00632
00633
00634 c_offset = c_mem_block;
00635 c_active_length = new_size;
00636 } else if (way == NEW_AT_BEGINNING) {
00637
00638
00639
00640 if (c_offset - c_mem_block < size_difference) {
00641
00642
00643 shift_data(TO_RIGHT);
00644 }
00645
00646
00647
00648 c_offset -= size_difference;
00649 c_active_length = new_size;
00650 } else {
00651
00652
00653
00654
00655
00656
00657
00658 shift_data(TO_LEFT);
00659 c_active_length = new_size;
00660 }
00661
00662
00663
00664
00665
00666 return common::OKAY;
00667 }
00668 }
00669
00670
00671
00672 c_active_length = new_size;
00673 if (way != DONT_COPY) {
00674 int where = 0;
00675 bool do_copy = false;
00676 contents *loopc_offset_old = old_off;
00677
00678
00679
00680
00681
00682 if (way == NEW_AT_BEGINNING) {
00683 where = new_size - old_len;
00684 if (where) do_copy = true;
00685 if (where < 0) {
00686
00687
00688
00689 loopc_offset_old -= where;
00690 where = 0;
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
00699 memmove(offset_in_new, posn_in_old, size_now * sizeof(contents));
00700 } else {
00701
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
00712
00713 if ( (c_flags & FLUSH_INVISIBLE) && !delete_old) {
00714
00715
00716
00717 if (new_size < old_len) {
00718
00719
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;
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
00754
00755 }
00756 }
00757 if (c_flags & FLUSH_INVISIBLE) {
00758
00759
00760
00761
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
00774 c_offset += position2 + 1;
00775 c_active_length -= position2 + 1;
00776 return common::OKAY;
00777 }
00778 const int difference = position2 - position1 + 1;
00779
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
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
00812
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;
00846 reset();
00847 swap_contents(new_contents);
00848 }
00849
00850
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866 }
00867
00868 #undef static_class_name
00869
00870 #endif
00871