+/* Internal routine to find entry in the hash table by `key' and `context'.
+ Returns the previous entry (if exists) as well. */
+
+static inline SilcHashTableEntry *
+silc_hash_table_find_internal_context(SilcHashTable ht, void *key,
+ void *context,
+ SilcHashTableEntry *prev_entry)
+{
+ SilcHashTableEntry *entry, prev = NULL;
+
+ entry = &ht->table[SILC_HASH_TABLE_HASH];
+ if (ht->compare) {
+ while (*entry && ht->compare((*entry)->key, key, ht->compare_user_context)
+ == FALSE && (*entry)->context != context) {
+ prev = *entry;
+ entry = &(*entry)->next;
+ }
+ } else {
+ while (*entry && (*entry)->key != key && (*entry)->context != context) {
+ prev = *entry;
+ entry = &(*entry)->next;
+ }
+ }
+
+ *prev_entry = prev;
+ return entry;
+}
+
+/* Internal routine to find entry in the hash table by `key'. */
+
+static inline SilcHashTableEntry *
+silc_hash_table_find_internal_simple(SilcHashTable ht, void *key,
+ SilcHashFunction hash,
+ void *hash_user_context,
+ SilcHashCompare compare,
+ void *compare_user_context)
+{
+ SilcHashTableEntry *entry;
+
+ if (hash)
+ entry = &ht->table[SILC_HASH_TABLE_HASH_F(hash, hash_user_context)];
+ else
+ entry = &ht->table[SILC_HASH_TABLE_HASH];
+ if (compare) {
+ while (*entry && !compare((*entry)->key, key, compare_user_context))
+ entry = &(*entry)->next;
+ } else if (ht->compare) {
+ while (*entry && !ht->compare((*entry)->key, key,
+ ht->compare_user_context))
+ entry = &(*entry)->next;
+ } else {
+ while (*entry && (*entry)->key != key)
+ entry = &(*entry)->next;
+ }
+
+ return entry;
+}
+
+/* Internal routine to find all keys by `key'. This may return multiple
+ entries if multiple entries with same key exists. */
+
+static inline bool
+silc_hash_table_find_internal_all(SilcHashTable ht, void *key,
+ SilcHashTableEntry **entries,
+ uint32 *count)
+{
+ SilcHashTableEntry *entry;
+
+ *entries = NULL;
+ *count = 0;
+
+ entry = &ht->table[SILC_HASH_TABLE_HASH];
+ if (ht->compare) {
+ while (*entry) {
+ if (ht->compare((*entry)->key, key, ht->compare_user_context)) {
+ *entries = silc_realloc(*entries, sizeof(**entries) * (*count + 1));
+ (*entries)[*count] = *entry;
+ (*count)++;
+ }
+ entry = &(*entry)->next;
+ }
+ } else {
+ while (*entry) {
+ if ((*entry)->key == key) {
+ *entries = silc_realloc(*entries, sizeof(**entries) * (*count + 1));
+ (*entries)[*count] = *entry;
+ (*count)++;
+ }
+ entry = &(*entry)->next;
+ }
+ }
+
+ return *entries ? TRUE : FALSE;
+}
+
+/* Internal routine to find all keys by `key'. This may return multiple
+ entries if multiple entries with same key exists. With specific
+ hash and comparison functions. */
+
+static inline bool
+silc_hash_table_find_internal_all_ext(SilcHashTable ht, void *key,
+ SilcHashTableEntry **entries,
+ uint32 *count,
+ SilcHashFunction hash,
+ void *hash_user_context,
+ SilcHashCompare compare,
+ void *compare_user_context)
+{
+ SilcHashTableEntry *entry;
+
+ *entries = NULL;
+ *count = 0;
+
+ entry = &ht->table[SILC_HASH_TABLE_HASH];
+ if (compare) {
+ while (*entry) {
+ if (compare((*entry)->key, key, compare_user_context)) {
+ *entries = silc_realloc(*entries, sizeof(**entries) * (*count + 1));
+ (*entries)[*count] = *entry;
+ (*count)++;
+ }
+ entry = &(*entry)->next;
+ }
+ } else {
+ while (*entry) {
+ if ((*entry)->key == key) {
+ *entries = silc_realloc(*entries, sizeof(**entries) * (*count + 1));
+ (*entries)[*count] = *entry;
+ (*count)++;
+ }
+ entry = &(*entry)->next;
+ }
+ }
+
+ return *entries ? TRUE : FALSE;
+}
+
+/* Internal routine to add new key to the hash table */
+
+static inline void
+silc_hash_table_add_internal(SilcHashTable ht, void *key, void *context,
+ SilcHashFunction hash,
+ void *hash_user_context)
+{
+ SilcHashTableEntry *entry;
+ uint32 index = (hash ? SILC_HASH_TABLE_HASH :
+ SILC_HASH_TABLE_HASH_F(hash, hash_user_context));
+
+ entry = &ht->table[index];
+ if (*entry) {
+ /* The entry exists already. We have a collision, add it to the
+ list to avoid collision. */
+ SilcHashTableEntry e, tmp;
+
+ e = *entry;
+ tmp = e->next;
+ while (tmp) {
+ e = tmp;
+ tmp = tmp->next;
+ }
+
+ e->next = silc_calloc(1, sizeof(*e->next));
+ e->next->key = key;
+ e->next->context = context;
+ ht->entry_count++;
+ } else {
+ /* New key */
+ *entry = silc_calloc(1, sizeof(**entry));
+ (*entry)->key = key;
+ (*entry)->context = context;
+ ht->entry_count++;
+ }
+}
+