7 ex__hash_8c
gullradriel edited this page 2026-10-25 10:46:33 +01:00

examples/ex_hash.c

Structures

Name
struct DATA
string and int holder

Functions

Name
int main(void )
void destroy_data(void * ptr)
destroy a DATA struct

Defines

Name
NB_HASH_ELEMENTS

Functions Documentation

function main

int main(
    void 
)

function destroy_data

void destroy_data(
    void * ptr
)

destroy a DATA struct

Parameters:

  • ptr A pointer to a DATA struct

Macros Documentation

define NB_HASH_ELEMENTS

#define NB_HASH_ELEMENTS 24

Source code

/*
 * Nilorea Library
 * Copyright (C) 2005-2026 Castagnier Mickael
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 */


#include "nilorea/n_str.h"
#include "nilorea/n_log.h"
#include "nilorea/n_list.h"
#include "nilorea/n_hash.h"

#define NB_HASH_ELEMENTS 24

typedef struct DATA {
    N_STR* rnd_str;
    int value;
} DATA;

void destroy_data(void* ptr) {
    DATA* data = (DATA*)ptr;
    free_nstr(&data->rnd_str);
    Free(data);
}

int main(void) {
    set_log_level(LOG_DEBUG);

    HASH_TABLE* htable = new_ht(NB_HASH_ELEMENTS / 3);
    LIST* keys_list = new_generic_list(NB_HASH_ELEMENTS + 1);
    DATA* data = NULL;
    char* str = NULL;

    n_log(LOG_INFO, "Filling HashTable with %d random elements", NB_HASH_ELEMENTS);
    for (int it = 0; it < NB_HASH_ELEMENTS; it++) {
        N_STR* nkey = NULL;
        int randomizator = rand() % 4;
        nstrprintf(nkey, "key%d_%d", it, randomizator);
        switch (randomizator) {
            default:
            case 0:
                ht_put_int(htable, _nstr(nkey), 666);
                n_log(LOG_INFO, "Put int 666 with key %s", _nstr(nkey));
                break;
            case 1:
                ht_put_double(htable, _nstr(nkey), 3.14);
                n_log(LOG_INFO, "Put double 3.14 with key %s", _nstr(nkey));
                break;
            case 2:
                Malloc(data, DATA, 1);
                data->rnd_str = NULL;
                nstrprintf(data->rnd_str, "%s%d", _nstr(nkey), rand() % 10);
                data->value = 7;
                ht_put_ptr(htable, _nstr(nkey), data, &destroy_data, NULL);
                n_log(LOG_INFO, "Put ptr rnd_str %s value %d with key %s", _nstr(data->rnd_str), data->value, _nstr(nkey));
                break;
            case 3:
                Malloc(str, char, 64);
                snprintf(str, 64, "%s%d", _nstr(nkey), rand() % 10);
                ht_put_string(htable, _nstr(nkey), str);
                n_log(LOG_INFO, "Put string %s key %s", str, _nstr(nkey));
                Free(str);
                break;
        }
        /* asving key for ulterior use */
        list_push(keys_list, nkey, free_nstr_ptr);
    }

    n_log(LOG_INFO, "Reading hash table with ht_foreach");
    HT_FOREACH(node, htable,
               {
                   n_log(LOG_INFO, "HT_FOREACH hash: %zu, key:%s", node->hash_value, _str(node->key));
               });
    HT_FOREACH_R(node, htable, hash_iterator,
                 {
                     n_log(LOG_INFO, "HT_FOREACH_R hash: %zu, key:%s", node->hash_value, _str(node->key));
                 });

    size_t optimal_size = ht_get_optimal_size(htable);
    n_log(LOG_INFO, "########");
    n_log(LOG_INFO, "collisions: %d %%", ht_get_table_collision_percentage(htable));
    n_log(LOG_INFO, "table size: %zu , table optimal size: %zu", htable->size, optimal_size);
    n_log(LOG_INFO, "resizing to %zu returned %d", optimal_size, ht_resize(&htable, optimal_size));
    n_log(LOG_INFO, "collisions after resize: %d %%", ht_get_table_collision_percentage(htable));
    n_log(LOG_INFO, "########");

    if (ht_optimize(&htable) == FALSE) {
        n_log(LOG_ERR, "Error when optimizing table %p", htable);
    }
    n_log(LOG_INFO, "collisions after ht_optimize: %d %%", ht_get_table_collision_percentage(htable));
    n_log(LOG_INFO, "########");

    LIST* results = ht_get_completion_list(htable, "key", NB_HASH_ELEMENTS);
    if (results) {
        list_foreach(node, results) {
            n_log(LOG_INFO, "completion result: %s", (char*)node->ptr);
        }
        list_destroy(&results);
    }

    int matching_nodes(HASH_NODE * node) {
        if (strncasecmp("key", node->key, 3) == 0)
            return TRUE;
        return FALSE;
    }
    results = ht_search(htable, &matching_nodes);
    list_foreach(node, results) {
        n_log(LOG_INFO, "htsearch: key: %s", (char*)node->ptr);
    }
    list_destroy(&results);

    /* test ht_get_ptr */
    Malloc(data, DATA, 1);
    if (data) {
        data->rnd_str = NULL;
        nstrprintf(data->rnd_str, "ptr_test_value");
        data->value = 42;
        ht_put_ptr(htable, "ptr_test_key", data, &destroy_data, NULL);
        void* retrieved = NULL;
        ht_get_ptr(htable, "ptr_test_key", &retrieved);
        if (retrieved) {
            DATA* rd = (DATA*)retrieved;
            n_log(LOG_INFO, "ht_get_ptr: value=%d str=%s", rd->value, _nstr(rd->rnd_str));
        }
    }

    /* test ht_remove */
    ht_put_int(htable, "remove_me", 999);
    n_log(LOG_INFO, "Before ht_remove, table has entries");
    ht_remove(htable, "remove_me");
    n_log(LOG_INFO, "After ht_remove(\"remove_me\")");
    {
        HASH_INT_TYPE check_val = -1;
        if (ht_get_int(htable, "remove_me", &check_val) == FALSE) {
            n_log(LOG_INFO, "ht_remove confirmed: key no longer found");
        }
    }

    /* test ht_duplicate */
    HASH_TABLE* htable_copy = ht_duplicate(htable);
    if (htable_copy) {
        n_log(LOG_INFO, "ht_duplicate: created copy with size %ld", htable_copy->size);
        destroy_ht(&htable_copy);
    }

    list_destroy(&keys_list);
    destroy_ht(&htable);

    /* testing empty destroy */
    htable = new_ht(1024);
    empty_ht(htable);
    destroy_ht(&htable);

    htable = new_ht_trie(256, 32);

    ht_put_int(htable, "TestInt", 1);
    ht_put_double(htable, "TestDouble", 2.0);
    ht_put_string(htable, "TestString", "MyString");
    HASH_INT_TYPE ival = -1;
    double fval = -1.0;
    ht_get_int(htable, "TestInt", &ival);
    ht_get_double(htable, "TestDouble", &fval);
    char* string = NULL;
    ht_get_string(htable, "TestString", &string);
    n_log(LOG_INFO, "Trie:%ld %f %s", (long)ival, fval, string);

    results = ht_get_completion_list(htable, "Test", 10);
    if (results) {
        list_foreach(node, results) {
            n_log(LOG_INFO, "completion result: %s", (char*)node->ptr);
        }
        list_destroy(&results);
    }

    destroy_ht(&htable);

    /* table seeds come from the OS random source: distinct per table, not the
     * old rand() % 100000 shared by every process, and lookups still work */
    {
        HASH_TABLE* t[4] = {NULL, NULL, NULL, NULL};
        int i, j, big = 0, distinct = 1, found = 1;
        for (i = 0; i < 4; i++) {
            t[i] = new_ht(64);
            if (!t[i]) {
                n_log(LOG_ERR, "FAIL: new_ht for the seed check");
                exit(1);
            }
            if (t[i]->seed >= 100000)
                big++;
            for (j = 0; j < i; j++)
                if (t[i]->seed == t[j]->seed)
                    distinct = 0;
            ht_put_int(t[i], "key", i);
        }
        for (i = 0; i < 4; i++) {
            HASH_INT_TYPE v = -1;
            if (ht_get_int(t[i], "key", &v) == FALSE || v != i)
                found = 0;
            destroy_ht(&t[i]);
        }
        if (!distinct || big == 0 || !found) {
            n_log(LOG_ERR, "FAIL: hash seeds distinct=%d big=%d lookups=%d", distinct, big, found);
            exit(1);
        }
        n_log(LOG_INFO, "hash seeds: distinct and unpredictable, lookups fine");
    }

    exit(0);

} /* END_OF_MAIN */