]> git.kaiwu.me - klib.git/commitdiff
Add allocation wrappers and error checking
authorRussell Belfer <rb@github.com>
Fri, 31 Aug 2012 23:06:32 +0000 (16:06 -0700)
committerRussell Belfer <rb@github.com>
Fri, 31 Aug 2012 23:06:32 +0000 (16:06 -0700)
When embedding khash in another project, it is convenient to be
able to replace the use of malloc/calloc/free with alternatives.
This wraps those calls with kmalloc/kcalloc/kfree, etc. macros
that can be easily redefined by the khash user to override the
allocators.

Additionally, the return value from allocations was not being
checked.  This adds a check whenever an allocation is performed
and a return code of -1 to indicate an allocation failure.

khash.h

diff --git a/khash.h b/khash.h
index 9a4049aa2ea3e39556ae5acb114f6e113834439f..1bc327c1c1d83131786eb27642b9a24cc41ddcb9 100644 (file)
--- a/khash.h
+++ b/khash.h
@@ -157,6 +157,19 @@ typedef khint_t khiter_t;
 #define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
 #endif
 
+#ifndef kcalloc
+#define kcalloc(N,Z) calloc(N,Z)
+#endif
+#ifndef kmalloc
+#define kmalloc(Z) malloc(Z)
+#endif
+#ifndef krealloc
+#define krealloc(P,Z) realloc(P,Z)
+#endif
+#ifndef kfree
+#define kfree(P) free(P)
+#endif
+
 static const double __ac_HASH_UPPER = 0.77;
 
 #define __KHASH_TYPE(name, khkey_t, khval_t) \
@@ -172,7 +185,7 @@ static const double __ac_HASH_UPPER = 0.77;
        extern void kh_destroy_##name(kh_##name##_t *h);                                        \
        extern void kh_clear_##name(kh_##name##_t *h);                                          \
        extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key);      \
-       extern void kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \
+       extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \
        extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \
        extern void kh_del_##name(kh_##name##_t *h, khint_t x);
 
@@ -183,9 +196,9 @@ static const double __ac_HASH_UPPER = 0.77;
        SCOPE void kh_destroy_##name(kh_##name##_t *h)                                          \
        {                                                                                                                                       \
                if (h) {                                                                                                                \
-                       free(h->keys); free(h->flags);                                                          \
-                       free(h->vals);                                                                                          \
-                       free(h);                                                                                                        \
+                       kfree((void *)h->keys); kfree(h->flags);                                        \
+                       kfree((void *)h->vals);                                                                         \
+                       kfree(h);                                                                                                       \
                }                                                                                                                               \
        }                                                                                                                                       \
        SCOPE void kh_clear_##name(kh_##name##_t *h)                                            \
@@ -209,7 +222,7 @@ static const double __ac_HASH_UPPER = 0.77;
                        return __ac_iseither(h->flags, i)? h->n_buckets : i;            \
                } else return 0;                                                                                                \
        }                                                                                                                                       \
-       SCOPE void kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
+       SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
        { /* This function uses 0.25*n_bucktes bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \
                khint32_t *new_flags = 0;                                                                               \
                khint_t j = 1;                                                                                                  \
@@ -218,11 +231,18 @@ static const double __ac_HASH_UPPER = 0.77;
                        if (new_n_buckets < 4) new_n_buckets = 4;                                       \
                        if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \
                        else { /* hash table size to be changed (shrink or expand); rehash */ \
-                               new_flags = (khint32_t*)malloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t));  \
+                               new_flags = (khint32_t*)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
+                               if (!new_flags) return -1;                                                              \
                                memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
                                if (h->n_buckets < new_n_buckets) {     /* expand */            \
-                                       h->keys = (khkey_t*)realloc(h->keys, new_n_buckets * sizeof(khkey_t)); \
-                                       if (kh_is_map) h->vals = (khval_t*)realloc(h->vals, new_n_buckets * sizeof(khval_t)); \
+                                       khkey_t *new_keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
+                                       if (!new_keys) return -1;                                                       \
+                                       h->keys = new_keys;                                                                     \
+                                       if (kh_is_map) {                                                                        \
+                                               khval_t *new_vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
+                                               if (!new_vals) return -1;                                               \
+                                               h->vals = new_vals;                                                             \
+                                       }                                                                                                       \
                                } /* otherwise shrink */                                                                \
                        }                                                                                                                       \
                }                                                                                                                               \
@@ -255,22 +275,28 @@ static const double __ac_HASH_UPPER = 0.77;
                                }                                                                                                               \
                        }                                                                                                                       \
                        if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
-                               h->keys = (khkey_t*)realloc(h->keys, new_n_buckets * sizeof(khkey_t)); \
-                               if (kh_is_map) h->vals = (khval_t*)realloc(h->vals, new_n_buckets * sizeof(khval_t)); \
+                               h->keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
+                               if (kh_is_map) h->vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
                        }                                                                                                                       \
-                       free(h->flags); /* free the working space */                            \
+                       kfree(h->flags); /* free the working space */                           \
                        h->flags = new_flags;                                                                           \
                        h->n_buckets = new_n_buckets;                                                           \
                        h->n_occupied = h->size;                                                                        \
                        h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \
                }                                                                                                                               \
+               return 0;                                                                                                               \
        }                                                                                                                                       \
        SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \
        {                                                                                                                                       \
                khint_t x;                                                                                                              \
                if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
-                       if (h->n_buckets > (h->size<<1)) kh_resize_##name(h, h->n_buckets - 1); /* clear "deleted" elements */ \
-                       else kh_resize_##name(h, h->n_buckets + 1); /* expand the hash table */ \
+                       if (h->n_buckets > (h->size<<1)) {                                                      \
+                               if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \
+                                       *ret = -1; return h->n_buckets;                                         \
+                               }                                                                                                               \
+                       } else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \
+                               *ret = -1; return h->n_buckets;                                                 \
+                       }                                                                                                                       \
                } /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
                {                                                                                                                               \
                        khint_t inc, k, i, site, last, mask = h->n_buckets - 1;         \