Thursday, September 9, 2010

Source Codes: Vector and Iterator

I have been practicing operator overloading, friend method, template, separate compilation, vector and iterators by writing up a sample vector class. Although this is not as great as the STL's templated container class, vector, one can look at this source code to get a feel of the inner structure of the vector class' coded. :)

A minimal commentary is available to understand the code.
Note: the indentation shown here are like 1-2 space.
Vector.h
#ifndef VECTOR_H
#define VECTOR_H

template <class Type>
class Vector{
public:
 Vector();
 void push_back(const Type& entry);
 void pop_back();
 void clear();
 void resize(int newSize);
 int size() const;

 /* read */
 Type operator[](int index) const;

 /* write */
 Type& operator[](int index);

 /* Nested Iterator class */
 class Iterator{

  /* Binary operator should be made a function */
  friend bool operator==(const Iterator& a, const Iterator& b){
   return a.current == b.current;
  }

  friend bool operator!=(const Iterator& a, const Iterator& b){
   return !(a == b); //return !operator==(a, b);
  }

 public:
  Iterator(Vector* parent = NULL);

  /* Advances the iterator by an offset */
  Iterator& operator+(int offset);
  Iterator& operator-(int offset);
  Iterator operator++();
  Iterator operator++(int);
  Iterator operator--();
  Iterator operator--(int);
  Type operator*();
  Type* operator->() const;

  /* sets the current pointer with the given pointer */
  void setCurrent(Type* given);

 private:
  Type* current;
 };

 Iterator begin();
 Iterator end();

private: 
 Type* data;
 int theSize, capacity;
 Iterator iterator;
};

#endif

Vector.cpp
#include <iostream>
#include "Vector.h"

template <class Type>
Vector<Type>::Vector():theSize(0), capacity(10){
 data = new Type[capacity];
 iterator = Iterator(this);
}

template <class Type>
void Vector<Type>::push_back(const Type& entry){
 if(theSize == capacity)
  resize(theSize*2); //doubles the size of the vector if capacity is reached
 data[++theSize] = entry; //increments the size, and adds the new entry
}

template <class Type>
void Vector<Type>::pop_back(){
 if(theSize == 0)
  return;
 data[theSize] = NULL;
 --theSize;
}

template <class Type>
void Vector<Type>::clear(){
 while(theSize > 0)
  pop_back();
}

/* Reduce the size to the newSize if current capacity is smaller greater than the newSize. 
   Otherwise grow the capacity to the demanded newSize, deep copying all the elements in existence. */
template <class Type>
void Vector<Type>::resize(int newSize){
 if(newSize > capacity){
  Type* backup = data;
  data = new Type[newSize];
  capacity = newSize;
  int j = theSize;
  theSize = 0;

  for(int i = 0; i < j; ++i){
   push_back(backup[i+1]);
  }
 }
 else{
  while(newSize < theSize)
   pop_back();
 }
}

template <class Type>
int Vector<Type>::size() const{
 return theSize;
}

template <class Type>
Type Vector<Type>::operator[](int index) const{
 return data[index+1];
}

template <class Type>
Type& Vector<Type>::operator[](int index){
 return data[index+1];
}

/* returns the Iterator that points to the first element in the data dynamic array */
template <class Type>
typename Vector<Type>::Iterator Vector<Type>::begin(){
 iterator.setCurrent(data + 1);
 return iterator;
}

/* returns the Iterator that points to the last element in the data dynamic array */
template <class Type>
typename Vector<Type>::Iterator Vector<Type>::end(){
 iterator.setCurrent(data + theSize + 1);
 return iterator;
}

/*********************** Iterator /***********************/

//template <class Type>
//bool operator==(const typename Vector<Type>::Iterator& a, const typename Vector<Type>::Iterator& b){
// return a.current == b.current;
//}
//
//template <class Type>
//bool operator!=(const typename Vector<Type>::Iterator& a, const typename Vector<Type>::Iterator& b){
// return !(a == b);
//}

template <class Type>
Vector<Type>::Iterator::Iterator(Vector* parent = NULL){
 current = (parent) ? (parent->data + 1) : NULL; // sets current to NULL if the parent pointer given is NULL.
}

template <class Type>
typename Vector<Type>::Iterator& Vector<Type>::Iterator::operator+(int offset){
 current += offset; // Pointer Arithmetic
 return *this;
}

template <class Type>
typename Vector<Type>::Iterator& Vector<Type>::Iterator::operator-(int offset){
 current -= offset; // Pointer Arithmetic
 return *this;
}

template <class Type>
typename Vector<Type>::Iterator Vector<Type>::Iterator::operator++(){ //pre-increment
 ++current;
 return *this;
}

template <class Type>
typename Vector<Type>::Iterator Vector<Type>::Iterator::operator++(int){ //post-increment
 Iterator backup = *this;
 ++current;
 return backup;
} 

template <class Type>
typename Vector<Type>::Iterator Vector<Type>::Iterator::operator--(){ //pre-decrement
 --current;
 return *this;
}

template <class Type>
typename Vector<Type>::Iterator Vector<Type>::Iterator::operator--(int){ //post-decrement
 Iterator backup = *this;
 --current;
 return backup;
} 

template <class Type>
Type Vector<Type>::Iterator::operator*(){
 return *current;
}

template <class Type>
Type* Vector<Type>::Iterator::operator->() const{
 return current;
}

template <class Type>
void Vector<Type>::Iterator::setCurrent(Type* given){
 current = given;
}

main.cpp
/* This source code is written by Wensheng Chen, anyone can freely redistribute the code under GPL. */
#include <iostream>
#include "Vector.h"
#include "Vector.cpp"
/* Note: Template and separate compilation do not work well together, 
one has to include both the header and the implementation file to 
achieve the goal of separation compilation. */

using namespace std;

class Cat{
 friend ostream& operator<<(ostream& os, const Cat& cat){
  os << cat.age;
  return os;
 }

public:
 Cat(){}
 Cat(int age):age(age){}
 string meow(){
  return "meow\n";
 }

private:
 int age;
};

int main(){
 Vector<Cat> number;
 for(int i = 0; i < 100; ++i){
  number.push_back(i);
 }

 for(int i = 0; i < number.size(); ++i){
  cout << number[i] << endl;
 }

 cout << "iterator begins now!!\n\n";
 int i = 0;
 for(Vector<Cat>::Iterator iter = number.begin() + 5; iter != number.end() - 9; ++iter, ++i){
  cout << i << ". " << *iter << " " << (iter->meow()).c_str() /* C++ cannot take both a cstring and a string at the same time.*/ << endl;
 }
 

}

No comments:

Post a Comment