summaryrefslogtreecommitdiffstats
path: root/private/ntos/dlc/sm2c/hashobj.c
blob: 9b348b3889f7a90537ba9a40f28b894490d90b24 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
/*++

Copyright (c) 1991  Microsoft Corporation
Copyright (c) 1991  Nokia Data Systems AB

Module Name:

    hashobj.c

Abstract:

    The module provides generic non-re-entrant hash object (the
    same object cannot be used in several threads simultaneously).
    The re-entrancy must be done in the specific implementations, 
    if it is necessary.

    The file includes the definiton of hash objects and its the 
    operator functions. All data is private. The hash operators are:
        - HashNew       // creates a new hash object and returns its handle
        - HashAdd       // adds new data to hash object
        - HashUnlink    // Unlinks the given data object from hash table
        - HashSearch    // Search a key from the hash table
        - HashRead      // reads the hash objects to a buffer
        - HashDelete    // deletes the object
	- HashLen       // returns the number of saved data elemets
        
    The client must provide these functions:
        - Comp      // compares objects, returns: -1, 0, 1
        - Hash      // Calculates the hash key for the object
        - Alloc     // Memory allocation subroutine
        - Free      // ... (guess what?)

Author:

    Antti Saarenheimo   [o-anttis]          06-MAY-1991

Revision History:
--*/

//**************** END CLASS HASH ******************

#ifdef NO_INCLUDES
#define FAR far
typedef unsigned int UINT;
typedef void FAR * PVOID;
enum _HashErrors {
    NO_ERROR = 0, 
    ERROR_HASH_NO_MEMORY, 
    ERROR_HASH_KEY_EXIST,
    ERROR_HASH_NOT_FOUND};

//**************** CLASS HASH ******************
//**** PUBLIC:
PVOID HashNew( 
    UINT    cElements,                          // appr. # elements 
    INT (*Hash)( PVOID pKey ),                  // returns the hash key
    INT (*Comp)( PVOID pKey1, PVOID pKey2 ),    // Compares the keys
    PVOID (*Alloc)( UINT cbSize ),              // Allocates a memory block
    VOID (*Free)( VOID *p)                       // Frees a memory block
    );
INT HashAdd( PVOID hHash, PVOID pData);
INT HashUnlink( PVOID hHash, PVOID pData);
PVOID HashSearch( PVOID hHash, PVOID pKey );
UINT HashRead( 
    PVOID hHash,        // hash handle
    UINT cElemRead,     // # elements to read
    UINT iFirstElem,    // index of the first element
    PVOID pBuf[]        // buffer for the elements
    );
UINT HashDelete( PVOID hHash );
UINT HashLen( PVOID hHash );

#else
#include <fsm.h>
#endif


// Declare these routines in a .h file:

//
//  
typedef struct _HASH_ELEMENT {
    PVOID   pData;
    struct _HASH_ELEMENT FAR *pNext;
} HASH_ELEMENT, FAR *PHASH_ELEMENT;

typedef struct _HASH {
    PHASH_ELEMENT FAR *apHashTable;
    INT (*Hash)( PVOID pData );
    INT (*Comp)( PVOID pData1, PVOID pData2 );
    PVOID (*Alloc)( UINT cbSize );
    VOID (*Free)( VOID *p );
    UINT        cElem;
    UINT        cHashTable;
} HASH, FAR *PHASH;

static PHASH_ELEMENT FAR *SearchAddr( PHASH pHash, PVOID pKey);

//
//  Creates a new hash objetc and returns its handle.
//
PVOID HashNew( 
    UINT    cElements,                          // appr. # elements 
    INT (*Hash)( PVOID pKey ),                  // returns the hash key
    INT (*Comp)( PVOID pData1, PVOID pData2 ),  // Compares the keys
    PVOID (*Alloc)( UINT cbSize ),               // Allocates a memory block
    VOID (*Free)( VOID *p)                       // Frees a memory block
    )
{
    PHASH   pHash = Alloc( sizeof( HASH ) );
    UINT    i;
    
    if (pHash == 0) return 0;

    if (!(pHash->apHashTable = Alloc( sizeof( PVOID ) * cElements )))
    {
        Free( pHash );
        return 0;
    }
    // Good optimizer should compile  this an efficient mem set
    for (i = 0; i < cElements; i++)
        pHash->apHashTable[i] = 0;
        
    pHash->cElem = 0;
    pHash->cHashTable = cElements;
    pHash->Hash = Hash;
    pHash->Alloc = Alloc;
    pHash->Free = Free;
    pHash->Comp = Comp;
    return (PVOID)pHash;
}

