#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 (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 INT_VECTOR_INCLUDED_HPP
#define INT_VECTOR_INCLUDED_HPP
#include <utility>
#include <iostream>
class IntVector {
private:
// Forward declarations
class Iterator;
public:
using iterator = Iterator;
/**
* \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 the last item of the list
* \warning Calling pop_back on an empty list has undefined behavior
*/
void pop_back();
/**
* \brief Returns the last item of the list
* \returns the last item in the list
* \warning Calling back() on an empty list has undefined behavior
*/
int 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 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 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:
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
/**
* \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 IntVector;
public:
using value_type = int;
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
*/
int& 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 IntVectors 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 IntVectors 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(int* curLoc);
int* curLoc_;
};
};
/**
* \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>
#include <algorithm>
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_} {
std::copy(orig.arr_, orig.arr_ + size_, arr_);
}
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) {
upsizeIfNeeded();
arr_[size_] = pushee;
++size_;
}
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
std::copy(arr_, arr_ + size_, newArr);
// Deallocate the old array
delete[] arr_;
// Take over the new array
arr_ = newArr;
capacity_ = newCapacity;
}
void IntVector::pop_back() {
downsizeIfNeeded();
--size_;
}
int IntVector::back() const {
return arr_[size_ - 1];
}
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 {
return std::equal(arr_, arr_ + size_, rhs.arr_, rhs.arr_ + size_);
}
bool IntVector::operator!=(const IntVector& rhs) const {
return !(*this == rhs);
}
int& IntVector::operator[](size_t index) {
return arr_[index];
}
IntVector::iterator IntVector::begin() {
return Iterator{arr_};
}
IntVector::iterator IntVector::end() {
return Iterator{arr_ + size_};
}
//////////////////////////
// Iterator functions
//////////////////////////
IntVector::Iterator::Iterator(int* curLoc) : curLoc_{curLoc} {
}
int& IntVector::Iterator::operator*() const {
return *curLoc_;
}
IntVector::Iterator& IntVector::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)
}
bool IntVector::Iterator::operator==(const Iterator& rhs) const {
return curLoc_ == rhs.curLoc_;
}
bool IntVector::Iterator::operator!=(const Iterator& rhs) const {
return !(*this == rhs);
}