From 205e1e48d0e1ffe54b3dd7f51443501cdbdfe418 Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Fri, 12 Jun 2026 14:05:55 +0000 Subject: [PATCH] core: import NSS bit and hash helpers into libnwcore --- AI.md | 23 +++ include/core/bit.h | 90 ++++++++ include/core/hash.h | 99 +++++++++ src/core/CMakeLists.txt | 12 +- src/core/bit.c | 79 ++++++++ src/core/hash.c | 440 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 742 insertions(+), 1 deletion(-) create mode 100644 include/core/bit.h create mode 100644 include/core/hash.h create mode 100644 src/core/bit.c create mode 100644 src/core/hash.c diff --git a/AI.md b/AI.md index 30798a5..5e0b4ff 100644 --- a/AI.md +++ b/AI.md @@ -1,5 +1,28 @@ # AI working notes for mars-nwe +## Current handoff status after NSS low-level imports 0404-0409 + +Current accepted MARS-NWE server line in this work session includes the NSS +low-level libnwcore imports through `0409`: + +- `0404` imports NSS `bitmap.c` directly as `src/core/bitmap.c`. +- `0405` moves the imported bitmap/NSS base headers directly into + `include/core/`. +- `0406` removes trailing whitespace from the imported NSS headers. +- `0407` imports NSS `crc.c`/`crc.h`; Unicode folding still uses the local + ASCII-compatible fallback until `xUnicode`/`NSSUniToLower` is imported. +- `0408` imports NSS `que.h` directly as `include/core/que.h`. +- `0409` imports NSS `bit.h`, `hash.h`, and `hash.c` into libnwcore. The + supplied NSS archives expose `LB_CountBits`, `LB_findHighBit`, + `LB_findLowBit`, `LB_RotateLeft`, and `LB_RotateRight` in `libNSS.imp`, but + do not include a `bit.c`; MARS-NWE therefore provides `src/core/bit.c` as a + small compatibility implementation that preserves the original NSS public + API names so imported `hash.c` links cleanly. + +Keep future NSS low-level imports directly under `src/core/.c` and +`include/core/.h`. Do not add a new `nwcore/nss/` or +`src/core/nss/` path for the active libnwcore imports. + ## Current handoff status after quota completion This file may keep patch chronology because it is the ChatGPT handoff document. diff --git a/include/core/bit.h b/include/core/bit.h new file mode 100644 index 0000000..c45583e --- /dev/null +++ b/include/core/bit.h @@ -0,0 +1,90 @@ +/**************************************************************************** + | + | (C) Copyright 1985, 1991, 1993, 1996 Novell, Inc. + | All Rights Reserved. + | + | This program is free software; you can redistribute it and/or + | modify it under the terms of version 2 of the GNU General Public + | License as published by the Free Software Foundation. + | + | This program 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, contact Novell, Inc. + | + | To contact Novell about this file by physical or electronic mail, + | you may find current contact information at www.novell.com + | + |*************************************************************************** + | + | NetWare Advance File Services (NSS) module + | + |--------------------------------------------------------------------------- + | + | $Author: taysom $ + | $Date: 2004-12-31 01:10:58 +0530 (Fri, 31 Dec 2004) $ + | + | $RCSfile$ + | $Revision: 465 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | NSS Library routine + | + | WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! + | + | This header file should ONLY be used for NSS internal development. + | This includes Semantic Agents (SA) and Loadable Storage Services (LSS). + | Any other use may cause conflicts which NSS will NOT fix. + +-------------------------------------------------------------------------*/ +#ifndef _BIT_H_ +#define _BIT_H_ + +#ifndef _OMNI_H_ +#include +#endif + +#ifdef _WATCOMC_ +#ifndef _INLINES_H_ +#include +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Translate the names */ +#define CountBits(p1) LB_CountBits(p1) +#define findHighBit(p1) LB_findHighBit(p1) +#define findLowBit(p1) LB_findLowBit(p1) + +extern NINT LB_CountBits(NINT word); +extern NINT LB_findHighBit(NINT n); +extern NINT LB_findLowBit(NINT n); + +#ifdef _WATCOMC_ + +#define RotateLeft(v,n) inline_RotateLeft(v,n) +#define RotateRight(v,n) inline_RotateRight(v,n) + +#else + +#define RotateLeft(p1,p2) LB_RotateLeft(p1,p2) +#define RotateRight(p1,p2) LB_RotateRight(p1,p2) + +NINT LB_RotateLeft(NINT value, NINT numBits); +NINT LB_RotateRight(NINT value, NINT numBits); + +#endif + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/core/hash.h b/include/core/hash.h new file mode 100644 index 0000000..3e92097 --- /dev/null +++ b/include/core/hash.h @@ -0,0 +1,99 @@ +/**************************************************************************** + | + | (C) Copyright 1995-1997 Novell, Inc. + | All Rights Reserved. + | + | This program is free software; you can redistribute it and/or + | modify it under the terms of version 2 of the GNU General Public + | License as published by the Free Software Foundation. + | + | This program 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, contact Novell, Inc. + | + | To contact Novell about this file by physical or electronic mail, + | you may find current contact information at www.novell.com + | + |*************************************************************************** + | + | NetWare Advance File Services (PSS) Initialization module + | + |--------------------------------------------------------------------------- + | + | $Author: taysom $ + | $Date: 2004-12-31 01:10:58 +0530 (Fri, 31 Dec 2004) $ + | $RCSfile$ + | $Revision: 465 $ + | + |--------------------------------------------------------------------------- + | This module is used to: Typedefs for hash code. + +-------------------------------------------------------------------------*/ +#ifndef _NSS_HASH_H_ +#define _NSS_HASH_H_ + +#ifndef _ZOMNI_H_ +#include "zOmni.h" +#endif + +#ifndef _CRC_H_ +#include "crc.h" +#endif + +typedef struct HashRecord_s { + struct HashRecord_s *next; + crc_t crc; +} HashRecord_s; + +typedef struct HashTable_s { + NINT mask; /* num buckets - 1 (num buckets is power of two) */ + NINT numRecords; + BOOL (*isMatch)(void *key, HashRecord_s *rec); + crc_t (*hash)(void *key); + void *(*alloc)(void *key, void *data); + void (*destroy)(void *rec); + HashRecord_s **table; +} HashTable_s; + +typedef struct HashStats_s +{ + NINT totalRecords; + NINT numBuckets; + NINT maxChain; + NINT minChain; +#ifdef UNIX + float avgChain; +#endif +} HashStats_s; + + /* + * Hash function prototypes + */ +extern HashTable_s *hashInit( + HashTable_s *ht, + NINT numBuckets, + BOOL (*isMatch)(void *key, HashRecord_s *rec), + crc_t (*hash)(void *key), + void *(*alloc)(void *key, void *data), + void (*destroy)(void *rec)); + +extern STATUS hashApply( + HashTable_s *ht, + STATUS (*myFunc)(HashRecord_s *rec, void *metaData), + void *metaData); + +extern HashStats_s *hashStats( + HashTable_s *ht, + HashStats_s *stats); + +extern void hashDelete(HashTable_s *ht, void *key); +extern void *hashFind(HashTable_s *ht, void *key); +extern void *hashInsert(HashTable_s *ht, void *key, void *data); +extern HashTable_s *hashGrow(HashTable_s *ht, NINT factor); +extern HashTable_s *hashShrink (HashTable_s *ht, NINT factor); +extern void hashDestroy(HashTable_s *ht); + +#endif diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 9dc176e..054bf2a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -51,6 +51,14 @@ configure_file( "${CMAKE_SOURCE_DIR}/include/core/crc.h" "${NWCORE_BUILD_INCLUDE_DIR}/crc.h" COPYONLY) +configure_file( + "${CMAKE_SOURCE_DIR}/include/core/bit.h" + "${NWCORE_BUILD_INCLUDE_DIR}/bit.h" + COPYONLY) +configure_file( + "${CMAKE_SOURCE_DIR}/include/core/hash.h" + "${NWCORE_BUILD_INCLUDE_DIR}/hash.h" + COPYONLY) configure_file( "${CMAKE_SOURCE_DIR}/include/core/que.h" "${NWCORE_BUILD_INCLUDE_DIR}/que.h" @@ -70,7 +78,9 @@ configure_file( set(NWCORE_IMPORTED_NSS_SOURCES bitmap.c - crc.c) + bit.c + crc.c + hash.c) add_library(nwcore SHARED core.c diff --git a/src/core/bit.c b/src/core/bit.c new file mode 100644 index 0000000..fa74a15 --- /dev/null +++ b/src/core/bit.c @@ -0,0 +1,79 @@ +/**************************************************************************** + | + | MARS-NWE libnwcore compatibility implementation for NSS bit.h symbols. + | + | The imported NSS public source archives provide shared/sdk/library/bit.h + | and export LB_CountBits, LB_findHighBit, LB_findLowBit, LB_RotateLeft and + | LB_RotateRight through libNSS.imp, but do not include a bit.c source file. + | Keep the original NSS public API names so later imported NSS helpers such + | as hash.c can link against libnwcore without a private wrapper namespace. + | + +-------------------------------------------------------------------------*/ +#include "bit.h" + +NINT LB_CountBits(NINT word) +{ + unsigned int value = (unsigned int)word; + NINT count = 0; + + while (value != 0) + { + value &= value - 1; + ++count; + } + return count; +} + +NINT LB_findHighBit(NINT n) +{ + unsigned int value = (unsigned int)n; + NINT bit = -1; + + while (value != 0) + { + value >>= 1; + ++bit; + } + return bit; +} + +NINT LB_findLowBit(NINT n) +{ + unsigned int value = (unsigned int)n; + NINT bit = 0; + + if (value == 0) + { + return -1; + } + while ((value & 1U) == 0) + { + value >>= 1; + ++bit; + } + return bit; +} + +NINT LB_RotateLeft(NINT value, NINT numBits) +{ + unsigned int v = (unsigned int)value; + unsigned int shift = (unsigned int)numBits & 31U; + + if (shift == 0) + { + return (NINT)v; + } + return (NINT)((v << shift) | (v >> (32U - shift))); +} + +NINT LB_RotateRight(NINT value, NINT numBits) +{ + unsigned int v = (unsigned int)value; + unsigned int shift = (unsigned int)numBits & 31U; + + if (shift == 0) + { + return (NINT)v; + } + return (NINT)((v >> shift) | (v << (32U - shift))); +} diff --git a/src/core/hash.c b/src/core/hash.c new file mode 100644 index 0000000..0876d37 --- /dev/null +++ b/src/core/hash.c @@ -0,0 +1,440 @@ +/**************************************************************************** + | + | (C) Copyright 1995-1997 Novell, Inc. + | All Rights Reserved. + | + | This program is free software; you can redistribute it and/or + | modify it under the terms of version 2 of the GNU General Public + | License as published by the Free Software Foundation. + | + | This program 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, contact Novell, Inc. + | + | To contact Novell about this file by physical or electronic mail, + | you may find current contact information at www.novell.com + | + |*************************************************************************** + | + | NetWare Advance File Services (PSS) Initialization module + | + |--------------------------------------------------------------------------- + | + | $Author: vandana $ + | $Date: 2005-08-10 01:03:51 +0530 (Wed, 10 Aug 2005) $ + | $RCSfile$ + | $Revision: 1177 $ + | + |--------------------------------------------------------------------------- + | This module is used to: Generic Hashing. + | + | Ideally, this routine should be in a library that is then loaded with + | another library that as the malloc/free/realloc code in it. So it + | can at load time pick-up the right routines. This requires creating + | yet another library in NSS which I'm not ready to do yet. + +-------------------------------------------------------------------------*/ +#include +#include +#include +#include "omni.h" +#include "bit.h" +#include "hash.h" + +/* + * The generic hash code provides a basic set of functions for + * managing hash tables. + * + * The code assumes each record has HashRecord_s at the beginning of + * each record stored in the hash table. By careful use of the macros + * offsetof (STRUCT), the HashRecord_s structure can be placed anywhere + * in the users data structures. The user supplies the HashTable_s + * structure, but the system allocates space for the actual table. + * + * hashInit - initializes the hash table + * numBuckets - number of buckets to use (we take the first power of + * 2 less than numBuckets). + * isMatch - returns True if the key for the record mathes the key + * passed in. + * hash - generates a hash of the key (see crc.c and crc.h). + * Even though the term CRC is used in the code, + * it does not have to be a CRC. CRC just make + * a very nice hash value. + * alloc - allocates the record, if it already exits, it can + * do nothing. + * destory - used to free the allocated record. + */ +HashTable_s *hashInit ( + HashTable_s *ht, + NINT numBuckets, + BOOL (*isMatch)(void *key, HashRecord_s *rec), + crc_t (*hash)(void *key), + void *(*alloc)(void *key, void *data), + void (*destroy)(void *rec)) +{ + HashRecord_s **table; + NINT highBit; + NINT size; + + if ((isMatch == NULL) + || (hash == NULL) + || (alloc == NULL) + || (destroy == NULL)) + { + return NULL; + } + highBit = findHighBit(numBuckets); + if (highBit > 28) // You've got to be kidding + { + return NULL; + } + numBuckets = (1<mask = numBuckets - 1; + ht->numRecords = 0; + ht->isMatch = isMatch; + ht->hash = hash; + ht->alloc = alloc; + ht->destroy = destroy; + ht->table = table; + + return ht; +} + + /* + * hashLookup looks for a record that matches the crc first + * and then the key. + */ +HashRecord_s *hashLookup ( + HashTable_s *ht, + crc_t crc, + void *key) +{ + NINT bucket; + HashRecord_s *next; + HashRecord_s *prev; + + bucket = crc & ht->mask; + next = ht->table[bucket]; + + if (next == NULL) + { + return NULL; + } + if (crc == next->crc) + { + if (ht->isMatch(key, next)) + { + return next; + } + } + for (;;) + { + prev = next; + next = prev->next; + + if (next == NULL) + { + return NULL; + } + if (crc == next->crc) + { + if (ht->isMatch(key, next)) + { + prev->next = next->next; + next->next = ht->table[bucket]; + ht->table[bucket] = next; + return next; + } + } + } +} + + /* + * hashFind computes the crc and then calls hashLookup + * which returns the record if it is found. + */ +void *hashFind (HashTable_s *ht, void *key) +{ + return hashLookup(ht, ht->hash(key), key); +} + + /* + * hashDelete deletes the record matching the key + */ +void hashDelete (HashTable_s *ht, void *key) +{ + HashRecord_s *rec; + + rec = hashLookup(ht, ht->hash(key), key); + if (rec != NULL) + { + ht->table[rec->crc & ht->mask] = rec->next; + ht->destroy(rec); + --ht->numRecords; + } +} + + /* + * hashInsert tries to insert a new record. If an record + * already exits that matches the key, that record is + * returned. + */ +void *hashInsert (HashTable_s *ht, void *key, void *data) +{ + crc_t crc; + NINT bucket; + HashRecord_s *rec; + + crc = ht->hash(key); + rec = hashLookup(ht, crc, key); + if (rec != NULL) + { + return rec; + } + rec = ht->alloc(key, data); + if (rec == NULL) + { + return NULL; + } + bucket = crc & ht->mask; + rec->next = ht->table[bucket]; + ht->table[bucket] = rec; + rec->crc = crc; + + ++ht->numRecords; + + return rec; +} + + /* + * hashApply applies the given function, myFunc, to each record + * in the table and passes along the metaData supplied + */ +STATUS hashApply ( + HashTable_s *ht, + STATUS (*myFunc)(HashRecord_s *rec, void *metaData), + void *metaData) +{ + STATUS rc; + unsigned i; + unsigned numBuckets = ht->mask + 1; + HashRecord_s **table = ht->table; + HashRecord_s *rec; + + for (i = 0; i < numBuckets; ++i) + { + rec = table[i]; + while (rec != NULL) + { + rc = myFunc(rec, metaData); + if (rc != 0) + { + return rc; + } + rec = rec->next; + } + } + return 0; +} + + /* + * Increases the number of hash buckets - the first power of + * 2 less than or equal to the factor is used. + */ +HashTable_s *hashGrow (HashTable_s *ht, NINT factor) +{ + NINT i; + NINT highBit; + NINT numBuckets = ht->mask + 1; + HashRecord_s **table = ht->table; + HashRecord_s *rec; + HashRecord_s *next; + NINT newMask; + NINT newNumBuckets; + NINT bucket; + + highBit = findHighBit(factor); + factor = (1 << highBit); + + newNumBuckets = numBuckets * factor; + newMask = newNumBuckets - 1; + table = realloc(table, newNumBuckets * sizeof(HashRecord_s *)); + if (table == NULL) + { + return NULL; + } + for (i = numBuckets; i < newNumBuckets; ++i) + { + table[i] = NULL; + } + for (i = 0; i < numBuckets; ++i) + { + rec = table[i]; + table[i] = NULL; + while (rec != NULL) + { + bucket = (rec->crc & newMask); + next = rec->next; + rec->next = table[bucket]; + table[bucket] = rec; + rec = next; + } + } + ht->mask = newMask; + ht->table = table; + return ht; +} + + /* + * Decreases the number of hash buckets - the first power of + * 2 less than or equal to the factor is used. + */ +HashTable_s *hashShrink (HashTable_s *ht, NINT factor) +{ + NINT i; + NINT highBit; + NINT numBuckets = ht->mask + 1; + HashRecord_s **table = ht->table; + HashRecord_s *rec; + HashRecord_s *next; + NINT newMask; + NINT newNumBuckets; + NINT bucket; + + highBit = findHighBit(factor); + factor = (1 << highBit); + + newNumBuckets = numBuckets / factor; + if (newNumBuckets == 0) + { + return NULL; + } + newMask = newNumBuckets - 1; + ht->mask = newMask; + + for (i = newNumBuckets; i < numBuckets; ++i) + { + rec = table[i]; + table[i] = NULL; + while (rec != NULL) + { + bucket = (rec->crc & newMask); + next = rec->next; + rec->next = table[bucket]; + table[bucket] = rec; + rec = next; + } + } + table = realloc(table, + newNumBuckets * sizeof(HashRecord_s *)); + if (table == NULL) + { + return ht; + } + ht->table = table; + return ht; +} + + /* + * Destory the hash table, all the users destroy function + * for each record and then freeing the table. + */ +void hashDestroy (HashTable_s *ht) +{ + NINT i; + NINT numBuckets = ht->mask + 1; + HashRecord_s **table = ht->table; + HashRecord_s *rec; + HashRecord_s *next; + + for (i = 0; i < numBuckets; ++i) + { + rec = table[i]; + while (rec != NULL) + { + next = rec->next; + ht->destroy(rec); + rec = next; + } + } + free(table); +} + + /* + * Generate statistics for the hash table + */ +HashStats_s *hashStats ( + HashTable_s *ht, + HashStats_s *stats) +{ + NINT maxChain = 0; + NINT minChain = ~0; + NINT total = 0; + NINT sum; + NINT i; + NINT numBuckets = ht->mask + 1; + HashRecord_s **table = ht->table; + HashRecord_s *rec; + + for (i = 0; i < numBuckets; ++i) + { + sum = 0; + rec = table[i]; + while (rec != NULL) + { + ++sum; + rec = rec->next; + } + total += sum; + if (sum > maxChain) + { + maxChain = sum; + } + if (sum < minChain) + { + minChain = sum; + } + } + stats->numBuckets = numBuckets; + stats->totalRecords = total; + stats->maxChain = maxChain; + stats->minChain = minChain; +#if 0 +// stats->avgChain = ((float)total) / numBuckets; +#endif + return stats; +} + + /* + * Dumps the hash table (just the CRC values) to the screen + */ +void hashDump (HashTable_s *ht) +{ + NINT i; + NINT numBuckets = ht->mask + 1; + HashRecord_s **table = ht->table; + HashRecord_s *rec; + + for (i = 0; i < numBuckets; ++i) + { + rec = table[i]; + while (rec != NULL) + { + //printf("%x ", rec->crc); + rec = rec->next; + } + printf("\n"); + } +}