
/******************************************************************************
* MODULE     : hashmap.gen.cc
* DESCRIPTION: fixed size hashmaps with reference counting
* COPYRIGHT  : (C) 1999  Joris van der Hoeven
*******************************************************************************
* This software falls under the GNU general public license and comes WITHOUT
* ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
* If you don't have this file, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
******************************************************************************/

#include <hashmap.gen.h>
#include <list.gen.cc>

#module code_hashmap (T,U)
#import hashmap (T,U)

/******************************************************************************
* Hashmap entries
******************************************************************************/

#define test1<T>
#define test2<U>
#define test<T,U>
#define H hashentry<T,U>

H::H (T key2, U im2): key (key2), im (im2) {}

H::operator tree () {
#ifdef no_tree_converter<T>
#ifdef no_tree_converter<U>
  return tree (ASSOCIATE, "?", "?");
#else
  return tree (ASSOCIATE, "?", (tree) im);
#endif
#else
#ifdef no_tree_converter<U>
#ifdef test1<identifier>
  return tree (ASSOCIATE, key.operator tree (), "?");
#else
  return tree (ASSOCIATE, (tree) key, "?");
#endif
#else
#ifdef test1<identifier>
  return tree (ASSOCIATE, key.operator tree (), (tree) im);
#else
  return tree (ASSOCIATE, (tree) key, (tree) im);
#endif
#endif
#endif
}

ostream&
operator << (ostream& out, H h) {
  out << h.key << "->" << h.im;
  return out;
}

bool
operator == (H h1, H h2) {
  return (h1.key==h2.key) && (h1.im==h2.im);
}

bool
operator != (H h1, H h2) {
  return (h1.key!=h2.key) || (h1.im!=h2.im);
}

/******************************************************************************
* Routines for hashmaps
******************************************************************************/

#import code_list (hashentry<T,U>)

void
hashmap_rep<T,U>::resize (int n2) {
  int i;
  int oldn= n;
  list<hashentry<T,U>>* olda= a;
  n= n2;
  a= new list<hashentry<T,U>>[n];
  for (i=0; i<oldn; i++) {
    list<hashentry<T,U>> l(olda[i]);
    while (!nil (l)) {
      list<hashentry<T,U>>& newl(a[hash(l->item.key)&(n-1)]);
      newl= list<hashentry<T,U>> (l->item, newl);
      l=l->next;
    }
  }
  delete[] olda;
}

bool
hashmap_rep<T,U>::contains (T x) {
  list<hashentry<T,U>>  l (a[hash(x)&(n-1)]);
  while (!nil (l)) {
    if (l->item.key==x) return TRUE;
    l= l->next;
  }
  return FALSE;
}

bool
hashmap_rep<T,U>::empty () {
  return size==0;
}

U&
hashmap_rep<T,U>::bracket_rw (T x) {
  register int hv= hash(x);
  list<hashentry<T,U>>  l (a[hv&(n-1)]);
  while (!nil (l)) {
    if (l->item.key==x) return l->item.im;
    l= l->next;
  }
  if (size>=n*max) resize (n<<1);
  list<hashentry<T,U>>& rl (a[hv&(n-1)]);
  rl= list<hashentry<T,U>> (H (x, init), rl);
  size ++;
  return rl->item.im;
}

U
hashmap_rep<T,U>::bracket_ro (T x) {
  list<hashentry<T,U>>  l (a[hash(x)&(n-1)]);
  while (!nil (l)) {
    if (l->item.key==x) return l->item.im;
    l= l->next;
  }
  return init;
}

void
hashmap_rep<T,U>::reset (T x) {
  list<hashentry<T,U>> *l= &(a[hash(x)&(n-1)]);
  while (!nil (*l)) {
    if ((*l)->item.key==x) {
      *l=(*l)->next;
      size --;
      if (size<(n>>1)*max) resize (n>>1);
      return;
    }
    l= &((*l)->next);
  }
}

void
hashmap_rep<T,U>::generate (void (*routine) (T)) {
  int i;
  for (i=0; i<n; i++) {
    list<hashentry<T,U>> l (a[i]);
    while (!nil (l)) {
      routine (l->item.key);
      l=l->next;
    }
  }
}

ostream&
operator << (ostream& out, hashmap<T,U> H) {
  int i=0, j=0, n=H->n, size=H->size;
  out << "{ ";
  for (; i<n; i++) {
    list<hashentry<T,U>> l=H->a[i];
    for (; !nil(l); l=l->next, j++) {
      out << l->item;
      if (j!=size-1) out << ", ";
    }
  }
  out << " }";
  return out;
}

hashmap<T,U>::operator tree () {
  int i=0, j=0, n=rep->n, size=rep->size;
  tree t (COLLECTION, size);
  for (; i<n; i++) {
    list<hashentry<T,U>> l=rep->a[i];
    for (; !nil(l); l=l->next, j++)
      t[j]= (tree) l->item;
  }
  return t;
}

#ifndef test2<tree>
#define copy(x) x
#endif

void
hashmap_rep<T,U>::join (hashmap<T,U> H) {
  int i=0, n=H->n;
  for (; i<n; i++) {
    list<hashentry<T,U>> l=H->a[i];
    for (; !nil(l); l=l->next)
      bracket_rw (l->item.key)= copy (l->item.im);
  }
}

#ifndef test2<tree>
#undef copy
#endif

#if defined(test<string,tree>) || defined (test<string,path>)
bool
operator == (hashmap<T,U> h1, hashmap<T,U> h2) {
  if (h1->size != h2->size) return FALSE;
  int i=0, n=h1->n;
  for (; i<n; i++) {
    list<hashentry<T,U>> l=h1->a[i];
    for (; !nil(l); l=l->next)
      if (h2[l->item.key] != l->item.im) return FALSE;
  }
  return TRUE;
}

bool
operator != (hashmap<T,U> h1, hashmap<T,U> h2) {
  return !(h1 == h2);
}
#endif

#undef H
#undef test<T,U>
#undef test2<U>
#undef test1<T>

#endmodule // code_hashmap (T,U)
