3
copyright 1991-96, Michael D. Brennan
5
This is a source file for mawk, an implementation of
6
the AWK programming language.
8
Mawk is distributed without warranty under the terms of
9
the GNU General Public License, version 2, 1991.
13
This file was generated with the command
15
notangle -R'"array.c"' array.w > array.c
17
Notangle is part of Norman Ramsey's noweb literate programming package
18
available from CTAN(ftp.shsu.edu).
20
It's easiest to read or modify this file by working with array.w.
29
typedef struct {struct anode *slink, *ilink ;} DUAL_LINK ;
31
typedef struct anode {
41
#define NOT_AN_IVALUE (-Max_Int-1) /* usually 0x80000000 */
43
#define STARTING_HMASK 63 /* 2^6-1, must have form 2^n-1 */
44
#define MAX_AVE_LIST_LENGTH 12
45
#define hmask_to_limit(x) (((x)+1)*MAX_AVE_LIST_LENGTH)
47
static ANODE* PROTO(find_by_ival,(ARRAY, Int, int)) ;
48
static ANODE* PROTO(find_by_sval,(ARRAY, STRING*, int)) ;
49
static void PROTO(add_string_associations,(ARRAY)) ;
50
static void PROTO(make_empty_table,(ARRAY, int)) ;
51
static void PROTO(convert_split_array_to_table,(ARRAY)) ;
52
static void PROTO(double_the_hash_table,(ARRAY)) ;
53
static unsigned PROTO(ahash, (STRING*)) ;
56
CELL* array_find(A, cp, create_flag)
62
if (A->size == 0 && !create_flag)
63
/* eliminating this trivial case early avoids unnecessary conversions later */
69
Int ival = d_to_I(d) ;
70
if ((double)ival == d) {
71
if (A->type == AY_SPLIT) {
72
if (ival >= 1 && ival <= A->size)
73
return (CELL*)A->ptr+(ival-1) ;
74
if (!create_flag) return (CELL*) 0 ;
75
convert_split_array_to_table(A) ;
77
else if (A->type == AY_NULL) make_empty_table(A, AY_INT) ;
78
ap = find_by_ival(A, ival, create_flag) ;
81
/* convert to string */
84
sprintf(buff, string(CONVFMT)->str, d) ;
85
sval = new_STRING(buff) ;
86
ap = find_by_sval(A,sval,create_flag) ;
93
ap = find_by_sval(A, &null_str, create_flag) ;
96
ap = find_by_sval(A, string(cp), create_flag) ;
99
return ap ? &ap->cell : (CELL *) 0 ;
102
void array_delete(A, cp)
107
if (A->size == 0) return ;
111
double d = cp->dval ;
112
Int ival = d_to_I(d) ;
113
if ((double)ival == d) {
114
if (A->type == AY_SPLIT)
115
if (ival >=1 && ival <= A->size) convert_split_array_to_table(A) ;
116
else return ; /* ival not in range */
117
ap = find_by_ival(A, ival, NO_CREATE) ;
118
if (ap) { /* remove from the front of the ilist */
119
DUAL_LINK *table = (DUAL_LINK*) A->ptr ;
120
table[ap->ival & A->hmask].ilink = ap->ilink ;
123
int index = ap->hval & A->hmask ;
124
p = table[index].slink ;
125
while(p != ap) { q = p ; p = q->slink ; }
126
if (q) q->slink = p->slink ;
127
else table[index].slink = p->slink ;
128
free_STRING(ap->sval) ;
131
cell_destroy(&ap->cell) ;
133
if (--A->size == 0) array_clear(A) ;
140
else { /* get the string value */
143
sprintf(buff, string(CONVFMT)->str, d) ;
144
sval = new_STRING(buff) ;
145
ap = find_by_sval(A, sval, NO_CREATE) ;
151
ap = find_by_sval(A, &null_str, NO_CREATE) ;
154
ap = find_by_sval(A, string(cp), NO_CREATE) ;
157
if (ap) { /* remove from the front of the slist */
158
DUAL_LINK *table = (DUAL_LINK*) A->ptr ;
159
table[ap->hval&A->hmask].slink = ap->slink ;
160
if (ap->ival != NOT_AN_IVALUE) {
162
int index = ap->ival & A->hmask ;
163
p = table[index].ilink ;
164
while(p != ap) { q = p ; p = q->ilink ; }
165
if (q) q->ilink = p->ilink ;
166
else table[index].ilink = p->ilink ;
169
free_STRING(ap->sval) ;
170
cell_destroy(&ap->cell) ;
172
if (--A->size == 0) array_clear(A) ;
178
void array_load(A, cnt)
182
CELL *cells ; /* storage for A[1..cnt] */
183
int i ; /* index into cells[] */
184
if (A->type != AY_SPLIT || A->limit < cnt) {
186
A->limit = (cnt&~3)+4 ;
187
A->ptr = zmalloc(A->limit*sizeof(CELL)) ;
191
for(i=0;i < A->size; i++) cell_destroy((CELL*)A->ptr+i) ;
193
cells = (CELL*) A->ptr ;
195
if (cnt > MAX_SPLIT) {
196
SPLIT_OV *p = split_ov_list ;
198
split_ov_list = (SPLIT_OV*) 0 ;
201
cells[i].type = C_MBSTRN ;
202
cells[i].ptr = (PTR) p->sval ;
203
q = p ; p = q->link ; ZFREE(q) ;
209
for(i=0;i < cnt; i++) {
210
cells[i].type = C_MBSTRN ;
211
cells[i].ptr = split_buff[i] ;
220
if (A->type == AY_SPLIT) {
221
for(i=0;i < A->size; i++) cell_destroy((CELL*)A->ptr+i) ;
222
zfree(A->ptr, A->limit * sizeof(CELL)) ;
224
else if (A->type & AY_STR) {
225
DUAL_LINK *table = (DUAL_LINK*) A->ptr ;
226
for(i=0;i <= A->hmask; i++) {
229
q = p ; p = q->slink ;
230
free_STRING(q->sval) ;
231
cell_destroy(&q->cell) ;
235
zfree(A->ptr, (A->hmask+1)*sizeof(DUAL_LINK)) ;
237
else if (A->type & AY_INT) {
238
DUAL_LINK *table = (DUAL_LINK*) A->ptr ;
239
for(i=0;i <= A->hmask; i++) {
242
q = p ; p = q->ilink ;
243
cell_destroy(&q->cell) ;
247
zfree(A->ptr, (A->hmask+1)*sizeof(DUAL_LINK)) ;
249
memset(A, 0, sizeof(*A)) ;
254
STRING** array_loop_vector(A, sizep)
261
if (!(A->type & AY_STR)) add_string_associations(A) ;
262
ret = (STRING**) zmalloc(A->size*sizeof(STRING*)) ;
264
int r = 0 ; /* indexes ret */
265
DUAL_LINK* table = (DUAL_LINK*) A->ptr ;
266
int i ; /* indexes table */
267
ANODE *p ; /* walks slists */
268
for(i=0;i <= A->hmask; i++) {
269
for(p = table[i].slink; p ; p = p->slink) {
278
else return (STRING**) 0 ;
281
CELL *array_cat(sp, cnt)
285
CELL *p ; /* walks the eval stack */
286
CELL subsep ; /* local copy of SUBSEP */
287
unsigned subsep_len ; /* string length of subsep_str */
290
unsigned total_len ; /* length of cat'ed expression */
291
CELL *top ; /* value of sp at entry */
292
char *target ; /* build cat'ed char* here */
293
STRING *sval ; /* build cat'ed STRING here */
294
cellcpy(&subsep, SUBSEP) ;
295
if ( subsep.type < C_STRING ) cast1_to_s(&subsep) ;
296
subsep_len = string(&subsep)->len ;
297
subsep_str = string(&subsep)->str ;
299
top = sp ; sp -= (cnt-1) ;
301
total_len = (cnt-1)*subsep_len ;
302
for(p = sp ; p <= top ; p++) {
303
if ( p->type < C_STRING ) cast1_to_s(p) ;
304
total_len += string(p)->len ;
307
sval = new_STRING0(total_len) ;
309
for(p = sp ; p < top ; p++) {
310
memcpy(target, string(p)->str, string(p)->len) ;
311
target += string(p)->len ;
312
memcpy(target, subsep_str, subsep_len) ;
313
target += subsep_len ;
316
memcpy(target, string(p)->str, string(p)->len) ;
318
for(p = sp; p <= top ; p++) free_STRING(string(p)) ;
319
free_STRING(string(&subsep)) ;
320
/* set contents of sp , sp->type > C_STRING is possible so reset */
321
sp->type = C_STRING ;
322
sp->ptr = (PTR) sval ;
327
static ANODE* find_by_ival(A, ival, create_flag)
332
DUAL_LINK *table = (DUAL_LINK*) A->ptr ;
333
unsigned index = ival & A->hmask ;
334
ANODE *p = table[index].ilink ; /* walks ilist */
335
ANODE *q = (ANODE*) 0 ; /* trails p */
339
if (A->type & AY_STR) {
340
/* need to search by string */
343
sprintf(buff, INT_FMT, ival) ;
344
sval = new_STRING(buff) ;
345
p = find_by_sval(A, sval, create_flag) ;
347
if (!p) return (ANODE*) 0 ;
349
else if (create_flag) {
351
p->sval = (STRING*) 0 ;
352
p->cell.type = C_NOINIT ;
353
if (++A->size > A->limit) {
354
double_the_hash_table(A) ; /* changes table, may change index */
355
table = (DUAL_LINK*) A->ptr ;
356
index = A->hmask & ival ;
359
else return (ANODE*) 0 ;
365
else if (p->ival == ival) {
366
/* found it, now move to the front */
367
if (!q) /* already at the front */
369
/* delete for insertion at the front */
370
q->ilink = p->ilink ;
373
q = p ; p = q->ilink ;
375
/* insert at the front */
376
p->ilink = table[index].ilink ;
377
table[index].ilink = p ;
381
static ANODE* find_by_sval(A, sval, create_flag)
386
unsigned hval = ahash(sval) ;
387
char *str = sval->str ;
390
ANODE *p ; /* walks list */
391
ANODE *q = (ANODE*) 0 ; /* trails p */
392
if (! (A->type & AY_STR)) add_string_associations(A) ;
393
table = (DUAL_LINK*) A->ptr ;
394
index = hval & A->hmask ;
395
p = table[index].slink ;
403
p->ival = NOT_AN_IVALUE ;
405
p->cell.type = C_NOINIT ;
406
if (++A->size > A->limit) {
407
double_the_hash_table(A) ; /* changes table, may change index */
408
table = (DUAL_LINK*) A->ptr ;
409
index = hval & A->hmask ;
415
else return (ANODE*) 0 ;
417
else if (p->hval == hval && strcmp(p->sval->str,str) == 0 ) {
419
if (!q) /* already at the front */
421
else { /* delete for move to the front */
422
q->slink = p->slink ;
426
q = p ; p = q->slink ;
428
p->slink = table[index].slink ;
429
table[index].slink = p ;
433
static void add_string_associations(A)
436
if (A->type == AY_NULL) make_empty_table(A, AY_STR) ;
439
int i ; /* walks table */
440
ANODE *p ; /* walks ilist */
442
if (A->type == AY_SPLIT) convert_split_array_to_table(A) ;
443
table = (DUAL_LINK*) A->ptr ;
444
for(i=0;i <= A->hmask; i++) {
447
sprintf(buff, INT_FMT, p->ival) ;
448
p->sval = new_STRING(buff) ;
449
p->hval = ahash(p->sval) ;
450
p->slink = table[A->hmask&p->hval].slink ;
451
table[A->hmask&p->hval].slink = p ;
459
static void make_empty_table(A, type)
461
int type ; /* AY_INT or AY_STR */
463
size_t sz = (STARTING_HMASK+1)*sizeof(DUAL_LINK) ;
465
A->hmask = STARTING_HMASK ;
466
A->limit = hmask_to_limit(STARTING_HMASK) ;
467
A->ptr = memset(zmalloc(sz), 0, sz) ;
470
static void convert_split_array_to_table(A)
473
CELL *cells = (CELL*) A->ptr ;
474
int i ; /* walks cells */
476
int j ; /* walks table */
477
unsigned entry_limit = A->limit ;
478
A->hmask = STARTING_HMASK ;
479
A->limit = hmask_to_limit(STARTING_HMASK) ;
480
while(A->size > A->limit) {
481
A->hmask = (A->hmask<<1) + 1 ; /* double the size */
482
A->limit = hmask_to_limit(A->hmask) ;
485
size_t sz = (A->hmask+1)*sizeof(DUAL_LINK) ;
486
A->ptr = memset(zmalloc(sz), 0, sz) ;
487
table = (DUAL_LINK*) A->ptr ;
491
/* insert each cells[i] in the new hash table on an ilist */
492
for(i=0, j=1 ;i < A->size; i++) {
493
ANODE *p = ZMALLOC(ANODE) ;
494
p->sval = (STRING*) 0 ;
497
p->ilink = table[j].ilink ;
499
j++ ; j &= A->hmask ;
502
zfree(cells, entry_limit*sizeof(CELL)) ;
505
static void double_the_hash_table(A)
508
unsigned old_hmask = A->hmask ;
509
unsigned new_hmask = (old_hmask<<1)+1 ;
511
A->ptr = zrealloc(A->ptr, (old_hmask+1)*sizeof(DUAL_LINK),
512
(new_hmask+1)*sizeof(DUAL_LINK)) ;
513
table = (DUAL_LINK*) A->ptr ;
514
/* zero out the new part which is the back half */
515
memset(&table[old_hmask+1], 0, (old_hmask+1)*sizeof(DUAL_LINK)) ;
517
if (A->type & AY_STR) {
518
int i ; /* index to old lists */
519
int j ; /* index to new lists */
520
ANODE *p ; /* walks an old list */
521
ANODE *q ; /* trails p for deletion */
522
ANODE *tail ; /* builds new list from the back */
523
ANODE dummy0, dummy1 ;
524
for(i=0, j=old_hmask+1;i <= old_hmask; i++, j++)
527
q->slink = p = table[i].slink ;
530
if ((p->hval&new_hmask) != i) { /* move it */
531
q->slink = p->slink ;
532
tail = tail->slink = p ;
537
table[i].slink = dummy0.slink ;
538
tail->slink = (ANODE*) 0 ;
539
table[j].slink = dummy1.slink ;
544
if (A->type & AY_INT) {
545
int i ; /* index to old lists */
546
int j ; /* index to new lists */
547
ANODE *p ; /* walks an old list */
548
ANODE *q ; /* trails p for deletion */
549
ANODE *tail ; /* builds new list from the back */
550
ANODE dummy0, dummy1 ;
551
for(i=0, j=old_hmask+1;i <= old_hmask; i++, j++)
554
q->ilink = p = table[i].ilink ;
557
if ((p->ival&new_hmask) != i) { /* move it */
558
q->ilink = p->ilink ;
559
tail = tail->ilink = p ;
564
table[i].ilink = dummy0.ilink ;
565
tail->ilink = (ANODE*) 0 ;
566
table[j].ilink = dummy1.ilink ;
571
A->hmask = new_hmask ;
572
A->limit = hmask_to_limit(new_hmask) ;
576
static unsigned ahash(sval)
579
unsigned sum1 = sval->len ;
580
unsigned sum2 = sum1 ;
581
unsigned char *p , *q ;
583
for(p=(unsigned char*)sval->str; *p ; p++) {
590
p = (unsigned char*)sval->str ; /* p starts at the front */
591
q = (unsigned char*)sval->str + (sum1-1) ; /* q starts at the back */