/* Copyright Per Bothner 1987. Read the file Q-INFO */
#ifndef HASH_H
#define HASH_H
#ifdef __GNUG__
#pragma interface
#endif

struct HashArray {
    unsigned char element_len;
    unsigned char element_len_log;
    unsigned char tab_len_log;
    unsigned char flags;
    struct HashFuncs *f;
    int cur_size;
    RootPtr *data;
    void initialize(int init_size, int el_size);
    HashArray() { }
    HashArray(int init_size, int el_size) { initialize(init_size, el_size); }
    
    void insert(void** data); // Key is data[0].
    void** remove(void* arg);
    // rehash_if_needed increments cur_size, and rehashes if over 7/8 full.
    void rehash_if_needed();
    void rehash();
};

struct HashTable : public HashArray {
  HashTable() { }
  HashTable(int init_size, void * defaultVal = 0); // el_size==8.
  static HashTable* New(int n, Root* defaultVal = 0);
};

#define FailedSearch(arg) (arg == 0 || arg == NoValue || False(arg))
#define SymbInTab(s) (_RefCount(s) == RefsInfinity)

#define HASH_WORD_LEN 16

#define DoForEachInTab(tab, action)			\
  { register HashTable *__tab__ = tab;		\
    register RootPtr *__element__ = __tab__->data;	\
    register __i__ = 1<<__tab__->tab_len_log;		\
    for (; __i__ > 0; __i__--,				\
       __element__ = (RootPtr*)((char*)__element__+__tab__->element_len))\
        if (!HashNone(*__element__))			\
	  { action(__element__[0], __element__[1]); } }


/* a hash element is element_len bytes long, and begins with a symbol pointer */
#define HashNull NULL
#define HashDeleted ((Object)1)
#define HashNone(x) ((unsigned)(x) <= 1) /*i.e. either HashNull or HashDeleted*/
#define NULLARG (Object)HashNull

/* flags bits */
#define HashSymbolsOnly 1
#define HashDefaultIsProc 2 /* get default as Apply(arg, default) */
#define HashDontFreeBuffer 4 // The data buffer may be statically allocated,
    // so don't free it when re-hasing or deleting.
/* *** NOTE when deleting, symbol should remain for faster searching !!! */

typedef void *(*LookupFunc)(struct HashArray *, void *);

struct HashFuncs {
    void *defaultVal;
    LookupFunc lookup;
    unsigned (* hash_it)(void*arg);
};
extern struct HashFuncs StdHashFuncs, IdentHashFuncs;
EXTERN void *Search(struct HashTable *tab, RootPtr arg);
EXTERN void Insert(struct HashTable *tab, const RootPtr arg, const void * val);
EXTERN void * SymbolLookup (struct HashArray *, void* arg);

extern unsigned HashAddr(void * addr);
#endif /* HASH_H */
