Blame cint_array.c

Packit 575503
/*
Packit 575503
 * cint_array.c - routines for arrays of (mostly) consecutive positive integer indices.
Packit 575503
 */
Packit 575503
Packit 575503
/*
Packit 575503
 * Copyright (C) 1986, 1988, 1989, 1991-2013, 2016, 2017,
Packit 575503
 * the Free Software Foundation, Inc.
Packit 575503
 *
Packit 575503
 * This file is part of GAWK, the GNU implementation of the
Packit 575503
 * AWK Programming Language.
Packit 575503
 *
Packit 575503
 * GAWK is free software; you can redistribute it and/or modify
Packit 575503
 * it under the terms of the GNU General Public License as published by
Packit 575503
 * the Free Software Foundation; either version 3 of the License, or
Packit 575503
 * (at your option) any later version.
Packit 575503
 *
Packit 575503
 * GAWK is distributed in the hope that it will be useful,
Packit 575503
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 575503
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 575503
 * GNU General Public License for more details.
Packit 575503
 *
Packit 575503
 * You should have received a copy of the GNU General Public License
Packit 575503
 * along with this program; if not, write to the Free Software
Packit 575503
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
Packit 575503
 */
Packit 575503
Packit 575503
#include "awk.h"
Packit 575503
Packit 575503
#define INT32_BIT 32
Packit 575503
Packit 575503
extern FILE *output_fp;
Packit 575503
extern void indent(int indent_level);
Packit 575503
extern NODE **is_integer(NODE *symbol, NODE *subs);
Packit 575503
Packit 575503
/*
Packit 575503
 * NHAT         ---  maximum size of a leaf array (2^NHAT).
Packit 575503
 * THRESHOLD    ---  Maximum capacity waste; THRESHOLD >= 2^(NHAT + 1).
Packit 575503
 */
Packit 575503
Packit 575503
static int NHAT = 10;
Packit 575503
static long THRESHOLD;
Packit 575503
Packit 575503
/*
Packit 575503
 * What is the optimium NHAT ? timing results suggest that 10 is a good choice,
Packit 575503
 * although differences aren't that significant for > 10.
Packit 575503
 */
Packit 575503
Packit 575503
Packit 575503
static NODE **cint_array_init(NODE *symbol, NODE *subs);
Packit 575503
static NODE **is_uinteger(NODE *symbol, NODE *subs);
Packit 575503
static NODE **cint_lookup(NODE *symbol, NODE *subs);
Packit 575503
static NODE **cint_exists(NODE *symbol, NODE *subs);
Packit 575503
static NODE **cint_clear(NODE *symbol, NODE *subs);
Packit 575503
static NODE **cint_remove(NODE *symbol, NODE *subs);
Packit 575503
static NODE **cint_list(NODE *symbol, NODE *t);
Packit 575503
static NODE **cint_copy(NODE *symbol, NODE *newsymb);
Packit 575503
static NODE **cint_dump(NODE *symbol, NODE *ndump);
Packit 575503
#ifdef ARRAYDEBUG
Packit 575503
static void cint_print(NODE *symbol);
Packit 575503
#endif
Packit 575503
Packit 575503
afunc_t cint_array_func[] = {
Packit 575503
	cint_array_init,
Packit 575503
	is_uinteger,
Packit 575503
	null_length,
Packit 575503
	cint_lookup,
Packit 575503
	cint_exists,
Packit 575503
	cint_clear,
Packit 575503
	cint_remove,
Packit 575503
	cint_list,
Packit 575503
	cint_copy,
Packit 575503
	cint_dump,
Packit 575503
	(afunc_t) 0,
Packit 575503
};
Packit 575503
Packit 575503
static inline int cint_hash(long k);
Packit 575503
static inline NODE **cint_find(NODE *symbol, long k, int h1);
Packit 575503
Packit 575503
static inline NODE *make_node(NODETYPE type);
Packit 575503
Packit 575503
static NODE **tree_lookup(NODE *symbol, NODE *tree, long k, int m, long base);
Packit 575503
static NODE **tree_exists(NODE *tree, long k);
Packit 575503
static void tree_clear(NODE *tree);
Packit 575503
static int tree_remove(NODE *symbol, NODE *tree, long k);
Packit 575503
static void tree_copy(NODE *newsymb, NODE *tree, NODE *newtree);
Packit 575503
static long tree_list(NODE *tree, NODE **list, assoc_kind_t assoc_kind);
Packit 575503
static inline NODE **tree_find(NODE *tree, long k, int i);
Packit 575503
static void tree_info(NODE *tree, NODE *ndump, const char *aname);
Packit 575503
static size_t tree_kilobytes(NODE *tree);
Packit 575503
#ifdef ARRAYDEBUG
Packit 575503
static void tree_print(NODE *tree, size_t bi, int indent_level);
Packit 575503
#endif
Packit 575503
Packit 575503
static inline NODE **leaf_lookup(NODE *symbol, NODE *array, long k, long size, long base);
Packit 575503
static inline NODE **leaf_exists(NODE *array, long k);
Packit 575503
static void leaf_clear(NODE *array);
Packit 575503
static int leaf_remove(NODE *symbol, NODE *array, long k);
Packit 575503
static void leaf_copy(NODE *newsymb, NODE *array, NODE *newarray);
Packit 575503
static long leaf_list(NODE *array, NODE **list, assoc_kind_t assoc_kind);
Packit 575503
static void leaf_info(NODE *array, NODE *ndump, const char *aname);
Packit 575503
#ifdef ARRAYDEBUG
Packit 575503
static void leaf_print(NODE *array, size_t bi, int indent_level);
Packit 575503
#endif
Packit 575503
Packit 575503
/* powers of 2 table upto 2^30 */
Packit 575503
static const long power_two_table[] = {
Packit 575503
	1, 2, 4, 8, 16, 32, 64,
Packit 575503
	128, 256, 512, 1024, 2048, 4096,
Packit 575503
	8192, 16384, 32768, 65536, 131072, 262144,
Packit 575503
	524288, 1048576, 2097152, 4194304, 8388608, 16777216,
Packit 575503
	33554432, 67108864, 134217728, 268435456, 536870912, 1073741824
Packit 575503
};
Packit 575503
Packit 575503
Packit 575503
#define ISUINT(a, s)	((((s)->flags & NUMINT) != 0 || is_integer(a, s) != NULL) \
Packit 575503
                                    && (s)->numbr >= 0)
