Am 01.10.2018 um 22:26 schrieb Jeff King:
> On Mon, Oct 01, 2018 at 09:15:53PM +0200, René Scharfe wrote:
> The reason hashmap.c was added was to avoid open addressing. ;)
Because efficient removal of elements is easier to implement with
chaining, according to 6a364ced49 (add a hashtable implementation that
supports O(1) removal).  khash.h deletes using its flags bitmap.  We
didn't compare their performance when entries are removed so far.

> So yeah, I think it could perhaps be improved, but in my mind talking
> about "hashmap.c" is fundamentally talking about chained buckets.

Admittedly I wouldn't touch hashmap.c, as I find its interface too
complex to wrap my head around.  But perhaps I just didn't try hard
enough, yet.

>> But I like how khash.h is both already in the tree and also really easy
>> to deploy, as it's just a single header file.  It's a tasty low-hanging
>> fruit.
> 
> Yeah. And if it really does perform better, I think we should stick with
> it in the code base. I wonder if we could stand to clean up the
> interfaces a little.  E.g., I had a hard time declaring a hash in one
> place, and then defining it somewhere else.

You can't use KHASH_DECLARE and KHASH_INIT together, as both declare
the same structs.  So I guess the idea is to have a header file with
KHASH_DECLARE and a .c file with KHASH_INIT, the latter *not* including
the former, but both including khash.h.  I didn't actually try that,
though.

> And I think as you found
> that it insists on heap-allocating the hash-table struct itself, which
> does not match our usual style.

Perhaps we can fix that with little effort (see below).

>> This is straight-forward, except for oidset_clear(), which needs to
>> allocate a kh_oid_t on the heap in order to be able to feed it to
>> kh_destroy_oid() for release it.  Alternatively we could open-code the
>> relevant parts of the latter, but that would be a layering violation.
> 
> This is kind of a layering violation, too. You're assuming that struct
> assignment is sufficient to make one kh struct freeable from another
> pointer. That's probably reasonable, since you're just destroying them
> both (e.g., some of our FLEX structs point into their own struct memory,
> making a hidden dependency; but they obviously would not need to free
> such a field).

Fair enough.  How about this on top?  (The khash.h part would go in
first in a separate patch in a proper series.)

NB: I stuck to the 4-spaces-tabs formatting in khash.h here.

---
 khash.h  | 9 +++++++--
 oidset.c | 4 +---
 2 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/khash.h b/khash.h
index 07b4cc2e67..d10caa0c35 100644
--- a/khash.h
+++ b/khash.h
@@ -82,11 +82,16 @@ static const double __ac_HASH_UPPER = 0.77;
        SCOPE kh_##name##_t *kh_init_##name(void) {                             
                        \
                return (kh_##name##_t*)xcalloc(1, sizeof(kh_##name##_t));       
        \
        }                                                                       
                                                                \
+       SCOPE void kh_release_##name(kh_##name##_t *h)                          
                \
+       {                                                                       
                                                                \
+               free(h->flags);                                                 
                                                \
+               free((void *)h->keys);                                          
                                        \
+               free((void *)h->vals);                                          
                                        \
+       }                                                                       
                                                                \
        SCOPE void kh_destroy_##name(kh_##name##_t *h)                          
                \
        {                                                                       
                                                                \
                if (h) {                                                        
                                                        \
-                       free((void *)h->keys); free(h->flags);                  
                \
-                       free((void *)h->vals);                                  
                                        \
+                       kh_release_##name(h);                                   
                                        \
                        free(h);                                                
                                                        \
                }                                                               
                                                                \
        }                                                                       
                                                                \
diff --git a/oidset.c b/oidset.c
index d15b2b7a89..9836d427ef 100644
--- a/oidset.c
+++ b/oidset.c
@@ -25,8 +25,6 @@ int oidset_remove(struct oidset *set, const struct object_id 
*oid)
 
 void oidset_clear(struct oidset *set)
 {
-       kh_oid_t *to_free = kh_init_oid();
-       *to_free = set->set;
-       kh_destroy_oid(to_free);
+       kh_release_oid(&set->set);
        oidset_init(set, 0);
 }
-- 
2.19.0

Reply via email to