//
//  Adds new data to has object. Returns 0 if OK.
//  Retunrs: NO_ERROR, ERROR_HASH_NO_MEMORY, ERROR_HASH_KEY_EXIST
//
INT HashAdd( PVOID hHash, PVOID pData)
{
    PHASH_ELEMENT FAR   *ppElem;
    PHASH_ELEMENT       pNext;

    if (HashSearch( hHash, pData) != NULL)
        return ERROR_HASH_KEY_EXIST;
    else
    {
        ppElem = SearchAddr( (PHASH)hHash, pData);
        pNext = *ppElem;
        if (!(*ppElem = ((PHASH)hHash)->Alloc( sizeof( HASH_ELEMENT ))))
            return ERROR_HASH_NO_MEMORY;
        (*ppElem)->pData = pData;
        (*ppElem)->pNext = pNext;
	((PHASH)hHash)->cElem++;
        return NO_ERROR;
    }
}

//
// Unlinks the given data element from the array
//
INT HashUnlink( PVOID hHash, PVOID pData)
{
    PHASH_ELEMENT FAR *ppElem;
    PHASH_ELEMENT pElem;
    
    if (HashSearch((PHASH)hHash, pData) == NULL)
        return ERROR_HASH_NOT_FOUND;

    ppElem = SearchAddr( (PHASH)hHash, pData);
    pElem = *ppElem;
    *ppElem = pElem->pNext;
    ((PHASH)hHash)->Free( pElem );
    ((PHASH)hHash)->cElem--;
    return NO_ERROR;
}

//
// Reads the data elemets from hash table to a buffer.
// Returns the number of read elements.
//
UINT HashRead( 
    PVOID hHash,        // hash handle
    UINT cElemRead,     // # elements to read
    UINT iFirstElem,    // index of the first element
    PVOID pBuf[]        // buffer for the elements
    )
{
    UINT    iCurElem = 0;
    UINT    iCurSlot;
    UINT    cElemCopied = 0;    
    UINT    cHashTable = ((PHASH)hHash)->cHashTable;
    PHASH_ELEMENT FAR * apHashTable = ((PHASH)hHash)->apHashTable;
    PHASH_ELEMENT pElem;

    for (iCurSlot = 0; iCurSlot < cHashTable; iCurSlot++)
    {
        for (pElem = apHashTable[iCurSlot]; pElem; pElem = pElem->pNext)
        {
            if (cElemCopied == cElemRead)
                return cElemCopied;

            if (iCurElem >= iFirstElem)
            {
                pBuf[cElemCopied++] = pElem;
            }
	    iCurElem++;
        }
    }
    return cElemCopied;
}

//
// Deletes the hash object and releases all memory allocated by 
// the object. It does not free any data allocated by the clients.
//
UINT HashDelete( PVOID hHash )
{
    PHASH_ELEMENT   aBuf[50];
    UINT            i, cRead;
    
    // read and remove all hash elements, every read scans 
    // the whole hash table => read the data objects in blocks
    while (cRead = HashRead( hHash, 50, 0, aBuf))
        for (i = 0; i < cRead; i++)
            HashUnlink( hHash, aBuf[i]->pData );

    ((PHASH)hHash)->Free( ((PHASH)hHash)->apHashTable );
    ((PHASH)hHash)->Free( hHash );
    return 0;
}

//
// Returns the number of data elemets in a hash object
//
UINT HashLen( PVOID hHash )
{
    return ((PHASH)hHash)->cElem;
}
//
// Search a key from the hash table
//
PVOID
HashSearch( PVOID pHash, PVOID pKey )
{
    INT iRet;
    PHASH_ELEMENT pElem;
    
    pElem = 
        ((PHASH)pHash)->apHashTable[ 
            ((PHASH)pHash)->Hash( pKey ) % ((PHASH)pHash)->cHashTable];
    for (;;)
    {
        // return the address of the memory pointer reserved for this
        // data object, it's address of a element in the hash table or
        // address of pNext pointer in the list. The objects are increasing
        // order in the list.
        if (pElem == NULL || 
            (iRet = ((PHASH)pHash)->Comp( pKey, pElem->pData)) > 0)
            return NULL;
        else if (iRet == 0)
            return pElem->pData;
        pElem = pElem->pNext;
    }
}

//
//  Returns the address of the next free slot 
//
static PHASH_ELEMENT FAR * 
SearchAddr( PHASH pHash, PVOID pKey )
{
    PHASH_ELEMENT FAR * ppElem;
    
    ppElem = &(pHash->apHashTable[ pHash->Hash( pKey ) % pHash->cHashTable ]);
    for (;;)
    {
        // return the address of the memory pointer reserved for this
        // data object, it's address of a element in the hash table or
        // address of pNext pointer in the list. The objects are increasing
        // order in the list.
        if (*ppElem == NULL || 
            pHash->Comp( pKey, (*ppElem)->pData) >= 0)
            return ppElem;
        ppElem = &((*ppElem)->pNext);
    }
}