cDict *dict_new(cList *keys, cList *values) { cDict *cnew; Int i, j, size; if (generic_empty_dict && list_length(keys) == 0) return dict_dup(generic_empty_dict); /* Construct a new dictionary. */ cnew = tmalloc(sizeof(cDict)); cnew->keys = list_dup(keys); cnew->values = list_dup(values); /* Calculate initial size of chain and hash table. */ cnew->hashtab_size = HASHTAB_STARTING_SIZE; while (cnew->hashtab_size < keys->len) { if (cnew->hashtab_size > 4096) cnew->hashtab_size += 4096; else cnew->hashtab_size = cnew->hashtab_size * 2 + MALLOC_DELTA; } /* Initialize chain entries and hash table. */ size = sizeof(Int) * cnew->hashtab_size; cnew->links = tmalloc(size); cnew->hashtab = tmalloc(size); memset(cnew->links, -1, size); memset(cnew->hashtab, -1, size); /* Insert the keys into the hash table, eliminating duplicates. */ i = j = 0; while (i < cnew->keys->len) { if (i != j) { cnew->keys->el[j] = cnew->keys->el[i]; cnew->values->el[j] = cnew->values->el[i]; } if (search(cnew, &keys->el[i]) == F_FAILURE) { insert_key(cnew, j++); } else { data_discard(&cnew->keys->el[i]); data_discard(&cnew->values->el[i]); } i++; } cnew->keys->len = cnew->values->len = j; cnew->refs = 1; if (!generic_empty_dict && list_length(keys) == 0) generic_empty_dict = dict_dup(cnew); return cnew; }
void discard_handled (cData *d) { HandledFrob *h = HANDLED_FROB(d); data_discard(&h->rep); ident_discard(h->handler); }
Hash * hash_new_with(cList *keys) { Hash *cnew; Int i, j; /* Construct a new hash */ cnew = EMALLOC(Hash, 1); cnew->keys = list_dup(keys); /* Calculate initial size of chain and hash table. */ cnew->hashtab_size = HASHTAB_STARTING_SIZE; while (cnew->hashtab_size < keys->len) cnew->hashtab_size = cnew->hashtab_size * 2 + MALLOC_DELTA; /* Initialize chain entries and hash table. */ cnew->links = EMALLOC(Int, cnew->hashtab_size); cnew->hashtab = EMALLOC(Int, cnew->hashtab_size); memset(cnew->links, -1, sizeof(Long)*cnew->hashtab_size); memset(cnew->hashtab, -1, sizeof(Long)*cnew->hashtab_size); /* Insert the keys into the hash table, eliminating duplicates. */ i = j = 0; while (i < cnew->keys->len) { if (i != j) cnew->keys->el[j] = cnew->keys->el[i]; if (hash_find(cnew, &keys->el[i]) == F_FAILURE) quickhash_insert_key(cnew, j++); else data_discard(&cnew->keys->el[i]); i++; } cnew->keys->len = j; cnew->refs = 1; return cnew; }
cList *list_prep(cList * list, Int start, Int len) { cList *cnew; Int i, resize, size; /* Figure out if we need to resize the list or move its contents. Moving * contents takes precedence. */ #if DISABLED resize = (len - start) * 4 < list->size; resize = resize && list->size > STARTING_SIZE; resize = resize || (list->size < len); #endif resize = list->size < len + start; /* Move the list contents into a new list. */ if ((list->refs > 1) || (resize && start > 0)) { cnew = list_new(len); cnew->len = len; len = (list->len < len) ? list->len : len; for (i = 0; i < len; i++) data_dup(&cnew->el[i], &list->el[start + i]); list_discard(list); return cnew; } /* Resize the list. We can assume that list->start == start == 0. */ else if (resize) { for (; list->len > len; list->len--) data_discard(&list->el[list->len - 1]); list->len = len; size = len; list = (cList *) erealloc(list, sizeof(cList) + (size * sizeof(cData))); list->size = size; return list; } else { for (; list->start < start; list->start++, list->len--) data_discard(&list->el[list->start]); for (; list->len > len; list->len--) data_discard(&list->el[list->start + list->len - 1]); list->start = start; list->len = len; return list; } }
/* Warning: do not discard a list before initializing its data elements. */ void list_discard(cList * list) { Int i; if (!--list->refs) { for (i = list->start; i < list->start + list->len; i++) data_discard(&list->el[i]); efree(list); } }
/* Error-checking on pos is the job of the calling function. */ cList *list_replace(cList * list, Int pos, cData * elem) { /* list_prep needed here only for multiply referenced lists */ if (list->refs > 1) list = list_prep(list, list->start, list->len); pos += list->start; data_discard(&list->el[pos]); data_dup(&list->el[pos], elem); return list; }
/* Error-checking on pos is the job of the calling function. */ cList *list_delete(cList * list, Int pos) { /* Special-case deletion of last element. */ if (pos == list->len - 1) return list_prep(list, list->start, list->len - 1); /* list_prep needed here only for multiply referenced lists */ if (list->refs > 1) list = list_prep(list, list->start, list->len); pos += list->start; data_discard(&list->el[pos]); MEMMOVE(list->el + pos, list->el + pos + 1, list->len - pos); list->len--; /* list_prep needed here only if list has shrunk */ if (((list->len - list->start) * 4 < list->size) && (list->size > STARTING_SIZE)) list = list_prep(list, list->start, list->len); return list; }
/* which is 1 for max, -1 for min. */ INTERNAL void find_extreme(Int which) { Int arg_start, num_args, i, type; cData *args, *extreme, d; arg_start = arg_starts[--arg_pos]; args = &stack[arg_start]; num_args = stack_pos - arg_start; if (!num_args) { cthrow(numargs_id, "Called with no arguments, requires at least one."); return; } type = args[0].type; if (type != INTEGER && type != STRING && type != FLOAT) { cthrow(type_id, "First argument (%D) not an integer, float or string.", &args[0]); return; } extreme = &args[0]; for (i = 1; i < num_args; i++) { if (args[i].type != type) { cthrow(type_id, "Arguments are not all of same type."); return; } if (data_cmp(&args[i], extreme) * which > 0) extreme = &args[i]; } /* Replace args[0] with extreme, and pop other arguments. */ data_dup(&d, extreme); data_discard(&args[0]); args[0] = d; pop(num_args - 1); }