From 7ae34cb1b6b0807bf4b1affbd1805b5bfccaa484 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Thu, 15 Feb 2024 17:55:39 +0100 Subject: [PATCH] localename: Refactor. * lib/struniq.h: New file, extracted from lib/localename.c. * lib/localename.c: Include it. * modules/localename (Files): Add lib/struniq.h. --- ChangeLog | 7 +++ lib/localename.c | 85 +------------------------------- lib/struniq.h | 119 +++++++++++++++++++++++++++++++++++++++++++++ modules/localename | 1 + 4 files changed, 128 insertions(+), 84 deletions(-) create mode 100644 lib/struniq.h diff --git a/ChangeLog b/ChangeLog index 4007567028..7a1f5a671f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2024-02-15 Bruno Haible + + localename: Refactor. + * lib/struniq.h: New file, extracted from lib/localename.c. + * lib/localename.c: Include it. + * modules/localename (Files): Add lib/struniq.h. + 2024-02-15 Bruno Haible localename: Speed up lookup of the LC_MESSAGES name on AIX ≥ 7.2. diff --git a/lib/localename.c b/lib/localename.c index f6879ac330..9a837fbae3 100644 --- a/lib/localename.c +++ b/lib/localename.c @@ -2634,90 +2634,7 @@ get_lcid (const char *locale_name) AIX >= 7.3, Solaris >= 11.4, Solaris 11 OpenIndiana, Solaris 11 OmniOS, Cygwin >= 2.6, Android API level >= 21 */ - -/* Simple hash set of strings. We don't want to drag in lots of hash table - code here. */ - -# define SIZE_BITS (sizeof (size_t) * CHAR_BIT) - -/* A hash function for NUL-terminated char* strings using - the method described by Bruno Haible. - See https://www.haible.de/bruno/hashfunc.html. */ -static size_t _GL_ATTRIBUTE_PURE -string_hash (const void *x) -{ - const char *s = (const char *) x; - size_t h = 0; - - for (; *s; s++) - h = *s + ((h << 9) | (h >> (SIZE_BITS - 9))); - - return h; -} - -/* A hash table of fixed size. Multiple threads can access it read-only - simultaneously, but only one thread can insert into it at the same time. */ - -/* A node in a hash bucket collision list. */ -struct struniq_hash_node - { - struct struniq_hash_node * volatile next; - char contents[FLEXIBLE_ARRAY_MEMBER]; - }; - -# define STRUNIQ_HASH_TABLE_SIZE 257 -static struct struniq_hash_node * volatile struniq_hash_table[STRUNIQ_HASH_TABLE_SIZE] - /* = { NULL, ..., NULL } */; - -/* This lock protects the struniq_hash_table against multiple simultaneous - insertions. */ -gl_lock_define_initialized(static, struniq_lock) - -/* Store a copy of the given string in a string pool with indefinite extent. - Return a pointer to this copy. */ -static const char * -struniq (const char *string) -{ - size_t hashcode = string_hash (string); - size_t slot = hashcode % STRUNIQ_HASH_TABLE_SIZE; - size_t size; - struct struniq_hash_node *new_node; - struct struniq_hash_node *p; - for (p = struniq_hash_table[slot]; p != NULL; p = p->next) - if (strcmp (p->contents, string) == 0) - return p->contents; - size = strlen (string) + 1; - new_node = - (struct struniq_hash_node *) - malloc (FLEXSIZEOF (struct struniq_hash_node, contents, size)); - if (new_node == NULL) - /* Out of memory. Return a statically allocated string. */ - return "C"; - memcpy (new_node->contents, string, size); - { - bool mt = gl_multithreaded (); - /* Lock while inserting new_node. */ - if (mt) gl_lock_lock (struniq_lock); - /* Check whether another thread already added the string while we were - waiting on the lock. */ - for (p = struniq_hash_table[slot]; p != NULL; p = p->next) - if (strcmp (p->contents, string) == 0) - { - free (new_node); - new_node = p; - goto done; - } - /* Really insert new_node into the hash table. Fill new_node entirely - first, because other threads may be iterating over the linked list. */ - new_node->next = struniq_hash_table[slot]; - struniq_hash_table[slot] = new_node; - done: - /* Unlock after new_node is inserted. */ - if (mt) gl_lock_unlock (struniq_lock); - } - return new_node->contents; -} - +# include "struniq.h" #endif diff --git a/lib/struniq.h b/lib/struniq.h new file mode 100644 index 0000000000..e67ea0fef4 --- /dev/null +++ b/lib/struniq.h @@ -0,0 +1,119 @@ +/* Define a file-local string uniquification function. + Copyright (C) 2009-2024 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +/* Written by Bruno Haible , 2009. */ + + +/* This file needs the following includes: + + #include + #include + #include + #include "flexmember.h" + #include "glthread/lock.h" + #include "thread-optim.h" + + and the following gnulib modules as dependencies: + + flexmember + lock + stdbool + thread-optim + */ + + +/* Simple hash set of strings. We don't want to drag in lots of hash table + code here. */ + +#define SIZE_BITS (sizeof (size_t) * CHAR_BIT) + +/* A hash function for NUL-terminated char* strings using + the method described by Bruno Haible. + See https://www.haible.de/bruno/hashfunc.html. */ +static size_t _GL_ATTRIBUTE_PURE +string_hash (const void *x) +{ + const char *s = (const char *) x; + size_t h = 0; + + for (; *s; s++) + h = *s + ((h << 9) | (h >> (SIZE_BITS - 9))); + + return h; +} + +/* A hash table of fixed size. Multiple threads can access it read-only + simultaneously, but only one thread can insert into it at the same time. */ + +/* A node in a hash bucket collision list. */ +struct struniq_hash_node + { + struct struniq_hash_node * volatile next; + char contents[FLEXIBLE_ARRAY_MEMBER]; + }; + +#define STRUNIQ_HASH_TABLE_SIZE 257 +static struct struniq_hash_node * volatile struniq_hash_table[STRUNIQ_HASH_TABLE_SIZE] + /* = { NULL, ..., NULL } */; + +/* This lock protects the struniq_hash_table against multiple simultaneous + insertions. */ +gl_lock_define_initialized(static, struniq_lock) + +/* Store a copy of the given string in a string pool with indefinite extent. + Return a pointer to this copy. */ +static const char * +struniq (const char *string) +{ + size_t hashcode = string_hash (string); + size_t slot = hashcode % STRUNIQ_HASH_TABLE_SIZE; + size_t size; + struct struniq_hash_node *new_node; + struct struniq_hash_node *p; + for (p = struniq_hash_table[slot]; p != NULL; p = p->next) + if (strcmp (p->contents, string) == 0) + return p->contents; + size = strlen (string) + 1; + new_node = + (struct struniq_hash_node *) + malloc (FLEXSIZEOF (struct struniq_hash_node, contents, size)); + if (new_node == NULL) + /* Out of memory. Return a statically allocated string. */ + return "C"; + memcpy (new_node->contents, string, size); + { + bool mt = gl_multithreaded (); + /* Lock while inserting new_node. */ + if (mt) gl_lock_lock (struniq_lock); + /* Check whether another thread already added the string while we were + waiting on the lock. */ + for (p = struniq_hash_table[slot]; p != NULL; p = p->next) + if (strcmp (p->contents, string) == 0) + { + free (new_node); + new_node = p; + goto done; + } + /* Really insert new_node into the hash table. Fill new_node entirely + first, because other threads may be iterating over the linked list. */ + new_node->next = struniq_hash_table[slot]; + struniq_hash_table[slot] = new_node; + done: + /* Unlock after new_node is inserted. */ + if (mt) gl_lock_unlock (struniq_lock); + } + return new_node->contents; +} diff --git a/modules/localename b/modules/localename index 4c33624548..859d235975 100644 --- a/modules/localename +++ b/modules/localename @@ -6,6 +6,7 @@ lib/localename.h lib/localename.c lib/localename-table.h lib/localename-table.c +lib/struniq.h m4/localename.m4 m4/intl-thread-locale.m4 m4/intlmacosx.m4 -- 2.39.5