/* Copyright (C) 2003 Nadav Har'El and Dan Kenigsberg */

#ifndef INCLUDED_HASH_H
#define INCLUDED_HASH_H

#include <stdlib.h>

/* we use tclHash.[ch] to implement the following API:

   typedef ...hspell_hash;
   void hspell_hash_init(hspell_hash *p);
   void hspell_hash_incr_int(hspell_hash *hashp, const char *key);

   typedef struct {
      const char *key;
      int value;
   } hspell_hash_keyvalue;
   hspell_hash_keyvalue *hspell_hash_build_keyvalue_array(hspell_hash *h,
                                                          int *size);
   void hspell_hash_free_keyvalue_array(hspell_hash *h, int size,
                                        hspell_hash_keyvalue *p);
   int hspell_hash_exists(hspell_hash *hashp, const char *key)
*/
#include "tclHash.h"

typedef Tcl_HashTable hspell_hash;

inline void hspell_hash_init(hspell_hash *p)
{
	Tcl_InitHashTable(p, TCL_STRING_KEYS);
}

/* hspell_hash_incr_int increments the integer value (we assume) stored
   for the key. If there is no value for this key yet, it is initialized
   to zero and then incremented to 1.
*/
inline void hspell_hash_incr_int(hspell_hash *hashp, const char *key)
{
	Tcl_HashEntry *e;
	int isnew;

	e=Tcl_CreateHashEntry(hashp, key, &isnew);

	/* Increment the value, as a an integer. We don't to cast the
	   address of clientData to another type in fear we'll write too
	   much, so we need explicit assignment and cast of the values:
	*/
	Tcl_SetHashValue(e, ((int)Tcl_GetHashValue(e))+1);
}

/* hspell_hash_exists returns 0 if there is no value for this key yet, 1
   otherwise.
*/
inline int hspell_hash_exists(hspell_hash *hashp, const char *key)
{
	Tcl_HashEntry *e;
	e=Tcl_FindHashEntry(hashp, key);
	return e ? 1 : 0;
}

typedef struct {
       	const char *key;
	int value;
} hspell_hash_keyvalue;

/* Hspell_hash_build_keyvalue_vector builds an array of keys and values
   from the given hash table.  Note that the keys are pointers to strings
   that sit inside the hash table, so they are only valid until the next
   time some key is deleted from the hash-table (or the hash table itself
   is deleted.
   This function return a pointer which the caller should free with
   hspell_hash_free_keyvalue_array(). 
*/
inline hspell_hash_keyvalue *hspell_hash_build_keyvalue_array(hspell_hash *h,
							      int *size)
{
	Tcl_HashEntry *e;
	Tcl_HashSearch s;
	hspell_hash_keyvalue *array, *arrayp, *arrayend;

	if(!h->numEntries){
		*size=0;
		return 0;
	}

	array=(hspell_hash_keyvalue *)
		malloc(h->numEntries*sizeof(hspell_hash_keyvalue));

	arrayp=array; /* moving pointer */
	arrayend=array+h->numEntries; /* pointer past end */

	for(e=Tcl_FirstHashEntry(h, &s); e; e=Tcl_NextHashEntry(&s)){
		if(arrayp>=arrayend){
			/* this cannot happen... */
			fprintf(stderr, "Internal error: allocated array of "
				"incorrect size. Truncating it.\n");
			break;
		}
		arrayp->key=Tcl_GetHashKey(h, e);
		arrayp->value=(int)Tcl_GetHashValue(e);
		arrayp++;
	}
	if(arrayp!=arrayend){
		/* this cannot happen... */
		fprintf(stderr, "Internal error: allocated array of incorrect"
			" size. Wasted space.\n");
		*size=(arrayp-array);
	} else
		*size=h->numEntries;

	return array;
}

inline void hspell_hash_free_keyvalue_array(hspell_hash *h, int size,
					    hspell_hash_keyvalue *p)
{
	if(p)
		free(p);
}

/* The following functions also keep integer values in the hash table.
   These values must be small enough to fit in the flatform's pointer
   (on modern machines, this is not a problem - pointers are usually
   as large, or even larger, than integers). These functions are useful for
   Hspell's "-n" option, for example.
   The get function returns 0 on failure, and 1 on success with the value
   put in the given pointer.
*/
inline int hspell_hash_get_int(hspell_hash *hashp, const char *key,
			       int *value)
{
	Tcl_HashEntry *e;

	if(!(e=Tcl_FindHashEntry(hashp, key)))
		return 0;
	*value=(int)Tcl_GetHashValue(e);
	return 1;
}

inline void hspell_hash_set_int(hspell_hash *hashp, const char *key,
				int value)
{
	Tcl_HashEntry *e;
	int isnew;

	e=Tcl_CreateHashEntry(hashp, key, &isnew);
	Tcl_SetHashValue(e, value);
}

#endif /* INCLUDED_HASH_H */


syntax highlighted by Code2HTML, v. 0.9.1