Bruce Eckel's Thinking in C++, 2nd Ed | Contents | Prev | Next |
as templates
//: C16:TStash.h // PSTASH using templates #ifndef TSTASH_H #define TSTASH_H #include "../require.h" #include <cstdlib> // More convenient than nesting in TStash: enum Owns { no = 0, yes = 1, Default }; // Declaration required: template<class Type, int sz> class TStashIter; template<class Type, int chunksize = 20> class TStash { int quantity; int next; Owns _owns; // Flag void inflate(int increase = chunksize); protected: Type** storage; public: TStash(Owns owns = yes); ~TStash(); Owns owns() const { return _owns; } void owns(Owns newOwns) { _owns = newOwns; } int add(Type* element); int remove(int index, Owns d = Default); Type* operator[](int index); int count() const { return next; } friend class TStashIter<Type, chunksize>; }; template<class Type, int sz = 20> class TStashIter { TStash<Type, sz>& ts; int index; public: TStashIter(TStash<Type, sz>& TS) : ts(TS), index(0) {} TStashIter(const TStashIter& rv) : ts(rv.ts), index(rv.index) {} // Jump interator forward or backward: void forward(int amount) { index += amount; if(index >= ts.next) index = ts.next -1; } void backward(int amount) { index -= amount; if(index < 0) index = 0; } // Return value of ++ and -- to be // used inside conditionals: int operator++() { if(++index >= ts.next) return 0; return 1; } int operator++(int) { return operator++(); } int operator--() { if(--index < 0) return 0; return 1; } int operator--(int) { return operator--(); } operator int() { return index >= 0 && index < ts.next; } Type* operator->() { Type* t = ts.storage[index]; if(t) return t; require(0,"TStashIter::operator->return 0"); return 0; // To allow inlining } // Remove the current element: int remove(Owns d = Default){ return ts.remove(index, d); } }; template<class Type, int sz> TStash<Type, sz>::TStash(Owns owns) : _owns(owns) { quantity = 0; storage = 0; next = 0; } // Destruction of contained objects: template<class Type, int sz> TStash<Type, sz>::~TStash() { if(!storage) return; if(_owns == yes) for(int i = 0; i < count(); i++) delete storage[i]; free(storage); } template<class Type, int sz> int TStash<Type, sz>::add(Type* element) { if(next >= quantity) inflate(); storage[next++] = element; return(next - 1); // Index number } template<class Type, int sz> int TStash<Type, sz>::remove(int index, Owns d){ if(index >= next || index < 0) return 0; switch(d) { case Default: if(_owns != yes) break; case yes: delete storage[index]; case no: storage[index] = 0; // Position is empty } return 1; } template<class Type, int sz> inline Type* TStash<Type, sz>::operator[](int index) { // Remove check for shipping application: require(index >= 0 && index < next); return storage[index]; } template<class Type, int sz> void TStash<Type, sz>::inflate(int increase) { void* v = realloc(storage, (quantity+increase)*sizeof(Type*)); require(v != 0); // Was it successful? storage = (Type**)v; quantity += increase; }
//: C16:TStashTest.cpp // Test TStash #include "TStash.h" #include "../require.h" #include <fstream> #include <vector> #include <string> using namespace std; ofstream out("tstest.out"); class Int { int i; public: Int(int ii = 0) : i(ii) { out << ">" << i << endl; } ~Int() { out << "~" << i << endl; } operator int() const { return i; } friend ostream& operator<<(ostream& os, const Int& x) { return os << x.i; } }; int main() { TStash<Int> intStash; // Instantiate for Int for(int i = 0; i < 30; i++) intStash.add(new Int(i)); TStashIter<Int> intIter(intStash); intIter.forward(5); for(int j = 0; j < 20; j++, intIter++) intIter.remove(); // Default removal for(int k = 0; k < intStash.count(); k++) if(intStash[k]) // Remove() causes "holes" out << *intStash[k] << endl; ifstream file("TStashTest.cpp"); assure(file, "TStashTest.cpp"); // Instantiate for String: TStash<string> stringStash; string line; while(getline(file, line)) stringStash.add(new string(line)); for(int u = 0; u < stringStash.count(); u++) if(stringStash[u]) out << *stringStash[u] << endl; TStashIter<string> it(stringStash); int n = 25; it.forward(n); while(it) { out << n++ << ": " << it->c_str() << endl; it++; }
//: C16:TStack.h // Stack using templates #ifndef TSTACK_H #define TSTACK_H // Declaration required: template<class T> class TStackIterator; template<class T> class TStack { struct Link { T* data; Link* next; Link(T* dat, Link* nxt) { data = dat; next = nxt; } }* head; int _owns; public: TStack(int own = 1) : head(0), _owns(own) {} ~TStack(); void push(T* dat) { head = new Link(dat,head); } T* peek() const { return head->data; } T* pop(); int owns() const { return _owns; } void owns(int newownership) { _owns = newownership; } friend class TStackIterator<T>; }; template<class T> T* TStack<T>::pop() { if(head == 0) return 0; T* result = head->data; Link* oldHead = head; head = head->next; delete oldHead; return result; } template<class T> TStack<T>::~TStack() { Link* cursor = head; while(head) { cursor = cursor->next; // Conditional cleanup of data: if(_owns) delete head->data; delete head; head = cursor; } } template<class T> class TStackIterator { TStack<T>::Link* p; public: TStackIterator(const TStack<T>& tl) : p(tl.head) {} TStackIterator(const TStackIterator& tl) : p(tl.p) {} // operator++ returns boolean indicating end: int operator++() { if(p->next) p = p->next; else p = 0; // Indicates end of list return int(p); } int operator++(int) { return operator++(); } // Smart pointer: T* operator->() const { if(!p) return 0; return p->data; } T* current() const { if(!p) return 0; return p->data; } // int conversion for conditional test: operator int() const { return p ? 1 : 0; } };
//: C16:TStackTest.cpp // Use template list & iterator #include "TStack.h" #include "../require.h" #include <iostream> #include <fstream> #include <string> using namespace std; int main() { ifstream file("TStackTest.cpp"); assure(file, "TStackTest.cpp"); TStack<string> textlines; // Read file and store lines in the list: string line; while(getline(file, line)) textlines.push(new string(line)); int i = 0; // Use iterator to print lines from the list: TStackIterator<string> it(textlines); TStackIterator<string>* it2 = 0; while(it) { cout << *it.current() << endl; it++; if(++i == 10) // Remember 10th line it2 = new TStackIterator<string>(it); } cout << *(it2->current()) << endl; delete it2;