File: hashtable.c

package info (click to toggle)
crossfire 1.75.0-9
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 24,168 kB
  • sloc: ansic: 83,169; sh: 4,659; perl: 1,736; lex: 1,443; makefile: 1,199; python: 43
file content (248 lines) | stat: -rw-r--r-- 7,896 bytes parent folder | download | duplicates (8)
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
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
/*****************************************************************************/
/* hashtable.c                                                               */
/* Author: Alex Schultz, 2006                                                */
/* Based upon shstr.c, origionally written by Kjetil T. Homme, Oslo 1992.    */
/*****************************************************************************/
/* This is a pointer association hash table library for plugins to use with  */
/* a simple interface. This file is named as it is for other hash table      */
/* types to be added if people wish to.                                      */
/*****************************************************************************/
/* That code is placed under the GNU General Public Licence (GPL)            */
/* (C)2001-2005 by Chachkoff Yann (Feel free to deliver your complaints)     */
/*****************************************************************************/
/*  CrossFire, A Multiplayer game for X-windows                              */
/*                                                                           */
/*  Copyright (C) 2000 Mark Wedel                                            */
/*  Copyright (C) 1992 Frank Tore Johansen                                   */
/*                                                                           */
/*  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 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 General Public License        */
/*  along with this program; if not, write to the Free Software              */
/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
/*                                                                           */
/*****************************************************************************/

#include <string.h>
#include <stdlib.h>

#ifdef WIN32
#include <global.h>
typedef UINT_PTR uintptr_t;
#include <malloc.h>
#else
#include <stdint.h>
#include <autoconf.h>
#endif
#ifdef HAVE_LIBDMALLOC
#include <dmalloc.h>
#endif

#include <hashtable.h>

/**
 * Initialises the hash table for a pointer association table.
 *
 * @param hash_table
 * Pointer to the hash table to initialise.
 */
void init_ptr_assoc_table(ptr_assoc **hash_table) {
    (void)memset((void *)hash_table, 0, PTR_ASSOC_TABLESIZE*sizeof(ptr_assoc *));
}

/**
 * Hashing-function used by the pointer association library. Currently
 * just takes the pointer modulus the table size (which should be a prime
 * number).
 *
 * @param ptr
 * The pointer to hash.
 *
 * @return
 * The returned hash value.
 */
static int hashptr(void *ptr) {
    return (int)((uintptr_t)ptr%PTR_ASSOC_TABLESIZE);
}

/**
 * Allocates and initialises a new ptr_assoc structure.
 *
 * @param key
 * The key to lookup by in the association.
 * @param value
 * The value to store with the key.
 *
 * @return
 * The new ptr_assoc structure.
 */
static ptr_assoc *new_ptr_assoc(void *key, void *value) {
    ptr_assoc *assoc;

    assoc = (ptr_assoc *)malloc(sizeof(ptr_assoc));
    assoc->previous = NULL;
    assoc->array = NULL;
    assoc->next = NULL;
    assoc->key = key;
    assoc->value = value;
    return assoc;
}

/**
 * Adds a value to a hash table which one can lookup with key.
 *
 * @param hash_table
 * Pointer to the hash table to add to.
 * @param key
 * The key to lookup by in the association.
 * @param value
 * The value to store with the key.
 */
void add_ptr_assoc(ptr_assoc **hash_table, void *key, void *value) {
    ptr_assoc *assoc;
    int ind;

    ind = hashptr(key);
    assoc = hash_table[ind];

    /* Is there an entry for that hash? */
    if (assoc) {
        /* Simple case first: See if the first pointer matches. */
        if (key != assoc->key) {
            /* Apparantly, a association with the same hash value has this
             * slot. We must see in the list if this perticular key has
             * been registered before.
             */
            while (assoc->next) {
                assoc = assoc->next;
                if (key != assoc->key) {
                    /* This wasn't the right key... */
                    continue;
                }
                /* We found an entry for this key. Make sure the value
                 * is set as we want it.
                 */
                assoc->value = value;
                return;
            }
            /* There are no occurences of this key in the hash table. */
            {
                ptr_assoc *new_assoc;

                new_assoc = new_ptr_assoc(key, value);
                assoc->next = new_assoc;
                new_assoc->previous = assoc;
                return;
            }
        }
        return;
    } else {
        /* The string isn't registered, and the slot is empty. */
        hash_table[ind] = new_ptr_assoc(key, value);

        hash_table[ind]->array = &(hash_table[ind]);

        return;
    }
}

/**
 * Find the ptr_assoc with a given key.
 *
 * @param hash_table
 * Pointer to the hash table to search.
 * @param key
 * The key to lookup by in the association.
 *
 * @return
 * The ptr_assoc that is found, or null if none is found.
 */
static ptr_assoc *find_ptr_assoc(ptr_assoc **hash_table, void *key) {
    ptr_assoc *assoc;
    int ind;

    ind = hashptr(key);
    assoc = hash_table[ind];

    /* Is there an entry for that hash? */
    if (assoc) {
        /* Simple case first: Is the first key the right one? */
        if (assoc->key == key) {
            return assoc;
        } else {
            /* Recurse through the linked list, if there's one. */
            while (assoc->next) {
                assoc = assoc->next;
                if (assoc->key == key) {
                    return assoc;
                }
            }
            /* No match. Fall through. */
        }
    }
    return NULL;
}

/**
 * Find the value associated with a given key.
 *
 * @param hash_table
 * Pointer to the hash table to search.
 * @param key
 * The key to lookup by in the association.
 *
 * @return
 * The value associated with the key.
 */
void *find_assoc_value(ptr_assoc **hash_table, void *key) {
    ptr_assoc *assoc;

    assoc = find_ptr_assoc(hash_table, key);
    if (!assoc)
        return NULL;
    return assoc->value;
}

/**
 * Remove the association with a given key.
 *
 * @param hash_table
 * Pointer to the hash table to search.
 * @param key
 * The key to lookup by in the association.
 */
void free_ptr_assoc(ptr_assoc **hash_table, void *key) {
    ptr_assoc *assoc;

    assoc = find_ptr_assoc(hash_table, key);
    if (!assoc)
        return;

    if (assoc->array) {
        /* We must put a new value into the hash_table[].
         */
        if (assoc->next) {
            *(assoc->array) = assoc->next;
            assoc->next->previous = NULL;
            assoc->next->array = assoc->array;
        } else {
            *(assoc->array) = NULL;
        }
         free(assoc);
    } else {
        /* Relink and free this struct.
         */
        if (assoc->next)
            assoc->next->previous = assoc->previous;
        assoc->previous->next = assoc->next;
        free(assoc);
    }
}