6
* $Id: table.c,v 1.6 2000-10-13 23:18:18 d3h325 Exp $
10
* Dynamic table module.
12
* Each table entry consists of an external data item and internal state.
13
* The size of the table is automatically increased if there isn't room
14
* to add another entry. The client can allocate, deallocate, verify
15
* entries, and perform both handle-->data and data-->handle lookup.
33
/* default # of initial table entries */
34
#define DEFAULT_TABLE_ENTRIES 32
40
/* state of a TableEntry */
43
TES_Unused = 0, /* never used */
44
TES_Allocated, /* currently in use */
45
TES_Deallocated /* formerly in use */
48
/* table entry consists of data and state */
49
typedef struct _TableEntry
51
TableData data; /* in this entry */
52
TableEntryState state; /* of this entry */
55
/* table is an array of table entries */
56
typedef TableEntry * Table;
62
/* currently only one table is managed */
63
private Table ma_table = NULL;
65
private Integer ma_table_capacity = 0;
66
private Integer ma_table_entries = 0;
67
private Integer ma_table_next_slot = 0;
70
** public routines for internal use only
73
/* ------------------------------------------------------------------------- */
75
* Allocate a table slot, store the given data into it, and return a handle
76
* by which the slot may be referenced. If a slot cannot be allocated,
77
* return TABLE_HANDLE_NONE.
79
/* ------------------------------------------------------------------------- */
81
public Integer ma_table_allocate(data)
82
TableData data; /* to store */
85
Integer new_ma_table_capacity;
86
unsigned new_ma_table_size;
88
Integer slots_examined;
90
/* expand the table if necessary */
91
if (ma_table_entries >= ma_table_capacity)
93
/* increase table capacity */
94
if (ma_table_capacity == 0)
95
/* set the initial capacity */
96
new_ma_table_capacity = DEFAULT_TABLE_ENTRIES;
98
/* double the current capacity */
99
new_ma_table_capacity = 2 * ma_table_capacity;
101
/* allocate space for new table */
102
new_ma_table_size = (unsigned)(new_ma_table_capacity * sizeof(TableEntry));
103
if ((new_ma_table = (Table)bytealloc(new_ma_table_size)) == (Table)NULL)
105
(void)sprintf(ma_ebuf,
106
"could not allocate %u bytes for ma_table",
108
ma_error(EL_Nonfatal, ET_Internal, "ma_table_allocate", ma_ebuf);
109
return TABLE_HANDLE_NONE;
112
/* copy and free old table */
113
if (ma_table_capacity > 0)
115
bytecopy(ma_table, new_ma_table, (ma_table_capacity * sizeof(TableEntry)));
119
/* initialize new part of new table */
120
for (i = new_ma_table_capacity-1; i >= ma_table_capacity; i--)
121
new_ma_table[i].state = TES_Unused;
123
/* remember the new table */
124
ma_table = new_ma_table;
125
ma_table_next_slot = ma_table_capacity;
126
ma_table_capacity = new_ma_table_capacity;
129
/* perform a linear circular search to find the next available slot */
130
for (slots_examined = 0, i = ma_table_next_slot;
131
slots_examined < ma_table_capacity;
132
slots_examined++, i = (i+1) % ma_table_capacity)
134
if (ma_table[i].state != TES_Allocated)
137
ma_table[i].data = data;
138
ma_table[i].state = TES_Allocated;
140
/* increment ma_table_entries */
143
/* advance ma_table_next_slot */
144
ma_table_next_slot = (i+1) % ma_table_capacity;
146
/* return the handle */
151
/* if we get here, something is wrong */
152
(void)sprintf(ma_ebuf,
153
"no ma_table slot available, %ld/%ld slots used",
154
(long)ma_table_entries, (long)ma_table_capacity);
155
ma_error(EL_Nonfatal, ET_Internal, "ma_table_allocate", ma_ebuf);
156
return TABLE_HANDLE_NONE;
159
/* ------------------------------------------------------------------------- */
161
* Deallocate the table slot corresponding to the given handle,
162
* which should have been verified previously (e.g., via ma_table_verify()).
163
* If handle is invalid, print an error message.
165
/* ------------------------------------------------------------------------- */
167
public void ma_table_deallocate(handle)
168
Integer handle; /* to deallocate */
170
if (ma_table_verify(handle, "ma_table_deallocate"))
172
/* deallocate the slot */
173
ma_table[handle].state = TES_Deallocated;
175
/* decrement ma_table_entries */
180
/* ------------------------------------------------------------------------- */
182
* Return the data in the table slot corresponding to the given handle,
183
* which should have been verified previously (e.g., via ma_table_verify()).
184
* If handle is invalid, print an error message and return NULL.
186
/* ------------------------------------------------------------------------- */
188
public TableData ma_table_lookup(handle)
189
Integer handle; /* to lookup */
191
if (ma_table_verify(handle, "ma_table_lookup"))
193
return ma_table[handle].data;
196
return (TableData)NULL;
199
/* ------------------------------------------------------------------------- */
201
* Return the handle for the table slot containing the given data (i.e.,
202
* perform an associative or inverted lookup), or TABLE_HANDLE_NONE if
203
* no currently allocated table slot contains the given data.
205
* If more than one table slot contains the given data, the one whose
206
* handle is returned is undefined (i.e., implementation dependent).
208
/* ------------------------------------------------------------------------- */
210
public Integer ma_table_lookup_assoc(data)
211
TableData data; /* to lookup */
215
/* perform a linear search from the first table slot */
216
for (i = 0; i < ma_table_capacity; i++)
217
if ((ma_table[i].state == TES_Allocated) && (ma_table[i].data == data))
222
return TABLE_HANDLE_NONE;
225
/* ------------------------------------------------------------------------- */
227
* Return MA_TRUE if the given handle corresponds to a valid table slot
228
* (one that is currently allocated), else return MA_FALSE and print an
231
/* ------------------------------------------------------------------------- */
233
public Boolean ma_table_verify(handle, caller)
234
Integer handle; /* to verify */
235
char *caller; /* name of calling routine */
237
Boolean badhandle; /* is handle invalid? */
239
badhandle = MA_FALSE;
241
/* if handle is invalid, construct an error message */
243
(handle >= ma_table_capacity) ||
244
(ma_table[handle].state == TES_Unused))
246
(void)sprintf(ma_ebuf,
247
"handle %ld is not valid",
251
else if (ma_table[handle].state == TES_Deallocated)
253
(void)sprintf(ma_ebuf,
254
"handle %ld already deallocated",
262
ma_error(EL_Nonfatal, ET_External, caller, ma_ebuf);