Sophie

Sophie

distrib > Mandriva > 2007.1 > i586 > by-pkgid > d483a12b90c5fa54128e77aa96863de6 > files > 18

libghthash0-devel-0.6.1-1mdv2007.1.i586.rpm

/*********************************************************************
 *
 * Copyright (C) 2002-2005,  Simon Kagstrom
 *
 * Filename:      alloc_example.c
 * Description:   A program that demonstrates the use of custom
 *                allocation functions.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 * $Id: alloc_example.c 8461 2006-06-04 08:13:06Z ska $
 *
 ********************************************************************/

#include <stdlib.h>    /* malloc */
#include <string.h>    /* strncpy */
#include <unistd.h>    /* ssize_t */
#include <stdio.h>     /* File reading etc. */
#include <sys/types.h> /* stat */
#include <sys/stat.h>  /* stat */
#include <assert.h>    /* assert */
#include <stddef.h>

#include "ght_hash_table.h"

/* Delimiters between words */
#define DELIMS " \".,;:?!-\'/*()=+&%[]#$\n\r"

#define NR_ELEMS 30
#define ELEM_SIZE (sizeof(ght_hash_entry_t)+sizeof(int))

/*
 * The allocation function calls the normal malloc to get a large
 * allocation chunks of many elements, and then hands these out on
 * alloc() calls.
 *  1               NR_ELEMS
 *  ____________..___
 * |  |XX|  |  |  |XX|
 * |__|XX|__|__|..|XX|
 *        ...   _____\____ Already used elements
 *  ___________/..___
 * |  |  |XX|XX|  |  |
 * |__|__|XX|XX|..|__|
 *
 * The trick we use here is that we know the size of the allocations,
 * which is just the entries plus the size of the key, the allocation
 * function can therefore be made simple and fast.
 *
 * Please note that this example might be pretty unrealistic, since it
 * does not really use the table in a meaningful way. Also, this is a
 * demonstration of custom allocators, not a thought-through malloc
 * implementation. I'm actually not even sure it really works ;-)
 */

/* A structure for the returned data from malloc */
typedef struct
{
  char elem[ELEM_SIZE];
  int  nr;
} elem_t;

/* One allocation chunk */
typedef struct s_alloc
{
  elem_t          elems[NR_ELEMS];
  ght_uint32_t    bitmask;
  struct s_alloc *p_next;
  struct s_alloc *p_prev;
} alloc_t;

alloc_t *p_freelist=NULL;


/* The allocate function to use */
void *my_alloc(size_t size)
{
  int i;

  assert(size == ELEM_SIZE);

  /* No free chunks, allocate a new one */
  if ( !p_freelist )
    {
      if ( !(p_freelist = (alloc_t*)malloc(sizeof(alloc_t))) )
	return (void*)NULL;
      memset(p_freelist, 0, sizeof(alloc_t));
    }

  /* Find a free entry */
  for (i=0; i<NR_ELEMS; i++)
    {
      if ( (p_freelist->bitmask & (1<<i)) == 0)
	{
	  void *p_ret = (void*)&p_freelist->elems[i].elem;

	  /* Found a free spot */
	  p_freelist->bitmask |= (1<<i);
	  p_freelist->elems[i].nr = i;

	  if ( p_freelist->bitmask == (1<<NR_ELEMS)-1 )
	    p_freelist = p_freelist->p_next; /* This entry is full */

	  return p_ret;
	}
    }

  /* We cannot be here */
  return NULL;
}

