[comp.lang.c++] Simula listhandling in C++.

jonasn@ttds.UUCP (Jonas Nygren) (03/09/89)

There have been a few requests for software IC's written in C++. Below you
find a shar file with an implementation of Simulas simset-class in C++. 
Simset is a general double-directed list facility with two classes which
you can use as base-classes for your own derived classes. I call this
set of classes for cset and they are found in the files cset.{h,c}.

Here is an example of how you could use cset to implement a list-container
class similar to the slist-class described in 'The C++ Programming Language', 
para 7.3.1, although the list-handling primitives are taken from simset and
I don't use the nifty iterator class. (You find this example code in file 
slist.c in the shar file below):

#include <stream.h>

#define generic entry
#include "cset.h"

typedef void *ent;

class entry : public link{
public:
	ent e;

	entry(ent a) { e = a; }
};

main(){
	head *slist;
	entry *sp;
	int i = 1;

	slist = new head;
	new entry((ent)1)->into(slist);
	(sp = new entry((ent)2))->into(slist);
	new entry((ent)4)->into(slist);
	new entry((ent)3)->follow(sp);
	sp->pred()->follow(sp->suc());
	
	cout << "Length of slist: " << slist->cardinal() << ".\n\n";
	for(sp = slist->first(); sp; sp = sp->suc())
		cout << "Entry " << i++ << " : " << (int)sp->e << ".\n";
}
	
A list element in slist consists of an instance of the entry-class which
is derived from the link-class. Here follows the class hierarchy together
with their member functions:

			linkage
			- suc
			- pred
			- prev

		  /                 \

	listhead			link
	- first				- out
	- last				- follow
	- empty				- precede
	- cardinal			- into

	  !				  !

	head				entry
	- <public listhead>		- ?

To implement these classes I have used a special construction which I have
named 'generic'. Generic is used to allow base classes to know about the yet
undefined derived classes, in the code above generic replaces the entry-class.

The generic is implemented with preprocessor macros and that is why the
'#include cset.h' is preceeded by a '#define generic entry'. Please
study the cset implementation for a full understanding.

If my construction don't correspond with current C-coding practise or if
you find my bugs, would you please let me know. This is my first C++ program.
Answer by email if possible.

/jonas

PS Run examble by: CC cset.c slist.c ; a.out DS

------- here comes the code

