1*324bb76bSAndroid Build Coastguard Worker /*****************************************************************************
2*324bb76bSAndroid Build Coastguard Worker
3*324bb76bSAndroid Build Coastguard Worker gif_hash.c -- module to support the following operations:
4*324bb76bSAndroid Build Coastguard Worker
5*324bb76bSAndroid Build Coastguard Worker 1. InitHashTable - initialize hash table.
6*324bb76bSAndroid Build Coastguard Worker 2. ClearHashTable - clear the hash table to an empty state.
7*324bb76bSAndroid Build Coastguard Worker 2. InsertHashTable - insert one item into data structure.
8*324bb76bSAndroid Build Coastguard Worker 3. ExistsHashTable - test if item exists in data structure.
9*324bb76bSAndroid Build Coastguard Worker
10*324bb76bSAndroid Build Coastguard Worker This module is used to hash the GIF codes during encoding.
11*324bb76bSAndroid Build Coastguard Worker
12*324bb76bSAndroid Build Coastguard Worker SPDX-License-Identifier: MIT
13*324bb76bSAndroid Build Coastguard Worker
14*324bb76bSAndroid Build Coastguard Worker *****************************************************************************/
15*324bb76bSAndroid Build Coastguard Worker
16*324bb76bSAndroid Build Coastguard Worker #include <fcntl.h>
17*324bb76bSAndroid Build Coastguard Worker #include <stdint.h>
18*324bb76bSAndroid Build Coastguard Worker #include <stdio.h>
19*324bb76bSAndroid Build Coastguard Worker #include <stdlib.h>
20*324bb76bSAndroid Build Coastguard Worker #include <string.h>
21*324bb76bSAndroid Build Coastguard Worker
22*324bb76bSAndroid Build Coastguard Worker #include "gif_hash.h"
23*324bb76bSAndroid Build Coastguard Worker #include "gif_lib.h"
24*324bb76bSAndroid Build Coastguard Worker #include "gif_lib_private.h"
25*324bb76bSAndroid Build Coastguard Worker
26*324bb76bSAndroid Build Coastguard Worker /* #define DEBUG_HIT_RATE Debug number of misses per hash Insert/Exists. */
27*324bb76bSAndroid Build Coastguard Worker
28*324bb76bSAndroid Build Coastguard Worker #ifdef DEBUG_HIT_RATE
29*324bb76bSAndroid Build Coastguard Worker static long NumberOfTests = 0, NumberOfMisses = 0;
30*324bb76bSAndroid Build Coastguard Worker #endif /* DEBUG_HIT_RATE */
31*324bb76bSAndroid Build Coastguard Worker
32*324bb76bSAndroid Build Coastguard Worker static int KeyItem(uint32_t Item);
33*324bb76bSAndroid Build Coastguard Worker
34*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
35*324bb76bSAndroid Build Coastguard Worker Initialize HashTable - allocate the memory needed and clear it. *
36*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
_InitHashTable(void)37*324bb76bSAndroid Build Coastguard Worker GifHashTableType *_InitHashTable(void) {
38*324bb76bSAndroid Build Coastguard Worker GifHashTableType *HashTable;
39*324bb76bSAndroid Build Coastguard Worker
40*324bb76bSAndroid Build Coastguard Worker if ((HashTable = (GifHashTableType *)malloc(
41*324bb76bSAndroid Build Coastguard Worker sizeof(GifHashTableType))) == NULL) {
42*324bb76bSAndroid Build Coastguard Worker return NULL;
43*324bb76bSAndroid Build Coastguard Worker }
44*324bb76bSAndroid Build Coastguard Worker
45*324bb76bSAndroid Build Coastguard Worker _ClearHashTable(HashTable);
46*324bb76bSAndroid Build Coastguard Worker
47*324bb76bSAndroid Build Coastguard Worker return HashTable;
48*324bb76bSAndroid Build Coastguard Worker }
49*324bb76bSAndroid Build Coastguard Worker
50*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
51*324bb76bSAndroid Build Coastguard Worker Routine to clear the HashTable to an empty state. *
52*324bb76bSAndroid Build Coastguard Worker This part is a little machine depended. Use the commented part otherwise. *
53*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
_ClearHashTable(GifHashTableType * HashTable)54*324bb76bSAndroid Build Coastguard Worker void _ClearHashTable(GifHashTableType *HashTable) {
55*324bb76bSAndroid Build Coastguard Worker memset(HashTable->HTable, 0xFF, HT_SIZE * sizeof(uint32_t));
56*324bb76bSAndroid Build Coastguard Worker }
57*324bb76bSAndroid Build Coastguard Worker
58*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
59*324bb76bSAndroid Build Coastguard Worker Routine to insert a new Item into the HashTable. The data is assumed to be *
60*324bb76bSAndroid Build Coastguard Worker new one. *
61*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
_InsertHashTable(GifHashTableType * HashTable,uint32_t Key,int Code)62*324bb76bSAndroid Build Coastguard Worker void _InsertHashTable(GifHashTableType *HashTable, uint32_t Key, int Code) {
63*324bb76bSAndroid Build Coastguard Worker int HKey = KeyItem(Key);
64*324bb76bSAndroid Build Coastguard Worker uint32_t *HTable = HashTable->HTable;
65*324bb76bSAndroid Build Coastguard Worker
66*324bb76bSAndroid Build Coastguard Worker #ifdef DEBUG_HIT_RATE
67*324bb76bSAndroid Build Coastguard Worker NumberOfTests++;
68*324bb76bSAndroid Build Coastguard Worker NumberOfMisses++;
69*324bb76bSAndroid Build Coastguard Worker #endif /* DEBUG_HIT_RATE */
70*324bb76bSAndroid Build Coastguard Worker
71*324bb76bSAndroid Build Coastguard Worker while (HT_GET_KEY(HTable[HKey]) != 0xFFFFFL) {
72*324bb76bSAndroid Build Coastguard Worker #ifdef DEBUG_HIT_RATE
73*324bb76bSAndroid Build Coastguard Worker NumberOfMisses++;
74*324bb76bSAndroid Build Coastguard Worker #endif /* DEBUG_HIT_RATE */
75*324bb76bSAndroid Build Coastguard Worker HKey = (HKey + 1) & HT_KEY_MASK;
76*324bb76bSAndroid Build Coastguard Worker }
77*324bb76bSAndroid Build Coastguard Worker HTable[HKey] = HT_PUT_KEY(Key) | HT_PUT_CODE(Code);
78*324bb76bSAndroid Build Coastguard Worker }
79*324bb76bSAndroid Build Coastguard Worker
80*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
81*324bb76bSAndroid Build Coastguard Worker Routine to test if given Key exists in HashTable and if so returns its code *
82*324bb76bSAndroid Build Coastguard Worker Returns the Code if key was found, -1 if not. *
83*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
_ExistsHashTable(GifHashTableType * HashTable,uint32_t Key)84*324bb76bSAndroid Build Coastguard Worker int _ExistsHashTable(GifHashTableType *HashTable, uint32_t Key) {
85*324bb76bSAndroid Build Coastguard Worker int HKey = KeyItem(Key);
86*324bb76bSAndroid Build Coastguard Worker uint32_t *HTable = HashTable->HTable, HTKey;
87*324bb76bSAndroid Build Coastguard Worker
88*324bb76bSAndroid Build Coastguard Worker #ifdef DEBUG_HIT_RATE
89*324bb76bSAndroid Build Coastguard Worker NumberOfTests++;
90*324bb76bSAndroid Build Coastguard Worker NumberOfMisses++;
91*324bb76bSAndroid Build Coastguard Worker #endif /* DEBUG_HIT_RATE */
92*324bb76bSAndroid Build Coastguard Worker
93*324bb76bSAndroid Build Coastguard Worker while ((HTKey = HT_GET_KEY(HTable[HKey])) != 0xFFFFFL) {
94*324bb76bSAndroid Build Coastguard Worker #ifdef DEBUG_HIT_RATE
95*324bb76bSAndroid Build Coastguard Worker NumberOfMisses++;
96*324bb76bSAndroid Build Coastguard Worker #endif /* DEBUG_HIT_RATE */
97*324bb76bSAndroid Build Coastguard Worker if (Key == HTKey) {
98*324bb76bSAndroid Build Coastguard Worker return HT_GET_CODE(HTable[HKey]);
99*324bb76bSAndroid Build Coastguard Worker }
100*324bb76bSAndroid Build Coastguard Worker HKey = (HKey + 1) & HT_KEY_MASK;
101*324bb76bSAndroid Build Coastguard Worker }
102*324bb76bSAndroid Build Coastguard Worker
103*324bb76bSAndroid Build Coastguard Worker return -1;
104*324bb76bSAndroid Build Coastguard Worker }
105*324bb76bSAndroid Build Coastguard Worker
106*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
107*324bb76bSAndroid Build Coastguard Worker Routine to generate an HKey for the hashtable out of the given unique key. *
108*324bb76bSAndroid Build Coastguard Worker The given Key is assumed to be 20 bits as follows: lower 8 bits are the *
109*324bb76bSAndroid Build Coastguard Worker new postfix character, while the upper 12 bits are the prefix code. *
110*324bb76bSAndroid Build Coastguard Worker Because the average hit ratio is only 2 (2 hash references per entry), *
111*324bb76bSAndroid Build Coastguard Worker evaluating more complex keys (such as twin prime keys) does not worth it! *
112*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
KeyItem(uint32_t Item)113*324bb76bSAndroid Build Coastguard Worker static int KeyItem(uint32_t Item) {
114*324bb76bSAndroid Build Coastguard Worker return ((Item >> 12) ^ Item) & HT_KEY_MASK;
115*324bb76bSAndroid Build Coastguard Worker }
116*324bb76bSAndroid Build Coastguard Worker
117*324bb76bSAndroid Build Coastguard Worker #ifdef DEBUG_HIT_RATE
118*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
119*324bb76bSAndroid Build Coastguard Worker Debugging routine to print the hit ratio - number of times the hash table *
120*324bb76bSAndroid Build Coastguard Worker was tested per operation. This routine was used to test the KeyItem routine *
121*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
HashTablePrintHitRatio(void)122*324bb76bSAndroid Build Coastguard Worker void HashTablePrintHitRatio(void) {
123*324bb76bSAndroid Build Coastguard Worker printf("Hash Table Hit Ratio is %ld/%ld = %ld%%.\n", NumberOfMisses,
124*324bb76bSAndroid Build Coastguard Worker NumberOfTests, NumberOfMisses * 100 / NumberOfTests);
125*324bb76bSAndroid Build Coastguard Worker }
126*324bb76bSAndroid Build Coastguard Worker #endif /* DEBUG_HIT_RATE */
127*324bb76bSAndroid Build Coastguard Worker
128*324bb76bSAndroid Build Coastguard Worker /* end */
129