Packit 575503
Packit 575503
/*
Packit 575503
 * To store 2^n integers, allocate top-level array of size n, elements
Packit 575503
 * of which are 1-Dimensional (leaf-array) of geometrically increasing
Packit 575503
 * size (power of 2).
Packit 575503
 *
Packit 575503
 *  [0]   -->  [ 0 ]
Packit 575503
 *  [1]   -->  [ 1 ]
Packit 575503
 *  |2|   -->  [ 2 | 3 ]
Packit 575503
 *  |3|   -->  [ 4 | 5 | 6 | 7 ]
Packit 575503
 *  |.|
Packit 575503
 *  |k|   -->  [ 2^(k - 1)| ...  | 2^k - 1 ]
Packit 575503
 *  ...
Packit 575503
 *
Packit 575503
 * For a given integer n (> 0), the leaf-array is at 1 + floor(log2(n)).
Packit 575503
 *
Packit 575503
 * The idea for the geometrically increasing array sizes is from:
Packit 575503
 * 	Fast Functional Lists, Hash-Lists, Deques and Variable Length Arrays.
Packit 575503
 * 	Bagwell, Phil (2002).
Packit 575503
 * 	http://infoscience.epfl.ch/record/64410/files/techlists.pdf
Packit 575503
 *
Packit 575503
 * Disadvantage:
Packit 575503
 * Worst case memory waste > 99% and will happen when each of the
Packit 575503
 * leaf arrays contains only a single element. Even with consecutive
Packit 575503
 * integers, memory waste can be as high as 50%.
Packit 575503
 *
Packit 575503
 * Solution: Hashed Array Trees (HATs).
Packit 575503
 *
Packit 575503
 */
