#include <iostream>
#include "vector.hpp"
constexpr size_t ITEM_LIMIT = 300;
int main() {
size_t numItems = 15;
std::cout << "How many items to push onto our array-backed list? ";
std::cin >> numItems;
if (numItems > ITEM_LIMIT) {
std::cout << "For sanity, let's just push " << ITEM_LIMIT << "...\n";
numItems = ITEM_LIMIT;
} else {
std::cout << "Okay, pushing " << numItems << " items\n";
}
Vector<int> vec;
for (size_t i = 1; i <= numItems; ++i) {
vec.push_back(i);
}
for (auto& i : vec) {
i += 40;
std::cout << i << std::endl;
}
return 0;
}
#ifndef VECTOR_INCLUDED_HPP
#define VECTOR_INCLUDED_HPP
#include <utility>
#include <iostream>
template <typename T>
class Vector {
private:
// Forward declarations
class Iterator;
public:
using iterator = Iterator;
/**
* \brief Constructs an empty Vector
*/
Vector();
/**
* \brief Constructs a deep copy of orig
* \param orig an existing Vector to be copied
*/
Vector(const Vector<T>& orig);
/**
* \brief Makes this Vector a deep copy of rhs
* \param rhs an existing Vector to be copied
* \returns a reference to this Vector
*/
Vector<T>& operator=(const Vector<T>& rhs);
/**
* \brief Destructor
*/
~Vector();
/**
* \brief Swaps all members between this Vector and rhs
* \param rhs an existing Vector to swap with
*/
void swap(Vector<T>& rhs);
/**
* \brief Adds the given T to the back of the list
* \param pushee the T to push to the list
*/
void push_back(const T& pushee);
/**
* \brief Removes the last item of the list
* \warning Calling pop_back on an empty list has undefined behavior
*/
void pop_back();
/**
* \brief Returns a const reference to the last item of the list
* \returns the last item in the list
* \warning Calling back() on an empty list has undefined behavior
*/
const T& back() const;
/**
* \brief Returns the number of items in the list
* \returns the number of items in the list
*/
std::size_t size() const;
/**
* \brief Returns true if the list is empty, false otherwise
* \returns a boolean indicating whether the list is empty
*/
bool empty() const;
/**
* \brief Compares the contents of two lists
* \param rhs an Vector to compare to
* \returns true if this Vector has the same contents in the same order
* as rhs, false otherwise
*/
bool operator==(const Vector<T>& rhs) const;
/**
* \brief Compares the contents of two lists
* \param rhs an Vector to compare to
* \returns false if this Vector has the same contents in the same order
* as rhs, true otherwise
*/
bool operator!=(const Vector<T>& rhs) const;
/**
* \brief Returns a reference to the item at the given index
* \param index The index of the item to return
* \returns The item at the given index
* \warning Calling operator[] with an out-of-bounds index has undefined
* behavior
*/
T& operator[](size_t index);
/**
* \brief Creates and returns an iterator positioned at the first item
* \returns An iterator positioned at the first item
*/
iterator begin();
/**
* \brief Creates and returns an iterator positioned "just past" the last
* item
* \returns An iterator positioned "just past" the last item
* \warning The returned iterator can only be used for comparison,
* reassignment, or destruction
*/
iterator end();
private:
T* arr_; // Contains the items in the list
std::size_t capacity_; // The size of the array
std::size_t size_; // The number of items in the list
/**
* \brief Doubles the capacity if the list is full
*/
void upsizeIfNeeded();
/**
* \brief Halves the capacity if the list is 1/4 full
*/
void downsizeIfNeeded();
/**
* \brief Changes the capacity of the list to the given value
* \param newCapacity the new capacity of the list
*/
void adjustCapacity(std::size_t newCapacity);
class Iterator {
friend class Vector<T>;
public:
using value_type = T;
using reference = value_type&;
using pointer = value_type*;
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
/**
* \brief Constructs an invalid iterator
* \warning A default-constructed iterator can only be reassigned, or
* destroyed
*/
Iterator() = default;
Iterator(const Iterator& orig) = default;
Iterator& operator=(const Iterator& rhs) = default;
~Iterator() = default;
/**
* \brief Returns a reference to the item at the current position
* \returns A reference to the item at the current position
* \warning Dereferencing the iterator returned by end has undefined
* behavior
*/
T& operator*() const;
/**
* \brief Advances the iterator to the next position
* \returns A reference to the iterator
* \warning Advancing the iterator returned by end has undefined
* behavior
*/
Iterator& operator++();
/**
* \brief Compares the positions of two iterators
* \returns True if the two iterators have the same position, false
* otherwise
* \warning Comparing iterators from different Vectors has
* undefined behavior
*/
bool operator==(const Iterator& rhs) const;
/**
* \brief Compares the positions of two iterators
* \returns False if the two iterators have the same position, true
* otherwise
* \warning Comparing iterators from different Vectors has
* undefined behavior
*/
bool operator!=(const Iterator& rhs) const;
private:
/**
* \brief Constructs an iterator positioned at the given location
* \param curLoc The address of the item in the array at which the
* iterator should be positioned
*/
explicit Iterator(T* curLoc);
T* curLoc_;
};
};
/**
* \brief Swaps the values of all members of two Vector objects
* \param lhs One of the lists to be swapped
* \param rhs The other list to be swapped
*/
template <typename T>
void swap(Vector<T>& lhs, Vector<T>& rhs);
#include "vector-private.hpp"
#endif // VECTOR_INCLUDED_HPP
// implementation file, included at the end of vector.hpp, nowhere else
#include <iostream>
#include <algorithm>
template <typename T>
Vector<T>::Vector() : arr_{new T[1]}, capacity_{1}, size_{0} {
}
template <typename T>
Vector<T>::Vector(const Vector<T>& orig)
: arr_{new T[orig.capacity_]},
capacity_{orig.capacity_},
size_{orig.size_} {
std::copy(orig.arr_, orig.arr_ + size_, arr_);
}
template <typename T>
Vector<T>& Vector<T>::operator=(const Vector<T>& rhs) {
Vector<T> copy = rhs;
swap(copy);
return *this;
}
template <typename T>
Vector<T>::~Vector() {
delete[] arr_;
}
template <typename T>
void Vector<T>::swap(Vector<T>& rhs) {
using std::swap;
swap(arr_, rhs.arr_);
swap(capacity_, rhs.capacity_);
swap(size_, rhs.size_);
}
template <typename T>
void Vector<T>::push_back(const T& pushee) {
upsizeIfNeeded();
arr_[size_] = pushee;
++size_;
}
template <typename T>
void Vector<T>::upsizeIfNeeded() {
if (size_ >= capacity_) {
adjustCapacity(2 * capacity_);
}
}
template <typename T>
void Vector<T>::adjustCapacity(size_t newCapacity) {
// Allocate the new array
T* newArr = new T[newCapacity];
// Copy the items over
std::copy(arr_, arr_ + size_, newArr);
// Deallocate the old array
delete[] arr_;
// Take over the new array
arr_ = newArr;
capacity_ = newCapacity;
}
template <typename T>
void Vector<T>::pop_back() {
downsizeIfNeeded();
--size_;
}
template <typename T>
const T& Vector<T>::back() const {
return arr_[size_ - 1];
}
template <typename T>
void Vector<T>::downsizeIfNeeded() {
if (size_ * 4 <= capacity_) {
adjustCapacity(capacity_ / 2);
}
}
template <typename T>
size_t Vector<T>::size() const {
return size_;
}
template <typename T>
bool Vector<T>::empty() const {
return size_ == 0;
}
template <typename T>
bool Vector<T>::operator==(const Vector<T>& rhs) const {
return std::equal(arr_, arr_ + size_, rhs.arr_, rhs.arr_ + size_);
}
template <typename T>
bool Vector<T>::operator!=(const Vector<T>& rhs) const {
return !(*this == rhs);
}
template <typename T>
T& Vector<T>::operator[](size_t index) {
return arr_[index];
}
template <typename T>
typename Vector<T>::iterator Vector<T>::begin() {
return Iterator{arr_};
}
template <typename T>
typename Vector<T>::iterator Vector<T>::end() {
return Iterator{arr_ + size_};
}
//////////////////////////
// Iterator functions
//////////////////////////
template <typename T>
Vector<T>::Iterator::Iterator(T* curLoc) : curLoc_{curLoc} {
}
template <typename T>
T& Vector<T>::Iterator::operator*() const {
return *curLoc_;
}
template <typename T>
typename Vector<T>::Iterator& Vector<T>::Iterator::operator++() {
++curLoc_;
return *this;
// ++x returns a reference to x, so you can do things like ++(++x);
// (Please, generally speaking, don't do that)
}
template <typename T>
bool Vector<T>::Iterator::operator==(const Iterator& rhs) const {
return curLoc_ == rhs.curLoc_;
}
template <typename T>
bool Vector<T>::Iterator::operator!=(const Iterator& rhs) const {
return !(*this == rhs);
}