/* Copyright (c) 1993 Stephen F. White */

#include "cool.h"
#include "proto.h"

static int size_methods (HashT * methods);
static int size_verbs (Verbdef * vb);
static int size_gvars (HashT * vars);
static int size_vars (Vardef * vd);
static int size_var (Var v);
static int size_list (List * list);
static int size_map (Map * map);
static int size_symbols (Object * o);
static int size_locks (Lock * l);

#define size_string(S) (sizeof((S)->len) + (S)->len)

int size_object (Object * o)
{
  int sz = 0;

  sz += sizeof (o->id.id) + sizeof (o->id.server);
  sz += size_list (o->parents);
  sz += size_symbols (o);
  sz += size_methods (o->methods);
  sz += size_gvars (o->vars);
  sz += size_verbs (o->verbs);
  sz += size_locks (o->locks);
  return sz;
}

static int size_methods (HashT * methods)
{
  int hval, sz = sizeof (int);  /* for nmethods */
  Method *m;

  if (methods) {
    for (hval = 0; hval < methods->size; hval++) {
      for (m = (Method *) methods->table[hval]; m; m = m->next) {
        sz += sizeof (m->name);
        sz += sizeof (unsigned char);   /* for blocked flag */
        sz += sizeof (m->ninst) + m->ninst * sizeof (Inst);
        sz += sizeof (int);     /* for nvars */
        sz += NERRS * sizeof (enum eh) + size_vars (m->vars);
      }
    }
  }
  return sz;
}

static int size_verbs (Verbdef * vb)
{
  int sz = sizeof (int);        /* for nverbs */

  for (; vb; vb = vb->next) {
    sz += 3 * sizeof (int);
  }
  return sz;
}

static int size_vars (Vardef * vd)
{
  int sz = 0;

  for (; vd; vd = vd->next) {
    sz += sizeof (vd->name) + size_var (vd->value);
  }
  return sz;
}

static int size_gvars (HashT * vars)
{
  int sz = sizeof (int);        /* for nvars */
  int hval;

  if (vars) {
    for (hval = 0; hval < vars->size; hval++) {
      sz += size_vars (vars->table[hval]);
    }
  }
  return sz;
}

static int size_var (Var v)
{
  switch (v.type) {
  case STR:
    /* 2 == 1 for string terminator, 1 for type */
    return size_string (v.v.str) + 1;
  case NUM:
    return sizeof (v.v.num) + 1;
  case OBJ:
    return sizeof (v.v.obj.id) + sizeof (v.v.obj.server) + 1;
  case LIST:
    return size_list (v.v.list) + 1;
  case MAP:
    return size_map (v.v.map) + 1;
  case ERR:
    return sizeof (v.v.err) + 1;
  case PC:                     /* should never happen */
    return 0;
  }
  return 0;                     /* should never happen */
}

static int size_list (List * list)
{
  int i, sz = sizeof (list->len);       /* size of nels */

  for (i = 0; i < list->len; i++) {
    sz += size_var (list->el[i]);
  }
  return sz;
}

static int size_map (Map * map)
{
  int i, sz = sizeof (map->num);        /* size of nels */
  MapPair *pair;

  for (i = 0; i < map->size; i++) {
    for (pair = map->table[i]; pair; pair = pair->next) {
      sz += size_var (pair->from);
      sz += size_var (pair->to);
    }
  }
  return sz;
}

static int size_symbols (Object * o)
{
  int i, sz = sizeof (o->nsymb) + sizeof (o->st_size);

  for (i = 0; i < o->nsymb; i++) {
    sz += sizeof (o->symbols[i].ref);
    if (o->symbols[i].ref) {
      sz += size_string (o->symbols[i].s);
    }
  }
  return sz;
}

static int size_locks (Lock * l)
{
  int sz = sizeof (int);        /* for nlocks */

  for (; l; l = l->next) {
    sz += size_string (l->name);
    sz += sizeof (l->added_by);
  }
  return sz;
}