/* Polymorphic lists in C */

#include <stdio.h>
#include <strings.h>
#include <stdlib.h>

typedef struct s_LHead {
  struct s_LHead * next;
  int type_tag;		/* Not strictly necessary, but nice to have */
} LHead;

#define NIL ((LHead *)0)


/* Find the length of _any_ List */
/* Note this function is declared ahead of any particular list */

static int length(const LHead * list)
{
  int count = 0;
  for(; list != NIL; list = list->next)
    count++;
  return count;
}

/* List of integers */

typedef struct s_LInt {
  LHead head;
  int datum;
} LInt;

#define LInt_type 1

/* List of numbers 0 .. n-1 */
/* Note that I went out of my way to avoid even implicit casts */

static LHead * iota(const int n)
{
  register int i;
  register LInt * p = (LInt *)0;
  for(i=0; i<n; i++)
  {
    LInt * p1 = (LInt *)calloc(1,sizeof(LInt));
    (p1->head).next = p == (LInt *)0 ? NIL : &(p->head);
    (p1->head).type_tag = LInt_type;
    p1->datum = i;
    p = p1;
  }
  return p == (LInt *)0 ? NIL : &(p->head);
}

/* List of strings */
typedef struct s_LStr {
  LHead head;
  const char * datum;
} LStr;

#define LStr_type 2

/* List of numbers 0 .. n-1 in their ASCII representation */
static LHead * iota_str(const int n)
{
  register int i;
  register LStr * p = (LStr *)0;
  char buffer [40];		/* enough for MAXINT */
  for(i=0; i<n; i++)
  {
    LStr * p1 = (LStr *)calloc(1,sizeof(LStr));
    (p1->head).next = p == (LStr *)0 ? NIL : &(p->head);
    (p1->head).type_tag = LStr_type;
    snprintf(buffer,sizeof(buffer)-1, "%d",i);
    p1->datum = strdup(buffer);
    p = p1;
  }
  return p == (LStr *)0 ? NIL : &(p->head);
}


#define PR_TEST(X) printf("Length of " #X " is %d\n",length(X))

int main(void)
{
  printf("Testing Polymorphic lists\n\n");
  PR_TEST(NIL);
  PR_TEST(iota(5));
  PR_TEST(iota_str(42));
  return 0;
}
