<URL: http://bugs.freeciv.org/Ticket/Display.html?id=40324 >

The attached patch implements GtkTreeIter style
iterators for hash tables:

{
  struct hash_iter iter;
  
  if (!hash_get_start_iter(h, &iter)) {
    /* Hash table 'h' is empty. */
  }
  
  do {
     void *key = hash_iter_get_key(&iter);
     void *value = hash_iter_get_value(&iter);

     /* Use key and/or value. */

  } while (hash_iter_next(&iter);
}

The point of the above interface is to avoid
the O(N^2) cost of using hash_{key,value}_by_number
to iterate over all items in a hash table (each call
to *_by_number being O(N), with N the number of items
in the table).

The patch also implements hash_fast_clear which does
the same as hash_delete_all_entries but much more
quickly and efficiently. (It cannot be used unfortunately
if the keys or values have associated free_funcs.)

These hash table improvements are needed for my
improved implementation of editor tile selection
(much cleaner than the current one using bitvectors).


----------------------------------------------------------------------
水曜日は働く代わりにほかの惑星で水を探しています。
diff --git a/utility/hash.c b/utility/hash.c
index e2e7dc2..e915bd6 100644
--- a/utility/hash.c
+++ b/utility/hash.c
@@ -771,3 +771,94 @@ const void *hash_value_by_number(const struct hash_table *h,
 {
   return hash_lookup_data(h, hash_key_by_number(h, entry_number));
 }
+
+/**************************************************************************
+  If the hash table is not empty, sets 'iter' to point to the start of the
+  hash table and returns TRUE. Otherwise returns FALSE.
+**************************************************************************/
+bool hash_get_start_iter(const struct hash_table *h,
+                         struct hash_iter *iter)
+{
+  if (!h || !iter || hash_num_entries(h) < 1) {
+    return FALSE;
+  }
+
+  iter->table = h;
+  iter->index = -1;
+  return hash_iter_next(iter);
+}
+
+/**************************************************************************
+  Set the iterator 'iter' to the next item in the hash table. Returns
+  FALSE if there are no more items.
+**************************************************************************/
+bool hash_iter_next(struct hash_iter *iter)
+{
+  const struct hash_table *h;
+  struct hash_bucket *bucket;
+
+  if (!iter || !iter->table) {
+    return FALSE;
+  }
+
+  h = iter->table;
+  iter->index++;
+
+  while (iter->index < hash_num_buckets(h)) {
+    bucket = h->buckets + iter->index;
+    if (bucket && bucket->used == BUCKET_USED) {
+      iter->key = bucket->key;
+      iter->value = bucket->data;
+      return TRUE;
+    }
+    iter->index++;
+  }
+
+  return FALSE;
+}
+
+/**************************************************************************
+  Returns the key of the hash table item pointed to by this iterator.
+**************************************************************************/
+void *hash_iter_get_key(struct hash_iter *iter)
+{
+  if (!iter) {
+    return NULL;
+  }
+  return (void *) iter->key;
+}
+
+/**************************************************************************
+  Returns the value (or "data) of the hash table item pointed to by this
+  iterator.
+**************************************************************************/
+void *hash_iter_get_value(struct hash_iter *iter)
+{
+  if (!iter) {
+    return NULL;
+  }
+  return (void *) iter->value;
+}
+
+/**************************************************************************
+  Quickly erase all items in the hash table returning it to an empty
+  state.
+  
+  NB: This function MUST NOT be used if you supplied a free_key_func
+  or free_data_func to hash_new_*. In that case you must use
+  hash_delete_all_entries instead.
+**************************************************************************/
+void hash_fast_clear(struct hash_table *h)
+{
+  if (!h) {
+    return;
+  }
+
+  assert(h->free_key_func == NULL);
+  assert(h->free_data_func == NULL);
+  
+  memset(h->buckets, 0, sizeof(struct hash_bucket) * h->num_buckets);
+  h->num_entries = 0;
+  h->num_deleted = 0;
+  h->frozen = FALSE;
+}
diff --git a/utility/hash.h b/utility/hash.h
index 9dc6e1d..b53f413 100644
--- a/utility/hash.h
+++ b/utility/hash.h
@@ -79,4 +79,19 @@ unsigned int hash_num_entries(const struct hash_table *h);
 unsigned int hash_num_buckets(const struct hash_table *h);
 unsigned int hash_num_deleted(const struct hash_table *h);
 
+void hash_fast_clear(struct hash_table *h);
+
+struct hash_iter {
+  const struct hash_table *table;
+  int index;
+  const void *key;
+  const void *value;
+};
+
+bool hash_get_start_iter(const struct hash_table *h,
+                         struct hash_iter *iter);
+bool hash_iter_next(struct hash_iter *iter);
+void *hash_iter_get_key(struct hash_iter *iter);
+void *hash_iter_get_value(struct hash_iter *iter);
+
 #endif  /* FC__HASH_H */
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to