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 <cstdlib> #include "../require.h" // 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 own; // Flag void inflate(int increase = chunksize); protected: Type** storage; public: TStash(owns Owns = yes); ~TStash(); int Owns() const { return own; } void Owns(owns newOwns) { own = 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) : own(Owns) { quantity = 0; storage = 0; next = 0; } // Destruction of contained objects: template<class Type, int sz> TStash<Type, sz>::~TStash() { if(!storage) return; if(own == 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(own != 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; } #endif // TSTASH_H ///:~
//: C16:Tstest.cpp // Test TStash #include <fstream> #include <vector> #include <string> #include "../require.h" #include "TStash.h" 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> Intit(intStash); Intit.forward(5); for(int j = 0; j < 20; j++, Intit++) Intit.remove(); // Default removal for(int k = 0; k < intStash.count(); k++) if(intStash[k]) // Remove() causes "holes" out << *intStash[k] << endl; ifstream file("Tstest.cpp"); assure(file, "Tstest.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 j = 25; it.forward(j); while(it) { out << j++ << ": " << 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* Data, Link* Next) { data = Data; next = Next; } } * head; int owns; public: TStack(int own = 1) : head(0), owns(own) {} ~TStack(); void push(T* Data) { head = new Link(Data,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; } }; #endif // TSTACK_H ///:~
//: C16:Tstktst.cpp // Use template list & iterator #include <iostream> #include <fstream> #include <string> #include "../require.h" #include "TStack.h" using namespace std; int main() { ifstream file("Tstktst.cpp"); assure(file, "Tstktst.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; } ///:~