52 template <
class contents>
53 class array :
public virtual root_object
115 int length()
const {
return c_active_length; }
118 int last()
const {
return c_active_length - 1; }
121 int flags()
const {
return c_flags; }
130 const contents &
get(
int index)
const;
172 const contents *
observe()
const {
return c_offset; }
176 contents *
access() {
return c_offset; }
260 contents *c_mem_block;
264 outcome allocator_reset(
int initial_elements,
int blocking);
277 int_array(
int number = 0,
const int *initial_contents = 0)
314 template <
class contents>
316 : root_object(), c_active_length(0), c_real_length(0), c_mem_block(
NULL_POINTER), c_offset(
NULL_POINTER), c_flags(flags)
320 throw "error: array::constructor: error in parameters! still passing a block size?";
326 allocator_reset(
num, 1);
330 template <
class contents>
332 : root_object(), c_active_length(0), c_real_length(0), c_mem_block(
NULL_POINTER), c_offset(
NULL_POINTER), c_flags(cf.c_flags)
334 allocator_reset(cf.c_active_length, 1);
338 template <
class contents>
342 if (c_mem_block)
delete [] c_mem_block;
348 template <
class contents>
350 { retrain(
num, init); }
352 template <
class contents>
355 if (
this == &cf)
return *
this;
356 c_flags = cf.c_flags;
358 c_offset = c_mem_block;
360 retrain(cf.c_active_length, cf.
observe());
364 template <
class contents>
368 return this->
access()[index];
371 template <
class contents>
375 return this->observe()[index];
378 template <
class contents>
382 if (!s1.
length())
return *
this;
387 int old_len = this->length();
388 resize(this->length() + s1.
length(), NEW_AT_END);
389 overwrite(old_len, s1);
393 template <
class contents>
396 resize(this->length() + 1, NEW_AT_END);
398 this->
access()[this->last()] = to_concatenate;
400 memcpy(&(this->
access()[this->last()]), &to_concatenate,
sizeof(contents));
404 template <
class contents>
408 if (!length)
return *
this;
409 const int old_len = this->length();
410 resize(this->length() + length, NEW_AT_END);
412 for (
int i = 0; i < length; i++)
413 this->
access()[old_len + i] = to_concatenate[i];
415 memcpy(&(this->
access()[old_len]), to_concatenate,
416 length *
sizeof(contents));
420 template <
class contents>
430 template <
class contents>
438 memcpy(&(to_return.
access()[to_return.
last()]), &s1,
sizeof(contents));
442 template <
class contents>
448 return array<contents>(end - start + 1, &(this->observe()[start]), c_flags);
451 template <
class contents>
454 if (
this == &other)
return;
455 swap_values(this->c_active_length, other.c_active_length);
456 swap_values(this->c_real_length, other.c_real_length);
462 template <
class contents>
465 if (!c_mem_block)
return common::OUT_OF_MEMORY;
466 if (c_active_length == c_real_length)
return common::OKAY;
467 array new_holder(*
this);
469 swap_contents(new_holder);
475 template <
class contents>
478 if (!lengthx || !this->length())
return common::OKAY;
479 int copy_len =
minimum(lengthx, this->length());
480 if (!this->simple()) {
481 for (
int i = 0; i < copy_len; i++)
482 to_stuff[i] = this->observe()[i];
484 memcpy(to_stuff, this->observe(), copy_len *
sizeof(contents));
489 template <
class contents>
493 if (!count)
return common::OKAY;
494 if ( (
this == &write_with) || !this->length() || !write_with.
length())
495 return common::BAD_INPUT;
496 bounds_return(position, 0, this->last(), common::OUT_OF_RANGE);
498 count = write_with.
length();
499 if (position > this->length() - count)
500 count = this->length() - position;
501 if (!this->simple()) {
502 for (
int i = position; i < position + count; i++)
506 count *
sizeof(contents));
511 template <
class contents>
517 throw "error: array::allocator_reset: has bad block size";
521 if (initial < 0) initial = 0;
524 delete [] c_mem_block;
528 c_active_length = initial;
529 c_real_length = initial + blocking;
531 c_mem_block =
new contents[c_real_length];
536 throw common::OUT_OF_MEMORY;
538 c_offset = c_mem_block;
543 template <
class contents>
546 if (where == TO_LEFT) {
549 if (c_offset == c_mem_block)
553 memmove(c_mem_block, c_offset, c_active_length *
sizeof(contents));
555 for (contents *ptr = c_offset; ptr < c_offset + c_active_length; ptr++)
556 c_mem_block[ptr - c_offset] = *ptr;
558 c_offset = c_mem_block;
559 if (c_flags & FLUSH_INVISIBLE) {
567 if (c_offset == c_mem_block + c_real_length - c_active_length)
570 memmove(&c_mem_block[c_real_length - c_active_length], c_offset, c_active_length *
sizeof(contents));
572 for (
int i = c_real_length - 1; i >= c_real_length - c_active_length; i--)
573 c_mem_block[i] = c_offset[i - c_real_length + c_active_length];
575 c_offset = c_mem_block + c_real_length - c_active_length;
576 if (c_flags & FLUSH_INVISIBLE) {
584 template <
class contents>
588 if (new_size < 0) new_size = 0;
589 if (new_size == c_active_length) {
595 contents *old_s = c_mem_block;
596 const int old_len = c_active_length;
597 contents *old_off = c_offset;
598 bool delete_old =
false;
609 if (c_real_length - (old_off - old_s) < new_size) {
611 if (c_real_length < new_size) {
617 if (exponential()) blocking = new_size + 1;
618 outcome ret = allocator_reset(new_size, blocking);
619 if (ret != common::OKAY) {
622 throw "error: array::resize: saw array reset failure";
630 const int size_difference = new_size - c_active_length;
633 if (way == DONT_COPY) {
636 c_offset = c_mem_block;
637 c_active_length = new_size;
638 }
else if (way == NEW_AT_BEGINNING) {
642 if (c_offset - c_mem_block < size_difference) {
645 shift_data(TO_RIGHT);
650 c_offset -= size_difference;
651 c_active_length = new_size;
661 c_active_length = new_size;
674 c_active_length = new_size;
675 if (way != DONT_COPY) {
677 bool do_copy =
false;
678 contents *loopc_offset_old = old_off;
684 if (way == NEW_AT_BEGINNING) {
685 where = new_size - old_len;
686 if (where) do_copy =
true;
691 loopc_offset_old -= where;
695 const int size_now =
minimum(old_len, c_active_length);
696 if (delete_old || do_copy) {
697 contents *offset_in_new = c_offset + where;
698 contents *posn_in_old = loopc_offset_old;
701 memmove(offset_in_new, posn_in_old, size_now *
sizeof(contents));
704 if (new_size >= old_len) {
705 for (
int i = size_now - 1; i >= 0; i--)
706 offset_in_new[i] = posn_in_old[i];
708 for (
int i = 0; i < size_now; i++)
709 offset_in_new[i] = posn_in_old[i];
715 if ( (c_flags & FLUSH_INVISIBLE) && !delete_old) {
719 if (new_size < old_len) {
726 if (delete_old)
delete [] old_s;
730 template <
class contents>
734 if (new_len < 0) new_len = 0;
736 if (to_set && (c_mem_block >= to_set) && (c_mem_block < to_set + new_len) ) {
737 throw "error: array::retrain: ranges overlap in retrain!";
740 outcome ret = resize(new_len, DONT_COPY);
741 if (ret != common::OKAY)
return ret;
743 if (new_len != c_active_length) {
744 throw "error: array resize set the wrong length";
749 memcpy(c_offset, to_set, c_active_length *
sizeof(contents));
751 for (
int i = 0; i < c_active_length; i++)
752 c_offset[i] = to_set[i];
754 if (c_flags & FLUSH_INVISIBLE) {
759 if (c_flags & FLUSH_INVISIBLE) {
768 template <
class contents>
771 if (position1 > position2)
return common::OKAY;
772 bounds_return(position1, 0, c_active_length - 1, common::OUT_OF_RANGE);
773 bounds_return(position2, 0, c_active_length - 1, common::OUT_OF_RANGE);
776 c_offset += position2 + 1;
777 c_active_length -= position2 + 1;
780 const int difference = position2 - position1 + 1;
783 if (c_active_length - difference - position1 > 0)
784 memmove(&c_offset[position1], &c_offset[position1 + difference],
785 (c_active_length - difference - position1) *
sizeof(contents));
787 for (
int i = position1; i < c_active_length - difference; i++)
788 c_offset[i] = c_offset[i + difference];
791 outcome ret = resize(c_active_length - difference, NEW_AT_END);
794 if (ret != common::OKAY) {
795 throw "error: array::zap: resize failure";
802 template <
class contents>
805 if (position < 0)
return common::OUT_OF_RANGE;
806 if (position > this->length())
807 position = this->length();
808 if (elem_to_add < 0)
return common::OUT_OF_RANGE;
810 if (position == 0) how = NEW_AT_BEGINNING;
811 resize(this->length() + elem_to_add, how);
815 if (how == NEW_AT_END) {
816 const contents simple_default_object = contents();
817 if (!this->simple()) {
818 for (
int i = this->last(); i >= position + elem_to_add; i--)
819 this->
access()[i] = this->observe()[i - elem_to_add];
820 for (
int j = position; j < position + elem_to_add; j++)
821 this->
access()[j] = simple_default_object;
823 memmove(&(this->
access()[position + elem_to_add]),
824 &(this->observe()[position]), (this->length() - position
825 - elem_to_add) *
sizeof(contents));
826 for (
int j = position; j < position + elem_to_add; j++)
827 memcpy(&this->
access()[j], &simple_default_object,
sizeof(contents));
833 template <
class contents>
838 this->
access()[index] = to_put;
840 memcpy(&(this->
access()[index]), &to_put,
sizeof(contents));
844 template <
class contents>
847 if (
this == &new_contents)
return;
849 swap_contents(new_contents);
870 #undef static_class_name
Represents a sequential, ordered, contiguous collection of objects.
specialc_flags
the flags specify how the array treats its contents and its length.
@ EXPONE
synonym for EXPONENTIAL_GROWTH.
@ SIMPLE_COPY
the contents can be memcpy'd and are not deep.
@ EXPONENTIAL_GROWTH
length is doubled when reallocation happens.
@ FLUSH_INVISIBLE
blanks out allocated but inaccessible elements.
@ NO_SPECIAL_MODES
do nothing extra; only valid by itself.
int flags() const
Provides the raw flags value, without interpreting what it means.
outcome put(int index, const contents &to_put)
Stores an object at the index "index" in the array.
outcome insert(int index, int new_indices)
Adds "new_indices" new positions for objects into the array at "index".
void reset(int number=0, const contents *initial_contents=NULL_POINTER)
Resizes this array and sets the contents from an array of contents.
outcome shrink()
Cuts loose any allocated space that is beyond the real length.
const contents * observe() const
Returns a pointer to the underlying C array of data.
virtual ~array()
destroys the memory allocated for the objects.
outcome overwrite(int index, const array &write_with, int count=-1)
Stores the array "write_with" into the current array at the "index".
array & concatenate(const array &to_concatenate)
Appends the array "to_concatenate" onto "this" and returns "this".
array subarray(int start, int end) const
Returns the array segment between the indices "start" and "end".
const contents & get(int index) const
Accesses individual objects stored in "this" at the "index" position.
const contents & operator[](int index) const
Synonym for get that provides the expected array indexing syntax.
const contents * internal_block_start() const
Gritty Internal: constant peek at the real allocated pointer.
array operator+(const array &to_cat) const
Synonym for concatenation.
array & concatenate(const contents *to_concatenate, int length)
Concatenates a C-array "to_concatenate" onto "this" and returns "this".
contents * access()
A non-constant access of the underlying C-array. BE REALLY CAREFUL.
contents *const * internal_offset_mem() const
Gritty Internal: the start of the actual stored data.
array concatenation(const contents &to_concatenate) const
Returns the concatenation of "this" and the object "to_concatenate".
array concatenation(const array &to_concatenate) const
Returns the concatenation of "this" and the array "to_concatenate".
array & operator+=(const array &to_concatenate)
Synonym for concatenate that modifies "this".
outcome retrain(int new_size, const contents *to_copy)
Resizes the C array and stuffs it with the contents in "to_copy".
bool simple() const
Reports whether the templated object is a simple type or not.
outcome resize(int new_size, how_to_copy way=NEW_AT_END)
Changes the size of the C array to "new_size".
int length() const
Returns the current reported length of the allocated C array.
outcome zap(int start, int end)
Deletes from "this" the objects inclusively between "start" and "end".
void swap_contents(array< contents > &other)
Exchanges the contents of "this" and "other".
outcome stuff(int length, contents *to_stuff) const
Copies at most "length" elements from this into the array "to_stuff".
array & concatenate(const contents &to_concatenate)
Appends the object "to_concatenate" onto "this" and returns "this".
array(const array< contents > ©_from)
copies the contents & sizing information from "copy_from".
DEFINE_CLASS_NAME("array")
bool exponential() const
Returns true if this allocator will grow exponentially on resize.
int internal_real_length() const
Gritty Internal: the real allocated length.
contents & use(int index)
A non-constant version of get(); the returned object can be modified.
void shift_data(shift_directions where)
The valid portion of the array is moved to the left or right.
int internal_offset() const
Gritty Internal: the offset from real start to stored data.
array & operator=(const array< contents > ©_from)
Copies the array in "copy_from" into this.
array(int number=0, const contents *init=NULL_POINTER, int flags=EXPONENTIAL_GROWTH|FLUSH_INVISIBLE)
Constructs an array with room for "number" objects.
int last() const
Returns the last valid element in the array.
void snarf(array &new_contents)
Drops "this" array's contents into the dustbin and uses "new_contents".
An array of double floating point numbers.
double_array(int len=0, double *data=NULL_POINTER)
double_array(const array< double > &to_copy)
A simple object that wraps a templated array of ints.
int_array(int number=0, const int *initial_contents=0)
Constructs an array of "number" integers.
Outcomes describe the state of completion for an operation.
Constants and objects used throughout HOOPLE.
#define NULL_POINTER
The value representing a pointer to nothing.
#define bounds_return(value, low, high, to_return)
Verifies that "value" is between "low" and "high", inclusive.
The guards collection helps in testing preconditions and reporting errors.
void swap_values(type &a, type &b)
Exchanges the values held by "a" & "b".
type minimum(type a, type b)
maximum returns the greater of two values.
bool negative(const type &a)
negative returns true if "a" is less than zero.