Merge "mini-glib.c: Fix GHashTable implementation." into idea133
diff --git a/distrib/mini-glib/src/glib-mini.c b/distrib/mini-glib/src/glib-mini.c
index 9a954be..65b5802 100644
--- a/distrib/mini-glib/src/glib-mini.c
+++ b/distrib/mini-glib/src/glib-mini.c
@@ -15,6 +15,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stdint.h>
#include <string.h>
// Print a panic message then exit the program immediately.
@@ -397,17 +398,25 @@
#define HASH_MIN_SHIFT 3
#define HASH_MIN_CAPACITY (1 << HASH_MIN_SHIFT)
+#define HASH_LOAD_SCALE 1024
+#define HASH_MIN_LOAD 256
+#define HASH_MAX_LOAD 768
+
struct _GHashTable {
int ref_count;
int num_items;
int num_used; // count of items + tombstones
- int shift;
int capacity;
GHashEntry* entries;
GHashFunc hash_func;
GEqualFunc key_equal_func;
};
+// Default hash function for pointers.
+static guint _gpointer_hash(gconstpointer key) {
+ return (guint)(uintptr_t)key;
+}
+
// Compute the hash value of a given key.
static inline size_t
_g_hash_table_hash(GHashTable* table, gconstpointer key) {
@@ -424,7 +433,7 @@
hash_table->num_items = 0;
hash_table->capacity = HASH_MIN_CAPACITY;
hash_table->entries = g_new0(GHashEntry, hash_table->capacity);
- hash_table->hash_func = hash_func;
+ hash_table->hash_func = hash_func ? hash_func : &_gpointer_hash;
hash_table->key_equal_func = key_equal_func;
return hash_table;
@@ -552,7 +561,7 @@
static void _g_hash_table_resize(GHashTable* hash_table) {
guint old_capacity = hash_table->capacity;
- // Compute new shift from new size
+ // Compute new capacity from new size
guint new_size = hash_table->num_items * 2;
guint new_capacity = HASH_MIN_CAPACITY;
while (new_capacity < new_size)
@@ -587,11 +596,22 @@
// Resize the hash table if needed.
static void _g_hash_table_maybe_resize(GHashTable* hash_table) {
- guint used = hash_table->num_used;
guint count = hash_table->num_items;
guint capacity = hash_table->capacity;
- if ((capacity > count * 4 && capacity > HASH_MIN_CAPACITY) ||
- capacity < used + (used / 16)) {
+ // Computations explained.
+ //
+ // load < min_load i.e.
+ // => used / capacity < min_load
+ // => used < min_load * capacity
+ // => used * HASH_SCALE < HASH_MIN_LOAD * capacity
+ //
+ // load > max_load
+ // => used / capacity > max_load
+ // => used * HASH_SCALER > HASH_MAX_LOAD * capacity
+ uint64_t load = (uint64_t)count * HASH_LOAD_SCALE;
+ uint64_t min_load = (uint64_t)capacity * HASH_MIN_LOAD;
+ uint64_t max_load = (uint64_t)capacity * HASH_MAX_LOAD;
+ if (load < min_load || load > max_load) {
_g_hash_table_resize(hash_table);
}
}