forked from cotillion/cd-gamedriver
-
Notifications
You must be signed in to change notification settings - Fork 0
/
otable.c
207 lines (176 loc) · 5.26 KB
/
otable.c
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
#include <stdio.h>
#include <string.h>
#include "config.h"
#include "lint.h"
#include "interpret.h"
#include "object.h"
#include "hash.h"
#include "simulate.h"
#include "exec.h"
/*
* Object name hash table. Object names are unique, so no special
* problems - like stralloc.c. For non-unique hashed names, we need
* a better package (if we want to be able to get at them all) - we
* cant move them to the head of the hash chain, for example.
*
* Note: if you change an object name, you must remove it and reenter it.
*/
/*
* hash table - list of pointers to heads of object chains.
* Each object in chain has a pointer, next_hash, to the next object.
* OTABLE_SIZE is in config.h
*/
static struct object *(obj_table[OTABLE_SIZE]);
/*
* Object hash function
*/
#define ObjHash(s) (hash_string(s) % (OTABLE_SIZE))
/*
* Looks for obj in table, moves it to head.
*/
static long long obj_searches = 0, obj_probes = 0, objs_found = 0;
static struct object *
find_obj_n(char *s)
{
struct object * curr, *prev;
unsigned int h = ObjHash(s);
curr = obj_table[h];
prev = 0;
obj_searches++;
while (curr)
{
obj_probes++;
if (strcmp(curr->name, s) == 0) { /* found it */
if (prev)
{ /* not at head of list */
prev->next_hash = curr->next_hash;
curr->next_hash = obj_table[h];
obj_table[h] = curr;
}
objs_found++;
return(curr); /* pointer to object */
}
prev = curr;
curr = curr->next_hash;
}
return(0); /* not found */
}
/*
* Add an object to the table - can't have duplicate names.
*/
static int objs_in_table = 0;
void
enter_object_hash(struct object *ob)
{
struct object *s, *sibling;
int h = ObjHash(ob->name);
/* Add to object list */
if (ob->flags & O_CLONE && ob->prog->clones) {
sibling = ob->prog->clones;
ob->next_all = sibling;
ob->prev_all = sibling->prev_all;
sibling->prev_all->next_all = ob;
sibling->prev_all = ob;
if (sibling == obj_list)
obj_list = ob;
} else if (obj_list) {
ob->next_all = obj_list;
ob->prev_all = obj_list->prev_all;
obj_list->prev_all->next_all = ob;
obj_list->prev_all = ob;
obj_list = ob;
}
else
obj_list = ob->next_all = ob->prev_all = ob;
if (ob->flags & O_CLONE) {
ob->prog->clones = ob;
ob->prog->num_clones++;
}
s = find_obj_n(ob->name);
if (s) {
if (s != ob)
fatal("Duplicate object \"%s\" in object hash table\n",
ob->name);
else
fatal("Entering object \"%s\" twice in object table\n",
ob->name);
}
if (ob->next_hash)
fatal("Object \"%s\" not found in object table but next link not null\n",
ob->name);
ob->next_hash = obj_table[h];
obj_table[h] = ob;
objs_in_table++;
}
/*
* Remove an object from the table - generally called when it
* is removed from the next_all list - i.e. in destruct.
*/
void
remove_object_hash(struct object *ob)
{
struct object * s;
int h = ObjHash(ob->name);
s = find_obj_n(ob->name);
if (s != ob)
fatal("Remove object \"%s\": found a different object!\n",
ob->name);
obj_table[h] = ob->next_hash;
ob->next_hash = 0;
objs_in_table--;
if (ob->flags & O_CLONE)
ob->prog->num_clones--;
if (ob->prog->clones == ob) {
if (ob->next_all->prog == ob->prog &&
ob->next_all->flags & O_CLONE &&
ob->next_all != ob)
ob->prog->clones = ob->next_all;
else
ob->prog->clones = NULL;
}
if (ob->next_all == ob)
obj_list = NULL;
else if (ob == obj_list)
obj_list = ob->next_all;
ob->prev_all->next_all = ob->next_all;
ob->next_all->prev_all = ob->prev_all;
}
/*
* Lookup an object in the hash table; if it isn't there, return null.
* This is only different to find_object_n in that it collects different
* stats; more finds are actually done than the user ever asks for.
*/
static int user_obj_lookups = 0, user_obj_found = 0;
struct object *
lookup_object_hash(char *s)
{
struct object * ob = find_obj_n(s);
user_obj_lookups++;
if (ob) user_obj_found++;
return(ob);
}
/*
* Print stats, returns the total size of the object table. All objects
* are in table, so their size is included as well.
*/
void
add_otable_status(char *debinf)
{
(void)strcat(debinf, "\nObject name hash table status:\n");
(void)strcat(debinf, "------------------------------\n");
(void)sprintf(debinf + strlen(debinf), "Average hash chain length %.2f\n",
(double)objs_in_table / OTABLE_SIZE);
(void)sprintf(debinf + strlen(debinf), "Searches/average search length %lld (%.2f)\n",
obj_searches, (double)obj_probes / (double)obj_searches);
(void)sprintf(debinf + strlen(debinf), "External lookups succeeded (succeed) %d (%d)\n",
user_obj_lookups, user_obj_found);
}
#ifdef DEALLOCATE_MEMORY_AT_SHUTDOWN
void
clear_otable()
{
int i;
for (i = 0; i < OTABLE_SIZE; i++)
obj_table[i] = NULL;
}
#endif