#ifndef ARRAY_H #define ARRAY_H #include #include namespace ecci { /** Implements a dynamic array container Stores copies of objects in sequential memory. Provides random access to any element by using an index (ToDo: and iterators). */ template class Array { public: /// Any new array created with default constructor will have memory for allocating /// @a initialCapacity elements static const size_t initialCapacity = 10; /// When there is not more room for store an element, the array must increase its capacity /// The new array will have memory for (@a increaseFactor * old_capacity) elements static const size_t increaseFactor = 2; /// Indicates a not valid index static const size_t npos = (size_t)-1; protected: /// Pointer to the first element of the actual array in dynamic memory DataType* data = nullptr; /// Indicates there is room for store @a capacity elements without creating a new vector size_t capacity = initialCapacity; /// The number of actual elements added to the array size_t count = 0; public: /// Default constructor explicit Array(size_t capacity = initialCapacity) : data( new DataType[capacity] ) , capacity(capacity) , count(0) { } /// Copy constructor Array(const Array& other) : data( new DataType[other.capacity] ) , capacity(other.capacity) , count(other.count) { for (size_t i = 0; i < count; ++i ) data[i] = other.data[i]; } /// Move constructor Array(Array&& temp) : data(temp.data) , capacity(capacity) , count(temp.count) { temp.data = nullptr; temp.count = temp.capacity = 0; } /// Copy assignment operator const Array& operator=(const Array& other) { if ( this != &other ) { if ( this->capacity != other.capacity ) { delete [] this->data; this->data = new DataType[other.capacity]; this->capacity = other.capacity; } for (size_t i = 0; i < other.count; ++i ) data[i] = other.data[i]; this->count = other.count; } return *this; } /// Move assignment operator const Array& operator=(Array&& temp) { if ( this != &temp ) { delete [] this->data; this->data = temp.data; this->capacity = temp.capacity; this->count = temp.count; temp.data = nullptr; temp.count = temp.capacity = 0; } return *this; } /// Destructor ~Array() { delete [] data; } /// Adds the given element @a value to the array. The array will store a copy of @a value /// @return true if the element was added to the array, false if there is not enough memory bool add(const DataType& value); /// Returns the number of elements currently stored in the array inline size_t getCount() const { return count; } /// ToDo: document inline const DataType& operator[](size_t i) const { return data[i]; } /// ToDo: document inline DataType& operator[](size_t i) { return data[i]; } /// size_t find(const DataType& elem, size_t start = 0) { for (size_t i = start; i < count; ++i) if ( data[i] == elem ) return i; return npos; } /// Inserts the given element at the given position /// @return true if the element was inserted, false if there is not available memory or the /// index @a i is not valid bool insert(size_t pos, const DataType& value); /// Returns true if this array has exactly the same elements than @a other in the same order bool operator==(const Array& other) const { if ( count != other.count ) return false; if ( this == &other ) return true; for (size_t i = 0; i < count; ++i ) if ( !(data[i] == other.data[i]) ) return false; return true; } /// Prints this array in format [e1, e2, e3, ..., eN] std::ostream& print(std::ostream& out, const char* separator = ", ") const { out << '['; for ( size_t i = 0; i < count; ++i ) { out << data[i]; if ( i < count - 1) out << separator; } return out << ']'; } protected: /// Increases the current capacity of the array /// This method is called each time an element is being added and there is no enough room for /// it. The old array is deleted and replaced for a new one of more capacity, exactly /// new_capacity := old_capacity * increaseFactor. Elements in old array are copied to the new /// one. @a capacity class member is updated /// @return true if capacity was increased, false if there is not enough memory (in that case /// old array remain untouched) bool increaseCapacity(); }; template bool Array::add(const DataType &value) { // If there is not room for the new value, increase the capacity if ( count == capacity ) if ( ! increaseCapacity() ) return false; // Copy the given value in the next available element and increase the counter of elements data[count++] = value; return true; } template bool Array::increaseCapacity() { // Create a bigger array with more capacity size_t newCapacity = increaseFactor * capacity; DataType* newData = new DataType[newCapacity]; if ( newData == nullptr ) return false; // Copy old elements to new elements for (size_t i = 0; i < count; ++i ) newData[i] = data[i]; // objects must override operator= // Replace old array with new one delete [] data; data = newData; capacity = newCapacity; return true; } template bool Array::insert(size_t pos, const DataType& value) { // Only valid position i is allowed if ( pos >= count ) return false; // If there is not room for the new value, increase the capacity if ( count == capacity ) if ( ! increaseCapacity() ) return false; // Shift old values one position right for (size_t i = count; i > pos; --i) data[i] = data[i - 1]; // Insert the element at the given position data[pos] = value; ++count; return true; } } // namespace ecci template inline ecci::Array& operator<<(ecci::Array& arr, const DataType& value) { arr.add(value); return arr; } template inline std::ostream& operator<<(std::ostream& out, const ecci::Array& arr) { return arr.print(out); } #endif // ARRAY_H