| 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;