#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include "sstr.h"

void oom();

struct sstr {
  unsigned used;
  struct sstr *next;
  char str[1];
};

static struct sstr *sl, *last;
unsigned used, strs, ents;
unsigned tlen, elen;
unsigned alcs, frees;
#include <stdio.h>
void sstrstat() {
  printf("strings: %u ents: %u maxused: %u, tlen=%u elen=%u, alcs=%u frees=%u\n",
		  strs, ents, used, tlen, elen, alcs, frees);
}

char *sstrdup(const char *str) {
  struct sstr *s;
  ++strs; tlen += strlen(str); ++alcs;
  if (last && strcmp(last->str, str) == 0) {
    if (used < ++last->used) used = last->used;
    return last->str;
  }
  for(s = sl; s; s = s->next)
    if (strcmp(str, s->str) == 0) {
      last = s;
      if (used < ++s->used) used = s->used;
      return s->str;
    }
  s = (struct sstr*)malloc(sizeof(*s) + strlen(str));
  if (!s) {
    oom();
    return NULL;
  }
  strcpy(s->str, str);
  s->used = 1;
  s->next = sl;
  sl = last = s;
  ++ents; elen += strlen(str);
  return s->str;
}

void sstrfree(char *str) {
  struct sstr *s;
  --strs; tlen -= strlen(str); ++frees;
  s = (struct sstr *)(str - offsetof(struct sstr, str));
  if (--s->used != 0) return;
  if (s == sl)
    sl = s->next;
  else {
    struct sstr *p = sl;
    while(p->next != s)
      if (!p->next) abort();
      else p = p->next;
    p->next = s->next;
  }
  free(s);
  if (last == s) last = NULL;
  --ents; elen -= strlen(str);
}
