Blame lib/Xm/Hash.c

Packit b099d7
/* $XConsortium: Hash.c /main/6 1995/10/25 20:06:11 cde-sun $ */
Packit b099d7
/*
Packit b099d7
 * Motif
Packit b099d7
 *
Packit b099d7
 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
Packit b099d7
 *
Packit b099d7
 * These libraries and programs are free software; you can
Packit b099d7
 * redistribute them and/or modify them under the terms of the GNU
Packit b099d7
 * Lesser General Public License as published by the Free Software
Packit b099d7
 * Foundation; either version 2 of the License, or (at your option)
Packit b099d7
 * any later version.
Packit b099d7
 *
Packit b099d7
 * These libraries and programs are distributed in the hope that
Packit b099d7
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
Packit b099d7
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
Packit b099d7
 * PURPOSE. See the GNU Lesser General Public License for more
Packit b099d7
 * details.
Packit b099d7
 *
Packit b099d7
 * You should have received a copy of the GNU Lesser General Public
Packit b099d7
 * License along with these librararies and programs; if not, write
Packit b099d7
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
Packit b099d7
 * Floor, Boston, MA 02110-1301 USA
Packit b099d7
 */
Packit b099d7
/*
Packit b099d7
 * HISTORY
Packit b099d7
 */
Packit b099d7
Packit b099d7
#ifdef HAVE_CONFIG_H
Packit b099d7
#include <config.h>
Packit b099d7
#endif
Packit b099d7
Packit b099d7
Packit b099d7
#include "XmI.h"
Packit b099d7
#include "HashI.h"
Packit b099d7
Packit b099d7
#define FIX_1264
Packit b099d7
Packit b099d7
/* Private data structures */
Packit b099d7
Packit b099d7
typedef struct _XmHashBucketRec {
Packit b099d7
  XmHashValue		  hashed_key;
Packit b099d7
  XmHashKey		  hash_key;
Packit b099d7
  XtPointer		  value;
Packit b099d7
  struct _XmHashBucketRec *next;
Packit b099d7
} XmHashBucketRec, *XmHashBucket;
Packit b099d7
Packit b099d7
typedef struct _XmHashTableRec {
Packit b099d7
  Cardinal		size;
Packit b099d7
  Cardinal		count;
Packit b099d7
  XmHashCompareProc	compare;
Packit b099d7
  XmHashFunction	hasher;
Packit b099d7
  XmHashBucket		*buckets;
Packit b099d7
} XmHashTableRec;
Packit b099d7
Packit b099d7
/* Static functions */
Packit b099d7
static XmHashBucket NewBucket(void);
Packit b099d7
static void FreeBucket(XmHashBucket);
Packit b099d7
Packit b099d7
/* Static data */
Packit b099d7
Packit b099d7
static XmHashBucket FreeBucketList = NULL;
Packit b099d7
Packit b099d7
/* Dumb default hash functions */
Packit b099d7
Packit b099d7
static Boolean 
Packit b099d7
Compare(XmHashKey x, XmHashKey y)
Packit b099d7
{
Packit b099d7
  return(x == y);
Packit b099d7
}
Packit b099d7
Packit b099d7
static XmHashValue
Packit b099d7
Hash(XmHashKey x)
Packit b099d7
{
Packit b099d7
  return((XmHashValue) (long) x);
Packit b099d7
}
Packit b099d7
Packit b099d7
/* Available table sizes,  should be prime numbers */
Packit b099d7
Packit b099d7
static XmConst int size_table[] = 
Packit b099d7
	{ 17, 31, 67, 131, 257, 521, 1031, 2053, 4099, 8209, 0 };
Packit b099d7
Packit b099d7
XmHashTable
Packit b099d7
_XmAllocHashTable(Cardinal size_hint, XmHashCompareProc cproc, 
Packit b099d7
		  XmHashFunction hproc)
