HashTable.m
上传用户:shenzhenrh
上传日期:2013-05-12
资源大小:2904k
文件大小:8k
源码类别:

信息检索与抽取

开发平台:

Unix_Linux

  1. /* Implementation of Objective C NeXT-compatible HashTable object
  2.    Copyright (C) 1993 Free Software Foundation, Inc.
  3.    
  4.    Written by:  R. Andrew McCallum <mccallum@cs.rochester.edu>
  5.    Dept. of Computer Science, U. of Rochester, Rochester, NY  14627
  6.    
  7.    This library is free software; you can redistribute it and/or
  8.    modify it under the terms of the GNU Library General Public
  9.    License as published by the Free Software Foundation; either
  10.    version 2 of the License, or (at your option) any later version.
  11.    
  12.    This library is distributed in the hope that it will be useful,
  13.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.    Library General Public License for more details.
  16.    
  17.    You should have received a copy of the GNU Library General Public
  18.    License along with this library; if not, write to the Free
  19.    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.    */ 
  21. #include "HashTable.h"
  22. #include <objc/objc-api.h>
  23. #include <swarmconfig.h> // PTRUINT, PTRINT
  24. #define DEFAULT_HASH_CAPACITY 32
  25. /* Some useful hash and compare functions not provided by hash.h */
  26. static inline unsigned int
  27. hash_object (cache_ptr cache, const void *key)
  28. {
  29.   return (([((id)key) hash]) & cache->mask);
  30. }
  31. static inline int
  32. compare_objects (const void *k1, const void *k2)
  33. {
  34.   return (int)[(id)k1 isEqual:(id)k2];
  35. }
  36. static inline PTRUINT
  37. hash_int (cache_ptr cache, const void *key)
  38. {
  39.   return ((PTRUINT) key & cache->mask);
  40. }
  41. static inline int
  42. compare_ints (const void *k1, const void *k2)
  43. {
  44.   return !((PTRINT) k1 - (PTRINT) k2);
  45. }
  46. static inline int
  47. compare_long_ints (const void *k1, const void *k2)
  48. {
  49.   return !((long int)k1 - (long int)k2);
  50. }
  51. @implementation HashTable
  52.   
  53. + initialize
  54. {
  55.   if (self == [HashTable class])
  56.     [self setVersion:-1]; /* alpha release */
  57.   return self;
  58. }
  59. - initKeyDesc: (const char *)aKeyDesc 
  60.   valueDesc: (const char *)aValueDesc 
  61.   capacity: (unsigned) aCapacity
  62. {
  63.   hash_func_type hf;
  64.   compare_func_type cf;
  65.   
  66.   if (!aKeyDesc) 
  67.     [self error:"in %s, NULL keyDescn", sel_get_name(_cmd)];
  68.   if (!aValueDesc) 
  69.     [self error:"in %s, NULL valueDescn", sel_get_name(_cmd)];
  70.   count = 0;
  71.   keyDesc = aKeyDesc;
  72.   valueDesc = aValueDesc;
  73.   switch (*aKeyDesc) 
  74.     {
  75.     case _C_ATOM:
  76.     case _C_CHARPTR : 
  77.       hf = (hash_func_type)hash_string;
  78.       cf = (compare_func_type)compare_strings;
  79.       break;
  80.     case _C_ID:
  81.     case _C_CLASS:
  82.       hf = (hash_func_type)hash_object;
  83.       cf = (compare_func_type)compare_objects;
  84.       break;
  85.     case _C_PTR: 
  86.       hf = (hash_func_type)hash_ptr;
  87.       cf = (compare_func_type)compare_ptrs;
  88.       break;
  89.     case _C_INT: 
  90.     case _C_SEL:
  91.     case _C_UINT: 
  92.       hf = (hash_func_type)hash_int;
  93.       cf = (compare_func_type)compare_ints;
  94.       break;
  95.     case _C_LNG: 
  96.     case _C_ULNG: 
  97.       hf = (hash_func_type)hash_int;
  98.       cf = (compare_func_type)compare_long_ints;
  99.       break;
  100.     case _C_FLT:
  101.       /* Fix this.  Do something better with floats. */
  102.       hf = (hash_func_type)hash_int;
  103.       cf = (compare_func_type)compare_ints;
  104.       break;
  105.     default: 
  106.       hf = (hash_func_type)hash_int;
  107.       cf = (compare_func_type)compare_ints;
  108.       break;
  109.     }
  110.   _buckets = hash_new(aCapacity, hf, cf);
  111.   _nbBuckets = _buckets->size;
  112.   return self;
  113. }
  114. - initKeyDesc:(const char *)aKeyDesc 
  115.   valueDesc:(const char *)aValueDesc
  116. {
  117.   return [self initKeyDesc:aKeyDesc 
  118.        valueDesc:aValueDesc 
  119.        capacity:DEFAULT_HASH_CAPACITY];
  120. }
  121. - initKeyDesc: (const char *)aKeyDesc
  122. {
  123.   return [self initKeyDesc:aKeyDesc
  124.        valueDesc:@encode(id)];
  125. }
  126. - init
  127. {
  128.   return [self initKeyDesc:@encode(id)];
  129. }
  130. - free
  131. {
  132.   hash_delete(_buckets);
  133.   return [super free];
  134. }
  135. - freeObjects
  136. {
  137.   node_ptr node;
  138.   void *val;
  139.   
  140.   while ((node = hash_next(_buckets, 0)))
  141.     {
  142.       val = node->value;
  143.       hash_remove(_buckets, node->key);
  144.       if (*valueDesc == _C_ID)
  145. [(id)val free];
  146.     }
  147.   count = 0;
  148.   _nbBuckets = _buckets->size;
  149.   return self;
  150. }
  151. - freeKeys:(void (*) (void *))keyFunc 
  152.   values:(void (*) (void *))valueFunc
  153. {
  154.   /* What exactly is this supposed to do? */
  155.   [self notImplemented:_cmd];
  156.   return self;
  157. }
  158. - empty
  159. {
  160.   node_ptr node;
  161.   
  162.   while ((node = hash_next(_buckets, 0)))
  163.     hash_remove(_buckets, node->key);
  164.   count = 0;
  165.   _nbBuckets = _buckets->size;
  166.   return self;
  167. }
  168. - shallowCopy
  169. {
  170.   HashTable *c;
  171.   node_ptr node;
  172.   
  173.   c = [super shallowCopy];
  174.   c->_buckets = hash_new(_buckets->size, 
  175.  _buckets->hash_func, 
  176.  _buckets->compare_func);
  177.   /* copy nodes to new copy */
  178.   node = 0;
  179.   while ((node = hash_next(_buckets, node)))
  180.     [c insertKey:node->key value:node->value];
  181.   return c;
  182. }
  183. - deepen
  184. {
  185.   node_ptr node = 0;
  186.   
  187.   if (*valueDesc == _C_ID) 
  188.     {
  189.       while ((node = hash_next(_buckets, node)))
  190. {
  191.   node->value = [(id)(node->value) deepCopy];
  192. }
  193.     }
  194.   /* If the hashtable contains strings should we copy them too??
  195.      But we definitely shouldn't copy "%" keys. */
  196.   return self;
  197. }
  198. - (unsigned) count
  199. {
  200.   return count;
  201. }
  202. - (BOOL) isKey:(const void *)aKey
  203. {
  204.   return (hash_value_for_key(_buckets, aKey)) ? YES : NO;
  205. }
  206. - (void *) valueForKey:(const void *)aKey
  207. {
  208.   return hash_value_for_key(_buckets, aKey);
  209. }
  210. - (void *) insertKey:(const void *)aKey value:(void *)aValue
  211. {
  212.   void *prevValue;
  213.   
  214.   prevValue = hash_value_for_key(_buckets, aKey);
  215.   if (prevValue)
  216.     hash_remove(_buckets, aKey);
  217.   hash_add(&_buckets, aKey, aValue);
  218.   count = _buckets->used;
  219.   _nbBuckets = _buckets->size;
  220.   return prevValue;
  221. }
  222. - (void *) removeKey:(const void *)aKey
  223. {
  224.   if (hash_value_for_key(_buckets, aKey)) 
  225.     {
  226.       hash_remove(_buckets, aKey);
  227.       count = _buckets->used;
  228.       _nbBuckets = _buckets->size;
  229.     }
  230.   return nil;
  231. }
  232. - (GNUHashState) initState
  233. {
  234.   return (GNUHashState) 0;
  235. }
  236. - (BOOL) nextState:(GNUHashState *)aState 
  237.          key:(const void **)aKey 
  238.          value:(void **)aValue
  239. {
  240.   *aState = hash_next(_buckets, *aState);
  241.   if (*aState) 
  242.     {
  243.       *aKey = (*aState)->key;
  244.       *aValue = (*aState)->value;
  245.       return YES;
  246.     }
  247.   else
  248.     return NO;
  249. }
  250. - write: (TypedStream*)aStream
  251. {
  252.   GNUHashState state = [self initState];
  253.   const void *k;
  254.   void *v;
  255.   if (!strcmp(keyDesc, "%"))
  256.     [self error:"Archiving atom strings, @encode()="%", not yet handled"];
  257.   [super write: aStream];
  258.   objc_write_types(aStream, "II**", 
  259.    [self count], _nbBuckets, keyDesc, valueDesc);
  260.   while ([self nextState:&state key:&k value:&v])
  261.     {
  262.       objc_write_type(aStream, keyDesc, &k);
  263.       objc_write_type(aStream, valueDesc, &v);
  264.     }
  265.   return self;
  266. }
  267. - read: (TypedStream*)aStream
  268. {
  269.   unsigned cnt, capacity;
  270.   unsigned i;
  271.   const void *k;
  272.   void *v;
  273.   [super read:aStream];
  274.   objc_read_types(aStream, "II**", 
  275.   &cnt, &capacity, &keyDesc, &valueDesc);
  276.   if (!strcmp(keyDesc, "%"))
  277.     [self error:"Archiving atom strings, @encode()="%", not yet handled"];
  278.   [self initKeyDesc:keyDesc valueDesc:valueDesc capacity:capacity];
  279.   for (i = 0; i < cnt; i++)
  280.     {
  281.       objc_read_type(aStream, keyDesc, &k);
  282.       objc_read_type(aStream, valueDesc, &v);
  283.       [self insertKey:k value:v];
  284.     }
  285.   return self;
  286. }
  287. + newKeyDesc: (const char *)aKeyDesc
  288. {
  289.   return [[[self class] alloc] initKeyDesc:aKeyDesc];
  290. }
  291. + newKeyDesc:(const char *)aKeyDesc 
  292.   valueDesc:(const char *)aValueDesc
  293. {
  294.   return [[self alloc] 
  295.   initKeyDesc:aKeyDesc
  296.   valueDesc:aValueDesc];
  297. }
  298. + newKeyDesc:(const char *)aKeyDesc 
  299.   valueDesc:(const char *)aValueDesc
  300.   capacity:(unsigned)aCapacity
  301. {
  302.   return [[self alloc]
  303.   initKeyDesc:aKeyDesc
  304.   valueDesc:aValueDesc
  305.   capacity:aCapacity];
  306. }
  307. - makeObjectsPerform:(SEL)aSel
  308. {
  309.   node_ptr node = 0;
  310.   
  311.   while ((node = hash_next(_buckets, node)))
  312.     [(id)(node->value) perform:aSel];
  313.   return self;
  314. }
  315. - makeObjectsPerform:(SEL)aSel with:anObject
  316. {
  317.   node_ptr node = 0;
  318.   
  319.   while ((node = hash_next(_buckets, node)))
  320.     [(id)(node->value) perform:aSel with:anObject];
  321.   return self;
  322. }
  323. @end