Templates

We have defined an ADT int_stack. Now assume that we also want a stack of doubles, of (pointers to) some type T etc. How can we use the int_stack code that we have already written to obtain, say, T_stack?

The straight-forward way, of course is to copy and modify. It is not that difficult to take an existing piece of code and alter it in a stylized fashion to obtain an ADT that operates on other types. The problem comes later, when one of the two (or more) copies is altered to fix a bug or to add an enhancement. We now have to keep track of which ADT implementations are related, and patch them all.

This is the problem that mechanisms like C++ templates were developed to address. C has no such equivalent. Instead, what I use is could be called "poor-mans template". It is not much more than an automated way of doing copy and modify.

To start with, I would create a file called stack.h.templ which would look like:


	#ifndef H_@type_stack
	#define H_@type_stack

	#include "@type_stack-private.h"

	typedef struct @type_stack *	@type_stack;

	@type_stack	make_@type_stack(void);
	void		push_@type_stack(@type_stack, @type);

	#define FOR_@TYPE_STACK(_stack,_i)	X_FOR_@TYPE_STACK(_stack,_i)
	#define END_@TYPE_STACK			X_END_@TYPE_STACK
	#endif

The @type and @TYPE are strings that will need to be modified after copying. To produce an int_stack.h from a stack.h.templ, we define a file called int_stack.table that controls how the strings will be modified after copying.


	@type	int
	@TYPE	INT

For a double_stack, double_stack.table would contain:


	@type	double
	@TYPE	DOUBLE

We have to come up with a tool that can automatically modify a template using a table to produce the actual code. This can be written any number of ways. I have used combinations of sed and gawk in the past. Currently I am using a python script. An abbreviated version of the Expand.py script is:


	import	sys

	table_file = sys.argv[1]
	input_file = sys.argv[2]
	output_file = sys.argv[3]

	# read the table
	table = {}
	while(1):
	  line = table_file.readline()
	  if( line == "" ):
	    break
	  words = line.split(None, 1)
	  table[words[0]] = words[1]

        # do the modification
	while(1):
	  line = input_file.readline()
	  if( line == "" ):
	    break
	  for old in table.keys():
	    line = line.replace(old, table[old])
	  output_file.write(line)

To produce int_stack.h from stack.h.templ, we would invoke the script as:


	python Expand.py int_stack.table stack.h.templ int_stack.h

Of course, all of these invocations are best put in a Makefile as:


	int_stack.h:	int_stack.table stack.h.templ
		python Expand.py int_stack.table stack.h.templ int_stack.h
	int_stack-private.h:	int_stack.table stack-private.h.templ
		python Expand.py int_stack.table stack-private.h.templ int_stack-private.h
	int_stack.c:	int_stack.table stack.c.templ
		python Expand.py int_stack.table stack.c.templ int_stack.c


Next Prev Main Top Feedback