summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Roche <xroche@users.noreply.github.com>2014-05-08 09:13:54 +0000
committerXavier Roche <xroche@users.noreply.github.com>2014-05-08 09:13:54 +0000
commit3a3d27386cc4e3ce21ca6032e435e3480a1052fa (patch)
tree4728f995c7c05679bda85511508b3ebc0932ee73
parentd59341813ded62de1542fc9edaebf90cb684db25 (diff)
Added assertion handlers to hashtables.
-rw-r--r--src/htsinthash.c114
-rw-r--r--src/htsinthash.h23
2 files changed, 94 insertions, 43 deletions
diff --git a/src/htsinthash.c b/src/htsinthash.c
index 32c8e1c..4b125c3 100644
--- a/src/htsinthash.c
+++ b/src/htsinthash.c
@@ -26,8 +26,7 @@ Please visit our Website: http://www.httrack.com
*/
/* ------------------------------------------------------------ */
-/* File: httrack.c subroutines: */
-/* hash tables */
+/* File: hash tables */
/* Author: Xavier Roche */
/* ------------------------------------------------------------ */
@@ -176,19 +175,25 @@ struct struct_inthash {
/** opaque argument **/
void *arg;
} key;
+
+ /** How to handle fatal assertions (might be NULL). **/
+ struct {
+ /** abort() **/
+ t_inthash_asserthandler fatal;
+ /** opaque argument **/
+ void *arg;
+ } error;
} custom;
};
/* Using httrack code */
-#ifdef LIBHTTRACK_EXPORTS
-#include "htsbase.h"
-#define inthash_assert assertf
-#else
static void inthash_fail(const char* exp, const char* file, int line) {
fprintf(stderr, "assertion '%s' failed at %s:%d\n", exp, file, line);
abort();
}
-#define inthash_assert(EXP) (void)( (EXP) || (inthash_fail(#EXP, __FILE__, __LINE__), 0) )
+#define inthash_assert(HASHTABLE, EXP) \
+ (void)( (EXP) || (inthash_assert_failed(HASHTABLE, #EXP, __FILE__, __LINE__), 0) )
+
/* Compiler-specific. */
#ifndef HTS_PRINTF_FUN
#ifdef __GNUC__
@@ -204,7 +209,6 @@ static void inthash_fail(const char* exp, const char* file, int line) {
#define HTS_INLINE
#endif
#endif
-#endif
/* Logging level. */
#if 0
@@ -233,12 +237,27 @@ static void inthash_fail(const char* exp, const char* file, int line) {
/* the empty string for the string pool */
static char the_empty_string[1] = { 0 };
+/* global assertion handler */
+static t_inthash_asserthandler global_assert_handler = NULL;
+
+/* Assert failed handler. */
+static void inthash_assert_failed(const inthash hashtable, const char* exp, const char* file, int line) {
+ if (hashtable != NULL && hashtable->custom.error.fatal != NULL) {
+ hashtable->custom.error.fatal(hashtable->custom.error.arg, exp, file, line);
+ } else if (global_assert_handler != NULL) {
+ global_assert_handler(hashtable, exp, file, line);
+ } else {
+ inthash_fail(exp, file, line);
+ }
+ abort();
+}
+
/* Logging */
static void inthash_log(const inthash hashtable, const char *format, ...)
HTS_PRINTF_FUN(2, 3);
static void inthash_log(const inthash hashtable, const char *format, ...) {
va_list args;
- inthash_assert(format != NULL);
+ inthash_assert(hashtable, format != NULL);
fprintf(stderr, "[%p] ", (void*) hashtable);
va_start(args, format);
(void) vfprintf(stderr, format, args);
@@ -417,7 +436,7 @@ static void inthash_compact_pool(inthash hashtable, size_t capacity) {
size_t count = 0;
/* we manage the string pool */
- assert(hashtable->custom.key.dup == NULL);
+ inthash_assert(hashtable, hashtable->custom.key.dup == NULL);
/* statistics */
hashtable->stats.pool_compact_count++;
@@ -436,7 +455,7 @@ static void inthash_compact_pool(inthash hashtable, size_t capacity) {
"** hashtable string pool compaction error: could not allocate "
"%"UINT_64_FORMAT" bytes",
(uint64_t) hashtable->pool.capacity);
- inthash_assert(! "hashtable string pool compaction error");
+ inthash_assert(hashtable, ! "hashtable string pool compaction error");
}
/* relocate a string on a different pool */
@@ -449,17 +468,18 @@ static void inthash_compact_pool(inthash hashtable, size_t capacity) {
char *const max_dest = \
&hashtable->pool.buffer[capacity]; \
/* copy string */ \
- inthash_assert(dest < max_dest); \
+ inthash_assert(hashtable, dest < max_dest); \
dest[0] = src[0]; \
{ \
size_t i; \
for(i = 1 ; src[i - 1] != '\0' ; i++) { \
- inthash_assert(&dest[i] < max_dest); \
+ inthash_assert(hashtable, &dest[i] < max_dest); \
dest[i] = src[i]; \
} \
/* update pool size */ \
hashtable->pool.size += i; \
- assert(hashtable->pool.size <= capacity); \
+ inthash_assert(hashtable, \
+ hashtable->pool.size <= capacity); \
} \
/* update source */ \
S = dest; \
@@ -498,7 +518,7 @@ static void inthash_realloc_pool(inthash hashtable, size_t capacity) {
size_t count = 0;
/* we manage the string pool */
- assert(hashtable->custom.key.dup == NULL);
+ inthash_assert(hashtable, hashtable->custom.key.dup == NULL);
/* compact instead ? */
if (hashtable->pool.used < ( hashtable->pool.size*3 ) / 4) {
@@ -520,17 +540,17 @@ static void inthash_realloc_pool(inthash hashtable, size_t capacity) {
"** hashtable string pool allocation error: could not allocate "
"%"UINT_64_FORMAT" bytes",
(uint64_t) hashtable->pool.capacity);
- inthash_assert(! "hashtable string pool allocation error");
+ inthash_assert(hashtable, ! "hashtable string pool allocation error");
}
/* recompute string address */
-#define RECOMPUTE_STRING(S) do { \
- if (S != NULL && S != the_empty_string) { \
- const size_t offset = (S) - oldbase; \
- assert(offset < hashtable->pool.capacity); \
- S = &hashtable->pool.buffer[offset]; \
- count++; \
- } \
+#define RECOMPUTE_STRING(S) do { \
+ if (S != NULL && S != the_empty_string) { \
+ const size_t offset = (S) - oldbase; \
+ inthash_assert(hashtable, offset < hashtable->pool.capacity); \
+ S = &hashtable->pool.buffer[offset]; \
+ count++; \
+ } \
} while(0)
/* recompute */
@@ -555,22 +575,22 @@ static char* inthash_dup_name_internal(inthash hashtable, const char *name) {
/* the pool does not allow empty strings for safety purpose ; handhe that
(keys are being emptied when free'd to detect duplicate free) */
if (len == 1) {
- assert(the_empty_string[0] == '\0');
+ inthash_assert(hashtable, the_empty_string[0] == '\0');
return the_empty_string;
}
/* expand pool capacity */
- assert(hashtable->pool.size <= hashtable->pool.capacity);
+ inthash_assert(hashtable, hashtable->pool.size <= hashtable->pool.capacity);
if (hashtable->pool.capacity - hashtable->pool.size < len) {
size_t capacity;
for(capacity = MIN_POOL_CAPACITY ; capacity < hashtable->pool.size + len
; capacity <<= 1) ;
- assert(hashtable->pool.size < capacity);
+ inthash_assert(hashtable, hashtable->pool.size < capacity);
inthash_realloc_pool(hashtable, capacity);
}
/* copy */
- assert(len + hashtable->pool.size <= hashtable->pool.capacity);
+ inthash_assert(hashtable, len + hashtable->pool.size <= hashtable->pool.capacity);
s = &hashtable->pool.buffer[hashtable->pool.size];
memcpy(s, name, len);
hashtable->pool.size += len;
@@ -593,11 +613,11 @@ static void inthash_free_key_internal(inthash hashtable, char *name) {
/* see inthash_dup_name_internal() handling */
if (len == 1 && name == the_empty_string) {
- assert(the_empty_string[0] == '\0');
+ inthash_assert(hashtable, the_empty_string[0] == '\0');
return ;
}
- assert(*name != '\0' || !"duplicate or bad string pool release");
+ inthash_assert(hashtable, *name != '\0' || !"duplicate or bad string pool release");
hashtable->pool.used -= len;
*name = '\0'; /* the string is now invalidated */
@@ -608,7 +628,7 @@ static void inthash_free_key_internal(inthash hashtable, char *name) {
if (hashtable->pool.used < capacity / 4) {
capacity /= 2;
}
- assert(hashtable->pool.used < capacity);
+ inthash_assert(hashtable, hashtable->pool.used < capacity);
inthash_compact_pool(hashtable, capacity);
}
}
@@ -811,7 +831,7 @@ static int inthash_add_item_(inthash hashtable, inthash_item item) {
cuckoo_hash = item.hashes.hash1;
}
else {
- inthash_assert(! "hashtable internal error: unexpected position");
+ inthash_assert(hashtable, ! "hashtable internal error: unexpected position");
}
/* we are looping (back to same hash) */
@@ -839,7 +859,7 @@ static int inthash_add_item_(inthash hashtable, inthash_item item) {
/* we are doomed. hopefully the probability is lower than being killed
by a wandering radioactive monkey */
inthash_log_stats(hashtable);
- inthash_assert(! "hashtable internal error: cuckoo/stash collision");
+ inthash_assert(hashtable, ! "hashtable internal error: cuckoo/stash collision");
/* not reachable code */
return -1;
}
@@ -882,7 +902,7 @@ int inthash_write_value(inthash hashtable, const char *name,
"** hashtable allocation error: "
"could not allocate %"UINT_64_FORMAT" bytes",
(uint64_t) alloc_size);
- inthash_assert(! "hashtable allocation error");
+ inthash_assert(hashtable, ! "hashtable allocation error");
}
/* clear upper half */
@@ -898,7 +918,7 @@ int inthash_write_value(inthash hashtable, const char *name,
const size_t pos = inthash_hash_to_pos(hashtable, hashes->hash1);
/* no more the expected position */
if (pos != i) {
- inthash_assert(pos >= prev_size);
+ inthash_assert(hashtable, pos >= prev_size);
hashtable->items[pos] = hashtable->items[i];
memset(&hashtable->items[i], 0, sizeof(hashtable->items[i]));
}
@@ -907,13 +927,13 @@ int inthash_write_value(inthash hashtable, const char *name,
const size_t pos = inthash_hash_to_pos(hashtable, hashes->hash2);
/* no more the expected position */
if (pos != i) {
- inthash_assert(pos >= prev_size);
+ inthash_assert(hashtable, pos >= prev_size);
hashtable->items[pos] = hashtable->items[i];
memset(&hashtable->items[i], 0, sizeof(hashtable->items[i]));
}
}
else {
- inthash_assert(! "hashtable unexpected internal error (bad position)");
+ inthash_assert(hashtable, ! "hashtable unexpected internal error (bad position)");
}
}
}
@@ -936,12 +956,12 @@ int inthash_write_value(inthash hashtable, const char *name,
for(i = 0 ; i < old_size ; i++) {
const int ret = inthash_add_item_(hashtable, stash[i]);
if (ret == 0) {
- inthash_assert(! "hashtable duplicate key when merging the stash");
+ inthash_assert(hashtable, ! "hashtable duplicate key when merging the stash");
}
}
/* logging */
- inthash_assert(hashtable->stash.size <= old_size);
+ inthash_assert(hashtable, hashtable->stash.size <= old_size);
if (hashtable->stash.size < old_size) {
inthash_debug(hashtable, "reduced stash size from %"UINT_64_FORMAT" "
"to %"UINT_64_FORMAT,
@@ -1028,7 +1048,7 @@ static size_t inthash_inc_(inthash hashtable, const char *name,
} else {
/* create a new value */
const int ret = inthash_write(hashtable, name, inc);
- inthash_assert(ret);
+ inthash_assert(hashtable, ret);
return inc;
}
}
@@ -1095,7 +1115,7 @@ int inthash_remove(inthash hashtable, const char *name) {
if (ret) {
/* item was removed: decrease count */
- inthash_assert(hashtable->used != 0);
+ inthash_assert(hashtable, hashtable->used != 0);
hashtable->used--;
/* can we place stash entry back to the table ? */
@@ -1202,7 +1222,7 @@ void inthash_value_set_key_handler(inthash hashtable,
t_inthash_cmphandler equals,
void *arg) {
/* dup and free must be consistent */
- assert( ( dup == NULL ) == ( free == NULL ) );
+ inthash_assert(hashtable, ( dup == NULL ) == ( free == NULL ) );
hashtable->custom.key.dup = dup;
hashtable->custom.key.free = free;
hashtable->custom.key.hash = hash;
@@ -1210,6 +1230,14 @@ void inthash_value_set_key_handler(inthash hashtable,
hashtable->custom.key.arg = arg;
}
+void inthash_set_assert_handler(inthash hashtable,
+ t_inthash_asserthandler fatal,
+ void *arg) {
+ inthash_assert(hashtable, fatal != NULL);
+ hashtable->custom.error.fatal = fatal;
+ hashtable->custom.error.arg = arg;
+}
+
size_t inthash_nitems(inthash hashtable) {
if (hashtable != NULL)
return hashtable->used;
@@ -1290,3 +1318,7 @@ inthash_item *inthash_enum_next(struct_inthash_enum * e) {
return NULL;
}
}
+
+void inthash_set_global_assert_handler(t_inthash_asserthandler fatal) {
+ global_assert_handler = fatal;
+}
diff --git a/src/htsinthash.h b/src/htsinthash.h
index 2a705ae..a4d8ea8 100644
--- a/src/htsinthash.h
+++ b/src/htsinthash.h
@@ -26,8 +26,7 @@ Please visit our Website: http://www.httrack.com
*/
/* ------------------------------------------------------------ */
-/* File: httrack.c subroutines: */
-/* hash table system (fast index) */
+/* File: hash table system (fast index) */
/* Author: Xavier Roche */
/* ------------------------------------------------------------ */
@@ -125,6 +124,9 @@ typedef char* (*t_inthash_duphandler) (void *arg, const char *name);
/** Hash computation handler. **/
typedef inthash_keys (*t_inthash_hasheshandler)(void *arg, const char *value);
+/** Hashtable fatal assertion failure. **/
+typedef void (*t_inthash_asserthandler)(void *arg, const char* exp, const char* file, int line);
+
/**
* Value comparison handler (returns non-zero value if strings are equal).
**/
@@ -216,6 +218,14 @@ void inthash_value_set_key_handler(inthash hashtable,
void *arg);
/**
+ * Set assertion failure handler.
+ * fatal: handled called upon serious programming error
+ **/
+void inthash_set_assert_handler(inthash hashtable,
+ t_inthash_asserthandler fatal,
+ void *arg);
+
+/**
* Read an integer entry from the hashtable.
* Return non-zero value upon success and sets intvalue.
**/
@@ -309,6 +319,15 @@ inthash_item *inthash_enum_next(struct_inthash_enum * e);
**/
inthash_keys inthash_hash_value(const char *value);
+/**
+ * Set default global assertion failure handler.
+ * The handler will be used if no specific handler was defined in the
+ * hashtable itself.
+ * fatal: handled called upon serious programming error (opaque argument
+ * is the hashtable)
+ **/
+void inthash_set_global_assert_handler(t_inthash_asserthandler fatal);
+
#endif
#endif