#include <iostream>
#include "intvector.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";
}
IntVector vec;
for (int i = 1; i <= numItems; ++i) {
vec.push_back(i);
}
// You can explore downsizing by uncommenting these lines.
// for (int i = 1; i <= numItems; ++i) {
// vec.pop_back();
// }
vec.showStats(std::cout << std::endl);
return 0;
}
#ifndef INT_VECTOR_INCLUDED_HPP
#define INT_VECTOR_INCLUDED_HPP
#include <utility>
#include <iostream>
class IntVector {
public:
/**
* \brief Constructs an empty IntVector
*/
IntVector();
/**
* \brief Constructs a deep copy of orig
* \param orig an existing IntVector to be copied
*/
IntVector(const IntVector& orig);
/**
* \brief Makes this IntVector a deep copy of rhs
* \param rhs an existing IntVector to be copied
* \returns a reference to this IntVector
*/
IntVector& operator=(const IntVector& rhs);
/**
* \brief Destructor
*/
~IntVector();
/**
* \brief Swaps all members between this IntVector and rhs
* \param rhs an existing IntVector to swap with
*/
void swap(IntVector& rhs);
/**
* \brief Adds the given int to the back of the list
* \param pushee the int to push to the list
*/
void push_back(int pushee);
/**
* \brief Removes and returns the last item of the list
* \returns the first item in the list
* \warning Calling pop_front on an empty list has undefined behavior
*/
int pop_back();
/**
* \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 IntVector to compare to
* \returns true if this IntVector has the same contents in the same order as rhs, false otherwise
*/
bool operator==(const IntVector& rhs) const;
/**
* \brief Compares the contents of two lists
* \param rhs an IntVector to compare to
* \returns false if this IntVector has the same contents in the same order as rhs, true otherwise
*/
bool operator!=(const IntVector& 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
*/
int& operator[](size_t index);
/**
* \brief Print stats about the vector.
* \param out std::ostream to print to
* \returns out
*/
std::ostream& showStats(std::ostream& out);
private:
int* 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
std::size_t pushes_ = 0; // Total pushes
std::size_t pops_ = 0; // Total pops
std::size_t moves_ = 0; // Total moves
/**
* \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);
};
/**
* \brief Swaps the values of all members of two IntList objects
* \param lhs One of the lists to be swapped
* \param rhs The other list to be swapped
*/
void swap(IntVector& lhs, IntVector& rhs);
#endif // INT_VECTOR_INCLUDED_HPP
#include "intvector.hpp"
#include <iostream>
using namespace std;
IntVector::IntVector() :
arr_{new int[1]},
capacity_{1},
size_{0} {
}
IntVector::IntVector(const IntVector& orig) :
arr_{new int[orig.capacity_]},
capacity_{orig.capacity_},
size_{orig.size_} {
// Copy the items from orig
for (size_t i = 0; i < size_; ++i) {
arr_[i] = orig.arr_[i];
}
}
IntVector& IntVector::operator=(const IntVector& rhs) {
IntVector copy = rhs;
swap(copy);
return *this;
}
IntVector::~IntVector() {
delete[] arr_;
}
void IntVector::swap(IntVector& rhs) {
using std::swap;
swap(arr_, rhs.arr_);
swap(capacity_, rhs.capacity_);
swap(size_, rhs.size_);
}
void IntVector::push_back(int pushee) {
std::cerr << "push_back(" << pushee << "):\n";
upsizeIfNeeded();
arr_[size_] = pushee;
++size_;
std::cerr << "\t+ Added " << pushee << " in an empty slot ("
<< (capacity_-size_) << " empty slots remaining)\n";
++pushes_;
}
void IntVector::upsizeIfNeeded() {
if (size_ >= capacity_) {
adjustCapacity(2*capacity_);
}
}
void IntVector::adjustCapacity(size_t newCapacity) {
// Allocate the new array
int* newArr = new int[newCapacity];
// Copy the items over
for (size_t i = 0; i < size_; ++i) {
newArr[i] = arr_[i];
std::cerr << "\t> Moved " << arr_[i] << " to new array.\n";
++moves_;
}
// Deallocate the old array
delete[] arr_;
// Take over the new array
arr_ = newArr;
capacity_ = newCapacity;
}
int IntVector::pop_back() {
std::cerr << "pop_back():\n";
downsizeIfNeeded();
int lastVal = arr_[size_-1];
std::cerr << "\t+ Removed " << lastVal << " from the array ("
<< (capacity_-size_) << " empty slots now)\n";
--size_;
++pops_;
return lastVal;
}
void IntVector::downsizeIfNeeded() {
if (size_*4 <= capacity_) {
adjustCapacity(capacity_/2);
}
}
size_t IntVector::size() const {
return size_;
}
bool IntVector::empty() const {
return size_ == 0;
}
bool IntVector::operator==(const IntVector& rhs) const {
if (size_ != rhs.size_) {
// The lists have different sizes and can't be equal
return false;
} else {
for (size_t i = 0; i < size_; ++i) {
if (arr_[i] != rhs.arr_[i]) {
return false;
}
}
// If we are here, all items are the same
return true;
}
}
bool IntVector::operator!=(const IntVector& rhs) const {
return !(*this == rhs);
}
int& IntVector::operator[](size_t index) {
return arr_[index];
}
std::ostream& IntVector::showStats(std::ostream& out) {
out << pushes_ << " pushes, "
<< pops_ << " pops, "
<< moves_ << " moves.\n";
return out;
}