aboutsummaryrefslogtreecommitdiff
path: root/tools/gnulib/patches/640-mem-hash-map.patch
diff options
context:
space:
mode:
Diffstat (limited to 'tools/gnulib/patches/640-mem-hash-map.patch')
-rw-r--r--tools/gnulib/patches/640-mem-hash-map.patch494
1 files changed, 494 insertions, 0 deletions
diff --git a/tools/gnulib/patches/640-mem-hash-map.patch b/tools/gnulib/patches/640-mem-hash-map.patch
new file mode 100644
index 0000000000..aaebe545fa
--- /dev/null
+++ b/tools/gnulib/patches/640-mem-hash-map.patch
@@ -0,0 +1,494 @@
+From 5a842672e79a7a5f6be837c483be4f9901a4ecc0 Mon Sep 17 00:00:00 2001
+From: Bruno Haible <bruno@clisp.org>
+Date: Wed, 30 Apr 2025 03:19:10 +0200
+Subject: [PATCH] New module mem-hash-map.
+
+* lib/mem-hash-map.h: New file, from GNU gettext.
+* lib/mem-hash-map.c: New file, from GNU gettext.
+* modules/mem-hash-map: New file, from GNU gettext.
+---
+ ChangeLog | 7 +
+ lib/mem-hash-map.c | 352 +++++++++++++++++++++++++++++++++++++++++++
+ lib/mem-hash-map.h | 90 +++++++++++
+ modules/mem-hash-map | 25 +++
+ 4 files changed, 474 insertions(+)
+ create mode 100644 lib/mem-hash-map.c
+ create mode 100644 lib/mem-hash-map.h
+ create mode 100644 modules/mem-hash-map
+
+--- /dev/null
++++ b/lib/mem-hash-map.c
+@@ -0,0 +1,352 @@
++/* Simple hash table (no removals) where the keys are memory blocks.
++ Copyright (C) 1994-2025 Free Software Foundation, Inc.
++ Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, October 1994.
++
++ This file is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published
++ by the Free Software Foundation, either version 3 of the License,
++ or (at your option) any later version.
++
++ This file is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <https://www.gnu.org/licenses/>. */
++
++#include <config.h>
++
++/* Specification. */
++#include "mem-hash-map.h"
++
++#include <stdlib.h>
++#include <string.h>
++#include <stdio.h>
++#include <limits.h>
++#include <sys/types.h>
++
++#include "next-prime.h"
++
++/* Since this simple implementation of hash tables allows only insertion, no
++ removal of entries, the right data structure for the memory holding all keys
++ is an obstack. */
++#include "obstack.h"
++
++/* Use checked memory allocation. */
++#include "xalloc.h"
++
++#define obstack_chunk_alloc xmalloc
++#define obstack_chunk_free free
++
++
++typedef struct hash_entry
++{
++ size_t used; /* Hash code of the key, or 0 for an unused entry. */
++ const void *key; /* Key. */
++ size_t keylen;
++ void *data; /* Value. */
++ struct hash_entry *next;
++}
++hash_entry;
++
++
++/* Initialize a hash table. INIT_SIZE > 1 is the initial number of available
++ entries.
++ Return 0 always. */
++int
++hash_init (hash_table *htab, size_t init_size)
++{
++ /* We need the size to be a prime. */
++ init_size = next_prime (init_size);
++
++ /* Initialize the data structure. */
++ htab->size = init_size;
++ htab->filled = 0;
++ htab->first = NULL;
++ htab->table = XCALLOC (init_size + 1, hash_entry);
++
++ obstack_init (&htab->mem_pool);
++
++ return 0;
++}
++
++
++/* Delete a hash table's contents.
++ Return 0 always. */
++int
++hash_destroy (hash_table *htab)
++{
++ free (htab->table);
++ obstack_free (&htab->mem_pool, NULL);
++ return 0;
++}
++
++
++/* Compute a hash code for a key consisting of KEYLEN bytes starting at KEY
++ in memory. */
++static size_t
++compute_hashval (const void *key, size_t keylen)
++{
++ size_t cnt;
++ size_t hval;
++
++ /* Compute the hash value for the given string. The algorithm
++ is taken from [Aho,Sethi,Ullman], fixed according to
++ https://haible.de/bruno/hashfunc.html. */
++ cnt = 0;
++ hval = keylen;
++ while (cnt < keylen)
++ {
++ hval = (hval << 9) | (hval >> (sizeof (size_t) * CHAR_BIT - 9));
++ hval += (size_t) *(((const char *) key) + cnt++);
++ }
++ return hval != 0 ? hval : ~((size_t) 0);
++}
++
++
++/* References:
++ [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
++ [Knuth] The Art of Computer Programming, part3 (6.4) */
++
++/* Look up a given key in the hash table.
++ Return the index of the entry, if present, or otherwise the index a free
++ entry where it could be inserted. */
++static size_t
++lookup (const hash_table *htab,
++ const void *key, size_t keylen,
++ size_t hval)
++{
++ size_t hash;
++ size_t idx;
++ hash_entry *table = htab->table;
++
++ /* First hash function: simply take the modul but prevent zero. */
++ hash = 1 + hval % htab->size;
++
++ idx = hash;
++
++ if (table[idx].used)
++ {
++ if (table[idx].used == hval && table[idx].keylen == keylen
++ && memcmp (table[idx].key, key, keylen) == 0)
++ return idx;
++
++ /* Second hash function as suggested in [Knuth]. */
++ hash = 1 + hval % (htab->size - 2);
++
++ do
++ {
++ if (idx <= hash)
++ idx = htab->size + idx - hash;
++ else
++ idx -= hash;
++
++ /* If entry is found use it. */
++ if (table[idx].used == hval && table[idx].keylen == keylen
++ && memcmp (table[idx].key, key, keylen) == 0)
++ return idx;
++ }
++ while (table[idx].used);
++ }
++ return idx;
++}
++
++
++/* Look up the value of a key in the given table.
++ If found, return 0 and set *RESULT to it. Otherwise return -1. */
++int
++hash_find_entry (const hash_table *htab, const void *key, size_t keylen,
++ void **result)
++{
++ hash_entry *table = htab->table;
++ size_t idx = lookup (htab, key, keylen, compute_hashval (key, keylen));
++
++ if (table[idx].used == 0)
++ return -1;
++
++ *result = table[idx].data;
++ return 0;
++}
++
++
++/* Insert the pair (KEY[0..KEYLEN-1], DATA) in the hash table at index IDX.
++ HVAL is the key's hash code. IDX depends on it. The table entry at index
++ IDX is known to be unused. */
++static void
++insert_entry_2 (hash_table *htab,
++ const void *key, size_t keylen,
++ size_t hval, size_t idx, void *data)
++{
++ hash_entry *table = htab->table;
++
++ table[idx].used = hval;
++ table[idx].key = key;
++ table[idx].keylen = keylen;
++ table[idx].data = data;
++
++ /* List the new value in the list. */
++ if (htab->first == NULL)
++ {
++ table[idx].next = &table[idx];
++ htab->first = &table[idx];
++ }
++ else
++ {
++ table[idx].next = htab->first->next;
++ htab->first->next = &table[idx];
++ htab->first = &table[idx];
++ }
++
++ ++htab->filled;
++}
++
++
++/* Grow the hash table. */
++static void
++resize (hash_table *htab)
++{
++ size_t old_size = htab->size;
++ hash_entry *table = htab->table;
++ size_t idx;
++
++ htab->size = next_prime (htab->size * 2);
++ htab->filled = 0;
++ htab->first = NULL;
++ htab->table = XCALLOC (1 + htab->size, hash_entry);
++
++ for (idx = 1; idx <= old_size; ++idx)
++ if (table[idx].used)
++ insert_entry_2 (htab, table[idx].key, table[idx].keylen,
++ table[idx].used,
++ lookup (htab, table[idx].key, table[idx].keylen,
++ table[idx].used),
++ table[idx].data);
++
++ free (table);
++}
++
++
++/* Try to insert the pair (KEY[0..KEYLEN-1], DATA) in the hash table.
++ Return non-NULL (more precisely, the address of the KEY inside the table's
++ memory pool) if successful, or NULL if there is already an entry with the
++ given key. */
++const void *
++hash_insert_entry (hash_table *htab,
++ const void *key, size_t keylen,
++ void *data)
++{
++ size_t hval = compute_hashval (key, keylen);
++ hash_entry *table = htab->table;
++ size_t idx = lookup (htab, key, keylen, hval);
++
++ if (table[idx].used)
++ /* We don't want to overwrite the old value. */
++ return NULL;
++ else
++ {
++ /* An empty bucket has been found. */
++ void *keycopy = obstack_copy (&htab->mem_pool, key, keylen);
++ insert_entry_2 (htab, keycopy, keylen, hval, idx, data);
++ if (100 * htab->filled > 75 * htab->size)
++ /* Table is filled more than 75%. Resize the table. */
++ resize (htab);
++ return keycopy;
++ }
++}
++
++
++/* Insert the pair (KEY[0..KEYLEN-1], DATA) in the hash table.
++ Return 0. */
++int
++hash_set_value (hash_table *htab,
++ const void *key, size_t keylen,
++ void *data)
++{
++ size_t hval = compute_hashval (key, keylen);
++ hash_entry *table = htab->table;
++ size_t idx = lookup (htab, key, keylen, hval);
++
++ if (table[idx].used)
++ {
++ /* Overwrite the old value. */
++ table[idx].data = data;
++ return 0;
++ }
++ else
++ {
++ /* An empty bucket has been found. */
++ void *keycopy = obstack_copy (&htab->mem_pool, key, keylen);
++ insert_entry_2 (htab, keycopy, keylen, hval, idx, data);
++ if (100 * htab->filled > 75 * htab->size)
++ /* Table is filled more than 75%. Resize the table. */
++ resize (htab);
++ return 0;
++ }
++}
++
++
++/* Steps *PTR forward to the next used entry in the given hash table. *PTR
++ should be initially set to NULL. Store information about the next entry
++ in *KEY, *KEYLEN, *DATA.
++ Return 0 normally, -1 when the whole hash table has been traversed. */
++int
++hash_iterate (hash_table *htab, void **ptr, const void **key, size_t *keylen,
++ void **data)
++{
++ hash_entry *curr;
++
++ if (*ptr == NULL)
++ {
++ if (htab->first == NULL)
++ return -1;
++ curr = htab->first;
++ }
++ else
++ {
++ if (*ptr == htab->first)
++ return -1;
++ curr = (hash_entry *) *ptr;
++ }
++ curr = curr->next;
++ *ptr = (void *) curr;
++
++ *key = curr->key;
++ *keylen = curr->keylen;
++ *data = curr->data;
++ return 0;
++}
++
++
++/* Steps *PTR forward to the next used entry in the given hash table. *PTR
++ should be initially set to NULL. Store information about the next entry
++ in *KEY, *KEYLEN, *DATAP. *DATAP is set to point to the storage of the
++ value; modifying **DATAP will modify the value of the entry.
++ Return 0 normally, -1 when the whole hash table has been traversed. */
++int
++hash_iterate_modify (hash_table *htab, void **ptr,
++ const void **key, size_t *keylen,
++ void ***datap)
++{
++ hash_entry *curr;
++
++ if (*ptr == NULL)
++ {
++ if (htab->first == NULL)
++ return -1;
++ curr = htab->first;
++ }
++ else
++ {
++ if (*ptr == htab->first)
++ return -1;
++ curr = (hash_entry *) *ptr;
++ }
++ curr = curr->next;
++ *ptr = (void *) curr;
++
++ *key = curr->key;
++ *keylen = curr->keylen;
++ *datap = &curr->data;
++ return 0;
++}
+--- /dev/null
++++ b/lib/mem-hash-map.h
+@@ -0,0 +1,90 @@
++/* Simple hash table (no removals) where the keys are memory blocks.
++ Copyright (C) 1995-2025 Free Software Foundation, Inc.
++
++ This file is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published
++ by the Free Software Foundation, either version 3 of the License,
++ or (at your option) any later version.
++
++ This file is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <https://www.gnu.org/licenses/>. */
++
++#ifndef _GL_MEM_HASH_MAP_H
++#define _GL_MEM_HASH_MAP_H
++
++#include <stddef.h>
++
++#include "obstack.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++struct hash_entry;
++
++typedef struct hash_table
++{
++ size_t size; /* Number of allocated entries. */
++ size_t filled; /* Number of used entries. */
++ struct hash_entry *first; /* Pointer to head of list of entries. */
++ struct hash_entry *table; /* Pointer to array of entries. */
++ struct obstack mem_pool; /* Memory pool holding the keys. */
++}
++hash_table;
++
++/* Initialize a hash table. INIT_SIZE > 1 is the initial number of available
++ entries.
++ Return 0 always. */
++extern int hash_init (hash_table *htab, size_t init_size);
++
++/* Delete a hash table's contents.
++ Return 0 always. */
++extern int hash_destroy (hash_table *htab);
++
++/* Look up the value of a key in the given table.
++ If found, return 0 and set *RESULT to it. Otherwise return -1. */
++extern int hash_find_entry (const hash_table *htab,
++ const void *key, size_t keylen,
++ void **result);
++
++/* Try to insert the pair (KEY[0..KEYLEN-1], DATA) in the hash table.
++ Return non-NULL (more precisely, the address of the KEY inside the table's
++ memory pool) if successful, or NULL if there is already an entry with the
++ given key. */
++extern const void * hash_insert_entry (hash_table *htab,
++ const void *key, size_t keylen,
++ void *data);
++
++/* Insert the pair (KEY[0..KEYLEN-1], DATA) in the hash table.
++ Return 0. */
++extern int hash_set_value (hash_table *htab,
++ const void *key, size_t keylen,
++ void *data);
++
++/* Steps *PTR forward to the next used entry in the given hash table. *PTR
++ should be initially set to NULL. Store information about the next entry
++ in *KEY, *KEYLEN, *DATA.
++ Return 0 normally, -1 when the whole hash table has been traversed. */
++extern int hash_iterate (hash_table *htab, void **ptr,
++ const void **key, size_t *keylen,
++ void **data);
++
++/* Steps *PTR forward to the next used entry in the given hash table. *PTR
++ should be initially set to NULL. Store information about the next entry
++ in *KEY, *KEYLEN, *DATAP. *DATAP is set to point to the storage of the
++ value; modifying **DATAP will modify the value of the entry.
++ Return 0 normally, -1 when the whole hash table has been traversed. */
++extern int hash_iterate_modify (hash_table *htab, void **ptr,
++ const void **key, size_t *keylen,
++ void ***datap);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* not _GL_MEM_HASH_MAP_H */
+--- /dev/null
++++ b/modules/mem-hash-map
+@@ -0,0 +1,25 @@
++Description:
++Simple hash table (no removals) where the keys are memory blocks.
++
++Files:
++lib/mem-hash-map.h
++lib/mem-hash-map.c
++
++Depends-on:
++next-prime
++obstack
++xalloc
++
++configure.ac:
++
++Makefile.am:
++lib_SOURCES += mem-hash-map.h mem-hash-map.c
++
++Include:
++"mem-hash-map.h"
++
++License:
++GPL
++
++Maintainer:
++Bruno Haible