#pragma once #include #include #include template class Vector { public: // Constructor Vector(unsigned int capacity = 10) : capacity(capacity), element_count(0), data(new T[capacity]) { } // Copy Constructor Vector(const Vector &other) : capacity(other.capacity), element_count(other.element_count), data(new T[capacity]) { // `std::copy` is used because it is more flexible than `std::memcpy`, // and the compiler will replace it with `memcpy` anyway if appropriate, // so there is no performance loss. std::copy(other.data, other.data + element_count, data); } // Move Constructor using the copy-and-swap-idiom Vector(Vector &&other) : data(new T[capacity]) { swap(*this, other); } // Copy Assignment Operator using the copy-and-swap-idiom // Since this takes a value rather than a const reference due to // copy-and-swap, this is also the Move Assignment Operator // This works because we pass-by-value, causing the copy constructor (which // does the actual copying) to be called, and then we swap the resulting // temporary into `this`. Vector &operator=(Vector other) { swap(*this, other); return *this; } // Destructor ~Vector() { delete[] data; } // Bracket Operator T &operator[](unsigned int position) const { return at(position); } // Equals Operator bool operator==(const Vector &other) { if (size() != other.size()) return false; for (unsigned int i = 0; i < size(); i++) { if (at(i) != other[i]) { return false; } } return true; } // Swap function for the copy-and-swap idiom. // See also: // https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom // The `friend` keyword is used so it is found through ADL. friend void swap(Vector &first, Vector &second) { // Enable ADL (good practice) using std::swap; swap(first.capacity, second.capacity); swap(first.element_count, second.element_count); swap(first.data, second.data); } void push_back(const T &element) { if (element_count >= capacity) { // TODO: Increase capacity! } // Use placement new to directly use pre-allocated memory new (data + element_count) T(element); element_count++; } void erase(unsigned int position) { assert(position < element_count); std::copy_backward(data + position + 1, data + element_count, data + element_count - 1); element_count--; } unsigned int size() const { return element_count; } unsigned int length() const { return capacity; } T &at(unsigned int position) const { assert(position < element_count); return data[position]; } // Expand the capacity (length) of the vector by the given addition void reserve(unsigned int addition) { // TODO: Actual reserve capacity += addition; } // Resize the size of the vector to the given new_size // If this decreases the size, some elements are deleted // If this increases the size, some default-constructed elements are added void resize(unsigned int new_size) { // TODO: Reserve if needed int difference = new_size - size(); if (difference > 0) { for (int i = 0; i < difference; i++) { data[element_count + i] = T(); } } else if (difference < 0) { for (int i = -1; i > difference; i--) { data[element_count + i].~T(); } } element_count += difference; } private: T *data; unsigned int element_count; unsigned int capacity; };