PageRenderTime 82ms CodeModel.GetById 10ms app.highlight 60ms RepoModel.GetById 1ms app.codeStats 1ms

/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_primhash.c

http://github.com/zpao/v8monkey
C | 617 lines | 278 code | 68 blank | 271 comment | 50 complexity | 26fa8445b8aecfbf21b0fde6fe0a3623 MD5 | raw file
  1/* ***** BEGIN LICENSE BLOCK *****
  2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3 *
  4 * The contents of this file are subject to the Mozilla Public License Version
  5 * 1.1 (the "License"); you may not use this file except in compliance with
  6 * the License. You may obtain a copy of the License at
  7 * http://www.mozilla.org/MPL/
  8 *
  9 * Software distributed under the License is distributed on an "AS IS" basis,
 10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 11 * for the specific language governing rights and limitations under the
 12 * License.
 13 *
 14 * The Original Code is the PKIX-C library.
 15 *
 16 * The Initial Developer of the Original Code is
 17 * Sun Microsystems, Inc.
 18 * Portions created by the Initial Developer are
 19 * Copyright 2004-2007 Sun Microsystems, Inc.  All Rights Reserved.
 20 *
 21 * Contributor(s):
 22 *   Sun Microsystems, Inc.
 23 *
 24 * Alternatively, the contents of this file may be used under the terms of
 25 * either the GNU General Public License Version 2 or later (the "GPL"), or
 26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 27 * in which case the provisions of the GPL or the LGPL are applicable instead
 28 * of those above. If you wish to allow use of your version of this file only
 29 * under the terms of either the GPL or the LGPL, and not to allow others to
 30 * use your version of this file under the terms of the MPL, indicate your
 31 * decision by deleting the provisions above and replace them with the notice
 32 * and other provisions required by the GPL or the LGPL. If you do not delete
 33 * the provisions above, a recipient may use your version of this file under
 34 * the terms of any one of the MPL, the GPL or the LGPL.
 35 *
 36 * ***** END LICENSE BLOCK ***** */
 37/*
 38 * pkix_pl_primhash.c
 39 *
 40 * Primitive (non-object) Hashtable Functions
 41 *
 42 */
 43
 44#include "pkix_pl_primhash.h"
 45
 46/* --Private-Functions---------------------------------------- */
 47
 48/*
 49 * FUNCTION: pkix_pl_KeyComparator_Default
 50 * DESCRIPTION:
 51 *
 52 *  Compares the integer pointed to by "firstKey" with the integer pointed to
 53 *  by "secondKey" for equality and stores the Boolean result at "pResult".
 54 *  This default key comparator assumes each key is a PKIX_UInt32, and it
 55 *  simply tests them for equality.
 56 *
 57 * PARAMETERS:
 58 *  "firstKey"
 59 *      Address of the first integer key to compare. Must be non-NULL.
 60 *      The EqualsCallback for this Object will be called.
 61 *  "secondKey"
 62 *      Address of the second integer key to compare. Must be non-NULL.
 63 *  "pResult"
 64 *      Address where Boolean will be stored. Must be non-NULL.
 65 *  "plContext"
 66 *      Platform-specific context pointer.
 67 * THREAD SAFETY:
 68 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
 69 * RETURNS:
 70 *  Returns NULL if the function succeeds.
 71 *  Returns a Fatal Error if the function fails in an unrecoverable way.
 72 */
 73static PKIX_Error *
 74pkix_pl_KeyComparator_Default(
 75        PKIX_UInt32 *firstKey,
 76        PKIX_UInt32 *secondKey,
 77        PKIX_Boolean *pResult,
 78        void *plContext)
 79{
 80        /* Assume both keys are pointers to PKIX_UInt32 */
 81        PKIX_UInt32 firstInt, secondInt;
 82
 83        PKIX_ENTER(HASHTABLE, "pkix_pl_KeyComparator_Default");
 84        PKIX_NULLCHECK_THREE(firstKey, secondKey, pResult);
 85
 86        firstInt = *firstKey;
 87        secondInt = *secondKey;
 88
 89        *pResult = (firstInt == secondInt)?PKIX_TRUE:PKIX_FALSE;
 90
 91        PKIX_RETURN(HASHTABLE);
 92}
 93
 94
 95/*
 96 * FUNCTION: pkix_pl_PrimHashTable_Create
 97 * DESCRIPTION:
 98 *
 99 *  Creates a new PrimHashtable object with a number of buckets equal to
100 *  "numBuckets" and stores the result at "pResult".
101 *
102 * PARAMETERS:
103 *  "numBuckets"
104 *      The number of hash table buckets. Must be non-zero.
105 *  "pResult"
106 *      Address where PrimHashTable pointer will be stored. Must be non-NULL.
107 *  "plContext"
108 *      Platform-specific context pointer.
109 * THREAD SAFETY:
110 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
111 * RETURNS:
112 *  Returns NULL if the function succeeds.
113 *  Returns a Fatal Error if the function fails in an unrecoverable way.
114 */
115PKIX_Error *
116pkix_pl_PrimHashTable_Create(
117        PKIX_UInt32 numBuckets,
118        pkix_pl_PrimHashTable **pResult,
119        void *plContext)
120{
121        pkix_pl_PrimHashTable *primHashTable = NULL;
122        PKIX_UInt32 i;
123
124        PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Create");
125        PKIX_NULLCHECK_ONE(pResult);
126
127        if (numBuckets == 0) {
128                PKIX_ERROR(PKIX_NUMBUCKETSEQUALSZERO);
129        }
130
131        /* Allocate a new hashtable */
132        PKIX_CHECK(PKIX_PL_Malloc
133                    (sizeof (pkix_pl_PrimHashTable),
134                    (void **)&primHashTable,
135                    plContext),
136                    PKIX_MALLOCFAILED);
137
138        primHashTable->size = numBuckets;
139
140        /* Allocate space for the buckets */
141        PKIX_CHECK(PKIX_PL_Malloc
142                    (numBuckets * sizeof (pkix_pl_HT_Elem*),
143                    (void **)&primHashTable->buckets,
144                    plContext),
145                    PKIX_MALLOCFAILED);
146
147        for (i = 0; i < numBuckets; i++) {
148                primHashTable->buckets[i] = NULL;
149        }
150
151        *pResult = primHashTable;
152
153cleanup:
154
155        if (PKIX_ERROR_RECEIVED){
156                PKIX_FREE(primHashTable);
157        }
158
159        PKIX_RETURN(HASHTABLE);
160}
161
162/*
163 * FUNCTION: pkix_pl_PrimHashTable_Add
164 * DESCRIPTION:
165 *
166 *  Adds the value pointed to by "value" to the PrimHashTable pointed to by
167 *  "ht" using the key pointed to by "key" and the hashCode value equal to
168 *  "hashCode", using the function pointed to by "keyComp" to compare keys.
169 *  Assumes the key is either a PKIX_UInt32 or a PKIX_PL_Object. If the value
170 *  already exists in the hashtable, this function returns a non-fatal error.
171 *
172 * PARAMETERS:
173 *  "ht"
174 *      Address of PrimHashtable to insert into. Must be non-NULL.
175 *  "key"
176 *      Address of key. Typically a PKIX_UInt32 or PKIX_PL_Object.
177 *      Must be non-NULL.
178 *  "value"
179 *      Address of Object to be added to PrimHashtable. Must be non-NULL.
180 *  "hashCode"
181 *      Hashcode value of the key.
182 *  "keyComp"
183 *      Address of function used to determine if two keys are equal.
184 *      If NULL, pkix_pl_KeyComparator_Default is used.
185 *  "plContext"
186 *      Platform-specific context pointer.
187 * THREAD SAFETY:
188 *  Not Thread Safe - assumes exclusive access to "ht"
189 *  (see Thread Safety Definitions in Programmer's Guide)
190 * RETURNS:
191 *  Returns NULL if the function succeeds.
192 *  Returns a HashTable Error if the function fails in a non-fatal way.
193 *  Returns a Fatal Error if the function fails in an unrecoverable way.
194 */
195PKIX_Error *
196pkix_pl_PrimHashTable_Add(
197        pkix_pl_PrimHashTable *ht,
198        void *key,
199        void *value,
200        PKIX_UInt32 hashCode,
201        PKIX_PL_EqualsCallback keyComp,
202        void *plContext)
203{
204        pkix_pl_HT_Elem **elemPtr = NULL;
205        pkix_pl_HT_Elem *element = NULL;
206        PKIX_Boolean compResult = PKIX_FALSE;
207
208        PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Add");
209        PKIX_NULLCHECK_THREE(ht, key, value);
210
211        for (elemPtr = &((ht->buckets)[hashCode%ht->size]), element = *elemPtr;
212            element != NULL; elemPtr = &(element->next), element = *elemPtr) {
213
214                if (element->hashCode != hashCode){
215                        /* no possibility of a match */
216                        continue;
217                }
218
219                if (keyComp == NULL){
220                        PKIX_CHECK(pkix_pl_KeyComparator_Default
221                                ((PKIX_UInt32 *)key,
222                                (PKIX_UInt32 *)(element->key),
223                                &compResult,
224                                plContext),
225                                PKIX_COULDNOTTESTWHETHERKEYSEQUAL);
226                } else {
227                        PKIX_CHECK(keyComp
228                                ((PKIX_PL_Object *)key,
229                                (PKIX_PL_Object *)(element->key),
230                                &compResult,
231                                plContext),
232                                PKIX_COULDNOTTESTWHETHERKEYSEQUAL);
233                }
234
235                if ((element->hashCode == hashCode) &&
236                    (compResult == PKIX_TRUE)){
237                        /* Same key already exists in the table */
238                    PKIX_ERROR(PKIX_ATTEMPTTOADDDUPLICATEKEY);
239                }
240        }
241
242        /* Next Element should be NULL at this point */
243        if (element != NULL) {
244                PKIX_ERROR(PKIX_ERRORTRAVERSINGBUCKET);
245        }
246
247        /* Create a new HT_Elem */
248        PKIX_CHECK(PKIX_PL_Malloc
249                    (sizeof (pkix_pl_HT_Elem), (void **)elemPtr, plContext),
250                    PKIX_MALLOCFAILED);
251
252        element = *elemPtr;
253
254        element->key = key;
255        element->value = value;
256        element->hashCode = hashCode;
257        element->next = NULL;
258
259cleanup:
260
261        PKIX_RETURN(HASHTABLE);
262}
263
264/*
265 * FUNCTION: pkix_pl_PrimHashTable_Remove
266 * DESCRIPTION:
267 *
268 *  Removes any objects with the key pointed to by "key" and hashCode value
269 *  equal to "hashCode" from the PrimHashtable pointed to by "ht", using the
270 *  function pointed to by "keyComp" to compare keys, and stores the object's
271 *  value at "pResult". Assumes "key" is a PKIX_UInt32 or a PKIX_PL_Object.
272 *  This function sets "pResult" to NULL if the key is not in the hashtable.
273 *
274 * PARAMETERS:
275 *  "ht"
276 *      Address of PrimHashtable to remove object. Must be non-NULL.
277 *  "key"
278 *      Address of key for lookup. Typically a PKIX_UInt32 or PKIX_PL_Object.
279 *      Must be non-NULL.
280 *  "value"
281 *      Address of Object to be added to PrimHashtable. Must be non-NULL.
282 *  "hashCode"
283 *      Hashcode value of the key.
284 *  "keyComp"
285 *      Address of function used to determine if two keys are equal.
286 *      If NULL, pkix_pl_KeyComparator_Default is used.
287 *  "pResult"
288 *      Address where value will be stored. Must be non-NULL.
289 *  "plContext"
290 *      Platform-specific context pointer.
291 * THREAD SAFETY:
292 *  Not Thread Safe - assumes exclusive access to "ht"
293 *  (see Thread Safety Definitions in Programmer's Guide)
294 * RETURNS:
295 *  Returns NULL if the function succeeds.
296 *  Returns a HashTable Error if the function fails in a non-fatal way.
297 *  Returns a Fatal Error if the function fails in an unrecoverable way.
298 */
299PKIX_Error *
300pkix_pl_PrimHashTable_Remove(
301        pkix_pl_PrimHashTable *ht,
302        void *key,
303        PKIX_UInt32 hashCode,
304        PKIX_PL_EqualsCallback keyComp,
305        void **pKey,
306        void **pValue,
307        void *plContext)
308{
309        pkix_pl_HT_Elem *element = NULL;
310        pkix_pl_HT_Elem *prior = NULL;
311        PKIX_Boolean compResult;
312
313        PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Remove");
314        PKIX_NULLCHECK_FOUR(ht, key, pKey, pValue);
315
316        *pKey = NULL;
317        *pValue = NULL;
318
319        for (element = ht->buckets[hashCode%ht->size], prior = element;
320            (element != NULL);
321            prior = element, element = element->next) {
322
323                if (element->hashCode != hashCode){
324                        /* no possibility of a match */
325                        continue;
326                }
327
328                if (keyComp == NULL){
329                        PKIX_CHECK(pkix_pl_KeyComparator_Default
330                                ((PKIX_UInt32 *)key,
331                                (PKIX_UInt32 *)(element->key),
332                                &compResult,
333                                plContext),
334                                PKIX_COULDNOTTESTWHETHERKEYSEQUAL);
335                } else {
336                        PKIX_CHECK(keyComp
337                                ((PKIX_PL_Object *)key,
338                                (PKIX_PL_Object *)(element->key),
339                                &compResult,
340                                plContext),
341                                PKIX_COULDNOTTESTWHETHERKEYSEQUAL);
342                }
343
344                if ((element->hashCode == hashCode) &&
345                    (compResult == PKIX_TRUE)){
346                        if (element != prior) {
347                                prior->next = element->next;
348                        } else {
349                                ht->buckets[hashCode%ht->size] = element->next;
350                        }
351                        *pKey = element->key;
352                        *pValue = element->value;
353                        element->key = NULL;
354                        element->value = NULL;
355                        element->next = NULL;
356                        PKIX_FREE(element);
357                        goto cleanup;
358                }
359        }
360
361cleanup:
362
363        PKIX_RETURN(HASHTABLE);
364}
365
366
367/*
368 * FUNCTION: pkix_pl_HashTableLookup
369 * DESCRIPTION:
370 *
371 *  Looks up object using the key pointed to by "key" and hashCode value
372 *  equal to "hashCode" from the PrimHashtable pointed to by "ht", using the
373 *  function pointed to by "keyComp" to compare keys, and stores the object's
374 *  value at "pResult". Assumes "key" is a PKIX_UInt32 or a PKIX_PL_Object.
375 *  This function sets "pResult" to NULL if the key is not in the hashtable.
376 *
377 * PARAMETERS:
378 *  "ht"
379 *      Address of PrimHashtable to lookup object from. Must be non-NULL.
380 *  "key"
381 *      Address of key for lookup. Typically a PKIX_UInt32 or PKIX_PL_Object.
382 *      Must be non-NULL.
383 *  "keyComp"
384 *      Address of function used to determine if two keys are equal.
385 *      If NULL, pkix_pl_KeyComparator_Default is used.
386 *  "hashCode"
387 *      Hashcode value of the key.
388 *  "pResult"
389 *      Address where value will be stored. Must be non-NULL.
390 *  "plContext"
391 *      Platform-specific context pointer.
392 * THREAD SAFETY:
393 *  Conditionally Thread Safe
394 *      (see Thread Safety Definitions in Programmer's Guide)
395 * RETURNS:
396 *  Returns NULL if the function succeeds.
397 *  Returns a Fatal Error if the function fails in an unrecoverable way.
398 */
399PKIX_Error *
400pkix_pl_PrimHashTable_Lookup(
401        pkix_pl_PrimHashTable *ht,
402        void *key,
403        PKIX_UInt32 hashCode,
404        PKIX_PL_EqualsCallback keyComp,
405        void **pResult,
406        void *plContext)
407{
408        pkix_pl_HT_Elem *element = NULL;
409        PKIX_Boolean compResult = PKIX_FALSE;
410
411        PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Lookup");
412        PKIX_NULLCHECK_THREE(ht, key, pResult);
413
414        *pResult = NULL;
415
416        for (element = (ht->buckets)[hashCode%ht->size];
417            (element != NULL) && (*pResult == NULL);
418            element = element->next) {
419
420                if (element->hashCode != hashCode){
421                        /* no possibility of a match */
422                        continue;
423                }
424
425                if (keyComp == NULL){
426                        PKIX_CHECK(pkix_pl_KeyComparator_Default
427                                ((PKIX_UInt32 *)key,
428                                (PKIX_UInt32 *)(element->key),
429                                &compResult,
430                                plContext),
431                                PKIX_COULDNOTTESTWHETHERKEYSEQUAL);
432                } else {
433                       pkixErrorResult =
434                           keyComp((PKIX_PL_Object *)key,
435                                   (PKIX_PL_Object *)(element->key),
436                                   &compResult,
437                                   plContext);
438                       if (pkixErrorResult) {
439                           pkixErrorClass = PKIX_FATAL_ERROR;
440                           pkixErrorCode = PKIX_COULDNOTTESTWHETHERKEYSEQUAL;
441                           goto cleanup;
442                       }
443                }
444
445                if ((element->hashCode == hashCode) &&
446                    (compResult == PKIX_TRUE)){
447                        *pResult = element->value;
448                        goto cleanup;
449                }
450        }
451
452        /* if we've reached here, specified key doesn't exist in hashtable */
453        *pResult = NULL;
454
455cleanup:
456
457        PKIX_RETURN(HASHTABLE);
458}
459
460/*
461 * FUNCTION: pkix_pl_PrimHashTable_Destroy
462 *
463 *  Destroys PrimHashTable pointed to by "ht".
464 *
465 * PARAMETERS:
466 *  "ht"
467 *      Address of PrimHashtable to free. Must be non-NULL.
468 *  "plContext"
469 *      Platform-specific context pointer.
470 * THREAD SAFETY:
471 *  Not Thread Safe - assumes exclusive access to "ht"
472 *  (see Thread Safety Definitions in Programmer's Guide)
473 * RETURNS
474 *  Returns NULL if the function succeeds.
475 *  Returns a HashTable Error if the function fails in a non-fatal way.
476 *  Returns a Fatal Error if the function fails in an unrecoverable way.
477 */
478PKIX_Error *
479pkix_pl_PrimHashTable_Destroy(
480        pkix_pl_PrimHashTable *ht,
481        void *plContext)
482{
483        pkix_pl_HT_Elem *element = NULL;
484        pkix_pl_HT_Elem *temp = NULL;
485        PKIX_UInt32 i;
486
487        PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Destroy");
488        PKIX_NULLCHECK_ONE(ht);
489
490        /* Free each element (list) */
491        for (i = 0; i < ht->size; i++) {
492                for (element = ht->buckets[i];
493                    element != NULL;
494                    element = temp) {
495                        temp = element->next;
496                        element->value = NULL;
497                        element->key = NULL;
498                        element->hashCode = 0;
499                        element->next = NULL;
500                        PKIX_FREE(element);
501                }
502        }
503
504        /* Free the pointer to the list array */
505        PKIX_FREE(ht->buckets);
506        ht->size = 0;
507
508        /* Free the table itself */
509        PKIX_FREE(ht);
510
511        PKIX_RETURN(HASHTABLE);
512}
513
514/*
515 * FUNCTION: pkix_pl_PrimHashTable_GetBucketSize
516 * DESCRIPTION:
517 *
518 *  Retruns number of entries in the bucket the "hashCode" is designated in
519 *  the hashtable "ht" in the address "pBucketSize".
520 *
521 * PARAMETERS:
522 *  "ht"
523 *      Address of PrimHashtable to get entries count. Must be non-NULL.
524 *  "hashCode"
525 *      Hashcode value of the key.
526 *  "pBucketSize"
527 *      Address that an PKIX_UInt32 is returned for number of entries in the
528 *      bucket associated with the hashCode. Must be non-NULL.
529 *  "plContext"
530 *      Platform-specific context pointer.
531 * THREAD SAFETY:
532 *  Not Thread Safe - assumes exclusive access to "ht"
533 *  (see Thread Safety Definitions in Programmer's Guide)
534 * RETURNS:
535 *  Returns NULL if the function succeeds.
536 *  Returns a HashTable Error if the function fails in a non-fatal way.
537 *  Returns a Fatal Error if the function fails in an unrecoverable way.
538 */
539PKIX_Error *
540pkix_pl_PrimHashTable_GetBucketSize(
541        pkix_pl_PrimHashTable *ht,
542        PKIX_UInt32 hashCode,
543        PKIX_UInt32 *pBucketSize,
544        void *plContext)
545{
546        pkix_pl_HT_Elem **elemPtr = NULL;
547        pkix_pl_HT_Elem *element = NULL;
548        PKIX_UInt32 bucketSize = 0;
549
550        PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_GetBucketSize");
551        PKIX_NULLCHECK_TWO(ht, pBucketSize);
552
553        for (elemPtr = &((ht->buckets)[hashCode%ht->size]), element = *elemPtr;
554            element != NULL; elemPtr = &(element->next), element = *elemPtr) {
555                bucketSize++;
556	}
557
558        *pBucketSize = bucketSize;
559
560        PKIX_RETURN(HASHTABLE);
561}
562
563/*
564 * FUNCTION: pkix_pl_PrimHashTable_RemoveFIFO
565 * DESCRIPTION:
566 *
567 *  Remove the first entry in the bucket the "hashCode" is designated in
568 *  the hashtable "ht". Since new entry is added at end of the link list
569 *  the first one is the oldest (FI) therefore removed first (FO).
570 *
571 * PARAMETERS:
572 *  "ht"
573 *      Address of PrimHashtable to get entries count. Must be non-NULL.
574 *  "hashCode"
575 *      Hashcode value of the key.
576 *  "pKey"
577 *      Address of key of the entry deleted. Must be non-NULL.
578 *  "pValue"
579 *      Address of Value of the entry deleted. Must be non-NULL.
580 *  "plContext"
581 *      Platform-specific context pointer.
582 * THREAD SAFETY:
583 *  Not Thread Safe - assumes exclusive access to "ht"
584 *  (see Thread Safety Definitions in Programmer's Guide)
585 * RETURNS:
586 *  Returns NULL if the function succeeds.
587 *  Returns a HashTable Error if the function fails in a non-fatal way.
588 *  Returns a Fatal Error if the function fails in an unrecoverable way.
589 */
590PKIX_Error *
591pkix_pl_PrimHashTable_RemoveFIFO(
592        pkix_pl_PrimHashTable *ht,
593        PKIX_UInt32 hashCode,
594        void **pKey,
595        void **pValue,
596        void *plContext)
597{
598        pkix_pl_HT_Elem *element = NULL;
599
600        PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Remove");
601        PKIX_NULLCHECK_THREE(ht, pKey, pValue);
602
603        element = (ht->buckets)[hashCode%ht->size];
604
605        if (element != NULL) {
606
607                *pKey = element->key;
608                *pValue = element->value;
609                ht->buckets[hashCode%ht->size] = element->next;
610                element->key = NULL;
611                element->value = NULL;
612                element->next = NULL;
613                PKIX_FREE(element);
614        }
615
616        PKIX_RETURN(HASHTABLE);
617}