/[m4]/m4/m4/hash.c
ViewVC logotype

Diff of /m4/m4/hash.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.9 by gary, Fri Jun 13 13:54:36 2003 UTC revision 1.10 by gary, Wed Jun 18 15:28:41 2003 UTC
# Line 26  Line 26 
26  #include "hash.h"  #include "hash.h"
27  #include "m4private.h"  #include "m4private.h"
28    
29  typedef struct m4_hash_node m4_hash_node;  typedef struct hash_node hash_node;
30    
31  struct m4_hash  struct m4_hash
32  {  {
# Line 34  struct m4_hash Line 34  struct m4_hash
34    size_t length;                /* number of elements inserted */    size_t length;                /* number of elements inserted */
35    m4_hash_hash_func *hash_func;    m4_hash_hash_func *hash_func;
36    m4_hash_cmp_func *cmp_func;    m4_hash_cmp_func *cmp_func;
37    m4_hash_node **buckets;    hash_node **buckets;
38  };  };
39    
40  struct m4_hash_node  struct hash_node
41  {  {
42    m4_hash_node *next;    hash_node *next;
43    const void *key;    const void *key;
44    void *value;    void *value;
45  };  };
46    
47    
48    
49  #define M4_HASH_SIZE(hash)      ((hash)->size)  #define HASH_SIZE(hash)         ((hash)->size)
50  #define M4_HASH_LENGTH(hash)    ((hash)->length)  #define HASH_LENGTH(hash)       ((hash)->length)
51  #define M4_HASH_BUCKETS(hash)   ((hash)->buckets)  #define HASH_BUCKETS(hash)      ((hash)->buckets)
52  #define M4_HASH_HASH_FUNC(hash) ((hash)->hash_func)  #define HASH_HASH_FUNC(hash)    ((hash)->hash_func)
53  #define M4_HASH_CMP_FUNC(hash)  ((hash)->cmp_func)  #define HASH_CMP_FUNC(hash)     ((hash)->cmp_func)
54    
55  #define M4_HASH_NODE_NEXT(node) ((node)->next)  #define NODE_NEXT(node) ((node)->next)
56  #define M4_HASH_NODE_KEY(node)  ((node)->key)  #define NODE_KEY(node)  ((node)->key)
57  #define M4_HASH_NODE_VAL(node)  ((node)->value)  #define NODE_VALUE(node)        ((node)->value)
58    
59  /* Helper macros. */  /* Helper macros. */
60  #define M4_HASH_BUCKET_NTH(hash, n)     (M4_HASH_BUCKETS (hash)[n])  #define BUCKET_NTH(hash, n)     (HASH_BUCKETS (hash)[n])
61  #define M4_HASH_BUCKET_NUM(hash, key)   \  #define BUCKET_COUNT(hash, key)                                 \
62          ((*M4_HASH_HASH_FUNC(hash))(key) % M4_HASH_SIZE(hash))          ((*HASH_HASH_FUNC(hash))(key) % HASH_SIZE(hash))
63  #define M4_HASH_BUCKET_KEY(hash, key)   \  #define BUCKET_KEY(hash, key)                                   \
64          (M4_HASH_BUCKET_NTH ((hash), M4_HASH_BUCKET_NUM ((hash), (key))))          (BUCKET_NTH ((hash), BUCKET_COUNT ((hash), (key))))
65    
66    
67    
68  static void             m4_hash_bucket_delete   (m4_hash *hash, size_t i);  static void             bucket_insert   (m4_hash *hash, hash_node *bucket);
69  static void             m4_hash_node_delete     (m4_hash *hash,  static void             bucket_delete   (m4_hash *hash, size_t i);
70                                                   m4_hash_node *node);  static hash_node *      node_new        (const void *key, void *value);
71  static m4_hash_node *   m4_hash_node_new        (const void *key, void *value);  static void             node_insert     (m4_hash *hash, hash_node *node);
72  static m4_hash_node *   m4_hash_lookup_node     (m4_hash *hash,  static hash_node *      node_lookup     (m4_hash *hash, const void *key);
73                                                   const void *key);  static void             node_delete     (m4_hash *hash, hash_node *node);
74  static void             m4_hash_maybe_grow      (m4_hash *hash);  static void             maybe_grow      (m4_hash *hash);
 static void             m4_hash_bucket_insert   (m4_hash *hash,  
                                                  m4_hash_node *bucket);  
 static void             m4_hash_node_insert     (m4_hash *hash,  
                                                  m4_hash_node *node);  
