|
Packit Service |
f629e6 |
/*
|
|
Packit Service |
f629e6 |
* int_array.c - routines for arrays of integer indices.
|
|
Packit Service |
f629e6 |
*/
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/*
|
|
Packit Service |
f629e6 |
* Copyright (C) 1986, 1988, 1989, 1991-2013, 2016, 2017,
|
|
Packit Service |
f629e6 |
* the Free Software Foundation, Inc.
|
|
Packit Service |
f629e6 |
*
|
|
Packit Service |
f629e6 |
* This file is part of GAWK, the GNU implementation of the
|
|
Packit Service |
f629e6 |
* AWK Programming Language.
|
|
Packit Service |
f629e6 |
*
|
|
Packit Service |
f629e6 |
* GAWK is free software; you can redistribute it and/or modify
|
|
Packit Service |
f629e6 |
* it under the terms of the GNU General Public License as published by
|
|
Packit Service |
f629e6 |
* the Free Software Foundation; either version 3 of the License, or
|
|
Packit Service |
f629e6 |
* (at your option) any later version.
|
|
Packit Service |
f629e6 |
*
|
|
Packit Service |
f629e6 |
* GAWK is distributed in the hope that it will be useful,
|
|
Packit Service |
f629e6 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
f629e6 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
f629e6 |
* GNU General Public License for more details.
|
|
Packit Service |
f629e6 |
*
|
|
Packit Service |
f629e6 |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
f629e6 |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
f629e6 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
Packit Service |
f629e6 |
*/
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
#include "awk.h"
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
extern FILE *output_fp;
|
|
Packit Service |
f629e6 |
extern void indent(int indent_level);
|
|
Packit Service |
f629e6 |
extern NODE **is_integer(NODE *symbol, NODE *subs);
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
static size_t INT_CHAIN_MAX = 2;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
static NODE **int_array_init(NODE *symbol, NODE *subs);
|
|
Packit Service |
f629e6 |
static NODE **int_lookup(NODE *symbol, NODE *subs);
|
|
Packit Service |
f629e6 |
static NODE **int_exists(NODE *symbol, NODE *subs);
|
|
Packit Service |
f629e6 |
static NODE **int_clear(NODE *symbol, NODE *subs);
|
|
Packit Service |
f629e6 |
static NODE **int_remove(NODE *symbol, NODE *subs);
|
|
Packit Service |
f629e6 |
static NODE **int_list(NODE *symbol, NODE *t);
|
|
Packit Service |
f629e6 |
static NODE **int_copy(NODE *symbol, NODE *newsymb);
|
|
Packit Service |
f629e6 |
static NODE **int_dump(NODE *symbol, NODE *ndump);
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
static uint32_t int_hash(uint32_t k, uint32_t hsize);
|
|
Packit Service |
f629e6 |
static inline NODE **int_find(NODE *symbol, long k, uint32_t hash1);
|
|
Packit Service |
f629e6 |
static NODE **int_insert(NODE *symbol, long k, uint32_t hash1);
|
|
Packit Service |
f629e6 |
static void grow_int_table(NODE *symbol);
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
afunc_t int_array_func[] = {
|
|
Packit Service |
f629e6 |
int_array_init,
|
|
Packit Service |
f629e6 |
is_integer,
|
|
Packit Service |
f629e6 |
null_length,
|
|
Packit Service |
f629e6 |
int_lookup,
|
|
Packit Service |
f629e6 |
int_exists,
|
|
Packit Service |
f629e6 |
int_clear,
|
|
Packit Service |
f629e6 |
int_remove,
|
|
Packit Service |
f629e6 |
int_list,
|
|
Packit Service |
f629e6 |
int_copy,
|
|
Packit Service |
f629e6 |
int_dump,
|
|
Packit Service |
f629e6 |
(afunc_t) 0,
|
|
Packit Service |
f629e6 |
};
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* int_array_init --- array initialization routine */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
static NODE **
|
|
Packit Service |
f629e6 |
int_array_init(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED)
|
|
Packit Service |
f629e6 |
{
|
|
Packit Service |
f629e6 |
if (symbol == NULL) { /* first time */
|
|
Packit Service |
f629e6 |
long newval;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* check relevant environment variables */
|
|
Packit Service |
f629e6 |
if ((newval = getenv_long("INT_CHAIN_MAX")) > 0)
|
|
Packit Service |
f629e6 |
INT_CHAIN_MAX = newval;
|
|
Packit Service |
f629e6 |
} else
|
|
Packit Service |
f629e6 |
null_array(symbol);
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
return & success_node;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/*
|
|
Packit Service |
f629e6 |
* standard_integer_string -- check whether the string matches what
|
|
Packit Service |
f629e6 |
* sprintf("%ld", <value>) would produce. This is accomplished by accepting
|
|
Packit Service |
f629e6 |
* only strings that look like /^0$/ or /^-?[1-9][0-9]*$/. This should be
|
|
Packit Service |
f629e6 |
* faster than comparing vs. the results of actually calling sprintf.
|
|
Packit Service |
f629e6 |
*/
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
static bool
|
|
Packit Service |
f629e6 |
standard_integer_string(const char *s, size_t len)
|
|
Packit Service |
f629e6 |
{
|
|
Packit Service |
f629e6 |
const char *end;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if (len == 0)
|
|
Packit Service |
f629e6 |
return false;
|
|
Packit Service |
f629e6 |
if (*s == '0' && len == 1)
|
|
Packit Service |
f629e6 |
return true;
|
|
Packit Service |
f629e6 |
end = s + len;
|
|
Packit Service |
f629e6 |
/* ignore leading minus sign */
|
|
Packit Service |
f629e6 |
if (*s == '-' && ++s == end)
|
|
Packit Service |
f629e6 |
return false;
|
|
Packit Service |
f629e6 |
/* check first char is [1-9] */
|
|
Packit Service |
f629e6 |
if (*s < '1' || *s > '9')
|
|
Packit Service |
f629e6 |
return false;
|
|
Packit Service |
f629e6 |
while (++s < end) {
|
|
Packit Service |
f629e6 |
if (*s < '0' || *s > '9')
|
|
Packit Service |
f629e6 |
return false;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
return true;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* is_integer --- check if subscript is an integer */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
NODE **
|
|
Packit Service |
f629e6 |
is_integer(NODE *symbol, NODE *subs)
|
|
Packit Service |
f629e6 |
{
|
|
Packit Service |
f629e6 |
#ifndef CHECK_INTEGER_USING_FORCE_NUMBER
|
|
Packit Service |
f629e6 |
long l;
|
|
Packit Service |
f629e6 |
#endif
|
|
Packit Service |
f629e6 |
AWKNUM d;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if ((subs->flags & NUMINT) != 0)
|
|
Packit Service |
f629e6 |
/* quick exit */
|
|
Packit Service |
f629e6 |
return & success_node;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if (subs == Nnull_string || do_mpfr)
|
|
Packit Service |
f629e6 |
return NULL;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
#ifdef CHECK_INTEGER_USING_FORCE_NUMBER
|
|
Packit Service |
f629e6 |
/*
|
|
Packit Service |
f629e6 |
* This approach is much simpler, because we remove all of the strtol
|
|
Packit Service |
f629e6 |
* logic below. But this may be slower in some usage cases.
|
|
Packit Service |
f629e6 |
*/
|
|
Packit Service |
f629e6 |
if ((subs->flags & NUMCUR) == 0) {
|
|
Packit Service |
f629e6 |
str2number(subs);
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* check again in case force_number set NUMINT */
|
|
Packit Service |
f629e6 |
if ((subs->flags & NUMINT) != 0)
|
|
Packit Service |
f629e6 |
return & success_node;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
#else /* CHECK_INTEGER_USING_FORCE_NUMBER */
|
|
Packit Service |
f629e6 |
if ((subs->flags & NUMCUR) != 0) {
|
|
Packit Service |
f629e6 |
#endif /* CHECK_INTEGER_USING_FORCE_NUMBER */
|
|
Packit Service |
f629e6 |
d = subs->numbr;
|
|
Packit Service |
f629e6 |
if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d) {
|
|
Packit Service |
f629e6 |
/*
|
|
Packit Service |
f629e6 |
* The numeric value is an integer, but we must
|
|
Packit Service |
f629e6 |
* protect against strings that cannot be generated
|
|
Packit Service |
f629e6 |
* from sprintf("%ld", <subscript>). This can happen
|
|
Packit Service |
f629e6 |
* with strnum or string values. We could skip this
|
|
Packit Service |
f629e6 |
* check for pure NUMBER values, but unfortunately the
|
|
Packit Service |
f629e6 |
* code does not currently distinguish between NUMBER
|
|
Packit Service |
f629e6 |
* and strnum values.
|
|
Packit Service |
f629e6 |
*/
|
|
Packit Service |
f629e6 |
if ( (subs->flags & STRCUR) == 0
|
|
Packit Service |
f629e6 |
|| standard_integer_string(subs->stptr, subs->stlen)) {
|
|
Packit Service |
f629e6 |
subs->flags |= NUMINT;
|
|
Packit Service |
f629e6 |
return & success_node;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
return NULL;
|
|
Packit Service |
f629e6 |
#ifndef CHECK_INTEGER_USING_FORCE_NUMBER
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* a[3]=1; print "3" in a -- true
|
|
Packit Service |
f629e6 |
* a[3]=1; print "+3" in a -- false
|
|
Packit Service |
f629e6 |
* a[3]=1; print "03" in a -- false
|
|
Packit Service |
f629e6 |
* a[-3]=1; print "-3" in a -- true
|
|
Packit Service |
f629e6 |
*/
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* must be a STRING */
|
|
Packit Service |
f629e6 |
char *cp = subs->stptr, *cpend, *ptr;
|
|
Packit Service |
f629e6 |
char save;
|
|
Packit Service |
f629e6 |
size_t len = subs->stlen;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if (len == 0 || (! isdigit((unsigned char) *cp) && *cp != '-'))
|
|
Packit Service |
f629e6 |
return NULL;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if (len > 1 &&
|
|
Packit Service |
f629e6 |
((*cp == '0') /* "00", "011" .. */
|
|
Packit Service |
f629e6 |
|| (*cp == '-' && *(cp + 1) == '0') /* "-0", "-011" .. */
|
|
Packit Service |
f629e6 |
)
|
|
Packit Service |
f629e6 |
)
|
|
Packit Service |
f629e6 |
return NULL;
|
|
Packit Service |
f629e6 |
if (len == 1 && *cp != '-') { /* single digit */
|
|
Packit Service |
f629e6 |
subs->numbr = (long) (*cp - '0');
|
|
Packit Service |
f629e6 |
if ((subs->flags & USER_INPUT) != 0) {
|
|
Packit Service |
f629e6 |
/* leave USER_INPUT set */
|
|
Packit Service |
f629e6 |
subs->flags &= ~STRING;
|
|
Packit Service |
f629e6 |
subs->flags |= NUMBER;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
subs->flags |= (NUMCUR|NUMINT);
|
|
Packit Service |
f629e6 |
return & success_node;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
cpend = cp + len;
|
|
Packit Service |
f629e6 |
save = *cpend;
|
|
Packit Service |
f629e6 |
*cpend = '\0';
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
errno = 0;
|
|
Packit Service |
f629e6 |
l = strtol(cp, & ptr, 10);
|
|
Packit Service |
f629e6 |
*cpend = save;
|
|
Packit Service |
f629e6 |
if (errno != 0 || ptr != cpend)
|
|
Packit Service |
f629e6 |
return NULL;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
subs->numbr = l;
|
|
Packit Service |
f629e6 |
if ((subs->flags & USER_INPUT) != 0) {
|
|
Packit Service |
f629e6 |
/* leave USER_INPUT set */
|
|
Packit Service |
f629e6 |
subs->flags &= ~STRING;
|
|
Packit Service |
f629e6 |
subs->flags |= NUMBER;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
subs->flags |= NUMCUR;
|
|
Packit Service |
f629e6 |
if (l <= INT32_MAX && l >= INT32_MIN) {
|
|
Packit Service |
f629e6 |
subs->flags |= NUMINT;
|
|
Packit Service |
f629e6 |
return & success_node;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
return NULL;
|
|
Packit Service |
f629e6 |
#endif /* CHECK_INTEGER_USING_FORCE_NUMBER */
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/*
|
|
Packit Service |
f629e6 |
* int_lookup --- Find SYMBOL[SUBS] in the assoc array. Install it with value ""
|
|
Packit Service |
f629e6 |
* if it isn't there. Returns a pointer ala get_lhs to where its value is stored.
|
|
Packit Service |
f629e6 |
*/
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
static NODE **
|
|
Packit Service |
f629e6 |
int_lookup(NODE *symbol, NODE *subs)
|
|
Packit Service |
f629e6 |
{
|
|
Packit Service |
f629e6 |
uint32_t hash1;
|
|
Packit Service |
f629e6 |
long k;
|
|
Packit Service |
f629e6 |
unsigned long size;
|
|
Packit Service |
f629e6 |
NODE **lhs;
|
|
Packit Service |
f629e6 |
NODE *xn;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/*
|
|
Packit Service |
f629e6 |
* N.B: symbol->table_size is the total # of non-integers (symbol->xarray)
|
|
Packit Service |
f629e6 |
* and integer elements. Also, symbol->xarray must have at least one
|
|
Packit Service |
f629e6 |
* item in it, and can not exist if there are no integer elements.
|
|
Packit Service |
f629e6 |
* In that case, symbol->xarray is promoted to 'symbol' (See int_remove).
|
|
Packit Service |
f629e6 |
*/
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if (! is_integer(symbol, subs)) {
|
|
Packit Service |
f629e6 |
xn = symbol->xarray;
|
|
Packit Service |
f629e6 |
if (xn == NULL) {
|
|
Packit Service |
f629e6 |
xn = symbol->xarray = make_array();
|
|
Packit Service |
f629e6 |
xn->vname = symbol->vname; /* shallow copy */
|
|
Packit Service |
f629e6 |
xn->flags |= XARRAY;
|
|
Packit Service |
f629e6 |
} else if ((lhs = xn->aexists(xn, subs)) != NULL)
|
|
Packit Service |
f629e6 |
return lhs;
|
|
Packit Service |
f629e6 |
symbol->table_size++;
|
|
Packit Service |
f629e6 |
return assoc_lookup(xn, subs);
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
k = subs->numbr;
|
|
Packit Service |
f629e6 |
if (symbol->buckets == NULL)
|
|
Packit Service |
f629e6 |
grow_int_table(symbol);
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
hash1 = int_hash(k, symbol->array_size);
|
|
Packit Service |
f629e6 |
if ((lhs = int_find(symbol, k, hash1)) != NULL)
|
|
Packit Service |
f629e6 |
return lhs;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* It's not there, install it */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
symbol->table_size++;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* first see if we would need to grow the array, before installing */
|
|
Packit Service |
f629e6 |
size = symbol->table_size;
|
|
Packit Service |
f629e6 |
if ((xn = symbol->xarray) != NULL)
|
|
Packit Service |
f629e6 |
size -= xn->table_size;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if ((symbol->flags & ARRAYMAXED) == 0
|
|
Packit Service |
f629e6 |
&& (size / symbol->array_size) > INT_CHAIN_MAX) {
|
|
Packit Service |
f629e6 |
grow_int_table(symbol);
|
|
Packit Service |
f629e6 |
/* have to recompute hash value for new size */
|
|
Packit Service |
f629e6 |
hash1 = int_hash(k, symbol->array_size);
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
return int_insert(symbol, k, hash1);
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/*
|
|
Packit Service |
f629e6 |
* int_exists --- test whether the array element symbol[subs] exists or not,
|
|
Packit Service |
f629e6 |
* return pointer to value if it does.
|
|
Packit Service |
f629e6 |
*/
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
static NODE **
|
|
Packit Service |
f629e6 |
int_exists(NODE *symbol, NODE *subs)
|
|
Packit Service |
f629e6 |
{
|
|
Packit Service |
f629e6 |
long k;
|
|
Packit Service |
f629e6 |
uint32_t hash1;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if (! is_integer(symbol, subs)) {
|
|
Packit Service |
f629e6 |
NODE *xn = symbol->xarray;
|
|
Packit Service |
f629e6 |
if (xn == NULL)
|
|
Packit Service |
f629e6 |
return NULL;
|
|
Packit Service |
f629e6 |
return xn->aexists(xn, subs);
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
if (symbol->buckets == NULL)
|
|
Packit Service |
f629e6 |
return NULL;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
k = subs->numbr;
|
|
Packit Service |
f629e6 |
hash1 = int_hash(k, symbol->array_size);
|
|
Packit Service |
f629e6 |
return int_find(symbol, k, hash1);
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* int_clear --- flush all the values in symbol[] */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
static NODE **
|
|
Packit Service |
f629e6 |
int_clear(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED)
|
|
Packit Service |
f629e6 |
{
|
|
Packit Service |
f629e6 |
unsigned long i;
|
|
Packit Service |
f629e6 |
int j;
|
|
Packit Service |
f629e6 |
BUCKET *b, *next;
|
|
Packit Service |
f629e6 |
NODE *r;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if (symbol->xarray != NULL) {
|
|
Packit Service |
f629e6 |
NODE *xn = symbol->xarray;
|
|
Packit Service |
f629e6 |
assoc_clear(xn);
|
|
Packit Service |
f629e6 |
freenode(xn);
|
|
Packit Service |
f629e6 |
symbol->xarray = NULL;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
for (i = 0; i < symbol->array_size; i++) {
|
|
Packit Service |
f629e6 |
for (b = symbol->buckets[i]; b != NULL; b = next) {
|
|
Packit Service |
f629e6 |
next = b->ainext;
|
|
Packit Service |
f629e6 |
for (j = 0; j < b->aicount; j++) {
|
|
Packit Service |
f629e6 |
r = b->aivalue[j];
|
|
Packit Service |
f629e6 |
if (r->type == Node_var_array) {
|
|
Packit Service |
f629e6 |
assoc_clear(r); /* recursively clear all sub-arrays */
|
|
Packit Service |
f629e6 |
efree(r->vname);
|
|
Packit Service |
f629e6 |
freenode(r);
|
|
Packit Service |
f629e6 |
} else
|
|
Packit Service |
f629e6 |
unref(r);
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
freebucket(b);
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
symbol->buckets[i] = NULL;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
if (symbol->buckets != NULL)
|
|
Packit Service |
f629e6 |
efree(symbol->buckets);
|
|
Packit Service |
f629e6 |
symbol->ainit(symbol, NULL); /* re-initialize symbol */
|
|
Packit Service |
f629e6 |
return NULL;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* int_remove --- If SUBS is already in the table, remove it. */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
static NODE **
|
|
Packit Service |
f629e6 |
int_remove(NODE *symbol, NODE *subs)
|
|
Packit Service |
f629e6 |
{
|
|
Packit Service |
f629e6 |
uint32_t hash1;
|
|
Packit Service |
f629e6 |
BUCKET *b, *prev = NULL;
|
|
Packit Service |
f629e6 |
long k;
|
|
Packit Service |
f629e6 |
int i;
|
|
Packit Service |
f629e6 |
NODE *xn = symbol->xarray;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if (symbol->table_size == 0 || symbol->buckets == NULL)
|
|
Packit Service |
f629e6 |
return NULL;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if (! is_integer(symbol, subs)) {
|
|
Packit Service |
f629e6 |
if (xn == NULL || xn->aremove(xn, subs) == NULL)
|
|
Packit Service |
f629e6 |
return NULL;
|
|
Packit Service |
f629e6 |
if (xn->table_size == 0) {
|
|
Packit Service |
f629e6 |
freenode(xn);
|
|
Packit Service |
f629e6 |
symbol->xarray = NULL;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
symbol->table_size--;
|
|
Packit Service |
f629e6 |
assert(symbol->table_size > 0);
|
|
Packit Service |
f629e6 |
return & success_node;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
k = subs->numbr;
|
|
Packit Service |
f629e6 |
hash1 = int_hash(k, symbol->array_size);
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
for (b = symbol->buckets[hash1]; b != NULL; prev = b, b = b->ainext) {
|
|
Packit Service |
f629e6 |
for (i = 0; i < b->aicount; i++) {
|
|
Packit Service |
f629e6 |
if (k != b->ainum[i])
|
|
Packit Service |
f629e6 |
continue;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* item found */
|
|
Packit Service |
f629e6 |
if (i == 0 && b->aicount == 2) {
|
|
Packit Service |
f629e6 |
/* removing the 1st item; move 2nd item from position 1 to 0 */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
b->ainum[0] = b->ainum[1];
|
|
Packit Service |
f629e6 |
b->aivalue[0] = b->aivalue[1];
|
|
Packit Service |
f629e6 |
} /* else
|
|
Packit Service |
f629e6 |
removing the only item or the 2nd item */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
goto removed;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if (b == NULL) /* item not in array */
|
|
Packit Service |
f629e6 |
return NULL;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
removed:
|
|
Packit Service |
f629e6 |
b->aicount--;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if (b->aicount == 0) {
|
|
Packit Service |
f629e6 |
/* detach bucket */
|
|
Packit Service |
f629e6 |
if (prev != NULL)
|
|
Packit Service |
f629e6 |
prev->ainext = b->ainext;
|
|
Packit Service |
f629e6 |
else
|
|
Packit Service |
f629e6 |
symbol->buckets[hash1] = b->ainext;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* delete bucket */
|
|
Packit Service |
f629e6 |
freebucket(b);
|
|
Packit Service |
f629e6 |
} else if (b != symbol->buckets[hash1]) {
|
|
Packit Service |
f629e6 |
BUCKET *head = symbol->buckets[hash1];
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
assert(b->aicount == 1);
|
|
Packit Service |
f629e6 |
/* move the last element from head to bucket to make it full. */
|
|
Packit Service |
f629e6 |
i = --head->aicount; /* head has one less element */
|
|
Packit Service |
f629e6 |
b->ainum[1] = head->ainum[i];
|
|
Packit Service |
f629e6 |
b->aivalue[1] = head->aivalue[i];
|
|
Packit Service |
f629e6 |
b->aicount++; /* bucket has one more element */
|
|
Packit Service |
f629e6 |
if (i == 0) {
|
|
Packit Service |
f629e6 |
/* head is now empty; delete head */
|
|
Packit Service |
f629e6 |
symbol->buckets[hash1] = head->ainext;
|
|
Packit Service |
f629e6 |
freebucket(head);
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
} /* else
|
|
Packit Service |
f629e6 |
do nothing */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
symbol->table_size--;
|
|
Packit Service |
f629e6 |
if (xn == NULL && symbol->table_size == 0) {
|
|
Packit Service |
f629e6 |
efree(symbol->buckets);
|
|
Packit Service |
f629e6 |
symbol->ainit(symbol, NULL); /* re-initialize array 'symbol' */
|
|
Packit Service |
f629e6 |
} else if (xn != NULL && symbol->table_size == xn->table_size) {
|
|
Packit Service |
f629e6 |
/* promote xn (str_array) to symbol */
|
|
Packit Service |
f629e6 |
xn->flags &= ~XARRAY;
|
|
Packit Service |
f629e6 |
xn->parent_array = symbol->parent_array;
|
|
Packit Service |
f629e6 |
efree(symbol->buckets);
|
|
Packit Service |
f629e6 |
*symbol = *xn;
|
|
Packit Service |
f629e6 |
freenode(xn);
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
return & success_node; /* return success */
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* int_copy --- duplicate input array "symbol" */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
static NODE **
|
|
Packit Service |
f629e6 |
int_copy(NODE *symbol, NODE *newsymb)
|
|
Packit Service |
f629e6 |
{
|
|
Packit Service |
f629e6 |
BUCKET **old, **new, **pnew;
|
|
Packit Service |
f629e6 |
BUCKET *chain, *newchain;
|
|
Packit Service |
f629e6 |
int j;
|
|
Packit Service |
f629e6 |
unsigned long i, cursize;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
assert(symbol->buckets != NULL);
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* find the current hash size */
|
|
Packit Service |
f629e6 |
cursize = symbol->array_size;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* allocate new table */
|
|
Packit Service |
f629e6 |
ezalloc(new, BUCKET **, cursize * sizeof(BUCKET *), "int_copy");
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
old = symbol->buckets;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
for (i = 0; i < cursize; i++) {
|
|
Packit Service |
f629e6 |
for (chain = old[i], pnew = & new[i]; chain != NULL;
|
|
Packit Service |
f629e6 |
chain = chain->ainext
|
|
Packit Service |
f629e6 |
) {
|
|
Packit Service |
f629e6 |
getbucket(newchain);
|
|
Packit Service |
f629e6 |
newchain->aicount = chain->aicount;
|
|
Packit Service |
f629e6 |
newchain->ainext = NULL;
|
|
Packit Service |
f629e6 |
for (j = 0; j < chain->aicount; j++) {
|
|
Packit Service |
f629e6 |
NODE *oldval;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/*
|
|
Packit Service |
f629e6 |
* copy the corresponding key and
|
|
Packit Service |
f629e6 |
* value from the original input list
|
|
Packit Service |
f629e6 |
*/
|
|
Packit Service |
f629e6 |
newchain->ainum[j] = chain->ainum[j];
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
oldval = chain->aivalue[j];
|
|
Packit Service |
f629e6 |
if (oldval->type == Node_val)
|
|
Packit Service |
f629e6 |
newchain->aivalue[j] = dupnode(oldval);
|
|
Packit Service |
f629e6 |
else {
|
|
Packit Service |
f629e6 |
NODE *r;
|
|
Packit Service |
f629e6 |
r = make_array();
|
|
Packit Service |
f629e6 |
r->vname = estrdup(oldval->vname, strlen(oldval->vname));
|
|
Packit Service |
f629e6 |
r->parent_array = newsymb;
|
|
Packit Service |
f629e6 |
newchain->aivalue[j] = assoc_copy(oldval, r);
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
*pnew = newchain;
|
|
Packit Service |
f629e6 |
newchain->ainext = NULL;
|
|
Packit Service |
f629e6 |
pnew = & newchain->ainext;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if (symbol->xarray != NULL) {
|
|
Packit Service |
f629e6 |
NODE *xn, *n;
|
|
Packit Service |
f629e6 |
xn = symbol->xarray;
|
|
Packit Service |
f629e6 |
n = make_array();
|
|
Packit Service |
f629e6 |
n->vname = newsymb->vname; /* shallow copy */
|
|
Packit Service |
f629e6 |
(void) xn->acopy(xn, n);
|
|
Packit Service |
f629e6 |
newsymb->xarray = n;
|
|
Packit Service |
f629e6 |
} else
|
|
Packit Service |
f629e6 |
newsymb->xarray = NULL;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
newsymb->table_size = symbol->table_size;
|
|
Packit Service |
f629e6 |
newsymb->buckets = new;
|
|
Packit Service |
f629e6 |
newsymb->array_size = cursize;
|
|
Packit Service |
f629e6 |
newsymb->flags = symbol->flags;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
return NULL;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* int_list --- return a list of array items */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
static NODE**
|
|
Packit Service |
f629e6 |
int_list(NODE *symbol, NODE *t)
|
|
Packit Service |
f629e6 |
{
|
|
Packit Service |
f629e6 |
NODE **list = NULL;
|
|
Packit Service |
f629e6 |
unsigned long num_elems, list_size, i, k = 0;
|
|
Packit Service |
f629e6 |
BUCKET *b;
|
|
Packit Service |
f629e6 |
NODE *r, *subs, *xn;
|
|
Packit Service |
f629e6 |
int j, elem_size = 1;
|
|
Packit Service |
f629e6 |
long num;
|
|
Packit Service |
f629e6 |
static char buf[100];
|
|
Packit Service |
f629e6 |
assoc_kind_t assoc_kind;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if (symbol->table_size == 0)
|
|
Packit Service |
f629e6 |
return NULL;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
assoc_kind = (assoc_kind_t) t->flags;
|
|
Packit Service |
f629e6 |
num_elems = symbol->table_size;
|
|
Packit Service |
f629e6 |
if ((assoc_kind & (AINDEX|AVALUE|ADELETE)) == (AINDEX|ADELETE))
|
|
Packit Service |
f629e6 |
num_elems = 1;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if ((assoc_kind & (AINDEX|AVALUE)) == (AINDEX|AVALUE))
|
|
Packit Service |
f629e6 |
elem_size = 2;
|
|
Packit Service |
f629e6 |
list_size = elem_size * num_elems;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if (symbol->xarray != NULL) {
|
|
Packit Service |
f629e6 |
xn = symbol->xarray;
|
|
Packit Service |
f629e6 |
list = xn->alist(xn, t);
|
|
Packit Service |
f629e6 |
assert(list != NULL);
|
|
Packit Service |
f629e6 |
if (num_elems == 1 || num_elems == xn->table_size)
|
|
Packit Service |
f629e6 |
return list;
|
|
Packit Service |
f629e6 |
erealloc(list, NODE **, list_size * sizeof(NODE *), "int_list");
|
|
Packit Service |
f629e6 |
k = elem_size * xn->table_size;
|
|
Packit Service |
f629e6 |
} else
|
|
Packit Service |
f629e6 |
emalloc(list, NODE **, list_size * sizeof(NODE *), "int_list");
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* populate it */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
for (i = 0; i < symbol->array_size; i++) {
|
|
Packit Service |
f629e6 |
for (b = symbol->buckets[i]; b != NULL; b = b->ainext) {
|
|
Packit Service |
f629e6 |
for (j = 0; j < b->aicount; j++) {
|
|
Packit Service |
f629e6 |
/* index */
|
|
Packit Service |
f629e6 |
num = b->ainum[j];
|
|
Packit Service |
f629e6 |
if ((assoc_kind & AISTR) != 0) {
|
|
Packit Service |
f629e6 |
sprintf(buf, "%ld", num);
|
|
Packit Service |
f629e6 |
subs = make_string(buf, strlen(buf));
|
|
Packit Service |
f629e6 |
subs->numbr = num;
|
|
Packit Service |
f629e6 |
subs->flags |= (NUMCUR|NUMINT);
|
|
Packit Service |
f629e6 |
} else {
|
|
Packit Service |
f629e6 |
subs = make_number((AWKNUM) num);
|
|
Packit Service |
f629e6 |
subs->flags |= (INTIND|NUMINT);
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
list[k++] = subs;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* value */
|
|
Packit Service |
f629e6 |
if ((assoc_kind & AVALUE) != 0) {
|
|
Packit Service |
f629e6 |
r = b->aivalue[j];
|
|
Packit Service |
f629e6 |
if (r->type == Node_val) {
|
|
Packit Service |
f629e6 |
if ((assoc_kind & AVNUM) != 0)
|
|
Packit Service |
f629e6 |
(void) force_number(r);
|
|
Packit Service |
f629e6 |
else if ((assoc_kind & AVSTR) != 0)
|
|
Packit Service |
f629e6 |
r = force_string(r);
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
list[k++] = r;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if (k >= list_size)
|
|
Packit Service |
f629e6 |
return list;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
return list;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* int_kilobytes --- calculate memory consumption of the assoc array */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
AWKNUM
|
|
Packit Service |
f629e6 |
int_kilobytes(NODE *symbol)
|
|
Packit Service |
f629e6 |
{
|
|
Packit Service |
f629e6 |
unsigned long i, bucket_cnt = 0;
|
|
Packit Service |
f629e6 |
BUCKET *b;
|
|
Packit Service |
f629e6 |
AWKNUM kb;
|
|
Packit Service |
f629e6 |
extern AWKNUM str_kilobytes(NODE *symbol);
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
for (i = 0; i < symbol->array_size; i++) {
|
|
Packit Service |
f629e6 |
for (b = symbol->buckets[i]; b != NULL; b = b->ainext)
|
|
Packit Service |
f629e6 |
bucket_cnt++;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
kb = (((AWKNUM) bucket_cnt) * sizeof (BUCKET) +
|
|
Packit Service |
f629e6 |
((AWKNUM) symbol->array_size) * sizeof (BUCKET *)) / 1024.0;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if (symbol->xarray != NULL)
|
|
Packit Service |
f629e6 |
kb += str_kilobytes(symbol->xarray);
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
return kb;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* int_dump --- dump array info */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
static NODE **
|
|
Packit Service |
f629e6 |
int_dump(NODE *symbol, NODE *ndump)
|
|
Packit Service |
f629e6 |
{
|
|
Packit Service |
f629e6 |
#define HCNT 31
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
int indent_level;
|
|
Packit Service |
f629e6 |
BUCKET *b;
|
|
Packit Service |
f629e6 |
NODE *xn = NULL;
|
|
Packit Service |
f629e6 |
unsigned long str_size = 0, int_size = 0;
|
|
Packit Service |
f629e6 |
unsigned long i;
|
|
Packit Service |
f629e6 |
size_t j, bucket_cnt;
|
|
Packit Service |
f629e6 |
static size_t hash_dist[HCNT + 1];
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
indent_level = ndump->alevel;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if (symbol->xarray != NULL) {
|
|
Packit Service |
f629e6 |
xn = symbol->xarray;
|
|
Packit Service |
f629e6 |
str_size = xn->table_size;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
int_size = symbol->table_size - str_size;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if ((symbol->flags & XARRAY) == 0)
|
|
Packit Service |
f629e6 |
fprintf(output_fp, "%s `%s'\n",
|
|
Packit Service |
f629e6 |
(symbol->parent_array == NULL) ? "array" : "sub-array",
|
|
Packit Service |
f629e6 |
array_vname(symbol));
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
indent_level++;
|
|
Packit Service |
f629e6 |
indent(indent_level);
|
|
Packit Service |
f629e6 |
fprintf(output_fp, "array_func: int_array_func\n");
|
|
Packit Service |
f629e6 |
if (symbol->flags != 0) {
|
|
Packit Service |
f629e6 |
indent(indent_level);
|
|
Packit Service |
f629e6 |
fprintf(output_fp, "flags: %s\n", flags2str(symbol->flags));
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
indent(indent_level);
|
|
Packit Service |
f629e6 |
fprintf(output_fp, "INT_CHAIN_MAX: %lu\n", (unsigned long) INT_CHAIN_MAX);
|
|
Packit Service |
f629e6 |
indent(indent_level);
|
|
Packit Service |
f629e6 |
fprintf(output_fp, "array_size: %lu (int)\n", (unsigned long) symbol->array_size);
|
|
Packit Service |
f629e6 |
indent(indent_level);
|
|
Packit Service |
f629e6 |
fprintf(output_fp, "table_size: %lu (total), %lu (int), %lu (str)\n",
|
|
Packit Service |
f629e6 |
(unsigned long) symbol->table_size, int_size, str_size);
|
|
Packit Service |
f629e6 |
indent(indent_level);
|
|
Packit Service |
f629e6 |
fprintf(output_fp, "Avg # of items per chain (int): %.2g\n",
|
|
Packit Service |
f629e6 |
((AWKNUM) int_size) / symbol->array_size);
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
indent(indent_level);
|
|
Packit Service |
f629e6 |
fprintf(output_fp, "memory: %.2g kB (total)\n", int_kilobytes(symbol));
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* hash value distribution */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
memset(hash_dist, '\0', (HCNT + 1) * sizeof(size_t));
|
|
Packit Service |
f629e6 |
for (i = 0; i < symbol->array_size; i++) {
|
|
Packit Service |
f629e6 |
bucket_cnt = 0;
|
|
Packit Service |
f629e6 |
for (b = symbol->buckets[i]; b != NULL; b = b->ainext)
|
|
Packit Service |
f629e6 |
bucket_cnt += b->aicount;
|
|
Packit Service |
f629e6 |
if (bucket_cnt >= HCNT)
|
|
Packit Service |
f629e6 |
bucket_cnt = HCNT;
|
|
Packit Service |
f629e6 |
hash_dist[bucket_cnt]++;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
indent(indent_level);
|
|
Packit Service |
f629e6 |
fprintf(output_fp, "Hash distribution:\n");
|
|
Packit Service |
f629e6 |
indent_level++;
|
|
Packit Service |
f629e6 |
for (j = 0; j <= HCNT; j++) {
|
|
Packit Service |
f629e6 |
if (hash_dist[j] > 0) {
|
|
Packit Service |
f629e6 |
indent(indent_level);
|
|
Packit Service |
f629e6 |
if (j == HCNT)
|
|
Packit Service |
f629e6 |
fprintf(output_fp, "[>=%lu]:%lu\n",
|
|
Packit Service |
f629e6 |
(unsigned long) HCNT, (unsigned long) hash_dist[j]);
|
|
Packit Service |
f629e6 |
else
|
|
Packit Service |
f629e6 |
fprintf(output_fp, "[%lu]:%lu\n",
|
|
Packit Service |
f629e6 |
(unsigned long) j, (unsigned long) hash_dist[j]);
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
indent_level--;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* dump elements */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if (ndump->adepth >= 0) {
|
|
Packit Service |
f629e6 |
NODE *subs;
|
|
Packit Service |
f629e6 |
const char *aname;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
fprintf(output_fp, "\n");
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
aname = make_aname(symbol);
|
|
Packit Service |
f629e6 |
subs = make_number((AWKNUM) 0);
|
|
Packit Service |
f629e6 |
subs->flags |= (INTIND|NUMINT);
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
for (i = 0; i < symbol->array_size; i++) {
|
|
Packit Service |
f629e6 |
for (b = symbol->buckets[i]; b != NULL; b = b->ainext) {
|
|
Packit Service |
f629e6 |
for (j = 0; j < b->aicount; j++) {
|
|
Packit Service |
f629e6 |
subs->numbr = b->ainum[j];
|
|
Packit Service |
f629e6 |
assoc_info(subs, b->aivalue[j], ndump, aname);
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
unref(subs);
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if (xn != NULL) {
|
|
Packit Service |
f629e6 |
fprintf(output_fp, "\n");
|
|
Packit Service |
f629e6 |
xn->adump(xn, ndump);
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
return NULL;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
#undef HCNT
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* int_hash --- calculate the hash function of the integer subs */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
static uint32_t
|
|
Packit Service |
f629e6 |
int_hash(uint32_t k, uint32_t hsize)
|
|
Packit Service |
f629e6 |
{
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/*
|
|
Packit Service |
f629e6 |
* Code snippet copied from:
|
|
Packit Service |
f629e6 |
* Hash functions (http://www.azillionmonkeys.com/qed/hash.html).
|
|
Packit Service |
f629e6 |
* Copyright 2004-2008 by Paul Hsieh. Licenced under LGPL 2.1.
|
|
Packit Service |
f629e6 |
*/
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* This is the final mixing function used by Paul Hsieh in SuperFastHash. */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
k ^= k << 3;
|
|
Packit Service |
f629e6 |
k += k >> 5;
|
|
Packit Service |
f629e6 |
k ^= k << 4;
|
|
Packit Service |
f629e6 |
k += k >> 17;
|
|
Packit Service |
f629e6 |
k ^= k << 25;
|
|
Packit Service |
f629e6 |
k += k >> 6;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if (k >= hsize)
|
|
Packit Service |
f629e6 |
k %= hsize;
|
|
Packit Service |
f629e6 |
return k;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* int_find --- locate symbol[subs] */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
static inline NODE **
|
|
Packit Service |
f629e6 |
int_find(NODE *symbol, long k, uint32_t hash1)
|
|
Packit Service |
f629e6 |
{
|
|
Packit Service |
f629e6 |
BUCKET *b;
|
|
Packit Service |
f629e6 |
int i;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
assert(symbol->buckets != NULL);
|
|
Packit Service |
f629e6 |
for (b = symbol->buckets[hash1]; b != NULL; b = b->ainext) {
|
|
Packit Service |
f629e6 |
for (i = 0; i < b->aicount; i++) {
|
|
Packit Service |
f629e6 |
if (b->ainum[i] == k)
|
|
Packit Service |
f629e6 |
return (b->aivalue + i);
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
return NULL;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* int_insert --- install subs in the assoc array */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
static NODE **
|
|
Packit Service |
f629e6 |
int_insert(NODE *symbol, long k, uint32_t hash1)
|
|
Packit Service |
f629e6 |
{
|
|
Packit Service |
f629e6 |
BUCKET *b;
|
|
Packit Service |
f629e6 |
int i;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
b = symbol->buckets[hash1];
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* Only the first bucket in the chain can be partially full, but is never empty. */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
if (b == NULL || (i = b->aicount) == 2) {
|
|
Packit Service |
f629e6 |
getbucket(b);
|
|
Packit Service |
f629e6 |
b->aicount = 0;
|
|
Packit Service |
f629e6 |
b->ainext = symbol->buckets[hash1];
|
|
Packit Service |
f629e6 |
symbol->buckets[hash1] = b;
|
|
Packit Service |
f629e6 |
i = 0;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
b->ainum[i] = k;
|
|
Packit Service |
f629e6 |
b->aivalue[i] = dupnode(Nnull_string);
|
|
Packit Service |
f629e6 |
b->aicount++;
|
|
Packit Service |
f629e6 |
return & b->aivalue[i];
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* grow_int_table --- grow the hash table */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
static void
|
|
Packit Service |
f629e6 |
grow_int_table(NODE *symbol)
|
|
Packit Service |
f629e6 |
{
|
|
Packit Service |
f629e6 |
BUCKET **old, **new;
|
|
Packit Service |
f629e6 |
BUCKET *chain, *next;
|
|
Packit Service |
f629e6 |
int i, j;
|
|
Packit Service |
f629e6 |
unsigned long oldsize, newsize, k;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/*
|
|
Packit Service |
f629e6 |
* This is an array of primes. We grow the table by an order of
|
|
Packit Service |
f629e6 |
* magnitude each time (not just doubling) so that growing is a
|
|
Packit Service |
f629e6 |
* rare operation. We expect, on average, that it won't happen
|
|
Packit Service |
f629e6 |
* more than twice. The final size is also chosen to be small
|
|
Packit Service |
f629e6 |
* enough so that MS-DOG mallocs can handle it. When things are
|
|
Packit Service |
f629e6 |
* very large (> 8K), we just double more or less, instead of
|
|
Packit Service |
f629e6 |
* just jumping from 8K to 64K.
|
|
Packit Service |
f629e6 |
*/
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
static const unsigned long sizes[] = {
|
|
Packit Service |
f629e6 |
13, 127, 1021, 8191, 16381, 32749, 65497,
|
|
Packit Service |
f629e6 |
131101, 262147, 524309, 1048583, 2097169,
|
|
Packit Service |
f629e6 |
4194319, 8388617, 16777259, 33554467,
|
|
Packit Service |
f629e6 |
67108879, 134217757, 268435459, 536870923,
|
|
Packit Service |
f629e6 |
1073741827
|
|
Packit Service |
f629e6 |
};
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* find next biggest hash size */
|
|
Packit Service |
f629e6 |
newsize = oldsize = symbol->array_size;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
for (i = 0, j = sizeof(sizes)/sizeof(sizes[0]); i < j; i++) {
|
|
Packit Service |
f629e6 |
if (oldsize < sizes[i]) {
|
|
Packit Service |
f629e6 |
newsize = sizes[i];
|
|
Packit Service |
f629e6 |
break;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
if (newsize == oldsize) { /* table already at max (!) */
|
|
Packit Service |
f629e6 |
symbol->flags |= ARRAYMAXED;
|
|
Packit Service |
f629e6 |
return;
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* allocate new table */
|
|
Packit Service |
f629e6 |
ezalloc(new, BUCKET **, newsize * sizeof(BUCKET *), "grow_int_table");
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
old = symbol->buckets;
|
|
Packit Service |
f629e6 |
symbol->buckets = new;
|
|
Packit Service |
f629e6 |
symbol->array_size = newsize;
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* brand new hash table */
|
|
Packit Service |
f629e6 |
if (old == NULL)
|
|
Packit Service |
f629e6 |
return; /* DO NOT initialize symbol->table_size */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
/* old hash table there, move stuff to new, free old */
|
|
Packit Service |
f629e6 |
/* note that symbol->table_size does not change if an old array. */
|
|
Packit Service |
f629e6 |
|
|
Packit Service |
f629e6 |
for (k = 0; k < oldsize; k++) {
|
|
Packit Service |
f629e6 |
long num;
|
|
Packit Service |
f629e6 |
for (chain = old[k]; chain != NULL; chain = next) {
|
|
Packit Service |
f629e6 |
for (i = 0; i < chain->aicount; i++) {
|
|
Packit Service |
f629e6 |
num = chain->ainum[i];
|
|
Packit Service |
f629e6 |
*int_insert(symbol, num, int_hash(num, newsize)) = chain->aivalue[i];
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
next = chain->ainext;
|
|
Packit Service |
f629e6 |
freebucket(chain);
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
}
|
|
Packit Service |
f629e6 |
efree(old);
|
|
Packit Service |
f629e6 |
}
|