I looked at converting man-db to use Gnulib's hash implementation rather
than its own.  One obstacle seems to be that there is one place where
man-db cares about the difference between a key not being in the hash at
all, and a key being in the hash but with a NULL value (in Perl syntax,
the difference between 'not exists $hash{$key}' and 'not defined
$hash{$key}').  I haven't spent much time looking at the relevant code
and so it may well be that it can be rewritten to avoid relying on this
distinction, but in general it does seem like a useful distinction to
draw; most high-level languages' built-in hash implementations allow you
to ask whether a key exists without testing the truth of its value.

The attached patch adds this feature.

Thanks,

-- 
Colin Watson                                       [cjwat...@debian.org]
diff --git a/ChangeLog b/ChangeLog
index c382d58..2f32364 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2010-02-14  Colin Watson  <cjwat...@debian.org>
+
+	* lib/hash.c (hash_contains): New function (trivial modification of
+	hash_lookup).
+	* lib/hash.h (hash_contains): New declaration.
+	* tests/test-hash.c (main): Test hash_contains.
+
 2010-02-10  Jim Meyering  <meyer...@redhat.com>
 
 	maint.mk: prohibit inclusion of "ignore-value.h" without_use
diff --git a/lib/hash.c b/lib/hash.c
index f9abb9f..de8b778 100644
--- a/lib/hash.c
+++ b/lib/hash.c
@@ -243,6 +243,28 @@ hash_print_statistics (const Hash_table *table, FILE *stream)
            (unsigned long int) max_bucket_length);
 }
 
+/* Return true if ENTRY matches an entry already in the hash table.  */
+
+bool
+hash_contains (const Hash_table *table, const void *entry)
+{
+  struct hash_entry const *bucket
+    = table->bucket + table->hasher (entry, table->n_buckets);
+  struct hash_entry const *cursor;
+
+  if (! (bucket < table->bucket_limit))
+    abort ();
+
+  if (bucket->data == NULL)
+    return false;
+
+  for (cursor = bucket; cursor; cursor = cursor->next)
+    if (entry == cursor->data || table->comparator (entry, cursor->data))
+      return true;
+
+  return false;
+}
+
 /* If ENTRY matches an entry already in the hash table, return the
    entry from the table.  Otherwise, return NULL.  */
 
diff --git a/lib/hash.h b/lib/hash.h
index e795cdc..00e2e1a 100644
--- a/lib/hash.h
+++ b/lib/hash.h
@@ -68,6 +68,7 @@ size_t hash_get_n_entries (const Hash_table *);
 size_t hash_get_max_bucket_length (const Hash_table *);
 bool hash_table_ok (const Hash_table *);
 void hash_print_statistics (const Hash_table *, FILE *);
+bool hash_contains (const Hash_table *, const void *);
 void *hash_lookup (const Hash_table *, const void *);
 
 /* Walking.  */
diff --git a/tests/test-hash.c b/tests/test-hash.c
index 1715033..756f0ae 100644
--- a/tests/test-hash.c
+++ b/tests/test-hash.c
@@ -164,7 +164,9 @@ main (int argc, char **argv)
         char *str = xstrdup ("a");
         insert_new (ht, "a");
         insert_new (ht, str);
+        ASSERT (hash_contains (ht, str));
         ASSERT (hash_lookup (ht, str) == str);
+        ASSERT (!hash_contains (ht, "b"));
         free (str);
       }
       hash_free (ht);

Reply via email to