#include #include #include using namespace std; template // template class from the beginning class dynamic_array { /* storage here */ /* Options: * new [] /delete [] * - calls a constructor and destructor * - No resize feature * mmap * - does it work on Windows? * + Makes it easy to save a data structure to disk * malloc / realloc / free * + Doesn't call a constructor when moving things * + Can reallocate * - Doesn't call a destructor with free! */ T* data; size_t _items = 0; size_t allocated_space; public: dynamic_array(){ data = (T*)malloc(10 * sizeof(T)); allocated_space = 10; } dynamic_array(size_t initial_size){ data = (T*)malloc(initial_size * sizeof(T)); allocated_space = initial_size; } // Runs in O(n) time, not O(1) dynamic_array(const dynamic_array& other){ data = (T*)malloc(other._items * sizeof(T)); // Call a copy constructor if T has one for(int i = 0; i < other._items; i++) data[i] = other.data[i]; _items = other._items; allocated_space = other._items; } void reserve(size_t new_capacity){ if(_items > new_capacity) _items = new_capacity; allocated_space = new_capacity; data = (T*)realloc(data, allocated_space * sizeof(T)); } void trim(){ allocated_space = _items; data = (T*)realloc(data, allocated_space * sizeof(T)); } void push_back(const T& new_item){ /* Do we have enough space? */ if(allocated_space <= _items) { /* We don't have enough space! */ allocated_space *= 2; data = (T*)realloc(data, allocated_space * sizeof(T)); } /* Call a constructor without allocating memory for our new T */ new (&data[_items]) T(new_item); _items++; } inline void operator+=(const T& new_item){ push_back(new_item); } T& operator[](size_t index){ return data[index]; } T pop_back(){ _items--; return data[_items]; } dynamic_array operator+(const dynamic_array& other){ dynamic_array toreturn(_items + other._items); for(int i = 0; i < _items; i++) toreturn.data[i] = data[i]; for(int i = 0; i < other._items; i++) toreturn.data[i + _items] = other.data[i]; toreturn._items = toreturn.allocated_space; return toreturn; } size_t items(){ return _items; } ~dynamic_array(){ /* If we didn't have a destructor, we don't need this loop. It would be O(1) then! */ if(!is_trivially_destructible::value) for(int i = 0; i < _items; i++) data[i].~T(); free(data); } }; int main(){ /* Test routine will go here */ dynamic_array dbarray; dbarray += 3.4; dbarray += 8.6; dbarray += 7.2; dbarray += 9.3; /* For demo of copy constructor */ { dynamic_array backup = dbarray; cout << "backup: " << backup[0] << endl; backup[1] = 10000; } dbarray.reserve(100); for(double newval = 20.1; newval < 49; newval += 1.05) dbarray += newval; dbarray.trim(); for(int i = 0; i < dbarray.items(); i++) cout << dbarray[i] << endl; for(int i = 0; i < 30; i++) dbarray.pop_back(); dbarray.trim(); cout << "After removing 30 items and trimming:\n"; for(int i = 0; i < dbarray.items(); i++) cout << dbarray[i] << endl; dynamic_array other_dbarray; other_dbarray += 100.1; other_dbarray += 100.2; other_dbarray += 100.3; cout << "Combining both arrays\n"; dynamic_array both = dbarray + other_dbarray; for(int i = 0; i < both.items(); i++) cout << both[i] << endl; /* What if we need to call a destructor? */ dynamic_array sarray; sarray += "There was once a shark that liked to eat grapes."; sarray += "It would follow boats, swimmers, and surfers seeking grapes."; sarray += "Nobody could catch it with bait, because they used the wrong type."; for(int i = 0; i < sarray.items(); i++) cout << sarray[i] << endl; return 0; }