// Jason Rohrer // SimpleVector.h /** * * Simple vector template class. Supports pushing at end and random-access deletions. * Dynamically sized. * * * Created 10-24-99 * Mods: * Jason Rohrer 12-11-99 Added deleteAll function * Jason Rohrer 1-30-2000 Changed to return NULL if get called on non-existent element * Jason Rohrer 12-20-2000 Added a function for deleting a particular * element. * Jason Rohrer 12-14-2001 Added a function for getting the index of * a particular element. * Jason Rohrer 1-24-2003 Added a functions for getting an array or * string of all elements. * Jason Rohrer 7-26-2005 Added template <> to explicitly specialized * getElementString. * Jason Rohrer 1-9-2009 Added setElementString method. * Jason Rohrer 9-7-2009 Fixed int types. * Added appendElementString. * Jason Rohrer 11-11-2009 Changed second deleteElement to allow * SimpleVectors containing ints. * Jason Rohrer 12-23-2009 New push_back for arrays. * Jason Rohrer 1-5-2010 Reduced default size to conserve memory. * Jason Rohrer 1-12-2010 Added copy constructor and assignment * operator. * Jason Rohrer 1-16-2010 Fixed bugs in new constructor/operator. * Jason Rohrer 1-18-2010 Fixed memmove/memcpy bugs. * Jason Rohrer 1-28-2010 Data protected for subclass access. * Jason Rohrer 4-28-2010 Fast version of getElement. * Jason Rohrer 5-14-2010 String parameters as const to fix warnings. */ #include "minorGems/common.h" #ifndef SIMPLEVECTOR_INCLUDED #define SIMPLEVECTOR_INCLUDED #include // for memory moving functions const int defaultStartSize = 2; template class SimpleVector { public: SimpleVector(); // create an empty vector SimpleVector(int sizeEstimate); // create an empty vector with a size estimate ~SimpleVector(); // copy constructor SimpleVector( const SimpleVector &inCopy ); // assignment operator SimpleVector & operator = (const SimpleVector &inOther ); void push_back(Type x); // add x to the end of the vector // add array of elements to the end of the vector void push_back(Type *inArray, int inLength); Type *getElement(int index); // get a ptr to element at index in vector Type *getElementFast(int index); // no bounds checking int size(); // return the number of allocated elements in the vector bool deleteElement(int index); // delete element at an index in vector /** * Deletes a particular element. Deletes the first element * in vector == to inElement. * * @param inElement the element to delete. * * @return true iff an element was deleted. */ bool deleteElementEqualTo( Type inElement ); /** * Gets the index of a particular element. Gets the index of the * first element in vector == to inElement. * * @param inElement the element to get the index of. * * @return the index if inElement, or -1 if inElement is not found. */ int getElementIndex( Type inElement ); void deleteAll(); // delete all elements from vector /** * Gets the elements as an array. * * @return the a new array containing all elements in this vector. * Must be destroyed by caller, though elements themselves are * not copied. */ Type *getElementArray(); /** * Gets the char elements as a \0-terminated string. * * @return a \0-terminated string containing all elements in this * vector. * Must be destroyed by caller. */ char *getElementString(); /** * Sets the char elements as a \0-terminated string. * * @param inString a \0-terminated string containing all elements to * set this vector with. * Must be destroyed by caller. */ void setElementString( const char *inString ); /** * Appends chars from a \0-terminated string. * * @param inString a \0-terminated string containing all elements to * append to this vector. * Must be destroyed by caller. */ void appendElementString( const char *inString ); protected: Type *elements; int numFilledElements; int maxSize; int minSize; // number of allocated elements when vector is empty }; template inline SimpleVector::SimpleVector() { elements = new Type[defaultStartSize]; numFilledElements = 0; maxSize = defaultStartSize; minSize = defaultStartSize; } template inline SimpleVector::SimpleVector(int sizeEstimate) { elements = new Type[sizeEstimate]; numFilledElements = 0; maxSize = sizeEstimate; minSize = sizeEstimate; } template inline SimpleVector::~SimpleVector() { delete [] elements; } // copy constructor template inline SimpleVector::SimpleVector( const SimpleVector &inCopy ) : elements( new Type[ inCopy.maxSize ] ), numFilledElements( inCopy.numFilledElements ), maxSize( inCopy.maxSize ), minSize( inCopy.minSize ) { // if these objects contain pointers to stack, etc, this is not // going to work (not a deep copy) // because it won't invoke the copy constructors of the objects! //memcpy( elements, inCopy.elements, sizeof( Type ) * numFilledElements ); for( int i=0; i inline SimpleVector & SimpleVector::operator = ( const SimpleVector &inOther ) { // pattern found on wikipedia: // avoid self-assignment if( this != &inOther ) { // 1: allocate new memory and copy the elements Type *newElements = new Type[ inOther.maxSize ]; // again, memcpy doesn't work here, because it doesn't invoke // copy constructor on contained object /*memcpy( newElements, inOther.elements, sizeof( Type ) * inOther.numFilledElements ); */ for( int i=0; i inline int SimpleVector::size() { return numFilledElements; } template inline Type *SimpleVector::getElement(int index) { if( index < numFilledElements && index >=0 ) { return &(elements[index]); } else return NULL; } template inline Type *SimpleVector::getElementFast(int index) { return &(elements[index]); } template inline bool SimpleVector::deleteElement(int index) { if( index < numFilledElements) { // if index valid for this vector if( index != numFilledElements - 1) { // this spot somewhere in middle // memmove NOT okay here, because it leaves shallow copies // behind that cause errors when the whole element array is // destroyed. /* // move memory towards front by one spot int sizeOfElement = sizeof(Type); int numBytesToMove = sizeOfElement*(numFilledElements - (index+1)); Type *destPtr = &(elements[index]); Type *srcPtr = &(elements[index+1]); memmove( (void *)destPtr, (void *)srcPtr, (unsigned int)numBytesToMove); */ for( int i=index+1; i inline bool SimpleVector::deleteElementEqualTo( Type inElement ) { int index = getElementIndex( inElement ); if( index != -1 ) { return deleteElement( index ); } else { return false; } } template inline int SimpleVector::getElementIndex( Type inElement ) { // walk through vector, looking for first match. for( int i=0; i inline void SimpleVector::deleteAll() { numFilledElements = 0; if( maxSize > minSize ) { // free memory if vector has grown delete [] elements; elements = new Type[minSize]; // reallocate an empty vector maxSize = minSize; } } template inline void SimpleVector::push_back(Type x) { if( numFilledElements < maxSize) { // still room in vector elements[numFilledElements] = x; numFilledElements++; } else { // need to allocate more space for vector int newMaxSize = maxSize << 1; // double size // NOTE: memcpy does not work here, because it does not invoke // copy constructors on elements. // And then "delete []" below causes destructors to be invoked // on old elements, which are shallow copies of new objects. Type *newAlloc = new Type[newMaxSize]; /* unsigned int sizeOfElement = sizeof(Type); unsigned int numBytesToMove = sizeOfElement*(numFilledElements); // move into new space memcpy((void *)newAlloc, (void *) elements, numBytesToMove); */ // must use element-by-element assignment to invoke constructors for( int i=0; i inline void SimpleVector::push_back(Type *inArray, int inLength) { for( int i=0; i inline Type *SimpleVector::getElementArray() { Type *newAlloc = new Type[ numFilledElements ]; // shallow copy not good enough! /* unsigned int sizeOfElement = sizeof( Type ); unsigned int numBytesToCopy = sizeOfElement * numFilledElements; // copy into new space //memcpy( (void *)newAlloc, (void *)elements, numBytesToCopy ); */ // use assignment to ensure that constructors are invoked on element copies for( int i=0; i inline char *SimpleVector::getElementString() { char *newAlloc = new char[ numFilledElements + 1 ]; unsigned int sizeOfElement = sizeof( char ); unsigned int numBytesToCopy = sizeOfElement * numFilledElements; // memcpy fine here, since shallow copy good enough for chars // copy into new space memcpy( (void *)newAlloc, (void *)elements, numBytesToCopy ); newAlloc[ numFilledElements ] = '\0'; return newAlloc; } template <> inline void SimpleVector::appendElementString( const char *inString ) { // slow but correct unsigned int numChars = strlen( inString ); for( unsigned int i=0; i inline void SimpleVector::setElementString( const char *inString ) { deleteAll(); appendElementString( inString ); } #endif