: This is a shar archive.  Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
echo 'Extracting cset.c'
sed 's/^X//' > cset.c << '+ END-OF-FILE cset.c'
X 
X/*
X	CSET - double-linked lists for C++.
X	===================================
X
X	The cset implementation is based on the SIMSET description in
X	a swedish Simula-bok, ISBN 91-85484-02-4, Y Sundblad och O Leringe.
X
X	The cset-code is free to use for any purpose whatsoever.
X
X	Jonas Nygren
X
X*/
X
X#include <stream.h>
X
X#define generic link
X
X#include "cset.h"
X
Xgeneric *link::out(){
X        if(SUC && PRED){
X                PRED->SUC = SUC;
X                SUC->PRED = PRED;
X                PRED = SUC = 0;
X		--HEAD->nelem;
X		HEAD = 0;
X        }
X	return((generic *) this);
X}
X 
Xvoid link::follow(generic *gp){
X	linkage *p = (linkage *)gp;
X        out();
X        if(p && p->SUC){
X                PRED = p;
X                SUC = p->SUC;
X                p->SUC = SUC->PRED = (linkage *)this;
X		HEAD = p->HEAD;
X		++HEAD->nelem;
X        }
X}
X 
Xvoid link::precede(generic *gp){
X	linkage *p = (linkage *)gp;
X        out();
X        if(p && p->PRED){
X                PRED = p->PRED;
X                SUC = p;
X                p->PRED = PRED->SUC = (linkage *)this;
X		HEAD = p->HEAD;
X		++HEAD->nelem;
X        }
X}
X	
Xvoid link::into(class head *s){
X	precede((generic *)s);
X}
X 
Xvoid listhead::clear() {
X        link *p;
X 
X        while(p = suc()) p->out();
X}
X
X#undef generic
X
+ END-OF-FILE cset.c
chmod 'u=rw,g=r,o=r' 'cset.c'
echo '	-rw-r--r--  1 jonasn       1251 Mar  8 14:49 cset.c        (as sent)'
echo -n '	'
/bin/ls -l cset.c
echo 'Extracting cset.h'
sed 's/^X//' > cset.h << '+ END-OF-FILE cset.h'
X 
X/*
X	CSET - double-linked lists for C++.
X	===================================
X
X	The cset implementation is based on the SIMSET description in
X	a swedish Simula-bok, ISBN 91-85484-02-4, Y Sundblad och O Leringe.
X
X	The cset-code is free to use for any purpose whatsoever.
X
X	Jonas Nygren
X
X*/
X
Xclass linkage{
Xpublic:
X        class linkage *SUC, *PRED;
X	class listhead *HEAD;
X        class generic *suc() {
X		return((generic *)(SUC == (linkage *)HEAD ? 0 : SUC)); }
X        class generic *pred() {
X		return((generic *)(PRED == (linkage *)HEAD ? 0 : PRED)); }
X	class linkage *prev(){ return(PRED); }
X};
X 
Xclass link : linkage {
Xpublic:
X        linkage::suc;
X        linkage::pred;
X        generic *out();
X        void follow(generic *p);
X        void precede(generic *p);
X	void into(class head *s);
X};
X 
Xclass listhead : linkage {
Xpublic:
X	int nelem;
X
X	linkage::suc;
X        listhead() {
X		SUC = PRED = (linkage *) this; 
X		HEAD = this;
X		nelem = 0;
X	}
X
X        generic *first() { return(suc()); }
X        generic *last() { return(pred()); }
X 
X        int empty() { return(nelem); }
X        int cardinal() { return(nelem); }
X
X        void clear();
X};
X
Xclass head : public listhead {
X	listhead::first;
X	listhead::last;
X	listhead::empty;
X	listhead::cardinal;
X	listhead::clear;
X};
+ END-OF-FILE cset.h
chmod 'u=rw,g=r,o=r' 'cset.h'
echo '	-rw-r--r--  1 jonasn       1273 Mar  8 14:47 cset.h        (as sent)'
echo -n '	'
/bin/ls -l cset.h
echo 'Extracting cset.o'
sed 's/^X//' > cset.o << '+ END-OF-FILE cset.o'
+ END-OF-FILE cset.o
chmod 'u=rw,g=r,o=r' 'cset.o'
echo '	-rw-r--r--  1 jonasn        933 Mar  8 14:50 cset.o        (as sent)'
echo -n '	'
/bin/ls -l cset.o
echo 'Extracting slist.c'
sed 's/^X//' > slist.c << '+ END-OF-FILE slist.c'
X#include <stream.h>
X
X#define generic entry
X#include "cset.h"
X
Xtypedef void *ent;
X
Xclass entry : public link{
Xpublic:
X	ent e;
X
X	entry(ent a) { e = a; }
X};
X
Xmain(){
X	head *slist;
X	entry *sp;
X	int i = 1;
X
X	slist = new head;
X	new entry((ent)1)->into(slist);
X	(sp = new entry((ent)2))->into(slist);
X	new entry((ent)4)->into(slist);
X	new entry((ent)3)->follow(sp);
X	sp->pred()->follow(sp->suc());
X	
X	cout << "Length of slist: " << slist->cardinal() << ".\n\n";
X	for(sp = slist->first(); sp; sp = sp->suc())
X		cout << "Entry " << i++ << " : " << (int)sp->e << ".\n";
X}
X	
+ END-OF-FILE slist.c
chmod 'u=rw,g=r,o=r' 'slist.c'
echo '	-rw-r--r--  1 jonasn        564 Mar  8 13:35 slist.c        (as sent)'
echo -n '	'
/bin/ls -l slist.c
exit 0