#ifndef _ARRAY_H #define _ARRAY_H // growable array // use like this: // // #include "Array.h" // // ... // // Array h(-1); // -1 is the default value for uninitialized elements // Array g; // uninitialized elements of g have no default value // // h[2] = 3; // // for (int i = 0; i < h.size(); ++i) ... // // g = h; // make g a deep copy of h (including the default values) // // h.clear(); // reset h to initial state // // #include #include #include "test_utilities.h" template class Array { VALUE *table; // NULL or pointer to new VALUE[table_size] int max_referenced; // largest index in table referenced so far int table_size; int use_default; // 0 or 1 - 1 iff initialize new cells VALUE default_init; // if use_default = 1, the default init value void copy(const Array& a); // copy a into this array void grow(); // replace the table with one twice as large // and copy the old contents into the new table public: ~Array(); // destructor Array(); // constructor without default, or... Array(const VALUE& def); // with default for newly allocated elements Array(const Array& a) { // copy constructor table = NULL; copy(a); } int size() const; // 1+largest index referenced so far VALUE & operator[](int i); // return a reference to the i'th elt // grow the table if necessary VALUE operator[](int i) const; // use only when i < size void clear(); // reset table to empty state // assignment operator Array operator=(const Array& a) { copy(a); return *this; } }; // print template std::ostream & operator<<(std::ostream & out, const Array & a) { out << "["; for (int i = 0; i < a.size(); ++i) { if (i != 0) out << ", "; out << a[i]; } out << "]"; return out; } // destructor template Array::~Array() { if (table) delete[] table; } // constructor without default template Array::Array() { use_default = 0; table_size = 0; max_referenced = -1; table = NULL; } // constructor with default template Array::Array(const VALUE& def) { use_default = 1; default_init = def; table_size = 0; max_referenced = -1; table = NULL; } // copy constructor -- defined in Array.h // clear template void Array::clear() { if (table) { delete[] table; table_size = 0; max_referenced = -1; table = NULL; } } // copy function template void Array::copy(const Array & a) { if (&a == this) return; clear(); use_default = a.use_default; default_init = a.default_init; max_referenced = a.max_referenced; table_size = a.table_size; if (a.table) { table = new VALUE[table_size]; if (!table) { die("Out of memory"); } for (int i = 0; i < table_size; ++i) table[i] = a.table[i]; } } // grow template void Array::grow() { int new_size = 2 * table_size; if (table == NULL) new_size = 3; VALUE *new_table = new VALUE[new_size]; if (! new_table) { die("Out of memory"); } int i; for (i = 0; i < table_size; ++i) new_table[i] = table[i]; if (use_default) for ( ; i < new_size; ++i) new_table[i] = default_init; if (table) delete[] table; table = new_table; table_size = new_size; } // operator[] template VALUE & Array::operator[](int index) { if (index < 0) die("Negative index"); while (index >= table_size) grow(); if (index > max_referenced) max_referenced = index; return table[index]; } // operator[] const template VALUE Array::operator[](int index) const { if (index > max_referenced) die("Array index out of bounds (index = " << index << ", max_referenced = " << max_referenced << ")"); if (index < 0) die("Negative index"); return table[index]; } // size template int Array::size() const { return max_referenced+1; } #endif