/* * File: vector.h * -------------- * This file exports the Vector class, which provides an * efficient, safe, convenient replacement for the array type in C++. */ #ifndef _vector_h #define _vector_h #include #include #include #include #include "foreach.h" #include "strlib.h" /* * Class: Vector * ------------------------ * This class stores an ordered list of values similar to an array. * It supports traditional array selection using square brackets, but * also supports inserting and deleting elements. It is similar in * function to the STL vector type, but is simpler both * to use and to implement. */ template class Vector { public: /* * Constructor: Vector * Usage: Vector vec; * Vector vec(n, value); * --------------------------------------- * Initializes a new vector. The default constructor creates an * empty vector. The second form creates an array with n * elements, each of which is initialized to value; * if value is missing, the elements are initialized * to the default value for the type. */ Vector(); explicit Vector(int n, ValueType value = ValueType()); /* * Destructor: ~Vector * ------------------- * Frees any heap storage allocated by this vector. */ virtual ~Vector(); /* * Method: size * Usage: int nElems = vec.size(); * ------------------------------- * Returns the number of elements in this vector. */ int size() const; /* * Method: isEmpty * Usage: if (vec.isEmpty()) ... * ----------------------------- * Returns true if this vector contains no elements. */ bool isEmpty() const; /* * Method: clear * Usage: vec.clear(); * ------------------- * Removes all elements from this vector. */ void clear(); /* * Method: get * Usage: ValueType val = vec.get(index); * -------------------------------------- * Returns the element at the specified index in this vector. This * method signals an error if the index is not in the array range. */ const ValueType & get(int index) const; /* * Method: set * Usage: vec.set(index, value); * ----------------------------- * Replaces the element at the specified index in this vector with * a new value. The previous value at that index is overwritten. * This method signals an error if the index is not in the array range. */ void set(int index, const ValueType & value); /* * Method: insert * Usage: vec.insert(0, value); * ---------------------------- * Inserts the element into this vector before the specified index. * All subsequent elements are shifted one position to the right. This * method signals an error if the index is outside the range from 0 * up to and including the length of the vector. */ void insert(int index, ValueType value); /* * Method: remove * Usage: vec.remove(index); * ------------------------- * Removes the element at the specified index from this vector. * All subsequent elements are shifted one position to the left. This * method signals an error if the index is outside the array range. */ void remove(int index); /* * Method: add * Usage: vec.add(value); * ---------------------- * Adds a new value to the end of this vector. To ensure compatibility * with the vector class in the Standard Template Library, * this method is also called push_back. */ void add(ValueType value); void push_back(ValueType value); /* * Operator: [] * Usage: vec[index] * ----------------- * Overloads [] to select elements from this vector. * This extension enables the use of traditional array notation to * get or set individual elements. This method signals an error if * the index is outside the array range. The file supports two * versions of this operator, one for const vectors and * one for mutable vectors. */ ValueType & operator[](int index); const ValueType & operator[](int index) const; /* * Operator: + * Usage: v1 + v2 * -------------- * Concatenates two vectors. */ Vector operator+(const Vector & v2) const; /* * Operator: += * Usage: v1 += v2; * v1 += value; * ------------------- * Adds all of the elements from v2 (or the single * specified value) to v1. As a convenience, the * Vector package also overloads the comma operator so * that it is possible to initialize a vector like this: * *
 *    Vector<int> digits;
 *    digits += 0, 1, 2, 3, 4, 5, 6, 7, 8, 9;
 *
