[Freeciv-Dev] (PR#40324) [patch] Hash table iterators and fast clear

2008-07-01 Thread Madeline Book

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

Committed to S2_2 (r14932) and trunk (r14933).

Shortly thereafter, also fixed a comment typo in the former
two commits thus preventing the atrocity remaining there
until the end of time. -_-


--
申し訳ございません

___
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev


[Freeciv-Dev] (PR#40324) [patch] Hash table iterators and fast clear

2008-06-27 Thread Madeline Book

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

Fixed two typos in the hash_iterate macro.


-
月曜日は働く代わりに猫さんたちと月に飛んでいます。
diff --git a/utility/hash.c b/utility/hash.c
index e2e7dc2..f1fbcb7 100644
--- a/utility/hash.c
+++ b/utility/hash.c
@@ -130,6 +130,7 @@ struct hash_table {
   unsigned int num_entries;	/* does not included deleted entries */
   unsigned int num_deleted;
   bool frozen;			/* do not auto-resize when set */
+  bool no_shrink; /* Do no shrink, settable by user. */
 };
 
 /* Calculate hash value given hash_table ptr and key: */
@@ -158,6 +159,7 @@ static void zero_htable(struct hash_table *h)
   h-free_data_func = NULL;
   h-num_buckets = h-num_entries = h-num_deleted = 0;
   h-frozen = FALSE;
+  h-no_shrink = FALSE;
 }
 
 
@@ -438,6 +440,9 @@ static void hash_maybe_resize(struct hash_table *h, bool expandingp)
   if (h-frozen) {
 return;
   }
+  if (!expandingp  h-no_shrink) {
+return;
+  }
   num_used = h-num_entries + h-num_deleted;
   if (expandingp) {
 limit = FULL_RATIO * h-num_buckets;
@@ -663,9 +668,16 @@ void hash_delete_all_entries(struct hash_table *h)
 {
   unsigned int bucket_nr;
 
-  /* Modeled after hash_key_by_number and hash_delete_entry. */
-  for (bucket_nr = 0; bucket_nr  h-num_buckets; bucket_nr++) {
-hash_delete_bucket(h, h-buckets[bucket_nr], NULL, NULL);
+  if (h-free_key_func == NULL  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;
+  } else {
+/* Modeled after hash_key_by_number and hash_delete_entry. */
+for (bucket_nr = 0; bucket_nr  h-num_buckets; bucket_nr++) {
+  hash_delete_bucket(h, h-buckets[bucket_nr], NULL, NULL);
+}
   }
   hash_maybe_shrink(h);
 }
@@ -771,3 +783,84 @@ 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;
+}
+
+/**
+  Prevent or allow the hash table automatically shrinking. Returns
+  the old value of the setting.
+**/
+bool hash_set_no_shrink(struct hash_table *h, bool no_shrink)
+{
+  bool old = h-no_shrink;
+
+  h-no_shrink = no_shrink;
+
+  return old;
+}
diff --git a/utility/hash.h b/utility/hash.h
index 9dc6e1d..d23f6f5 100644
--- a/utility/hash.h
+++ b/utility/hash.h
@@ -79,4 +79,32 @@ 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);
 
+bool hash_set_no_shrink(struct hash_table *h,
+bool no_shrink);
+
+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,
+ 

[Freeciv-Dev] (PR#40324) [patch] Hash table iterators and fast clear

2008-06-25 Thread Madeline Book

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


Re: [Freeciv-Dev] (PR#40324) [patch] Hash table iterators and fast clear

2008-06-25 Thread Jason Dorje Short

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

Madeline Book wrote:

 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.)

Why not just give hash_delete_all_entries a special case after a check 
for if there's a free_func?  Having a second function that does almost 
the same thing isn't so good.

-jason



___
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev


[Freeciv-Dev] (PR#40324) [patch] Hash table iterators and fast clear

2008-06-25 Thread Madeline Book

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

 [EMAIL PROTECTED] - Wed Jun 25 17:31:41 2008]:
 
 Madeline Book wrote:
 
  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.)
 
 Why not just give hash_delete_all_entries a special case after
 a check for if there's a free_func?  Having a second function that
 does almost the same thing isn't so good.

Oh, very good point. Version 2 of the patch makes the body
of hash_fast_clear a special case of hash_delete_all_entries
when there are no free_funcs.

Also added is a wrapper macro for iteration, hash_iterate,
to make the iteration interface analogous to list iteration.

Finally, for the case when the programmer knows it would
be more efficient if the hash table did not shrink automatically,
a function hash_set_no_shrink is added.


--
木曜日は働く代わりに木を食べようとします。
diff --git a/utility/hash.c b/utility/hash.c
index e2e7dc2..f1fbcb7 100644
--- a/utility/hash.c
+++ b/utility/hash.c
@@ -130,6 +130,7 @@ struct hash_table {
   unsigned int num_entries;	/* does not included deleted entries */
   unsigned int num_deleted;
   bool frozen;			/* do not auto-resize when set */
+  bool no_shrink; /* Do no shrink, settable by user. */
 };
 
 /* Calculate hash value given hash_table ptr and key: */
@@ -158,6 +159,7 @@ static void zero_htable(struct hash_table *h)
   h-free_data_func = NULL;
   h-num_buckets = h-num_entries = h-num_deleted = 0;
   h-frozen = FALSE;
+  h-no_shrink = FALSE;
 }
 
 
@@ -438,6 +440,9 @@ static void hash_maybe_resize(struct hash_table *h, bool expandingp)
   if (h-frozen) {
 return;
   }
+  if (!expandingp  h-no_shrink) {
+return;
+  }
   num_used = h-num_entries + h-num_deleted;
   if (expandingp) {
 limit = FULL_RATIO * h-num_buckets;
@@ -663,9 +668,16 @@ void hash_delete_all_entries(struct hash_table *h)
 {
   unsigned int bucket_nr;
 
-  /* Modeled after hash_key_by_number and hash_delete_entry. */
-  for (bucket_nr = 0; bucket_nr  h-num_buckets; bucket_nr++) {
-hash_delete_bucket(h, h-buckets[bucket_nr], NULL, NULL);
+  if (h-free_key_func == NULL  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;
+  } else {
+/* Modeled after hash_key_by_number and hash_delete_entry. */
+for (bucket_nr = 0; bucket_nr  h-num_buckets; bucket_nr++) {
+  hash_delete_bucket(h, h-buckets[bucket_nr], NULL, NULL);
+}
   }
   hash_maybe_shrink(h);
 }
@@ -771,3 +783,84 @@ 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;
+}
+
+/**
+  Prevent or allow the hash table