#ifndef _ARRAY_H #define _ARRAY_H // growable array // public interface: /* // constructor without default Array(); // constructor with default for newly allocated elements Array(const VALUE& def); // copy constructor Array(const Array& a); // assignment operator Array operator=(const Array& a); // 1+largest index referenced so far int size(); // has i'th element been accessed? bool exists(int i); // make i'th element not exist void remove(int i); // return a reference to the i'th elt // grow the table if necessary VALUE & operator[](int i); // use only when exists(i) VALUE operator[](int i); // reset table to empty state void clear(); // set the default_init value void set_default(const VALUE& v); // don't use any default_init void clear_default(); // "adopt" a VALUE* // the item is placed in this[i] // (responsibility for deleting the object is now ours) void adopt(int i, VALUE* v); // "orphan" an item // the item is removed from this // (responsibility for deleting the object is no longer ours) VALUE* orphan(int i); */ #include #include #include "test_utilities.h" template class Array { typedef VALUE *PTR; typedef VALUE const *CPTR; PTR *table; // NULL or pointer to new PTR[table_size] int max_referenced; // largest index in table referenced so far int table_size; PTR default_init; // NULL or pointer to default value for new cells // free old table, allocate new one of given size void reset_table(const int size = 0) { if (table) { for (int i = 0; i < table_size; ++i) if (table[i]) delete table[i]; delete[] table; table = NULL; } max_referenced = -1; table_size = size; if (table_size > 0) { table = new PTR[table_size]; for (int i = 0; i < table_size; ++i) table[i] = NULL; } } void reset_value(PTR & p, const CPTR v = NULL) { if (p) delete p; if (v) p = new VALUE(*v); else p = NULL; } void copy_table(const Array& a) { reset_table(a.table_size); max_referenced = a.max_referenced; if (table_size > 0) for (int i = 0; i < table_size; ++i) reset_value(table[i], a.table[i]); } void copy(const Array& a) { // copy a into this array if (&a == this) return; copy_table(a); reset_value(default_init, a.default_init); max_referenced = a.max_referenced; } void construct() { table = NULL; default_init = NULL; table_size = 0; max_referenced = -1; } void grow() { // replace the table with one twice as large // and copy the old contents into the new table int new_size = table_size ? 2*table_size : 4; PTR *new_table = new PTR[new_size]; int i; for (i = 0; i < table_size; ++i) new_table[i] = table[i]; for ( ; i < new_size; ++i) new_table[i] = NULL; if (table) delete[] table; table = new_table; table_size = new_size; } public: void set_default(const VALUE& v) { reset_value(default_init, &v); } void clear_default() { reset_value(default_init); } void clear() { // reset table to empty state reset_table(); } ~Array() { // destructor clear(); clear_default(); } Array() { // constructor without default construct(); } Array(const VALUE& def) {// with default for newly allocated elements construct(); set_default(def); } Array(const Array& a) { // copy constructor construct(); copy(a); } Array operator=(const Array& a) { // assignment operator copy(a); return *this; } int size() const { // 1+largest index referenced so far return 1+max_referenced; } bool exists(int i) const { return i >= 0 && i < table_size && table[i]; } void remove(int i) { if (exists(i)) reset_value(table[i]); } VALUE & operator[](int i) { // return a reference to the i'th elt // grow the table if necessary if (i < 0) die("Array::operator[] called with negative index"); if (i > max_referenced) max_referenced = i; while (i >= table_size) grow(); if (!table[i]) table[i] = default_init ? new VALUE(*default_init) : new VALUE; return *table[i]; } VALUE operator[](int i) const { // use only when exists(i) if (!exists(i)) die("Array::operator[] const called with non-existent index"); return *table[i]; } void adopt(int i, VALUE* v) { if(i < 0) die("Array::adopt called with negative index"); while (i >= table_size) grow(); if (i > max_referenced) max_referenced = i; reset_value(table[i]); table[i] = v; } VALUE *orphan(int i) { if(exists(i)) { VALUE *v = table[i]; table[i] = NULL; return v; } else return NULL; } }; // print template std::ostream & operator<<(std::ostream & out, const Array & a) { out << "["; for (int i = 0; i < a.size(); ++i) { if (i != 0) out << ", "; if (a.exists(i)) out << a[i]; } out << "]"; return out; } #endif