X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdictionary.c;h=c11f6f4124036b380b572390adf0b496c990ef60;hb=53ceff2865473a6b561b521986fafd31a993a1a6;hp=0fd59e1172113cd1f8754b82c3b08a48d5072943;hpb=317e6b778833b5dcd5dd195c0b677835a8024b2a;p=pspp diff --git a/src/dictionary.c b/src/dictionary.c index 0fd59e1172..c11f6f4124 100644 --- a/src/dictionary.c +++ b/src/dictionary.c @@ -1,5 +1,5 @@ /* PSPP - computes sample statistics. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. Written by Ben Pfaff . This program is free software; you can redistribute it and/or @@ -24,6 +24,8 @@ #include "algorithm.h" #include "alloc.h" #include "case.h" +#include "cat.h" +#include "cat-routines.h" #include "error.h" #include "hash.h" #include "misc.h" @@ -32,6 +34,9 @@ #include "value-labels.h" #include "var.h" +#include "gettext.h" +#define _(msgid) gettext (msgid) + /* A dictionary. */ struct dictionary { @@ -97,7 +102,7 @@ dict_clone (const struct dictionary *s) d->split_cnt = s->split_cnt; if (d->split_cnt > 0) { - d->split = xmalloc (d->split_cnt * sizeof *d->split); + d->split = xnmalloc (d->split_cnt, sizeof *d->split); for (i = 0; i < d->split_cnt; i++) d->split[i] = dict_lookup_var_assert (d, s->split[i]->name); } @@ -113,7 +118,7 @@ dict_clone (const struct dictionary *s) dict_set_documents (d, dict_get_documents (s)); d->vector_cnt = s->vector_cnt; - d->vector = xmalloc (d->vector_cnt * sizeof *d->vector); + d->vector = xnmalloc (d->vector_cnt, sizeof *d->vector); for (i = 0; i < s->vector_cnt; i++) { struct vector *sv = s->vector[i]; @@ -123,7 +128,7 @@ dict_clone (const struct dictionary *s) dv->idx = i; strcpy (dv->name, sv->name); dv->cnt = sv->cnt; - dv->var = xmalloc (dv->cnt * sizeof *dv->var); + dv->var = xnmalloc (dv->cnt, sizeof *dv->var); for (j = 0; j < dv->cnt; j++) dv->var[j] = d->var[sv->var[j]->index]; } @@ -237,7 +242,7 @@ dict_get_vars (const struct dictionary *d, struct variable ***vars, if (!(exclude_classes & (1u << dict_class_from_id (d->var[i]->name)))) count++; - *vars = xmalloc (count * sizeof **vars); + *vars = xnmalloc (count, sizeof **vars); *cnt = 0; for (i = 0; i < d->var_cnt; i++) if (!(exclude_classes & (1u << dict_class_from_id (d->var[i]->name)))) @@ -257,10 +262,9 @@ dict_create_var (struct dictionary *d, const char *name, int width) assert (d != NULL); assert (name != NULL); - assert (strlen (name) >= 1); - assert (strlen (name) <= LONG_NAME_LEN); - assert (width >= 0 && width < 256); + + assert (var_is_valid_name(name,0)); /* Make sure there's not already a variable by that name. */ if (dict_lookup_var (d, name) != NULL) @@ -276,23 +280,17 @@ dict_create_var (struct dictionary *d, const char *name, int width) v->init = 1; v->reinit = dict_class_from_id (v->name) != DC_SCRATCH; v->index = d->var_cnt; - v->miss_type = MISSING_NONE; + mv_init (&v->miss, width); if (v->type == NUMERIC) { - v->print.type = FMT_F; - v->print.w = 8; - v->print.d = 2; - + v->print = f8_2; v->alignment = ALIGN_RIGHT; v->display_width = 8; v->measure = MEASURE_SCALE; } else { - v->print.type = FMT_A; - v->print.w = v->width; - v->print.d = 0; - + v->print = make_output_format (FMT_A, v->width, 0); v->alignment = ALIGN_LEFT; v->display_width = 8; v->measure = MEASURE_NOMINAL; @@ -303,12 +301,13 @@ dict_create_var (struct dictionary *d, const char *name, int width) var_clear_short_name (v); v->aux = NULL; v->aux_dtor = NULL; + v->obs_vals = NULL; /* Update dictionary. */ if (d->var_cnt >= d->var_cap) { d->var_cap = 8 + 2 * d->var_cap; - d->var = xrealloc (d->var, d->var_cap * sizeof *d->var); + d->var = xnrealloc (d->var, d->var_cap, sizeof *d->var); } d->var[v->index] = v; d->var_cnt++; @@ -357,8 +356,7 @@ dict_clone_var (struct dictionary *d, const struct variable *ov, the same short name. */ nv->init = 1; nv->reinit = ov->reinit; - nv->miss_type = ov->miss_type; - memcpy (nv->missing, ov->missing, sizeof nv->missing); + mv_copy (&nv->miss, &ov->miss); nv->print = ov->print; nv->write = ov->write; val_labs_destroy (nv->val_labs); @@ -409,8 +407,9 @@ dict_lookup_var_assert (const struct dictionary *d, const char *name) return v; } -/* Returns nonzero if variable V is in dictionary D. */ -int +/* Returns true if variable V is in dictionary D, + false otherwise. */ +bool dict_contains_var (const struct dictionary *d, const struct variable *v) { assert (d != NULL); @@ -476,6 +475,7 @@ dict_delete_var (struct dictionary *d, struct variable *v) /* Free memory. */ val_labs_destroy (v->val_labs); + cat_stored_values_destroy (v); free (v->label); free (v); } @@ -495,6 +495,23 @@ dict_delete_vars (struct dictionary *d, dict_delete_var (d, *vars++); } +/* Deletes scratch variables from dictionary D. */ +void +dict_delete_scratch_vars (struct dictionary *d) +{ + int i; + + /* FIXME: this can be done in O(count) time, but this algorithm + is O(count**2). */ + assert (d != NULL); + + for (i = 0; i < d->var_cnt; ) + if (dict_class_from_id (d->var[i]->name) == DC_SCRATCH) + dict_delete_var (d, d->var[i]); + else + i++; +} + /* Moves V to 0-based position IDX in D. Other variables in D, if any, retain their relative positions. Runs in time linear in the distance moved. */ @@ -533,7 +550,7 @@ dict_reorder_vars (struct dictionary *d, assert (count == 0 || order != NULL); assert (count <= d->var_cnt); - new_var = xmalloc (d->var_cnt * sizeof *new_var); + new_var = xnmalloc (d->var_cnt, sizeof *new_var); memcpy (new_var, order, count * sizeof *new_var); for (i = 0; i < count; i++) { @@ -578,18 +595,18 @@ dict_rename_var (struct dictionary *d, struct variable *v, /* Renames COUNT variables specified in VARS to the names given in NEW_NAMES within dictionary D. If the renaming would - result in a duplicate variable name, returns zero and stores a + result in a duplicate variable name, returns false and stores a name that would be duplicated into *ERR_NAME (if ERR_NAME is - non-null). Otherwise, the renaming is successful, and nonzero + non-null). Otherwise, the renaming is successful, and true is returned. */ -int +bool dict_rename_vars (struct dictionary *d, struct variable **vars, char **new_names, size_t count, char **err_name) { char **old_names; size_t i; - int success = 1; + bool success = true; assert (d != NULL); assert (count == 0 || vars != NULL); @@ -597,7 +614,7 @@ dict_rename_vars (struct dictionary *d, /* Remove the variables to be renamed from the name hash, save their names, and rename them. */ - old_names = xmalloc (count * sizeof *old_names); + old_names = xnmalloc (count, sizeof *old_names); for (i = 0; i < count; i++) { assert (d->var[vars[i]->index] == vars[i]); @@ -634,7 +651,7 @@ dict_rename_vars (struct dictionary *d, hsh_force_insert (d->name_tab, vars[i]); } - success = 0; + success = false; goto done; } } @@ -681,7 +698,7 @@ dict_get_case_weight (const struct dictionary *d, const struct ccase *c, else { double w = case_num (c, d->weight->fv); - if ( w < 0.0 || w == SYSMIS || is_num_user_missing(w, d->weight) ) + if (w < 0.0 || mv_is_num_missing (&d->weight->miss, w)) w = 0.0; if ( w == 0.0 && *warn_on_invalid ) { *warn_on_invalid = 0; @@ -792,30 +809,6 @@ dict_compact_values (struct dictionary *d) } } -/* Copies values from SRC, which represents a case arranged - according to dictionary D, to DST, which represents a case - arranged according to the dictionary that will be produced by - dict_compact_values(D). */ -void -dict_compact_case (const struct dictionary *d, - struct ccase *dst, const struct ccase *src) -{ - size_t i; - size_t value_idx; - - value_idx = 0; - for (i = 0; i < d->var_cnt; i++) - { - struct variable *v = d->var[i]; - - if (dict_class_from_id (v->name) != DC_SCRATCH) - { - case_copy (dst, value_idx, src, v->fv, v->nv); - value_idx += v->nv; - } - } -} - /* Returns the number of values that would be used by a case if dict_compact_values() were called. */ size_t @@ -842,7 +835,7 @@ dict_get_compacted_idx_to_fv (const struct dictionary *d) size_t next_value_idx; int *idx_to_fv; - idx_to_fv = xmalloc (d->var_cnt * sizeof *idx_to_fv); + idx_to_fv = xnmalloc (d->var_cnt, sizeof *idx_to_fv); next_value_idx = 0; for (i = 0; i < d->var_cnt; i++) { @@ -859,6 +852,112 @@ dict_get_compacted_idx_to_fv (const struct dictionary *d) return idx_to_fv; } +/* Returns true if a case for dictionary D would be smaller after + compaction, false otherwise. Compacting a case eliminates + "holes" between values and after the last value. Holes are + created by deleting variables (or by scratch variables). + + The return value may differ from whether compacting a case + from dictionary D would *change* the case: compaction could + rearrange values even if it didn't reduce space + requirements. */ +bool +dict_needs_compaction (const struct dictionary *d) +{ + return dict_get_compacted_value_cnt (d) < dict_get_next_value_idx (d); +} + +/* How to copy a contiguous range of values between cases. */ +struct copy_map + { + size_t src_idx; /* Starting value index in source case. */ + size_t dst_idx; /* Starting value index in target case. */ + size_t cnt; /* Number of values. */ + }; + +/* How to compact a case. */ +struct dict_compactor + { + struct copy_map *maps; /* Array of mappings. */ + size_t map_cnt; /* Number of mappings. */ + }; + +/* Creates and returns a dict_compactor that can be used to + compact cases for dictionary D. + + Compacting a case eliminates "holes" between values and after + the last value. Holes are created by deleting variables (or + by scratch variables). */ +struct dict_compactor * +dict_make_compactor (const struct dictionary *d) +{ + struct dict_compactor *compactor; + struct copy_map *map; + size_t map_allocated; + size_t value_idx; + size_t i; + + compactor = xmalloc (sizeof *compactor); + compactor->maps = NULL; + compactor->map_cnt = 0; + map_allocated = 0; + + value_idx = 0; + map = NULL; + for (i = 0; i < d->var_cnt; i++) + { + struct variable *v = d->var[i]; + + if (dict_class_from_id (v->name) == DC_SCRATCH) + continue; + if (map != NULL && map->src_idx + map->cnt == v->fv) + map->cnt += v->nv; + else + { + if (compactor->map_cnt == map_allocated) + compactor->maps = x2nrealloc (compactor->maps, &map_allocated, + sizeof *compactor->maps); + map = &compactor->maps[compactor->map_cnt++]; + map->src_idx = v->fv; + map->dst_idx = value_idx; + map->cnt = v->nv; + } + value_idx += v->nv; + } + + return compactor; +} + +/* Compacts SRC by copying it to DST according to the scheme in + COMPACTOR. + + Compacting a case eliminates "holes" between values and after + the last value. Holes are created by deleting variables (or + by scratch variables). */ +void +dict_compactor_compact (const struct dict_compactor *compactor, + struct ccase *dst, const struct ccase *src) +{ + size_t i; + + for (i = 0; i < compactor->map_cnt; i++) + { + const struct copy_map *map = &compactor->maps[i]; + case_copy (dst, map->dst_idx, src, map->src_idx, map->cnt); + } +} + +/* Destroys COMPACTOR. */ +void +dict_compactor_destroy (struct dict_compactor *compactor) +{ + if (compactor != NULL) + { + free (compactor->maps); + free (compactor); + } +} + /* Returns the SPLIT FILE vars (see cmd_split_file()). Call dict_get_split_cnt() to determine how many SPLIT FILE vars there are. Returns a null pointer if and only if there are no @@ -889,7 +988,7 @@ dict_set_split_vars (struct dictionary *d, assert (cnt == 0 || split != NULL); d->split_cnt = cnt; - d->split = xrealloc (d->split, cnt * sizeof *d->split); + d->split = xnrealloc (d->split, cnt, sizeof *d->split); memcpy (d->split, split, cnt * sizeof *d->split); } @@ -948,9 +1047,9 @@ dict_set_documents (struct dictionary *d, const char *documents) } /* Creates in D a vector named NAME that contains CNT variables - VAR (see cmd_vector()). Returns nonzero if successful, or - zero if a vector named NAME already exists in D. */ -int + VAR (see cmd_vector()). Returns true if successful, or + false if a vector named NAME already exists in D. */ +bool dict_create_vector (struct dictionary *d, const char *name, struct variable **var, size_t cnt) @@ -965,13 +1064,13 @@ dict_create_vector (struct dictionary *d, assert (cnt > 0); if (dict_lookup_vector (d, name) != NULL) - return 0; + return false; - d->vector = xrealloc (d->vector, (d->vector_cnt + 1) * sizeof *d->vector); + d->vector = xnrealloc (d->vector, d->vector_cnt + 1, sizeof *d->vector); vector = d->vector[d->vector_cnt] = xmalloc (sizeof *vector); vector->idx = d->vector_cnt++; str_copy_trunc (vector->name, sizeof vector->name, name); - vector->var = xmalloc (cnt * sizeof *var); + vector->var = xnmalloc (cnt, sizeof *var); for (i = 0; i < cnt; i++) { assert (dict_contains_var (d, var[i])); @@ -979,7 +1078,7 @@ dict_create_vector (struct dictionary *d, } vector->cnt = cnt; - return 1; + return true; } /* Returns the vector in D with index IDX, which must be less