/* The free function to use */
void my_free(void *p)
{
  elem_t *p_elem = (elem_t *)p;
  alloc_t *p_alloc = (alloc_t*) (p_elem-p_elem->nr);

  if ( (p_alloc->bitmask & ((1<<NR_ELEMS)-1) ) == ((1<<NR_ELEMS)-1) )
    {
      /* There were no free elements here before, insert first into freelist */
      p_alloc->p_next = p_freelist;
      p_alloc->p_prev = NULL;
      p_freelist->p_prev = p_alloc;
      p_freelist = p_alloc;
    }
  else if ( p_alloc->bitmask == ((unsigned int)1<<p_elem->nr) )
    {
      alloc_t *p_prev = p_alloc->p_prev;
      alloc_t *p_next = p_alloc->p_next;

      /* There was only one entry (now removed), free this chunk */
      if (p_prev)
	p_prev->p_next = p_next;
      else
	p_freelist = p_next; /* First in list */

      if (p_next)
	p_next->p_prev = p_prev;

      free(p_alloc);

      return;
    }

  /* There are some free, some non-free entries. Mark this as free. */
  p_alloc->bitmask &= ~(1<<p_elem->nr);
}

/*
 * This is an example program that reads words from a text-file (a
 * book or something like that) and uses those as data in a hash
 * table. The words are case sensitive.
 *
 * The meaning with this program is to test the speed of the table and
 * to provide an example of its use.
 */
int main(int argc, char *argv[])
{
  FILE *p_file;
  char *p_dict_name;
  ght_hash_table_t *p_table;
  ght_iterator_t iterator;
  struct stat stat_struct;
  int i_std_malloc=0;
  int i_cnt;
  char *p_buf;
  char *p_tok;
  const void *p_key;
  void *p_e;

  /* Create a new hash table */
  if ( !(p_table = ght_create(1000)) )
    {
      return 1;
    }
  ght_set_rehash(p_table, TRUE);

  /* Parse the arguments */
  if (argc < 2)
    {
      printf("Usage: alloc_example [-m|-t|-s] textfile\n");
      return 0;
    }
  else if (argc > 2)
    {
      if(strcmp(argv[1], "-m"))
	ght_set_heuristics(p_table, GHT_HEURISTICS_MOVE_TO_FRONT);
      else if(strcmp(argv[1], "-t"))
	ght_set_heuristics(p_table, GHT_HEURISTICS_TRANSPOSE);
      p_dict_name = argv[2];
    }
  else
    {
      /* 2 arguments */
      p_dict_name = argv[1];
    }

  /* Set the allocation/deallocation functions for the table */
  if (!i_std_malloc)
    {
      ght_set_alloc(p_table, my_alloc, my_free);
    }

  /* Open the dictionary file (first check its size) */
  if (stat(p_dict_name, &stat_struct) < 0)
    {
      perror("stat");
      return 1;
    }
  if (!(p_buf = (char*)malloc(stat_struct.st_size)))
    {
      perror("malloc");
      return 1;
    }

  /* Open the dictionary file and read that into the buffer. */
  if (! (p_file = fopen(p_dict_name, "r")) )
    {
      perror("fopen");
      return 1;
    }
  fread(p_buf, sizeof(char), stat_struct.st_size, p_file);
  fclose(p_file);

  /* For each word in the dictionary file, insert it into the hash table. */
  p_tok = strtok(p_buf, DELIMS);
  i_cnt = 0;
  while (p_tok)
    {
      char *p_data;

      if ( !(p_data = (char*)malloc( strlen(p_tok)+1 )) )
	{
	  perror("malloc");
	  return 1;
	}
      strcpy(p_data, p_tok);
      p_data[strlen(p_tok)] = '\0';

      /* Insert the word into the table */
      if (ght_insert(p_table,
		     p_data,
		     sizeof(int), &i_cnt) < 0)
	{
	  free(p_data); /* Could not insert the item (already exists), free it. */
	}

      p_tok = strtok(NULL, DELIMS);
      i_cnt++;
    }
  printf("Done reading %d words from the wordlist.\n", i_cnt);

  free(p_buf);

  /* Free the entry data in the table */
  for(p_e = ght_first(p_table, &iterator, &p_key); p_e; p_e = ght_next(p_table, &iterator, &p_key))
    {
      free(p_e);
    }

  /* Free the table */
  ght_finalize(p_table);

  return 0;
}