File: hash.c

package info (click to toggle)
iqtree 1.5.3%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 9,780 kB
  • ctags: 11,529
  • sloc: cpp: 96,162; ansic: 59,874; python: 242; sh: 189; makefile: 45
file content (219 lines) | stat: -rw-r--r-- 6,714 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
/** 
 * PLL (version 1.0.0) a software library for phylogenetic inference
 * Copyright (C) 2013 Tomas Flouri and Alexandros Stamatakis
 *
 * Derived from 
 * RAxML-HPC, a program for sequential and parallel estimation of phylogenetic
 * trees by Alexandros Stamatakis
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 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 General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * For any other enquiries send an Email to Tomas Flouri
 * Tomas.Flouri@h-its.org
 *
 * When publishing work that uses PLL please cite PLL
 * 
 * @file hash.c
 */
#include <stdio.h>
#include <string.h>
#include "pll.h"
#include "mem_alloc.h"

static const unsigned int initTable[] = 
  {
    53,         97,         193,       389,       769,    
    1543,       3079,       6151,      12289,     24593, 
    49157,      98317,      196613,    393241,    786433, 
    1572869,    3145739,    6291469,   12582917,  25165843, 
    50331653,   100663319,  201326611, 402653189, 805306457, 
    1610612741, 3221225473, 4294967291
  };
       
/** @brief Generate the hash value for a string 

    Generates the hash value of a string \a s.

    @param s     The string to compute the hash for
    @param size  Size of the hash table
    @return      String hash \a s, i.e. index in hash table
*/
unsigned int pllHashString (const char * s, unsigned int size)
{
  unsigned int hash = 0;

  for (; *s; ++s) hash = (hash << 5) - hash + (unsigned int )*s;

  return (hash % size);
}

/** @brief Add a string and its data to a hashtable
    
    Add an \a item and possibly a string \a s to hashtable \a hTable at position
    \a hash, where \a hash must be a value between 0 and \a hTable->size - 1. If
    string \a s is given and another record with the same computed hash and the
    same associated string exists in the hash table, then the new record will \b not be added and the
    value \b PLL_FALSE is returned. Otherwise, the new item is added at the
    beginning of the corresponding linked list and the value \b PLL_TRUE is
    returned.

    @param hTable Hashtable
    @param hash   Position where to store in hash table
    @param s      String
    @param item   Data associated with \a s
    @return       Returns \b PLL_TRUE if added with success, otherwise \b PLL_FALSE
*/
int pllHashAdd  (pllHashTable * hTable, unsigned int hash, const char * s, void * item)
{
  pllHashItem * hItem;

  hItem = hTable->Items[hash];

  /* If a string was given, check whether the record already exists */
  if (s)
   {
     for (; hItem; hItem = hItem->next)
      {
        if (hItem->str && !strcmp (s, hItem->str)) return (PLL_FALSE);
      }
   }

  hItem = (pllHashItem *) rax_malloc (sizeof (pllHashItem));

  /* store the string together with the element if given */
  if (s)
   {
     hItem->str = (char *) rax_malloc ((strlen(s) + 1) * sizeof (char));
     strcpy (hItem->str, s);
   }
  else
   hItem->str = NULL;

  hItem->data = item;

  hItem->next = hTable->Items[hash];
  hTable->Items[hash] = hItem;
  hTable->entries += 1;

  return (PLL_TRUE);
}

       
/** @brief Initialize hash table
    
    Create a hash table of size at least \a n. The size of the hash table will
    be the first prime number higher or equal to \a n.

    @param n  Minimum size of hash table
    @return   In case of success, returns a pointer to the created hash table, otherwise returns \b NULL
*/
pllHashTable * pllHashInit (unsigned int n)
{ 
  pllHashTable * hTable;
  unsigned int i;
  unsigned int primeTableLength;
       
  hTable = (pllHashTable *) rax_malloc (sizeof (pllHashTable));
  if (!hTable) return (NULL);
  
  primeTableLength = sizeof (initTable) / sizeof(initTable[0]);

  i = 0;
 
  while (initTable[i] < n && i < primeTableLength) ++ i;
 
  n = initTable[i];  
 
  hTable->Items = (pllHashItem **) rax_calloc (n, sizeof (pllHashItem *));
  if (!hTable->Items)
   {
     rax_free (hTable);
     return (NULL);
   }
  hTable->size    = n;
  hTable->entries = 0;
 
  return (hTable);
}

/** @brief Retrieve the data stored in hash table for a given string

    Retrieve the data stored in hash table \a hTable under a given string \a s.
    In case the string is found in the hash table, the associated data are
    stored in \a item and the function returns \b PLL_TRUE. In the opposite
    case, or if \a s is given as \b NULL then \b PLL_FALSE is returned.

    @param hTable   Hash table to be searched
    @param s        String to look for
    @param item     Where to store the retrieved data
    @return         Returns \b PLL_TRUE if the string was found, otherwise \b PLL_FALSE
*/
int pllHashSearch (pllHashTable * hTable, char * s, void ** item)
{
  unsigned int pos;
  pllHashItem * hItem;

  if (!s) return (PLL_FALSE);

  pos   = pllHashString (s, hTable->size);
  hItem = hTable->Items[pos];

  for (; hItem; hItem = hItem->next)
   {
     if (hItem->str && !strcmp (s, hItem->str))
      {
        *item = hItem->data;
        return (PLL_TRUE);
      }
   }

  return (PLL_FALSE);
}

/** @brief Deallocate a hash table

    Deallocates the hash table. A callback function may be specified as \a
    cbDealloc which will be executed upon all \a data elements of the hash
    table, for deallocating custom data. If no deallocation is required for the
    custom data, then \a cbDealloc must be set to \b NULL. The strings
    associated with each hash element are deallocated.

    @param hTable    Hash table to be deallocated
    @pram  cbDealloc Callback function to perform deallocation of each data element of the hash table
    @notes
      Deallocates the structure for the hash table. Note that the 
      data associated with the indexed strings are not deallocated.
*/
void pllHashDestroy (pllHashTable ** hTable, void (*cbDealloc)(void *))
{
  unsigned int i;
  pllHashItem * hItem;
  pllHashItem * tmp;

  for (i = 0; i < (*hTable)->size; ++ i)
  {
    hItem = (*hTable)->Items[i];
    while (hItem)
     {
       tmp   = hItem;
       hItem = hItem->next;
       if (tmp->str)  rax_free (tmp->str);
       if (cbDealloc) cbDealloc (tmp->data);
       rax_free (tmp);
     }
  }
  rax_free ((*hTable)->Items);
  rax_free (*hTable);
  *hTable = NULL;
}