Packit b099d7
{
Packit b099d7
  XmHashTable   table;
Packit b099d7
  int		i;
Packit b099d7
Packit b099d7
  table = (XmHashTable) XtMalloc(sizeof(XmHashTableRec));
Packit b099d7
Packit b099d7
  if (hproc)
Packit b099d7
    table -> hasher = hproc;
Packit b099d7
  else
Packit b099d7
    table -> hasher = Hash;
Packit b099d7
Packit b099d7
  if (cproc)
Packit b099d7
    table -> compare = cproc;
Packit b099d7
  else
Packit b099d7
    table -> compare = Compare;
Packit b099d7
  
Packit b099d7
  i = 0;
Packit b099d7
Packit b099d7
  /* Search size_table for size which is bigger than size_hint */
Packit b099d7
  while(size_table[i] != 0 &&
Packit b099d7
	size_table[i] < size_hint) i++;
Packit b099d7
Packit b099d7
  if (size_table[i] == 0) i--;
Packit b099d7
Packit b099d7
  table -> size = size_table[i];
Packit b099d7
  table -> count = 0;
Packit b099d7
Packit b099d7
  /* Create the array of pointers */
Packit b099d7
  table->buckets = (XmHashBucket*) XtCalloc(table->size, sizeof(XmHashBucket));
Packit b099d7
Packit b099d7
  return(table);
Packit b099d7
}
Packit b099d7
Packit b099d7
void
Packit b099d7
_XmFreeHashTable(XmHashTable table)
Packit b099d7
{
Packit b099d7
  int i;
Packit b099d7
  XmHashBucket bucket, next;
Packit b099d7
Packit b099d7
  for(i = 0; i < table -> size; i++) {
Packit b099d7
    bucket = table -> buckets[i];
Packit b099d7
    while(bucket) {
Packit b099d7
      next = bucket -> next;
Packit b099d7
      FreeBucket(bucket);
Packit b099d7
      bucket = next;
Packit b099d7
    }
Packit b099d7
  }
Packit b099d7
Packit b099d7
  XtFree((char*) table -> buckets);
Packit b099d7
  XtFree((char*) table);
Packit b099d7
}
Packit b099d7
Packit b099d7
void
Packit b099d7
_XmResizeHashTable(XmHashTable table, Cardinal new_size)
Packit b099d7
{
Packit b099d7
  int i, index;
Packit b099d7
  int oldsize;
Packit b099d7
  XmHashBucket current, last, next, new_h;
Packit b099d7
Packit b099d7
  i = 0;
Packit b099d7
Packit b099d7
  /* Search size_table for size which is bigger than size_hint */
Packit b099d7
  while(size_table[i] != 0 &&
Packit b099d7
	size_table[i] < new_size) i++;
Packit b099d7
Packit b099d7
  if (size_table[i] == 0) i--;
Packit b099d7
Packit b099d7
  /* New size should be larger,  otherwise return */
Packit b099d7
  if (size_table[i] <= table -> size) return;
Packit b099d7
Packit b099d7
  /* Realloc table */
Packit b099d7
  oldsize = table -> size;
Packit b099d7
  table -> size = size_table[i];
Packit b099d7
  table -> buckets = 
Packit b099d7
    (XmHashBucket*) XtRealloc((char*) table -> buckets, 
Packit b099d7
			      table -> size * sizeof(XmHashBucket));
Packit b099d7
  /* NULL new array entries */
Packit b099d7
  for(i = oldsize; i < table -> size; i++) table -> buckets[i] = NULL;
Packit b099d7
Packit b099d7
  /* Rearrange buckets,  this is a slow method,  but always
Packit b099d7
     correct.  We will end up rescanning any moved buckets */
Packit b099d7
  for(i = 0; i < table -> size; i++) {
Packit b099d7
    last = NULL;
Packit b099d7
    current = table -> buckets[i];
Packit b099d7
    while(current) {
Packit b099d7
      /* If this bucket goes somewhere else,  remove 
Packit b099d7
	 from this chain and reinstall */
Packit b099d7
      next = current -> next;
Packit b099d7
      index = current -> hashed_key % table -> size;
Packit b099d7
      if (index != i) {
Packit b099d7
	if (last != NULL)
Packit b099d7
	  last -> next = current -> next;
Packit b099d7
	else
Packit b099d7
	  table -> buckets[i] = current -> next;
Packit b099d7
	/* Now put at end of new bucket chain,  we must do
Packit b099d7
	   this to maintain ordering */
Packit b099d7
	current -> next = NULL;
Packit b099d7
	new_h = table -> buckets[index];
Packit b099d7
	if (new_h != NULL) {
Packit b099d7
	  while(new_h -> next != NULL) 
Packit b099d7
	    new_h = new_h -> next;
Packit b099d7
	  new_h -> next = current;
Packit b099d7
	} else {
Packit b099d7
	  table -> buckets[index] = current;
Packit b099d7
	}
Packit b099d7
      }
Packit b099d7
#ifdef FIX_1264
Packit b099d7
      else last = current;
Packit b099d7
#endif
Packit b099d7
      current = next;
Packit b099d7
    }
Packit b099d7
  }
Packit b099d7
}
Packit b099d7
Packit b099d7
XtPointer
Packit b099d7
_XmGetHashEntryIterate(XmHashTable table, XmHashKey key, XtPointer *iterator)
Packit b099d7
{
Packit b099d7
  XmHashValue index;
Packit b099d7
  XmHashBucket entry;
Packit b099d7
Packit b099d7
  if (iterator && *iterator != NULL) {
Packit b099d7
    /* If iterating over a number of matching entries */
Packit b099d7
    entry = (XmHashBucket) *iterator;
Packit b099d7
    entry = entry -> next;
Packit b099d7
  } else { 
Packit b099d7
    /* Normal case */
Packit b099d7
    index = (table -> hasher(key)) % table -> size;
Packit b099d7
    entry = table -> buckets[index];
Packit b099d7
  }
Packit b099d7
Packit b099d7
  while(entry) {
Packit b099d7
    if (table -> compare(entry -> hash_key, key)) {
Packit b099d7
      if (iterator) *iterator = (XtPointer) entry;
Packit b099d7
      return(entry -> value);
Packit b099d7
    }
Packit b099d7
    entry = entry -> next;
Packit b099d7
  }
Packit b099d7
Packit b099d7
  if (iterator) *iterator = NULL;
Packit b099d7
  return(NULL);
Packit b099d7
}
Packit b099d7
Packit b099d7
void 
Packit b099d7
_XmAddHashEntry(XmHashTable table, XmHashKey key, XtPointer value)
Packit b099d7
{
Packit b099d7
  int hash;
Packit b099d7
  XmHashValue index;
Packit b099d7
  XmHashBucket entry;
Packit b099d7
Packit b099d7
  hash = table -> hasher(key);
Packit b099d7
  index = hash % table -> size;
Packit b099d7
Packit b099d7
  entry = NewBucket();
Packit b099d7
  entry -> hashed_key = hash;
Packit b099d7
  entry -> hash_key = key;
Packit b099d7
  entry -> value = value;
Packit b099d7
  entry -> next = table -> buckets[index];
Packit b099d7
  table -> buckets[index] = entry;
Packit b099d7
  table -> count++;
Packit b099d7
}
Packit b099d7
Packit b099d7
XtPointer
Packit b099d7
_XmRemoveHashEntry(XmHashTable table, XmHashKey key)
Packit b099d7
{
Packit b099d7
  XmHashValue index;
Packit b099d7
  XmHashBucket entry, last = NULL;
Packit b099d7
Packit b099d7
  index = (table -> hasher(key)) % table -> size;
Packit b099d7
Packit b099d7
  entry = table -> buckets[index];
Packit b099d7
  while(entry) {
Packit b099d7
    if (table -> compare(entry -> hash_key, key)) {
Packit b099d7
      if (last == NULL) {
Packit b099d7
	/* First entry is handled differently */
Packit b099d7
	table -> buckets[index] = entry -> next;
Packit b099d7
      } else {
Packit b099d7
	last -> next = entry -> next;
Packit b099d7
      }
Packit b099d7
Packit b099d7
      table -> count--;
Packit b099d7
      FreeBucket(entry);
Packit b099d7
      return(entry -> hash_key);
Packit b099d7
    }
Packit b099d7
    last = entry;
Packit b099d7
    entry = entry -> next;
Packit b099d7
  }
Packit b099d7
  return(NULL);
Packit b099d7
}
Packit b099d7
Packit b099d7
XtPointer 
Packit b099d7
_XmRemoveHashIterator(XmHashTable table, XtPointer *iterator)
Packit b099d7
{
Packit b099d7
  XmHashValue index;
Packit b099d7
  XmHashBucket entry, current, last = NULL;
Packit b099d7
Packit b099d7
  if (! iterator) return(NULL);
Packit b099d7
Packit b099d7
  entry = (XmHashBucket) *iterator;
Packit b099d7
Packit b099d7
  index = (table -> hasher(entry -> hash_key)) % table -> size;
Packit b099d7
Packit b099d7
  current = table -> buckets[index];
Packit b099d7
Packit b099d7
  while(current) {
Packit b099d7
    if (current == entry) {
Packit b099d7
      if (last == NULL) {
Packit b099d7
	/* First entry is handled differently */
Packit b099d7
	table -> buckets[index] = current -> next;
Packit b099d7
      } else {
Packit b099d7
	last -> next = current -> next;
Packit b099d7
      }
Packit b099d7
Packit b099d7
      table -> count--;
Packit b099d7
      FreeBucket(current);
Packit b099d7
      return(current -> hash_key);
Packit b099d7
    }
Packit b099d7
    last = current;
Packit b099d7
    current = current -> next;
Packit b099d7
  }
Packit b099d7
  return(NULL);
Packit b099d7
}
Packit b099d7
Packit b099d7
Cardinal
Packit b099d7
_XmHashTableCount(XmHashTable table)
Packit b099d7
{
Packit b099d7
  return(table -> count);
Packit b099d7
}
Packit b099d7
Packit b099d7
Cardinal
Packit b099d7
_XmHashTableSize(XmHashTable table)
Packit b099d7
{
Packit b099d7
  return(table -> size);
Packit b099d7
}
Packit b099d7
Packit b099d7
/****************************************************************/
Packit b099d7
/* _XmMapHashTable(table, proc, client_data)			*/
Packit b099d7
/* Iterate over entire hash table.  Mostly useful for debugging */
Packit b099d7
/* code using hash tables.					*/
Packit b099d7
/****************************************************************/
Packit b099d7
Packit b099d7
void 
Packit b099d7
_XmMapHashTable(XmHashTable table, XmHashMapProc proc, XtPointer client_data)
Packit b099d7
{
Packit b099d7
  int i;
Packit b099d7
  XmHashBucket entry, next;
Packit b099d7
Packit b099d7
  for(i = 0; i < table -> size; i++) {
Packit b099d7
    entry = table -> buckets[i];
Packit b099d7
    while(entry) {
Packit b099d7
      /* Can free key and value in this proc */
Packit b099d7
      next = entry -> next;
Packit b099d7
Packit b099d7
      /* Terminate processing if the XmHashMapProc return True. */
Packit b099d7
      if (proc (entry -> hash_key, entry -> value, client_data))
Packit b099d7
	return;
Packit b099d7
Packit b099d7
      entry = next;
Packit b099d7
    }
Packit b099d7
  }
Packit b099d7
}
Packit b099d7
Packit b099d7
/* Bucket management */
Packit b099d7
#define NUMBUCKETS 256
Packit b099d7
Packit b099d7
static XmHashBucket 
Packit b099d7
NewBucket(void)
Packit b099d7
{
Packit b099d7
  XmHashBucket rbucket;
Packit b099d7
  XmHashBucket buckets;
Packit b099d7
  int i;
Packit b099d7
Packit b099d7
  if (FreeBucketList == NULL) {
Packit b099d7
    /* Allocate alot of buckets at once to cut down on fragmentation */
Packit b099d7
    buckets = (XmHashBucket) XtMalloc(NUMBUCKETS * sizeof(XmHashBucketRec));
Packit b099d7
Packit b099d7
    /* Chain them together */
Packit b099d7
    for(i = 0; i < NUMBUCKETS; i++) buckets[i].next = &buckets[i+1];
Packit b099d7
Packit b099d7
    /* The last points to nothing */
Packit b099d7
    buckets[NUMBUCKETS - 1].next = (XmHashBucket) NULL;
Packit b099d7
Packit b099d7
    FreeBucketList = buckets;
Packit b099d7
  }
Packit b099d7
Packit b099d7
  rbucket = FreeBucketList;
Packit b099d7
  FreeBucketList = FreeBucketList -> next;
Packit b099d7
Packit b099d7
  return(rbucket);
Packit b099d7
}
Packit b099d7
Packit b099d7
static void
Packit b099d7
FreeBucket(XmHashBucket b)
Packit b099d7
{
Packit b099d7
  b -> next = FreeBucketList;
Packit b099d7
  FreeBucketList = b;
Packit b099d7
}
Packit b099d7
Packit b099d7
Packit b099d7
#ifdef DEBUG
Packit b099d7
Packit b099d7
void
Packit b099d7
_XmPrintHashTable(XmHashTable table)
Packit b099d7
{
Packit b099d7
  int i, max, total_in_use;
Packit b099d7
  int count;
Packit b099d7
  XmHashBucket entry;
Packit b099d7
Packit b099d7
  max = 0;
Packit b099d7
  total_in_use = 0;
Packit b099d7
Packit b099d7
  printf("size %d hash function %lx compare function %lx\n",
Packit b099d7
	 table->size, (unsigned long) table->hasher, 
Packit b099d7
	 (unsigned long) table->compare);
Packit b099d7
Packit b099d7
  for (i = 0; i < table -> size; i++) {
Packit b099d7
    entry = table -> buckets[i];
Packit b099d7
    count = 0;
Packit b099d7
    while(entry) {
Packit b099d7
      count++;
Packit b099d7
      entry = entry -> next;
Packit b099d7
    }
Packit b099d7
    if (count > 0) total_in_use++;
Packit b099d7
    if (count > max) max = count;
Packit b099d7
  }
Packit b099d7
Packit b099d7
  printf("total entries %d\n", table -> count);
Packit b099d7
  printf("total bucket chains in use %d or %d percent\n", total_in_use,
Packit b099d7
	 (total_in_use * 100)/table -> size);
Packit b099d7
  printf("bucket chain length %d average / %d max\n",
Packit b099d7
	 table -> count / total_in_use, max);
Packit b099d7
}
Packit b099d7
Packit b099d7
#endif