*/ Vector & operator+=(const Vector & v2); Vector & operator+=(const ValueType & value); bool operator==(const Vector & v2); bool operator!=(const Vector & v2); /* * Method: toString * Usage: string str = vec.toString(); * ----------------------------------- * Converts the vector to a printable string representation. */ std::string toString(); /* * Method: mapAll * Usage: vec.mapAll(fn); * ---------------------- * Calls the specified function on each element of the vector in * ascending index order. */ void mapAll(void (*fn)(ValueType)) const; void mapAll(void (*fn)(const ValueType &)) const; template void mapAll(FunctorType fn) const; /* * Additional Vector operations * ---------------------------- * In addition to the methods listed in this interface, the Vector * class supports the following operations: * * - Stream I/O using the << and >> operators * - Deep copying for the copy constructor and assignment operator * - Iteration using the range-based for statement or STL iterators * * The iteration forms process the Vector in index order. */ /* Private section */ /**********************************************************************/ /* Note: Everything below this point in the file is logically part */ /* of the implementation and should not be of interest to clients. */ /**********************************************************************/ private: /* * Implementation notes: Vector data structure * ------------------------------------------- * The elements of the Vector are stored in a dynamic array of * the specified element type. If the space in the array is ever * exhausted, the implementation doubles the array capacity. */ /* Instance variables */ ValueType *elements; /* A dynamic array of the elements */ int capacity; /* The allocated size of the array */ int count; /* The number of elements in use */ /* Private methods */ void expandCapacity(); void deepCopy(const Vector & src); /* * Hidden features * --------------- * The remainder of this file consists of the code required to * support deep copying and iteration. Including these methods * in the public interface would make that interface more * difficult to understand for the average client. */ public: /* * Deep copying support * -------------------- * This copy constructor and operator= are defined to make a deep copy, * making it possible to pass or return vectors by value and assign * from one vector to another. */ Vector(const Vector & src); Vector & operator=(const Vector & src); /* * Operator: , * ----------- * Adds an element to the vector passed as the left-hand operatand. * This form makes it easier to initialize vectors in old versions of C++. */ Vector & operator,(const ValueType & value); /* * Iterator support * ---------------- * The classes in the StanfordCPPLib collection implement input * iterators so that they work symmetrically with respect to the * corresponding STL classes. */ class iterator : public std::iterator { private: const Vector *vp; int index; public: iterator() { this->vp = NULL; } iterator(const iterator & it) { this->vp = it.vp; this->index = it.index; } iterator(const Vector *vp, int index) { this->vp = vp; this->index = index; } iterator & operator++() { index++; return *this; } iterator operator++(int) { iterator copy(*this); operator++(); return copy; } iterator & operator--() { index--; return *this; } iterator operator--(int) { iterator copy(*this); operator--(); return copy; } bool operator==(const iterator & rhs) { return vp == rhs.vp && index == rhs.index; } bool operator!=(const iterator & rhs) { return !(*this == rhs); } bool operator<(const iterator & rhs) { extern void error(std::string msg); if (vp != rhs.vp) error("Iterators are in different vectors"); return index < rhs.index; } bool operator<=(const iterator & rhs) { extern void error(std::string msg); if (vp != rhs.vp) error("Iterators are in different vectors"); return index <= rhs.index; } bool operator>(const iterator & rhs) { extern void error(std::string msg); if (vp != rhs.vp) error("Iterators are in different vectors"); return index > rhs.index; } bool operator>=(const iterator & rhs) { extern void error(std::string msg); if (vp != rhs.vp) error("Iterators are in different vectors"); return index >= rhs.index; } iterator operator+(const int & rhs) { return iterator(vp, index + rhs); } iterator operator+=(const int & rhs) { index += rhs; return *this; } iterator operator-(const int & rhs) { return iterator(vp, index - rhs); } iterator operator-=(const int & rhs) { index -= rhs; return *this; } int operator-(const iterator & rhs) { extern void error(std::string msg); if (vp != rhs.vp) error("Iterators are in different vectors"); return index - rhs.index; } ValueType & operator*() { return vp->elements[index]; } ValueType *operator->() { return &vp->elements[index]; } ValueType & operator[](int k) { return vp->elements[index + k]; } }; iterator begin() const { return iterator(this, 0); } iterator end() const { return iterator(this, count); } }; /* Implementation section */ extern void error(std::string msg); /* * Implementation notes: Vector constructor and destructor * ------------------------------------------------------- * The constructor allocates storage for the dynamic array * and initializes the other fields of the object. The * destructor frees the memory used for the array. */ template Vector::Vector() { count = capacity = 0; elements = NULL; } template Vector::Vector(int n, ValueType value) { count = capacity = n; elements = (n == 0) ? NULL : new ValueType[n]; for (int i = 0; i < n; i++) { elements[i] = value; } } template Vector::~Vector() { if (elements != NULL) delete[] elements; } /* * Implementation notes: Vector methods * ------------------------------------ * The basic Vector methods are straightforward and should require * no detailed documentation. */ template int Vector::size() const { return count; } template bool Vector::isEmpty() const { return count == 0; } template void Vector::clear() { if (elements != NULL) delete[] elements; count = capacity = 0; elements = NULL; } template const ValueType & Vector::get(int index) const { if (index < 0 || index >= count) error("get: index out of range"); return elements[index]; } template void Vector::set(int index, const ValueType & value) { if (index < 0 || index >= count) error("set: index out of range"); elements[index] = value; } /* * Implementation notes: insert, remove, add * ----------------------------------------- * These methods must shift the existing elements in the array to * make room for a new element or to close up the space left by a * deleted one. */ template void Vector::insert(int index, ValueType value) { if (count == capacity) expandCapacity(); if (index < 0 || index > count) { error("insert: index out of range"); } for (int i = count; i > index; i--) { elements[i] = elements[i - 1]; } elements[index] = value; count++; } template void Vector::remove(int index) { if (index < 0 || index >= count) error("remove: index out of range"); for (int i = index; i < count - 1; i++) { elements[i] = elements[i + 1]; } count--; } template void Vector::add(ValueType value) { insert(count, value); } template void Vector::push_back(ValueType value) { insert(count, value); } /* * Implementation notes: Vector selection * -------------------------------------- * The following code implements traditional array selection using * square brackets for the index. */ template ValueType & Vector::operator[](int index) { if (index < 0 || index >= count) error("Selection index out of range"); return elements[index]; } template const ValueType & Vector::operator[](int index) const { if (index < 0 || index >= count) error("Selection index out of range"); return elements[index]; } template Vector Vector::operator+(const Vector & v2) const { Vector vec = *this; foreach (ValueType value in v2) { vec.add(value); } return vec; } template Vector & Vector::operator+=(const Vector & v2) { foreach (ValueType value in v2) { *this += value; } return *this; } template Vector & Vector::operator+=(const ValueType & value) { this->add(value); return *this; } template bool Vector::operator==(const Vector & v2) { if (this->size() != v2.size()) { return false; } for (int i = 0, size = this->size(); i < size; i++) { if (this->get(i) != v2.get(i)) { return false; } } return true; } template bool Vector::operator!=(const Vector & v2) { return !(*this == v2); } template std::string Vector::toString() { ostringstream os; os << *this; return os.str(); } /* * Implementation notes: copy constructor and assignment operator * -------------------------------------------------------------- * The constructor and assignment operators follow a standard paradigm, * as described in the associated textbook. */ template Vector::Vector(const Vector & src) { deepCopy(src); } template Vector & Vector::operator=(const Vector & src) { if (this != &src) { if (elements != NULL) delete[] elements; deepCopy(src); } return *this; } template void Vector::deepCopy(const Vector & src) { count = capacity = src.count; elements = (capacity == 0) ? NULL : new ValueType[capacity]; for (int i = 0; i < count; i++) { elements[i] = src.elements[i]; } } /* * Implementation notes: The , operator * ------------------------------------ * The comma operator works adding the right operand to the vector and * then returning the vector by reference so that it is set for the next * value in the chain. */ template Vector & Vector::operator,(const ValueType & value) { this->add(value); return *this; } /* * Implementation notes: mapAll * ---------------------------- * The various versions of the mapAll function apply the function or * function object to each element in ascending index order. */ template void Vector::mapAll(void (*fn)(ValueType)) const { for (int i = 0; i < count; i++) { fn(elements[i]); } } template void Vector::mapAll(void (*fn)(const ValueType &)) const { for (int i = 0; i < count; i++) { fn(elements[i]); } } template template void Vector::mapAll(FunctorType fn) const { for (int i = 0; i < count; i++) { fn(elements[i]); } } /* * Implementation notes: expandCapacity * ------------------------------------ * This function doubles the array capacity, copies the old elements * into the new array, and then frees the old one. */ template void Vector::expandCapacity() { capacity = max(1, capacity * 2); ValueType *array = new ValueType[capacity]; for (int i = 0; i < count; i++) { array[i] = elements[i]; } if (elements != NULL) delete[] elements; elements = array; } /* * Implementation notes: << and >> * ------------------------------- * The insertion and extraction operators use the template facilities in * strlib.h to read and write generic values in a way that treats strings * specially. */ template std::ostream & operator<<(std::ostream & os, const Vector & vec) { os << "{"; int len = vec.size(); for (int i = 0; i < len; i++) { if (i > 0) os << ", "; writeGenericValue(os, vec[i], true); } return os << "}"; } template std::istream & operator>>(std::istream & is, Vector & vec) { char ch; is >> ch; if (ch != '{') error("operator >>: Missing {"); vec.clear(); is >> ch; if (ch != '}') { is.unget(); while (true) { ValueType value; readGenericValue(is, value); vec += value; is >> ch; if (ch == '}') break; if (ch != ',') { error(std::string("operator >>: Unexpected character ") + ch); } } } return is; } // hashing functions for vectors; defined in hashmap.cpp int hashCode(const Vector& v); int hashCode(const Vector& v); int hashCode(const Vector& v); int hashCode(const Vector& v); int hashCode(const Vector& v); #endif