Packit 575503
Packit 575503
/* cint_array_init ---  array initialization routine */
Packit 575503
Packit 575503
static NODE **
Packit 575503
cint_array_init(NODE *symbol ATTRIBUTE_UNUSED, NODE *subs ATTRIBUTE_UNUSED)
Packit 575503
{
Packit 575503
	if (symbol == NULL) {
Packit 575503
		long newval;
Packit 575503
		size_t nelems = (sizeof(power_two_table) / sizeof(power_two_table[0]));
Packit 575503
Packit 575503
		/* check relevant environment variables */
Packit 575503
		if ((newval = getenv_long("NHAT")) > 1 && newval < INT32_BIT)
Packit 575503
			NHAT = newval;
Packit 575503
		/* don't allow overflow off the end of the table */
Packit 575503
		if (NHAT >= nelems)
Packit 575503
			NHAT = nelems - 2;
Packit 575503
		THRESHOLD = power_two_table[NHAT + 1];
Packit 575503
	} else
Packit 575503
		null_array(symbol);
Packit 575503
Packit 575503
	return & success_node;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* is_uinteger --- test if the subscript is an integer >= 0 */
Packit 575503
Packit 575503
NODE **
Packit 575503
is_uinteger(NODE *symbol, NODE *subs)
Packit 575503
{
Packit 575503
	if (is_integer(symbol, subs) != NULL && subs->numbr >= 0)
Packit 575503
		return & success_node;
Packit 575503
	return NULL;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* cint_lookup --- Find the subscript in the array; Install it if it isn't there. */
Packit 575503
Packit 575503
static NODE **
Packit 575503
cint_lookup(NODE *symbol, NODE *subs)
Packit 575503
{
Packit 575503
	NODE **lhs;
Packit 575503
	long k;
Packit 575503
	int h1 = -1, m, li;
Packit 575503
	NODE *tn, *xn;
Packit 575503
	long cint_size, capacity;
Packit 575503
Packit 575503
	k = -1;
Packit 575503
	if (ISUINT(symbol, subs)) {
Packit 575503
		k = subs->numbr;	/* k >= 0 */
Packit 575503
		h1 = cint_hash(k);	/* h1 >= NHAT */
Packit 575503
		if ((lhs = cint_find(symbol, k, h1)) != NULL)
Packit 575503
			return lhs;
Packit 575503
	}
Packit 575503
	xn = symbol->xarray;
Packit 575503
	if (xn != NULL && (lhs = xn->aexists(xn, subs)) != NULL)
Packit 575503
		return lhs;
Packit 575503
Packit 575503
	/* It's not there, install it */
Packit 575503
Packit 575503
	if (k < 0)
Packit 575503
		goto xinstall;
Packit 575503
Packit 575503
	m = h1 - 1;	/* m >= (NHAT- 1) */
Packit 575503
Packit 575503
	/* Estimate capacity upper bound.
Packit 575503
	 * capacity upper bound = current capacity + leaf array size.
Packit 575503
	 */
Packit 575503
	li = m > NHAT ? m : NHAT;
Packit 575503
	while (li >= NHAT) {
Packit 575503
		/* leaf-array of a HAT */
Packit 575503
		li = (li + 1) / 2;
Packit 575503
	}
Packit 575503
	capacity = symbol->array_capacity + power_two_table[li];
Packit 575503
Packit 575503
	cint_size = (xn == NULL) ? symbol->table_size
Packit 575503
				: (symbol->table_size - xn->table_size);
Packit 575503
	assert(cint_size >= 0);
Packit 575503
	if ((capacity - cint_size) > THRESHOLD)
Packit 575503
		goto xinstall;
Packit 575503
Packit 575503
	if (symbol->nodes == NULL) {
Packit 575503
		symbol->array_capacity = 0;
Packit 575503
		assert(symbol->table_size == 0);
Packit 575503
Packit 575503
		/* nodes[0] .. nodes[NHAT- 1] not used */
Packit 575503
		ezalloc(symbol->nodes, NODE **, INT32_BIT * sizeof(NODE *), "cint_lookup");
Packit 575503
	}
Packit 575503
Packit 575503
	symbol->table_size++;	/* one more element in array */
Packit 575503
Packit 575503
	tn = symbol->nodes[h1];
Packit 575503
	if (tn == NULL) {
Packit 575503
		tn = make_node(Node_array_tree);
Packit 575503
		symbol->nodes[h1] = tn;
Packit 575503
	}
Packit 575503
Packit 575503
	if (m < NHAT)
Packit 575503
		return tree_lookup(symbol, tn, k, NHAT, 0);
Packit 575503
	return tree_lookup(symbol, tn, k, m, power_two_table[m]);
Packit 575503
Packit 575503
xinstall:
Packit 575503
Packit 575503
	symbol->table_size++;
Packit 575503
	if (xn == NULL) {
Packit 575503
		xn = symbol->xarray = make_array();
Packit 575503
		xn->vname = symbol->vname;	/* shallow copy */
Packit 575503
Packit 575503
		/*
Packit 575503
		 * Avoid using assoc_lookup(xn, subs) which may lead
Packit 575503
		 * to infinite recursion.
Packit 575503
		 */
Packit 575503
Packit 575503
		if (is_integer(xn, subs))
Packit 575503
			xn->array_funcs = int_array_func;
Packit 575503
		else
Packit 575503
			xn->array_funcs = str_array_func;
Packit 575503
		xn->flags |= XARRAY;
Packit 575503
	}
Packit 575503
	return xn->alookup(xn, subs);
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* cint_exists --- test whether an index is in the array or not. */
Packit 575503
Packit 575503
static NODE **
Packit 575503
cint_exists(NODE *symbol, NODE *subs)
Packit 575503
{
Packit 575503
	NODE *xn;
Packit 575503
Packit 575503
	if (ISUINT(symbol, subs)) {
Packit 575503
		long k = subs->numbr;
Packit 575503
		NODE **lhs;
Packit 575503
		if ((lhs = cint_find(symbol, k, cint_hash(k))) != NULL)
Packit 575503
			return lhs;
Packit 575503
	}
Packit 575503
	if ((xn = symbol->xarray) == NULL)
Packit 575503
		return NULL;
Packit 575503
	return xn->aexists(xn, subs);
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* cint_clear --- flush all the values in symbol[] */
Packit 575503
Packit 575503
static NODE **
Packit 575503
cint_clear(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED)
Packit 575503
{
Packit 575503
	size_t i;
Packit 575503
	NODE *tn;
Packit 575503
Packit 575503
	assert(symbol->nodes != NULL);
Packit 575503
Packit 575503
	if (symbol->xarray != NULL) {
Packit 575503
		NODE *xn = symbol->xarray;
Packit 575503
		assoc_clear(xn);
Packit 575503
		freenode(xn);
Packit 575503
		symbol->xarray = NULL;
Packit 575503
	}
Packit 575503
Packit 575503
	for (i = NHAT; i < INT32_BIT; i++) {
Packit 575503
		tn = symbol->nodes[i];
Packit 575503
		if (tn != NULL) {
Packit 575503
			tree_clear(tn);
Packit 575503
			freenode(tn);
Packit 575503
		}
Packit 575503
	}
Packit 575503
Packit 575503
	efree(symbol->nodes);
Packit 575503
	symbol->ainit(symbol, NULL);	/* re-initialize symbol */
Packit 575503
	return NULL;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* cint_remove --- remove an index from the array */
Packit 575503
Packit 575503
static NODE **
Packit 575503
cint_remove(NODE *symbol, NODE *subs)
Packit 575503
{
Packit 575503
	long k;
Packit 575503
	int h1;
Packit 575503
	NODE *tn, *xn = symbol->xarray;
Packit 575503
Packit 575503
	if (symbol->table_size == 0)
Packit 575503
		return NULL;
Packit 575503
Packit 575503
	if (! ISUINT(symbol, subs))
Packit 575503
		goto xremove;
Packit 575503
Packit 575503
	assert(symbol->nodes != NULL);
Packit 575503
Packit 575503
	k = subs->numbr;
Packit 575503
	h1 = cint_hash(k);
Packit 575503
	tn = symbol->nodes[h1];
Packit 575503
	if (tn == NULL || ! tree_remove(symbol, tn, k))
Packit 575503
		goto xremove;
Packit 575503
Packit 575503
	if (tn->table_size == 0) {
Packit 575503
		freenode(tn);
Packit 575503
		symbol->nodes[h1] = NULL;
Packit 575503
	}
Packit 575503
Packit 575503
	symbol->table_size--;
Packit 575503
Packit 575503
	if (xn == NULL && symbol->table_size == 0) {
Packit 575503
		efree(symbol->nodes);
Packit 575503
		symbol->ainit(symbol, NULL);	/* re-initialize array 'symbol' */
Packit 575503
	} else if(xn != NULL && symbol->table_size == xn->table_size) {
Packit 575503
		/* promote xn to symbol */
Packit 575503
Packit 575503
		xn->flags &= ~XARRAY;
Packit 575503
		xn->parent_array = symbol->parent_array;
Packit 575503
		efree(symbol->nodes);
Packit 575503
		*symbol = *xn;
Packit 575503
		freenode(xn);
Packit 575503
	}
Packit 575503
Packit 575503
	return & success_node;
Packit 575503
Packit 575503
xremove:
Packit 575503
	xn = symbol->xarray;
Packit 575503
	if (xn == NULL || xn->aremove(xn, subs) == NULL)
Packit 575503
		return NULL;
Packit 575503
	if (xn->table_size == 0) {
Packit 575503
		freenode(xn);
Packit 575503
		symbol->xarray = NULL;
Packit 575503
	}
Packit 575503
	symbol->table_size--;
Packit 575503
	assert(symbol->table_size > 0);
Packit 575503
Packit 575503
	return & success_node;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* cint_copy --- duplicate input array "symbol" */
Packit 575503
Packit 575503
static NODE **
Packit 575503
cint_copy(NODE *symbol, NODE *newsymb)
Packit 575503
{
Packit 575503
	NODE **old, **new;
Packit 575503
	size_t i;
Packit 575503
Packit 575503
	assert(symbol->nodes != NULL);
Packit 575503
Packit 575503
	/* allocate new table */
Packit 575503
	ezalloc(new, NODE **, INT32_BIT * sizeof(NODE *), "cint_copy");
Packit 575503
Packit 575503
	old = symbol->nodes;
Packit 575503
	for (i = NHAT; i < INT32_BIT; i++) {
Packit 575503
		if (old[i] == NULL)
Packit 575503
			continue;
Packit 575503
		new[i] = make_node(Node_array_tree);
Packit 575503
		tree_copy(newsymb, old[i], new[i]);
Packit 575503
	}
Packit 575503
Packit 575503
	if (symbol->xarray != NULL) {
Packit 575503
		NODE *xn, *n;
Packit 575503
		xn = symbol->xarray;
Packit 575503
		n = make_array();
Packit 575503
		n->vname = newsymb->vname;
Packit 575503
		(void) xn->acopy(xn, n);
Packit 575503
		newsymb->xarray = n;
Packit 575503
	} else
Packit 575503
		newsymb->xarray = NULL;
Packit 575503
Packit 575503
	newsymb->nodes = new;
Packit 575503
	newsymb->table_size = symbol->table_size;
Packit 575503
	newsymb->array_capacity = symbol->array_capacity;
Packit 575503
	newsymb->flags = symbol->flags;
Packit 575503
Packit 575503
	return NULL;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* cint_list --- return a list of items */
Packit 575503
Packit 575503
static NODE**
Packit 575503
cint_list(NODE *symbol, NODE *t)
Packit 575503
{
Packit 575503
	NODE **list = NULL;
Packit 575503
	NODE *tn, *xn;
Packit 575503
	unsigned long k = 0, num_elems, list_size;
Packit 575503
	size_t j, ja, jd;
Packit 575503
	int elem_size = 1;
Packit 575503
	assoc_kind_t assoc_kind;
Packit 575503
Packit 575503
	num_elems = symbol->table_size;
Packit 575503
	if (num_elems == 0)
Packit 575503
		return NULL;
Packit 575503
	assoc_kind = (assoc_kind_t) t->flags;
Packit 575503
	if ((assoc_kind & (AINDEX|AVALUE|ADELETE)) == (AINDEX|ADELETE))
Packit 575503
		num_elems = 1;
Packit 575503
Packit 575503
	if ((assoc_kind & (AINDEX|AVALUE)) == (AINDEX|AVALUE))
Packit 575503
		elem_size = 2;
Packit 575503
	list_size = num_elems * elem_size;
Packit 575503
Packit 575503
	if (symbol->xarray != NULL) {
Packit 575503
		xn = symbol->xarray;
Packit 575503
		list = xn->alist(xn, t);
Packit 575503
		assert(list != NULL);
Packit 575503
		assoc_kind &= ~(AASC|ADESC);
Packit 575503
		t->flags = (unsigned int) assoc_kind;
Packit 575503
		if (num_elems == 1 || num_elems == xn->table_size)
Packit 575503
			return list;
Packit 575503
		erealloc(list, NODE **, list_size * sizeof(NODE *), "cint_list");
Packit 575503
		k = elem_size * xn->table_size;
Packit 575503
	} else
Packit 575503
		emalloc(list, NODE **, list_size * sizeof(NODE *), "cint_list");
Packit 575503
Packit 575503
	if ((assoc_kind & AINUM) == 0) {
Packit 575503
		/* not sorting by "index num" */
Packit 575503
		assoc_kind &= ~(AASC|ADESC);
Packit 575503
		t->flags = (unsigned int) assoc_kind;
Packit 575503
	}
Packit 575503
Packit 575503
	/* populate it with index in ascending or descending order */
Packit 575503
Packit 575503
	for (ja = NHAT, jd = INT32_BIT - 1; ja < INT32_BIT && jd >= NHAT; ) {
Packit 575503
		j = (assoc_kind & ADESC) != 0 ? jd-- : ja++;
Packit 575503
		tn = symbol->nodes[j];
Packit 575503
		if (tn == NULL)
Packit 575503
			continue;
Packit 575503
		k += tree_list(tn, list + k, assoc_kind);
Packit 575503
		if (k >= list_size)
Packit 575503
			return list;
Packit 575503
	}
Packit 575503
	return list;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* cint_dump --- dump array info */
Packit 575503
Packit 575503
static NODE **
Packit 575503
cint_dump(NODE *symbol, NODE *ndump)
Packit 575503
{
Packit 575503
	NODE *tn, *xn = NULL;
Packit 575503
	int indent_level;
Packit 575503
	size_t i;
Packit 575503
	long cint_size = 0, xsize = 0;
Packit 575503
	AWKNUM kb = 0;
Packit 575503
	extern AWKNUM int_kilobytes(NODE *symbol);
Packit 575503
	extern AWKNUM str_kilobytes(NODE *symbol);
Packit 575503
Packit 575503
	indent_level = ndump->alevel;
Packit 575503
Packit 575503
	if (symbol->xarray != NULL) {
Packit 575503
		xn = symbol->xarray;
Packit 575503
		xsize = xn->table_size;
Packit 575503
	}
Packit 575503
	cint_size = symbol->table_size - xsize;
Packit 575503
Packit 575503
	if ((symbol->flags & XARRAY) == 0)
Packit 575503
		fprintf(output_fp, "%s `%s'\n",
Packit 575503
			(symbol->parent_array == NULL) ? "array" : "sub-array",
Packit 575503
			array_vname(symbol));
Packit 575503
	indent_level++;
Packit 575503
	indent(indent_level);
Packit 575503
	fprintf(output_fp, "array_func: cint_array_func\n");
Packit 575503
	if (symbol->flags != 0) {
Packit 575503
		indent(indent_level);
Packit 575503
		fprintf(output_fp, "flags: %s\n", flags2str(symbol->flags));
Packit 575503
	}
Packit 575503
	indent(indent_level);
Packit 575503
	fprintf(output_fp, "NHAT: %d\n", NHAT);
Packit 575503
	indent(indent_level);
Packit 575503
	fprintf(output_fp, "THRESHOLD: %ld\n", THRESHOLD);
Packit 575503
	indent(indent_level);
Packit 575503
	fprintf(output_fp, "table_size: %ld (total), %ld (cint), %ld (int + str)\n",
Packit 575503
				symbol->table_size, cint_size, xsize);
Packit 575503
	indent(indent_level);
Packit 575503
	fprintf(output_fp, "array_capacity: %lu\n", (unsigned long) symbol->array_capacity);
Packit 575503
	indent(indent_level);
Packit 575503
	fprintf(output_fp, "Load Factor: %.2g\n", (AWKNUM) cint_size / symbol->array_capacity);
Packit 575503
Packit 575503
	for (i = NHAT; i < INT32_BIT; i++) {
Packit 575503
		tn = symbol->nodes[i];
Packit 575503
		if (tn == NULL)
Packit 575503
			continue;
Packit 575503
		/* Node_array_tree  + HAT */
Packit 575503
		kb += (sizeof(NODE) + tree_kilobytes(tn)) / 1024.0;
Packit 575503
	}
Packit 575503
	kb += (INT32_BIT * sizeof(NODE *)) / 1024.0;	/* symbol->nodes */
Packit 575503
	kb += (symbol->array_capacity * sizeof(NODE *)) / 1024.0;	/* value nodes in Node_array_leaf(s) */
Packit 575503
	if (xn != NULL) {
Packit 575503
		if (xn->array_funcs == int_array_func)
Packit 575503
			kb += int_kilobytes(xn);
Packit 575503
		else
Packit 575503
			kb += str_kilobytes(xn);
Packit 575503
	}
Packit 575503
Packit 575503
	indent(indent_level);
Packit 575503
	fprintf(output_fp, "memory: %.2g kB (total)\n", kb);
Packit 575503
Packit 575503
	/* dump elements */
Packit 575503
Packit 575503
	if (ndump->adepth >= 0) {
Packit 575503
		const char *aname;
Packit 575503
Packit 575503
		fprintf(output_fp, "\n");
Packit 575503
		aname = make_aname(symbol);
Packit 575503
		for (i = NHAT; i < INT32_BIT; i++) {
Packit 575503
			tn = symbol->nodes[i];
Packit 575503
			if (tn != NULL)
Packit 575503
				tree_info(tn, ndump, aname);
Packit 575503
		}
Packit 575503
	}
Packit 575503
Packit 575503
	if (xn != NULL) {
Packit 575503
		fprintf(output_fp, "\n");
Packit 575503
		xn->adump(xn, ndump);
Packit 575503
	}
Packit 575503
Packit 575503
#ifdef ARRAYDEBUG
Packit 575503
	if (ndump->adepth < -999)
Packit 575503
		cint_print(symbol);
Packit 575503
#endif
Packit 575503
Packit 575503
	return NULL;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* cint_hash --- locate the HAT for a given number 'k' */
Packit 575503
Packit 575503
static inline int
Packit 575503
cint_hash(long k)
Packit 575503
{
Packit 575503
	uint32_t num, r, shift;
Packit 575503
Packit 575503
	assert(k >= 0);
Packit 575503
	if (k == 0)
Packit 575503
		return NHAT;
Packit 575503
	num = k;
Packit 575503
Packit 575503
	/* Find the Floor(log base 2 of 32-bit integer) */
Packit 575503
Packit 575503
	/*
Packit 575503
	 * Warren Jr., Henry S. (2002). Hacker's Delight.
Packit 575503
	 * Addison Wesley. pp. pp. 215. ISBN 978-0201914658.
Packit 575503
	 *
Packit 575503
	 *	r = 0;
Packit 575503
	 *	if (num >= 1<<16) { num >>= 16;	r += 16; }
Packit 575503
	 *	if (num >= 1<< 8) { num >>=  8;	r +=  8; }
Packit 575503
	 *	if (num >= 1<< 4) { num >>=  4;	r +=  4; }
Packit 575503
	 *	if (num >= 1<< 2) { num >>=  2;	r +=  2; }
Packit 575503
	 *	if (num >= 1<< 1) {		r +=  1; }
Packit 575503
	 */
Packit 575503
Packit 575503
Packit 575503
	/*
Packit 575503
	 * Slightly different code copied from:
Packit 575503
	 *
Packit 575503
	 * http://www-graphics.stanford.edu/~seander/bithacks.html
Packit 575503
	 * Bit Twiddling Hacks
Packit 575503
	 * By Sean Eron Anderson
Packit 575503
	 * seander@cs.stanford.edu
Packit 575503
	 * Individually, the code snippets here are in the public domain
Packit 575503
	 * (unless otherwise noted) --- feel free to use them however you please.
Packit 575503
	 * The aggregate collection and descriptions are (C) 1997-2005
Packit 575503
	 * Sean Eron Anderson. The code and descriptions are distributed in the
Packit 575503
	 * hope that they will be useful, but WITHOUT ANY WARRANTY and without
Packit 575503
	 * even the implied warranty of merchantability or fitness for a particular
Packit 575503
	 * purpose.
Packit 575503
	 *
Packit 575503
	 */
Packit 575503
Packit 575503
	r = (num > 0xFFFF) << 4; num >>= r;
Packit 575503
	shift = (num > 0xFF) << 3; num >>= shift; r |= shift;
Packit 575503
	shift = (num > 0x0F) << 2; num >>= shift; r |= shift;
Packit 575503
	shift = (num > 0x03) << 1; num >>= shift; r |= shift;
Packit 575503
	r |= (num >> 1);
Packit 575503
Packit 575503
	/* We use a single HAT for 0 <= num < 2^NHAT */
Packit 575503
	if (r < NHAT)
Packit 575503
		return NHAT;
Packit 575503
Packit 575503
	return (1 + r);
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* cint_find --- locate the integer subscript */
Packit 575503
Packit 575503
static inline NODE **
Packit 575503
cint_find(NODE *symbol, long k, int h1)
Packit 575503
{
Packit 575503
	NODE *tn;
Packit 575503
Packit 575503
	if (symbol->nodes == NULL || (tn = symbol->nodes[h1]) == NULL)
Packit 575503
		return NULL;
Packit 575503
	return tree_exists(tn, k);
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
#ifdef ARRAYDEBUG
Packit 575503
Packit 575503
/* cint_print --- print structural info */
Packit 575503
Packit 575503
static void
Packit 575503
cint_print(NODE *symbol)
Packit 575503
{
Packit 575503
	NODE *tn;
Packit 575503
	size_t i;
Packit 575503
Packit 575503
	fprintf(output_fp, "I[%4lu:%-4lu]\n", (unsigned long) INT32_BIT,
Packit 575503
				(unsigned long) symbol->table_size);
Packit 575503
	for (i = NHAT; i < INT32_BIT; i++) {
Packit 575503
		tn = symbol->nodes[i];
Packit 575503
		if (tn == NULL)
Packit 575503
			continue;
Packit 575503
		tree_print(tn, i, 1);
Packit 575503
	}
Packit 575503
}
Packit 575503
Packit 575503
#endif
Packit 575503
Packit 575503
Packit 575503
/*------------------------ Hashed Array Trees -----------------------------*/
Packit 575503
Packit 575503
/*
Packit 575503
 * HATs: Hashed Array Trees
Packit 575503
 * Fast variable-length arrays
Packit 575503
 * Edward Sitarski
Packit 575503
 * http://www.drdobbs.com/architecture-and-design/184409965
Packit 575503
 *
Packit 575503
 *  HAT has a top-level array containing a power of two
Packit 575503
 *  number of leaf arrays. All leaf arrays are the same size as the
Packit 575503
 *  top-level array. A full HAT can hold n^2 elements,
Packit 575503
 *  where n (some power of 2) is the size of each leaf array.
Packit 575503
 *  [i/n][i & (n - 1)] locates the `i th' element in a HAT.
Packit 575503
 *
Packit 575503
 */
Packit 575503
Packit 575503
/*
Packit 575503
 *  A half HAT is defined here as a HAT with a top-level array of size n^2/2
Packit 575503
 *  and holds the first n^2/2 elements.
Packit 575503
 *
Packit 575503
 *   1. 2^8 elements can be stored in a full HAT of size 2^4.
Packit 575503
 *   2. 2^9 elements can be stored in a half HAT of size 2^5.
Packit 575503
 *   3. When the number of elements is some power of 2, it
Packit 575503
 *      can be stored in a full or a half HAT.
Packit 575503
 *   4. When the number of elements is some power of 2, it
Packit 575503
 *      can be stored in a HAT (full or half) with HATs as leaf elements
Packit 575503
 *      (full or half),  and so on (e.g. 2^8 elements in a HAT of size 2^4 (top-level
Packit 575503
 *      array dimension) with each leaf array being a HAT of size 2^2).
Packit 575503
 *
Packit 575503
 *  IMPLEMENTATION DETAILS:
Packit 575503
 *    1. A HAT of 2^12 elements needs 2^6 house-keeping NODEs
Packit 575503
 *       of Node_array_leaf.
Packit 575503
 *
Packit 575503
 *    2. A HAT of HATS of 2^12 elements needs
Packit 575503
 *       2^6 * (1 Node_array_tree + 2^3 Node_array_leaf)
Packit 575503
 *       ~ 2^9 house-keeping NODEs.
Packit 575503
 *
Packit 575503
 *    3. When a leaf array (or leaf HAT) becomes empty, the memory
Packit 575503
 *       is deallocated, and when there is no leaf array (or leaf HAT) left,
Packit 575503
 *       the HAT is deleted.
Packit 575503
 *
Packit 575503
 *    4. A HAT stores the base (first) element, and locates the leaf array/HAT
Packit 575503
 *       for the `i th' element using integer division
Packit 575503
 *       (i - base)/n where n is the size of the top-level array.
Packit 575503
 *
Packit 575503
 */
Packit 575503
Packit 575503
/* make_node --- initialize a NODE */
Packit 575503
Packit 575503
static inline NODE *
Packit 575503
make_node(NODETYPE type)
Packit 575503
{
Packit 575503
	NODE *n;
Packit 575503
	getnode(n);
Packit 575503
	memset(n, '\0', sizeof(NODE));
Packit 575503
	n->type = type;
Packit 575503
	return n;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* tree_lookup --- Find an integer subscript in a HAT; Install it if it isn't there */
Packit 575503
Packit 575503
static NODE **
Packit 575503
tree_lookup(NODE *symbol, NODE *tree, long k, int m, long base)
Packit 575503
{
Packit 575503
	NODE **lhs;
Packit 575503
	NODE *tn;
Packit 575503
	int i, n;
Packit 575503
	size_t size;
Packit 575503
	long num = k;
Packit 575503
Packit 575503
	/*
Packit 575503
	 * HAT size (size of Top & Leaf array) = 2^n
Packit 575503
	 * where n = Floor ((m + 1)/2). For an odd value of m,
Packit 575503
	 * only the first half of the HAT is needed.
Packit 575503
	 */
Packit 575503
Packit 575503
	n = (m + 1) / 2;
Packit 575503
Packit 575503
	if (tree->table_size == 0) {
Packit 575503
		size_t actual_size;
Packit 575503
		NODE **table;
Packit 575503
Packit 575503
		assert(tree->nodes == NULL);
Packit 575503
Packit 575503
		/* initialize top-level array */
Packit 575503
		size = actual_size = power_two_table[n];
Packit 575503
		tree->array_base = base;
Packit 575503
		tree->array_size = size;
Packit 575503
		tree->table_size = 0;	/* # of elements in the array */
Packit 575503
		if (n > m/2) {
Packit 575503
			/* only first half of the array used */
Packit 575503
			actual_size /= 2;
Packit 575503
			tree->flags |= HALFHAT;
Packit 575503
		}
Packit 575503
		ezalloc(table, NODE **, actual_size * sizeof(NODE *), "tree_lookup");
Packit 575503
		tree->nodes = table;
Packit 575503
	} else
Packit 575503
		size = tree->array_size;
Packit 575503
Packit 575503
	num -= tree->array_base;
Packit 575503
	i = num / size;	/* top-level array index */
Packit 575503
	assert(i >= 0);
Packit 575503
Packit 575503
	if ((lhs = tree_find(tree, k, i)) != NULL)
Packit 575503
		return lhs;
Packit 575503
Packit 575503
	/* It's not there, install it */
Packit 575503
Packit 575503
	tree->table_size++;
Packit 575503
	base += (size * i);
Packit 575503
	tn = tree->nodes[i];
Packit 575503
	if (n > NHAT) {
Packit 575503
		if (tn == NULL)
Packit 575503
			tn = tree->nodes[i] = make_node(Node_array_tree);
Packit 575503
		return tree_lookup(symbol, tn, k, n, base);
Packit 575503
	} else {
Packit 575503
		if (tn == NULL)
Packit 575503
			tn = tree->nodes[i] = make_node(Node_array_leaf);
Packit 575503
		return leaf_lookup(symbol, tn, k, size, base);
Packit 575503
	}
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* tree_exists --- test whether integer subscript `k' exists or not */
Packit 575503
Packit 575503
static NODE **
Packit 575503
tree_exists(NODE *tree, long k)
Packit 575503
{
Packit 575503
	int i;
Packit 575503
	NODE *tn;
Packit 575503
Packit 575503
	i = (k - tree->array_base) / tree->array_size;
Packit 575503
	assert(i >= 0);
Packit 575503
	tn = tree->nodes[i];
Packit 575503
	if (tn == NULL)
Packit 575503
		return NULL;
Packit 575503
	if (tn->type == Node_array_tree)
Packit 575503
		return tree_exists(tn, k);
Packit 575503
	return leaf_exists(tn, k);
Packit 575503
}
Packit 575503
Packit 575503
/* tree_clear --- flush all the values */
Packit 575503
Packit 575503
static void
Packit 575503
tree_clear(NODE *tree)
Packit 575503
{
Packit 575503
	NODE *tn;
Packit 575503
	size_t	j, hsize;
Packit 575503
Packit 575503
	hsize = tree->array_size;
Packit 575503
	if ((tree->flags & HALFHAT) != 0)
Packit 575503
		hsize /= 2;
Packit 575503
Packit 575503
	for (j = 0; j < hsize; j++) {
Packit 575503
		tn = tree->nodes[j];
Packit 575503
		if (tn == NULL)
Packit 575503
			continue;
Packit 575503
		if (tn->type == Node_array_tree)
Packit 575503
			tree_clear(tn);
Packit 575503
		else
Packit 575503
			leaf_clear(tn);
Packit 575503
		freenode(tn);
Packit 575503
	}
Packit 575503
Packit 575503
	efree(tree->nodes);
Packit 575503
	memset(tree, '\0', sizeof(NODE));
Packit 575503
	tree->type = Node_array_tree;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* tree_remove --- If the integer subscript is in the HAT, remove it */
Packit 575503
Packit 575503
static int
Packit 575503
tree_remove(NODE *symbol, NODE *tree, long k)
Packit 575503
{
Packit 575503
	int i;
Packit 575503
	NODE *tn;
Packit 575503
Packit 575503
	i = (k - tree->array_base) / tree->array_size;
Packit 575503
	assert(i >= 0);
Packit 575503
	tn = tree->nodes[i];
Packit 575503
	if (tn == NULL)
Packit 575503
		return false;
Packit 575503
Packit 575503
	if (tn->type == Node_array_tree
Packit 575503
			&& ! tree_remove(symbol, tn, k))
Packit 575503
		return false;
Packit 575503
	else if (tn->type == Node_array_leaf
Packit 575503
			&& ! leaf_remove(symbol, tn, k))
Packit 575503
		return false;
Packit 575503
Packit 575503
	if (tn->table_size == 0) {
Packit 575503
		freenode(tn);
Packit 575503
		tree->nodes[i] = NULL;
Packit 575503
	}
Packit 575503
Packit 575503
	/* one less item in array */
Packit 575503
	if (--tree->table_size == 0) {
Packit 575503
		efree(tree->nodes);
Packit 575503
		memset(tree, '\0', sizeof(NODE));
Packit 575503
		tree->type = Node_array_tree;
Packit 575503
	}
Packit 575503
	return true;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* tree_find --- locate an interger subscript in the HAT */
Packit 575503
Packit 575503
static inline NODE **
Packit 575503
tree_find(NODE *tree, long k, int i)
Packit 575503
{
Packit 575503
	NODE *tn;
Packit 575503
Packit 575503
	assert(tree->nodes != NULL);
Packit 575503
	tn = tree->nodes[i];
Packit 575503
	if (tn != NULL) {
Packit 575503
		if (tn->type == Node_array_tree)
Packit 575503
			return tree_exists(tn, k);
Packit 575503
		return leaf_exists(tn, k);
Packit 575503
	}
Packit 575503
	return NULL;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* tree_list --- return a list of items in the HAT */
Packit 575503
Packit 575503
static long
Packit 575503
tree_list(NODE *tree, NODE **list, assoc_kind_t assoc_kind)
Packit 575503
{
Packit 575503
	NODE *tn;
Packit 575503
	size_t j, cj, hsize;
Packit 575503
	long k = 0;
Packit 575503
Packit 575503
	assert(list != NULL);
Packit 575503
Packit 575503
	hsize = tree->array_size;
Packit 575503
	if ((tree->flags & HALFHAT) != 0)
Packit 575503
		hsize /= 2;
Packit 575503
Packit 575503
	for (j = 0; j < hsize; j++) {
Packit 575503
		cj = (assoc_kind & ADESC) != 0 ? (hsize - 1 - j) : j;
Packit 575503
		tn = tree->nodes[cj];
Packit 575503
		if (tn == NULL)
Packit 575503
			continue;
Packit 575503
		if (tn->type == Node_array_tree)
Packit 575503
			k += tree_list(tn, list + k, assoc_kind);
Packit 575503
		else
Packit 575503
			k += leaf_list(tn, list + k, assoc_kind);
Packit 575503
		if ((assoc_kind & ADELETE) != 0 && k >= 1)
Packit 575503
			return k;
Packit 575503
	}
Packit 575503
	return k;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* tree_copy --- duplicate a HAT */
Packit 575503
Packit 575503
static void
Packit 575503
tree_copy(NODE *newsymb, NODE *tree, NODE *newtree)
Packit 575503
{
Packit 575503
	NODE **old, **new;
Packit 575503
	size_t j, hsize;
Packit 575503
Packit 575503
	hsize = tree->array_size;
Packit 575503
	if ((tree->flags & HALFHAT) != 0)
Packit 575503
		hsize /= 2;
Packit 575503
Packit 575503
	ezalloc(new, NODE **, hsize * sizeof(NODE *), "tree_copy");
Packit 575503
	newtree->nodes = new;
Packit 575503
	newtree->array_base = tree->array_base;
Packit 575503
	newtree->array_size = tree->array_size;
Packit 575503
	newtree->table_size = tree->table_size;
Packit 575503
	newtree->flags = tree->flags;
Packit 575503
Packit 575503
	old = tree->nodes;
Packit 575503
	for (j = 0; j < hsize; j++) {
Packit 575503
		if (old[j] == NULL)
Packit 575503
			continue;
Packit 575503
		if (old[j]->type == Node_array_tree) {
Packit 575503
			new[j] = make_node(Node_array_tree);
Packit 575503
			tree_copy(newsymb, old[j], new[j]);
Packit 575503
		} else {
Packit 575503
			new[j] = make_node(Node_array_leaf);
Packit 575503
			leaf_copy(newsymb, old[j], new[j]);
Packit 575503
		}
Packit 575503
	}
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* tree_info --- print index, value info */
Packit 575503
Packit 575503
static void
Packit 575503
tree_info(NODE *tree, NODE *ndump, const char *aname)
Packit 575503
{
Packit 575503
	NODE *tn;
Packit 575503
	size_t j, hsize;
Packit 575503
Packit 575503
	hsize = tree->array_size;
Packit 575503
	if ((tree->flags & HALFHAT) != 0)
Packit 575503
		hsize /= 2;
Packit 575503
Packit 575503
	for (j = 0; j < hsize; j++) {
Packit 575503
		tn = tree->nodes[j];
Packit 575503
		if (tn == NULL)
Packit 575503
			continue;
Packit 575503
		if (tn->type == Node_array_tree)
Packit 575503
			tree_info(tn, ndump, aname);
Packit 575503
		else
Packit 575503
			leaf_info(tn, ndump, aname);
Packit 575503
	}
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* tree_kilobytes --- calculate memory consumption of a HAT */
Packit 575503
Packit 575503
static size_t
Packit 575503
tree_kilobytes(NODE *tree)
Packit 575503
{
Packit 575503
	NODE *tn;
Packit 575503
	size_t j, hsize;
Packit 575503
	size_t sz = 0;
Packit 575503
Packit 575503
	hsize = tree->array_size;
Packit 575503
	if ((tree->flags & HALFHAT) != 0)
Packit 575503
		hsize /= 2;
Packit 575503
	for (j = 0; j < hsize; j++) {
Packit 575503
		tn = tree->nodes[j];
Packit 575503
		if (tn == NULL)
Packit 575503
			continue;
Packit 575503
		sz += sizeof(NODE);	/* Node_array_tree or Node_array_leaf */
Packit 575503
		if (tn->type == Node_array_tree)
Packit 575503
			sz += tree_kilobytes(tn);
Packit 575503
	}
Packit 575503
	sz += hsize * sizeof(NODE *);	/* tree->nodes */
Packit 575503
	return sz;
Packit 575503
}
Packit 575503
Packit 575503
#ifdef ARRAYDEBUG
Packit 575503
Packit 575503
/* tree_print --- print the HAT structures */
Packit 575503
Packit 575503
static void
Packit 575503
tree_print(NODE *tree, size_t bi, int indent_level)
Packit 575503
{
Packit 575503
	NODE *tn;
Packit 575503
	size_t j, hsize;
Packit 575503
Packit 575503
	indent(indent_level);
Packit 575503
Packit 575503
	hsize = tree->array_size;
Packit 575503
	if ((tree->flags & HALFHAT) != 0)
Packit 575503
		hsize /= 2;
Packit 575503
	fprintf(output_fp, "%4lu:%s[%4lu:%-4lu]\n",
Packit 575503
			(unsigned long) bi,
Packit 575503
			(tree->flags & HALFHAT) != 0 ? "HH" : "H",
Packit 575503
			(unsigned long) hsize, (unsigned long) tree->table_size);
Packit 575503
Packit 575503
	for (j = 0; j < hsize; j++) {
Packit 575503
		tn = tree->nodes[j];
Packit 575503
		if (tn == NULL)
Packit 575503
			continue;
Packit 575503
		if (tn->type == Node_array_tree)
Packit 575503
			tree_print(tn, j, indent_level + 1);
Packit 575503
		else
Packit 575503
			leaf_print(tn, j, indent_level + 1);
Packit 575503
	}
Packit 575503
}
Packit 575503
#endif
Packit 575503
Packit 575503
/*--------------------- leaf (linear 1-D) array --------------------*/
Packit 575503
Packit 575503
/*
Packit 575503
 * leaf_lookup --- find an integer subscript in the array; Install it if
Packit 575503
 *	it isn't there.
Packit 575503
 */
Packit 575503
Packit 575503
static inline NODE **
Packit 575503
leaf_lookup(NODE *symbol, NODE *array, long k, long size, long base)
Packit 575503
{
Packit 575503
	NODE **lhs;
Packit 575503
Packit 575503
	if (array->nodes == NULL) {
Packit 575503
		array->table_size = 0;	/* sanity */
Packit 575503
		array->array_size = size;
Packit 575503
		array->array_base = base;
Packit 575503
		ezalloc(array->nodes, NODE **, size * sizeof(NODE *), "leaf_lookup");
Packit 575503
		symbol->array_capacity += size;
Packit 575503
	}
Packit 575503
Packit 575503
	lhs = array->nodes + (k - base); /* leaf element */
Packit 575503
	if (*lhs == NULL) {
Packit 575503
		array->table_size++;	/* one more element in leaf array */
Packit 575503
		*lhs = dupnode(Nnull_string);
Packit 575503
	}
Packit 575503
	return lhs;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* leaf_exists --- check if the array contains an integer subscript */
Packit 575503
Packit 575503
static inline NODE **
Packit 575503
leaf_exists(NODE *array, long k)
Packit 575503
{
Packit 575503
	NODE **lhs;
Packit 575503
	lhs = array->nodes + (k - array->array_base);
Packit 575503
	return (*lhs != NULL) ? lhs : NULL;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* leaf_clear --- flush all values in the array */
Packit 575503
Packit 575503
static void
Packit 575503
leaf_clear(NODE *array)
Packit 575503
{
Packit 575503
	long i, size = array->array_size;
Packit 575503
	NODE *r;
Packit 575503
Packit 575503
	for (i = 0; i < size; i++) {
Packit 575503
		r = array->nodes[i];
Packit 575503
		if (r == NULL)
Packit 575503
			continue;
Packit 575503
		if (r->type == Node_var_array) {
Packit 575503
			assoc_clear(r);		/* recursively clear all sub-arrays */
Packit 575503
			efree(r->vname);
Packit 575503
			freenode(r);
Packit 575503
		} else
Packit 575503
			unref(r);
Packit 575503
	}
Packit 575503
	efree(array->nodes);
Packit 575503
	array->nodes = NULL;
Packit 575503
	array->array_size = array->table_size = 0;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* leaf_remove --- remove an integer subscript from the array */
Packit 575503
Packit 575503
static int
Packit 575503
leaf_remove(NODE *symbol, NODE *array, long k)
Packit 575503
{
Packit 575503
	NODE **lhs;
Packit 575503
Packit 575503
	lhs = array->nodes + (k - array->array_base);
Packit 575503
	if (*lhs == NULL)
Packit 575503
		return false;
Packit 575503
	*lhs = NULL;
Packit 575503
	if (--array->table_size == 0) {
Packit 575503
		efree(array->nodes);
Packit 575503
		array->nodes = NULL;
Packit 575503
		symbol->array_capacity -= array->array_size;
Packit 575503
		array->array_size = 0;	/* sanity */
Packit 575503
	}
Packit 575503
	return true;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* leaf_copy --- duplicate a leaf array */
Packit 575503
Packit 575503
static void
Packit 575503
leaf_copy(NODE *newsymb, NODE *array, NODE *newarray)
Packit 575503
{
Packit 575503
	NODE **old, **new;
Packit 575503
	long size, i;
Packit 575503
Packit 575503
	size = array->array_size;
Packit 575503
	ezalloc(new, NODE **, size * sizeof(NODE *), "leaf_copy");
Packit 575503
	newarray->nodes = new;
Packit 575503
	newarray->array_size = size;
Packit 575503
	newarray->array_base = array->array_base;
Packit 575503
	newarray->flags = array->flags;
Packit 575503
	newarray->table_size = array->table_size;
Packit 575503
Packit 575503
	old = array->nodes;
Packit 575503
	for (i = 0; i < size; i++) {
Packit 575503
		if (old[i] == NULL)
Packit 575503
			continue;
Packit 575503
		if (old[i]->type == Node_val)
Packit 575503
			new[i] = dupnode(old[i]);
Packit 575503
		else {
Packit 575503
			NODE *r;
Packit 575503
			r = make_array();
Packit 575503
			r->vname = estrdup(old[i]->vname, strlen(old[i]->vname));
Packit 575503
			r->parent_array = newsymb;
Packit 575503
			new[i] = assoc_copy(old[i], r);
Packit 575503
		}
Packit 575503
	}
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* leaf_list --- return a list of items */
Packit 575503
Packit 575503
static long
Packit 575503
leaf_list(NODE *array, NODE **list, assoc_kind_t assoc_kind)
Packit 575503
{
Packit 575503
	NODE *r, *subs;
Packit 575503
	long num, i, ci, k = 0;
Packit 575503
	long size = array->array_size;
Packit 575503
	static char buf[100];
Packit 575503
Packit 575503
	for (i = 0; i < size; i++) {
Packit 575503
		ci = (assoc_kind & ADESC) != 0 ? (size - 1 - i) : i;
Packit 575503
		r = array->nodes[ci];
Packit 575503
		if (r == NULL)
Packit 575503
			continue;
Packit 575503
Packit 575503
		/* index */
Packit 575503
		num = array->array_base + ci;
Packit 575503
		if ((assoc_kind & AISTR) != 0) {
Packit 575503
			sprintf(buf, "%ld", num);
Packit 575503
			subs = make_string(buf, strlen(buf));
Packit 575503
			subs->numbr = num;
Packit 575503
			subs->flags |= (NUMCUR|NUMINT);
Packit 575503
		} else {
Packit 575503
			subs = make_number((AWKNUM) num);
Packit 575503
			subs->flags |= (INTIND|NUMINT);
Packit 575503
		}
Packit 575503
		list[k++] = subs;
Packit 575503
Packit 575503
		/* value */
Packit 575503
		if ((assoc_kind & AVALUE) != 0) {
Packit 575503
			if (r->type == Node_val) {
Packit 575503
				if ((assoc_kind & AVNUM) != 0)
Packit 575503
					(void) force_number(r);
Packit 575503
				else if ((assoc_kind & AVSTR) != 0)
Packit 575503
					r = force_string(r);
Packit 575503
			}
Packit 575503
			list[k++] = r;
Packit 575503
		}
Packit 575503
		if ((assoc_kind & ADELETE) != 0 && k >= 1)
Packit 575503
			return k;
Packit 575503
	}
Packit 575503
Packit 575503
	return k;
Packit 575503
}
Packit 575503
Packit 575503
Packit 575503
/* leaf_info --- print index, value info */
Packit 575503
Packit 575503
static void
Packit 575503
leaf_info(NODE *array, NODE *ndump, const char *aname)
Packit 575503
{
Packit 575503
	NODE *subs, *val;
Packit 575503
	size_t i, size;
Packit 575503
Packit 575503
	size = array->array_size;
Packit 575503
Packit 575503
	subs = make_number((AWKNUM) 0.0);
Packit 575503
	subs->flags |= (INTIND|NUMINT);
Packit 575503
	for (i = 0; i < size; i++) {
Packit 575503
		val = array->nodes[i];
Packit 575503
		if (val == NULL)
Packit 575503
			continue;
Packit 575503
		subs->numbr = array->array_base + i;
Packit 575503
		assoc_info(subs, val, ndump, aname);
Packit 575503
	}
Packit 575503
	unref(subs);
Packit 575503
}
Packit 575503
Packit 575503
#ifdef ARRAYDEBUG
Packit 575503
Packit 575503
/* leaf_print --- print the leaf-array structure */
Packit 575503
Packit 575503
Packit 575503
static void
Packit 575503
leaf_print(NODE *array, size_t bi, int indent_level)
Packit 575503
{
Packit 575503
	indent(indent_level);
Packit 575503
	fprintf(output_fp, "%4lu:L[%4lu:%-4lu]\n",
Packit 575503
			(unsigned long) bi,
Packit 575503
			(unsigned long) array->array_size,
Packit 575503
			(unsigned long) array->table_size);
Packit 575503
}
Packit 575503
#endif