75    
76    
77    
78  static m4_hash_node *m4_hash_node_free_list = 0;  static hash_node *free_list = 0;
79    
80    
81    
# Line 87  static m4_hash_node *m4_hash_node_free_l Line 83  static m4_hash_node *m4_hash_node_free_l
83     SIZE buckets, where HASH_FUNC will be used to generate bucket numbers     SIZE buckets, where HASH_FUNC will be used to generate bucket numbers
84     and CMP_FUNC will be called to compare keys.  */     and CMP_FUNC will be called to compare keys.  */
85  m4_hash *  m4_hash *
86  m4_hash_new (size_t size, m4_hash_hash_func *hash_func, m4_hash_cmp_func *cmp_func)  m4_hash_new (size_t size, m4_hash_hash_func *hash_func,
87                 m4_hash_cmp_func *cmp_func)
88  {  {
89    m4_hash *hash;    m4_hash *hash;
90    
# Line 97  m4_hash_new (size_t size, m4_hash_hash_f Line 94  m4_hash_new (size_t size, m4_hash_hash_f
94    if (size == 0)    if (size == 0)
95      size = M4_HASH_DEFAULT_SIZE;      size = M4_HASH_DEFAULT_SIZE;
96    
97    hash                      = XMALLOC (m4_hash, 1);    hash                  = XMALLOC (m4_hash, 1);
98    M4_HASH_SIZE (hash)       = size;    HASH_SIZE (hash)      = size;
99    M4_HASH_LENGTH (hash)     = 0;    HASH_LENGTH (hash)    = 0;
100    M4_HASH_BUCKETS (hash)    = XCALLOC (m4_hash_node *, size);    HASH_BUCKETS (hash)   = XCALLOC (hash_node *, size);
101    M4_HASH_HASH_FUNC (hash)  = hash_func;    HASH_HASH_FUNC (hash) = hash_func;
102    M4_HASH_CMP_FUNC (hash)   = cmp_func;    HASH_CMP_FUNC (hash)  = cmp_func;
103    
104    return hash;    return hash;
105  }  }
106    
107    m4_hash *
108    m4_hash_dup (m4_hash *src, m4_hash_copy_func *copy)
109    {
110      m4_hash *dest;
111    
112      assert (src);
113      assert (copy);
114    
115      dest = m4_hash_new (HASH_SIZE (src), HASH_HASH_FUNC (src),
116                          HASH_CMP_FUNC (src));
117    
118      m4_hash_apply (src, (m4_hash_apply_func *) copy, dest);
119    
120      return dest;
121    }
122    
123  /* Recycle each of the nodes in HASH onto the free list, and release  /* Recycle each of the nodes in HASH onto the free list, and release
124     the rest of the memory used by the table.  Memory addressed by     the rest of the memory used by the table.  Memory addressed by
125     the recycled nodes is _NOT_ freed:  this needs to be done manually     the recycled nodes is _NOT_ freed:  this needs to be done manually
# Line 118  m4_hash_delete (m4_hash *hash) Line 131  m4_hash_delete (m4_hash *hash)
131    
132    assert (hash);    assert (hash);
133    
134    for (i = 0; i < M4_HASH_SIZE (hash); ++i)    for (i = 0; i < HASH_SIZE (hash); ++i)
135      if (M4_HASH_BUCKET_NTH (hash, i))      if (BUCKET_NTH (hash, i))
136        m4_hash_bucket_delete (hash, i);        bucket_delete (hash, i);
137    XFREE (M4_HASH_BUCKETS (hash));    XFREE (HASH_BUCKETS (hash));
138    XFREE (hash);    XFREE (hash);
139  }  }
140    
141  /* Check that the nodes in bucket I have been cleared, and recycle  /* Check that the nodes in bucket I have been cleared, and recycle
142     each of the nodes in the bucket to the free list.  Bucket I must     each of the nodes in the bucket to the free list.  Bucket I must
143     not be empty when this function is called.  */     not be empty when this function is called.  */
144  void  static void
145  m4_hash_bucket_delete (m4_hash *hash, size_t i)  bucket_delete (m4_hash *hash, size_t i)
146  {  {
147    m4_hash_node *node;    hash_node *node;
148    
149    assert (hash);    assert (hash);
150    assert (M4_HASH_BUCKET_NTH (hash, i));    assert (BUCKET_NTH (hash, i));
151    assert (i < M4_HASH_SIZE (hash));    assert (i < HASH_SIZE (hash));
152    
153    for (node = M4_HASH_BUCKET_NTH (hash, i);    for (node = BUCKET_NTH (hash, i); node->next; node = NODE_NEXT (node))
        node->next;  
        node = M4_HASH_NODE_NEXT (node))  
154      {      {
155        assert (M4_HASH_NODE_KEY(node) == 0);        assert (NODE_KEY(node) == 0);
156        --M4_HASH_LENGTH (hash);        --HASH_LENGTH (hash);
157      }      }
158    
159    assert (M4_HASH_NODE_KEY(node) == 0);    assert (NODE_KEY(node) == 0);
160    --M4_HASH_LENGTH (hash);    --HASH_LENGTH (hash);
161    
162    M4_HASH_NODE_NEXT (node)      = m4_hash_node_free_list;    NODE_NEXT (node)      = free_list;
163    m4_hash_node_free_list        = M4_HASH_BUCKET_NTH (hash, i);    free_list             = BUCKET_NTH (hash, i);
164    M4_HASH_BUCKET_NTH (hash, i)  = 0;    BUCKET_NTH (hash, i)  = 0;
165  }  }
166    
167  /* Create and initialise a new node with KEY and VALUE, by reusing a  /* Create and initialise a new node with KEY and VALUE, by reusing a
168     node from the free list if possible.  */     node from the free list if possible.  */
169  m4_hash_node *  static hash_node *
170  m4_hash_node_new (const void *key, void *value)  node_new (const void *key, void *value)
171  {  {
172    m4_hash_node *node = 0;    hash_node *node = 0;
173    
174    if (m4_hash_node_free_list)    if (free_list)
175      {      {
176        node = m4_hash_node_free_list;        node      = free_list;
177        m4_hash_node_free_list = M4_HASH_NODE_NEXT (m4_hash_node_free_list);        free_list = NODE_NEXT (free_list);
178      }      }
179    else    else
180      {      {
181        node = XMALLOC (m4_hash_node, 1);        node      = XMALLOC (hash_node, 1);
182      }      }
183    
184    assert (node);    assert (node);
185    
186    M4_HASH_NODE_NEXT (node)= 0;    NODE_NEXT  (node)     = 0;
187    M4_HASH_NODE_KEY (node) = key;    NODE_KEY   (node)     = key;
188    M4_HASH_NODE_VAL (node) = value;    NODE_VALUE (node)     = value;
189    
190    return node;    return node;
191  }  }
192    
193  /* Check that NODE has been cleared, and recycle it to the free list.  */  /* Check that NODE has been cleared, and recycle it to the free list.  */
194  void  static void
195  m4_hash_node_delete (m4_hash *hash, m4_hash_node *node)  node_delete (m4_hash *hash, hash_node *node)
196  {  {
197    assert (node);    assert (node);
198    assert (M4_HASH_NODE_KEY(node) == 0);    assert (NODE_KEY(node) == 0);
199    
200    M4_HASH_NODE_NEXT (node)      = m4_hash_node_free_list;    NODE_NEXT (node)      = free_list;
201    m4_hash_node_free_list        = node;    free_list             = node;
202    
203    --M4_HASH_LENGTH (hash);    --HASH_LENGTH (hash);
204  }  }
205    
206  /* Create a new entry in HASH with KEY and VALUE, making use of  /* Create a new entry in HASH with KEY and VALUE, making use of
207     nodes in the free list if possible, and potentially growing     nodes in the free list if possible, and potentially growing
208     the size of the table if node density is too high.  */     the size of the table if node density is too high.  */
209  void  const void *
210  m4_hash_insert (m4_hash *hash, const void *key, void *value)  m4_hash_insert (m4_hash *hash, const void *key, void *value)
211  {  {
212    m4_hash_node *node;    hash_node *node;
213    
214    assert (hash);    assert (hash);
215    
216    node = m4_hash_node_new (key, value);    node = node_new (key, value);
217    m4_hash_node_insert (hash, node);    node_insert (hash, node);
218    m4_hash_maybe_grow (hash);    maybe_grow (hash);
219    
220      return key;
221  }  }
222    
223  /* Push the unconnected NODE on to the front of the appropriate  /* Push the unconnected NODE on to the front of the appropriate
224     bucket, effectively preventing retrieval of other nodes with     bucket, effectively preventing retrieval of other nodes with
225     the same key (where "sameness" is determined by HASH's     the same key (where "sameness" is determined by HASH's
226     cmp_func).  */     cmp_func).  */
227  void  static void
228  m4_hash_node_insert (m4_hash *hash, m4_hash_node *node)  node_insert (m4_hash *hash, hash_node *node)
229  {  {
230    size_t n;    size_t n;
231    
232    assert (hash);    assert (hash);
233    assert (node);    assert (node);
234    assert (M4_HASH_NODE_NEXT (node) == 0);    assert (NODE_NEXT (node) == 0);
235    
236    n = M4_HASH_BUCKET_NUM (hash, M4_HASH_NODE_KEY (node));    n = BUCKET_COUNT (hash, NODE_KEY (node));
237    M4_HASH_NODE_NEXT (node)      = M4_HASH_BUCKET_NTH (hash, n);    NODE_NEXT (node)      = BUCKET_NTH (hash, n);
238    M4_HASH_BUCKET_NTH (hash, n)  = node;    BUCKET_NTH (hash, n)  = node;
239    
240    ++M4_HASH_LENGTH (hash);    ++HASH_LENGTH (hash);
241  }  }
242    
243  /* Remove from HASH, the first node with key KEY; comparing keys  /* Remove from HASH, the first node with key KEY; comparing keys
# Line 238  m4_hash_remove (m4_hash *hash, const voi Line 251  m4_hash_remove (m4_hash *hash, const voi
251    
252    assert (hash);    assert (hash);
253    
254    n = M4_HASH_BUCKET_NUM (hash, key);    n = BUCKET_COUNT (hash, key);
255    
256    {    {
257      m4_hash_node *node = 0;      hash_node *node = 0;
258    
259      do      do
260        {        {
261          m4_hash_node *next = node          hash_node *next = node ? NODE_NEXT (node) : BUCKET_NTH (hash, n);
           ? M4_HASH_NODE_NEXT (node)  
           : M4_HASH_BUCKET_NTH (hash, n);  
262    
263          if (next          if (next && ((*HASH_CMP_FUNC (hash)) (NODE_KEY (next), key) == 0))
             && ((*M4_HASH_CMP_FUNC (hash))(M4_HASH_NODE_KEY (next), key) == 0))  
264            {            {
265              if (node)              if (node)
266                M4_HASH_NODE_NEXT (node) = M4_HASH_NODE_NEXT (next);                NODE_NEXT (node)      = NODE_NEXT (next);
267              else              else
268                M4_HASH_BUCKET_NTH (hash, n)= M4_HASH_NODE_NEXT (next);                BUCKET_NTH (hash, n)  = NODE_NEXT (next);
269    
270              key = M4_HASH_NODE_KEY (next);              key = NODE_KEY (next);
271  #ifndef NDEBUG  #ifndef NDEBUG
272              M4_HASH_NODE_KEY (next) = 0;              NODE_KEY (next) = 0;
273  #endif  #endif
274              m4_hash_node_delete (hash, next);              node_delete (hash, next);
275              break;              break;
276            }            }
277          node = next;          node = next;
# Line 280  m4_hash_remove (m4_hash *hash, const voi Line 290  m4_hash_remove (m4_hash *hash, const voi
290  void **  void **
291  m4_hash_lookup (m4_hash *hash, const void *key)  m4_hash_lookup (m4_hash *hash, const void *key)
292  {  {
293    m4_hash_node *node;    hash_node *node;
294    
295    assert (hash);    assert (hash);
296    
297    node = m4_hash_lookup_node (hash, key);    node = node_lookup (hash, key);
298    
299    return node ? &M4_HASH_NODE_VAL (node) : 0;    return node ? &NODE_VALUE (node) : 0;
300  }  }
301    
302  /* Return the first node in HASH that has a matching KEY.  */  /* Return the first node in HASH that has a matching KEY.  */
303  m4_hash_node *  static hash_node *
304  m4_hash_lookup_node (m4_hash *hash, const void *key)  node_lookup (m4_hash *hash, const void *key)
305  {  {
306    m4_hash_node *node;    hash_node *node;
307    
308    assert (hash);    assert (hash);
309    
310    node = M4_HASH_BUCKET_KEY (hash, key);    node = BUCKET_KEY (hash, key);
311    
312    while (node && (*M4_HASH_CMP_FUNC (hash)) (M4_HASH_NODE_KEY (node), key))    while (node && (*HASH_CMP_FUNC (hash)) (NODE_KEY (node), key))
313      node = M4_HASH_NODE_NEXT (node);      node = NODE_NEXT (node);
314    
315    return node;    return node;
316  }  }
317    
318  /* How many entries are currently contained by HASH.  */  /* How many entries are currently contained by HASH.  */
319  size_t  size_t
320  m4_hash_length (m4_hash *hash)  m4_get_hash_length (m4_hash *hash)
321  {  {
322    assert (hash);    assert (hash);
323    
324    return M4_HASH_LENGTH (hash);    return HASH_LENGTH (hash);
325  }  }
326    
327  /* Force the number of buckets to be the given value.  You probably ought  /* Force the number of buckets to be the given value.  You probably ought
# Line 325  m4_hash_length (m4_hash *hash) Line 335  m4_hash_length (m4_hash *hash)
335  void  void
336  m4_hash_resize (m4_hash *hash, size_t size)  m4_hash_resize (m4_hash *hash, size_t size)
337  {  {
338    m4_hash_node **original_buckets;    hash_node **original_buckets;
339    size_t original_size;    size_t original_size;
340    
341    assert (hash);    assert (hash);
342    
343    original_size         = M4_HASH_SIZE (hash);    original_size         = HASH_SIZE (hash);
344    original_buckets      = M4_HASH_BUCKETS (hash);    original_buckets      = HASH_BUCKETS (hash);
345    
346    M4_HASH_SIZE (hash)   = size;    HASH_SIZE (hash)      = size;
347    M4_HASH_BUCKETS (hash)= XCALLOC (m4_hash_node *, size);    HASH_BUCKETS (hash)= XCALLOC (hash_node *, size);
348    
349    {    {
350      size_t i;      size_t i;
351      for (i = 0; i < original_size; ++i)      for (i = 0; i < original_size; ++i)
352        if (original_buckets[i])        if (original_buckets[i])
353          m4_hash_bucket_insert (hash, original_buckets[i]);          bucket_insert (hash, original_buckets[i]);
354    }    }
355    
356    XFREE (original_buckets);    XFREE (original_buckets);
# Line 348  m4_hash_resize (m4_hash *hash, size_t si Line 358  m4_hash_resize (m4_hash *hash, size_t si
358    
359  /* If the node density breaks the threshold, increase the size of  /* If the node density breaks the threshold, increase the size of
360     HASH and repopulate with the original nodes.  */     HASH and repopulate with the original nodes.  */
361  void  static void
362  m4_hash_maybe_grow (m4_hash *hash)  maybe_grow (m4_hash *hash)
363  {  {
364    float nodes_per_bucket;    float nodes_per_bucket;
365    
366    assert (hash);    assert (hash);
367    
368    nodes_per_bucket = (float) M4_HASH_LENGTH (hash)    nodes_per_bucket = (float) HASH_LENGTH (hash) / (float) HASH_SIZE (hash);
                         / (float) M4_HASH_SIZE (hash);  
369    
370    if (nodes_per_bucket > M4_HASH_MAXIMUM_DENSITY)    if (nodes_per_bucket > M4_HASH_MAXIMUM_DENSITY)
371      {      {
372        size_t original_size = M4_HASH_SIZE (hash);        size_t original_size = HASH_SIZE (hash);
373        m4_hash_node **original_buckets = M4_HASH_BUCKETS (hash);        hash_node **original_buckets = HASH_BUCKETS (hash);
374    
375        /* HASH sizes are always 1 less than a power of 2.  */        /* HASH sizes are always 1 less than a power of 2.  */
376        M4_HASH_SIZE (hash)    = (2* (1+ original_size)) -1;        HASH_SIZE (hash)    = (2* (1+ original_size)) -1;
377        M4_HASH_BUCKETS (hash) = XCALLOC (m4_hash_node *, hash->size);        HASH_BUCKETS (hash) = XCALLOC (hash_node *, hash->size);
378    
379        {        {
380          size_t i;          size_t i;
381          for (i = 0; i < original_size; ++i)          for (i = 0; i < original_size; ++i)
382            if (original_buckets[i])            if (original_buckets[i])
383              m4_hash_bucket_insert (hash, original_buckets[i]);              bucket_insert (hash, original_buckets[i]);
384        }        }
385    
386        XFREE (original_buckets);        XFREE (original_buckets);
# Line 380  m4_hash_maybe_grow (m4_hash *hash) Line 389  m4_hash_maybe_grow (m4_hash *hash)
389    
390  /* Insert each node in BUCKET into HASH.  Relative ordering of nodes  /* Insert each node in BUCKET into HASH.  Relative ordering of nodes
391     is not preserved.  */     is not preserved.  */
392  void  static void
393  m4_hash_bucket_insert (m4_hash *hash, m4_hash_node *bucket)  bucket_insert (m4_hash *hash, hash_node *bucket)
394  {  {
395    assert (hash);    assert (hash);
396    assert (bucket);    assert (bucket);
397    
398    do    do
399      {      {
400        m4_hash_node *next = M4_HASH_NODE_NEXT (bucket);        hash_node *next = NODE_NEXT (bucket);
401    
402        /* Break link to rest of the bucket before reinserting.  */        /* Break link to rest of the bucket before reinserting.  */
403        M4_HASH_NODE_NEXT (bucket) = 0;        NODE_NEXT (bucket) = 0;
404        m4_hash_node_insert (hash, bucket);        node_insert (hash, bucket);
405    
406        bucket = next;        bucket = next;
407      }      }
# Line 402  m4_hash_bucket_insert (m4_hash *hash, m4 Line 411  m4_hash_bucket_insert (m4_hash *hash, m4
411  void  void
412  m4_hash_exit (void)  m4_hash_exit (void)
413  {  {
414    while (m4_hash_node_free_list)    while (free_list)
415      {      {
416        m4_hash_node *stale = m4_hash_node_free_list;        hash_node *stale = free_list;
417        m4_hash_node_free_list = M4_HASH_NODE_NEXT (stale);        free_list = NODE_NEXT (stale);
418        xfree (stale);        xfree (stale);
419      }      }
420  }  }
# Line 415  m4_hash_exit (void) Line 424  m4_hash_exit (void)
424  struct m4_hash_iterator  struct m4_hash_iterator
425  {  {
426    const m4_hash *hash;          /* contains the buckets */    const m4_hash *hash;          /* contains the buckets */
427    m4_hash_node *place;          /* the node we are about to return */    hash_node *   place;          /* the node we are about to return */
428    m4_hash_node *next;           /* the next node, incase PLACE is removed */    hash_node *   next;           /* the next node, incase PLACE is removed */
429    size_t        next_bucket;    /* the next bucket index following NEXT */    size_t        next_bucket;    /* the next bucket index following NEXT */
430  };  };
431    
432  #define M4_ITERATOR_HASH(i)         ((i)->hash)  #define ITERATOR_HASH(i)        ((i)->hash)
433  #define M4_ITERATOR_PLACE(i)        ((i)->place)  #define ITERATOR_PLACE(i)       ((i)->place)
434  #define M4_ITERATOR_NEXT(i)         ((i)->next)  #define ITERATOR_NEXT(i)        ((i)->next)
435  #define M4_ITERATOR_NEXT_BUCKET(i)  ((i)->next_bucket)  #define ITERATOR_NEXT_BUCKET(i) ((i)->next_bucket)
436    
437  #define M4_ITERATOR_NEXT_NEXT(i)   M4_HASH_NODE_NEXT (M4_ITERATOR_PLACE (i))  #define ITERATOR_NEXT_NEXT(i)   NODE_NEXT (ITERATOR_PLACE (i))
438    
439  m4_hash_iterator *  m4_hash_iterator *
440  m4_hash_iterator_next (const m4_hash *hash, m4_hash_iterator *place)  m4_get_hash_iterator_next (const m4_hash *hash, m4_hash_iterator *place)
441  {  {
442    assert (hash);    assert (hash);
443    assert (!place || (M4_ITERATOR_HASH (place) == hash));    assert (!place || (ITERATOR_HASH (place) == hash));
444    
445    /* On the first iteration, allocate an iterator.  */    /* On the first iteration, allocate an iterator.  */
446    if (!place)    if (!place)
447      {      {
448        place = XCALLOC (m4_hash_iterator, 1);        place = XCALLOC (m4_hash_iterator, 1);
449        M4_ITERATOR_HASH (place) = hash;        ITERATOR_HASH (place) = hash;
450      }      }
451    
452   next:   next:
453    M4_ITERATOR_PLACE (place) = M4_ITERATOR_NEXT (place);    ITERATOR_PLACE (place) = ITERATOR_NEXT (place);
454    
455    /* If there is another node in the current bucket, select it.  */    /* If there is another node in the current bucket, select it.  */
456    if (M4_ITERATOR_NEXT (place) && M4_HASH_NODE_NEXT (M4_ITERATOR_NEXT (place)))    if (ITERATOR_NEXT (place) && NODE_NEXT (ITERATOR_NEXT (place)))
457      {      {
458        M4_ITERATOR_NEXT (place) = M4_HASH_NODE_NEXT (M4_ITERATOR_NEXT (place));        ITERATOR_NEXT (place) = NODE_NEXT (ITERATOR_NEXT (place));
459      }      }
460    else    else
461      {      {
462        /* Find the next non-empty bucket.  */        /* Find the next non-empty bucket.  */
463        while ((M4_ITERATOR_NEXT_BUCKET (place) < M4_HASH_SIZE (hash))        while ((ITERATOR_NEXT_BUCKET (place) < HASH_SIZE (hash))
464           && (M4_HASH_BUCKET_NTH (hash, M4_ITERATOR_NEXT_BUCKET (place)) == 0))           && (BUCKET_NTH (hash, ITERATOR_NEXT_BUCKET (place)) == 0))
465          {          {
466            ++M4_ITERATOR_NEXT_BUCKET (place);            ++ITERATOR_NEXT_BUCKET (place);
467          }          }
468    
469        /* Select the first node in the new bucket.  */        /* Select the first node in the new bucket.  */
470        if (M4_ITERATOR_NEXT_BUCKET (place) < M4_HASH_SIZE (hash))        if (ITERATOR_NEXT_BUCKET (place) < HASH_SIZE (hash))
471          {          {
472            M4_ITERATOR_NEXT (place)            ITERATOR_NEXT (place)
473              = M4_HASH_BUCKET_NTH (hash, M4_ITERATOR_NEXT_BUCKET (place));              = BUCKET_NTH (hash, ITERATOR_NEXT_BUCKET (place));
474          }          }
475        else        else
476          M4_ITERATOR_NEXT (place) = 0;          ITERATOR_NEXT (place) = 0;
477    
478        /* Advance the `next' reference.  */        /* Advance the `next' reference.  */
479        ++M4_ITERATOR_NEXT_BUCKET (place);        ++ITERATOR_NEXT_BUCKET (place);
480      }      }
481    
482    /* If there are no more nodes to return, recycle the iterator memory.  */    /* If there are no more nodes to return, recycle the iterator memory.  */
483    if (! (M4_ITERATOR_PLACE (place) || M4_ITERATOR_NEXT (place)))    if (! (ITERATOR_PLACE (place) || ITERATOR_NEXT (place)))
484      {      {
485        XFREE (place);        XFREE (place);
486        return 0;        return 0;
# Line 479  m4_hash_iterator_next (const m4_hash *ha Line 488  m4_hash_iterator_next (const m4_hash *ha
488    
489    /* On the first call we need to put the 1st node in PLACE and    /* On the first call we need to put the 1st node in PLACE and
490       the 2nd node in NEXT.  */       the 2nd node in NEXT.  */
491    if (M4_ITERATOR_NEXT (place) && !M4_ITERATOR_PLACE (place))    if (ITERATOR_NEXT (place) && !ITERATOR_PLACE (place))
492      goto next;      goto next;
493    
494    assert (place && M4_ITERATOR_PLACE (place));    assert (place && ITERATOR_PLACE (place));
495    
496    return place;    return place;
497  }  }
498    
499  const void *  const void *
500  m4_hash_iterator_key (m4_hash_iterator *place)  m4_get_hash_iterator_key (m4_hash_iterator *place)
501  {  {
502    assert (place);    assert (place);
503    
504    return M4_HASH_NODE_KEY (M4_ITERATOR_PLACE (place));    return NODE_KEY (ITERATOR_PLACE (place));
505  }  }
506    
507  void *  void *
508  m4_hash_iterator_value (m4_hash_iterator *place)  m4_get_hash_iterator_value (m4_hash_iterator *place)
509  {  {
510    assert (place);    assert (place);
511    
512    return M4_HASH_NODE_VAL (M4_ITERATOR_PLACE (place));    return NODE_VALUE (ITERATOR_PLACE (place));
513  }  }
514    
515  /* The following function is used for the cases where we want to do  /* The following function is used for the cases where we want to do
# Line 508  m4_hash_iterator_value (m4_hash_iterator Line 517  m4_hash_iterator_value (m4_hash_iterator
517     traverses the hash table, and calls a specified function FUNC for     traverses the hash table, and calls a specified function FUNC for
518     each entry in the table.  FUNC is called with a pointer to the     each entry in the table.  FUNC is called with a pointer to the
519     entry key, value, and the passed DATA argument.  */     entry key, value, and the passed DATA argument.  */
520  int  void *
521  m4_hash_apply (m4_hash *hash, m4_hash_apply_func *func, void *data)  m4_hash_apply (m4_hash *hash, m4_hash_apply_func *func, void *userdata)
522  {  {
523    int result = 0;    m4_hash_iterator *place  = NULL;
524    m4_hash_iterator *place = NULL;    void *            result = NULL;
525    
526      assert (hash);
527    assert (func);    assert (func);
528    
529    while ((place = m4_hash_iterator_next (hash, place)))    while ((place = m4_get_hash_iterator_next (hash, place)))
530      {      {
531        result = (*func) (hash, m4_hash_iterator_key (place),        result = (*func) (hash, m4_get_hash_iterator_key (place),
532                          m4_hash_iterator_value (place), data);                          m4_get_hash_iterator_value (place), userdata);
533    
534        if (result != 0)        if (result != NULL)
535          break;          break;
536      }      }
537    

Legend:
Removed from v.1.9  
changed lines
  Added in v.1.10

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26