From: Ben Pfaff Date: Wed, 2 Jan 2013 02:30:39 +0000 (-0800) Subject: case-map: Drop use of variable aux data. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=016e159c842c81a26b32b4e220fd5fb1edfde049;p=pspp case-map: Drop use of variable aux data. The variable aux data interfaces are not very clean, and furthermore they have few users. This commit eliminates one of the users. --- diff --git a/src/data/case-map.c b/src/data/case-map.c index c54e6753fe..3cbe24792a 100644 --- a/src/data/case-map.c +++ b/src/data/case-map.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2011 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2011, 2013 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -27,6 +27,8 @@ #include "data/variable.h" #include "data/case.h" #include "libpspp/assertion.h" +#include "libpspp/hash-functions.h" +#include "libpspp/hmap.h" #include "gl/xalloc.h" @@ -209,57 +211,115 @@ case_map_to_compact_dict (const struct dictionary *d, return map; } + +struct stage_var + { + struct hmap_node hmap_node; /* In struct case_map_stage's 'stage_vars'. */ + const struct variable *var; + int case_index; + }; -/* Prepares dictionary D for producing a case map. Afterward, - the caller may delete, reorder, or rename variables within D - at will before using case_map_from_dict() to produce the case +struct case_map_stage + { + const struct dictionary *dict; + struct hmap stage_vars; + }; + +/* Prepares and returns a "struct case_map_stage" for producing a case map for + DICT. Afterward, the caller may delete, reorder, or rename variables within + DICT at will before using case_map_stage_get_case_map() to produce the case map. - Uses D's aux members, which must otherwise not be in use. */ -void -case_map_prepare_dict (const struct dictionary *d) + The caller must *not* add new variables to DICT. */ +struct case_map_stage * +case_map_stage_create (const struct dictionary *dict) { - size_t var_cnt = dict_get_var_cnt (d); + size_t n_vars = dict_get_var_cnt (dict); + struct case_map_stage *stage; size_t i; - for (i = 0; i < var_cnt; i++) + stage = xmalloc (sizeof *stage); + stage->dict = dict; + hmap_init (&stage->stage_vars); + + for (i = 0; i < n_vars; i++) { - struct variable *v = dict_get_var (d, i); - int *src_fv = xmalloc (sizeof *src_fv); - *src_fv = var_get_case_index (v); - var_attach_aux (v, src_fv, var_dtor_free); + const struct variable *var = dict_get_var (dict, i); + struct stage_var *stage_var; + + stage_var = xmalloc (sizeof *stage_var); + stage_var->var = var; + stage_var->case_index = var_get_case_index (var); + hmap_insert (&stage->stage_vars, &stage_var->hmap_node, + hash_pointer (var, 0)); + } + + return stage; +} + +/* Destroys STAGE, which was created by case_map_stage_create(). */ +void +case_map_stage_destroy (struct case_map_stage *stage) +{ + if (stage != NULL) + { + struct stage_var *stage_var, *next_stage_var; + + HMAP_FOR_EACH_SAFE (stage_var, next_stage_var, + struct stage_var, hmap_node, &stage->stage_vars) + { + hmap_delete (&stage->stage_vars, &stage_var->hmap_node); + free (stage_var); + } + hmap_destroy (&stage->stage_vars); + free (stage); } } -/* Produces a case map from dictionary D, which must have been - previously prepared with case_map_prepare_dict(). +static const struct stage_var * +case_map_stage_find_var (const struct case_map_stage *stage, + const struct variable *var) +{ + const struct stage_var *stage_var; + + HMAP_FOR_EACH_IN_BUCKET (stage_var, struct stage_var, hmap_node, + hash_pointer (var, 0), &stage->stage_vars) + if (stage_var->var == var) + return stage_var; + + /* If the following assertion is reached, it indicates a bug in the + case_map_stage client: the client allowed a new variable to be added to + the dictionary. This is not allowed, because of the risk that the new + varaible might have the same address as an old variable that has been + deleted. */ + NOT_REACHED (); +} - Does not retain any reference to D, and clears the aux members - set up by case_map_prepare_dict(). +/* Produces a case map from STAGE, which must have been previously created with + case_map_stage_create(). The case map maps from the original case index of + the variables in STAGE's dictionary to their current case indexes. - Returns the new case map, or a null pointer if no mapping is - required (that is, no data has changed position). */ + Returns the new case map, or a null pointer if no mapping is required (that + is, no data has changed position). */ struct case_map * -case_map_from_dict (const struct dictionary *d) +case_map_stage_get_case_map (const struct case_map_stage *stage) { struct case_map *map; - size_t var_cnt = dict_get_var_cnt (d); + size_t n_vars = dict_get_var_cnt (stage->dict); size_t n_values; size_t i; bool identity_map = true; - map = create_case_map (dict_get_proto (d)); - for (i = 0; i < var_cnt; i++) + map = create_case_map (dict_get_proto (stage->dict)); + for (i = 0; i < n_vars; i++) { - struct variable *v = dict_get_var (d, i); - int *src_fv = var_detach_aux (v); + const struct variable *var = dict_get_var (stage->dict, i); + const struct stage_var *stage_var = case_map_stage_find_var (stage, var); - if (var_get_case_index (v) != *src_fv) + if (var_get_case_index (var) != stage_var->case_index) identity_map = false; - insert_mapping (map, *src_fv, var_get_case_index (v)); - - free (src_fv); + insert_mapping (map, stage_var->case_index, var_get_case_index (var)); } if (identity_map) diff --git a/src/data/case-map.h b/src/data/case-map.h index cefbe7667a..0e9970a873 100644 --- a/src/data/case-map.h +++ b/src/data/case-map.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2007, 2009, 2012 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -45,8 +45,9 @@ struct casewriter *case_map_create_output_translator (struct case_map *, /* For mapping cases for one version of a dictionary to those in a modified version of the same dictionary. */ -void case_map_prepare_dict (const struct dictionary *); -struct case_map *case_map_from_dict (const struct dictionary *); +struct case_map_stage *case_map_stage_create (const struct dictionary *); +void case_map_stage_destroy (struct case_map_stage *); +struct case_map *case_map_stage_get_case_map (const struct case_map_stage *); /* For eliminating "holes" in a case. */ struct case_map *case_map_to_compact_dict (const struct dictionary *d, diff --git a/src/language/data-io/get.c b/src/language/data-io/get.c index 35b894a750..1218a27b18 100644 --- a/src/language/data-io/get.c +++ b/src/language/data-io/get.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006, 2007, 2010, 2011, 2012 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 2007, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -73,6 +73,7 @@ parse_read_command (struct lexer *lexer, struct dataset *ds, struct file_handle *fh = NULL; struct dictionary *dict = NULL; struct case_map *map = NULL; + struct case_map_stage *stage = NULL; char *encoding = NULL; for (;;) @@ -125,7 +126,7 @@ parse_read_command (struct lexer *lexer, struct dataset *ds, if (reader == NULL) goto error; - case_map_prepare_dict (dict); + stage = case_map_stage_create (dict); while (lex_token (lexer) != T_ENDCMD) { @@ -135,7 +136,8 @@ parse_read_command (struct lexer *lexer, struct dataset *ds, } dict_compact_values (dict); - map = case_map_from_dict (dict); + map = case_map_stage_get_case_map (stage); + case_map_stage_destroy (stage); if (map != NULL) reader = case_map_create_input_translator (map, reader); @@ -147,6 +149,7 @@ parse_read_command (struct lexer *lexer, struct dataset *ds, return CMD_SUCCESS; error: + case_map_stage_destroy (stage); fh_unref (fh); casereader_destroy (reader); if (dict != NULL) diff --git a/src/language/data-io/save-translate.c b/src/language/data-io/save-translate.c index bc68e553e1..6601f30b18 100644 --- a/src/language/data-io/save-translate.c +++ b/src/language/data-io/save-translate.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2010, 2011 Free Software Foundation, Inc. + Copyright (C) 2010, 2011, 2013 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -45,6 +45,7 @@ cmd_save_translate (struct lexer *lexer, struct dataset *ds) enum { CSV_FILE = 1, TAB_FILE } type; struct dictionary *dict; + struct case_map_stage *stage; struct case_map *map; struct casewriter *writer; struct file_handle *handle; @@ -67,6 +68,7 @@ cmd_save_translate (struct lexer *lexer, struct dataset *ds) type = 0; dict = dict_clone (dataset_dict (ds)); + stage = NULL; map = NULL; handle = NULL; @@ -81,7 +83,7 @@ cmd_save_translate (struct lexer *lexer, struct dataset *ds) delimiter = 0; qualifier = '"'; - case_map_prepare_dict (dict); + stage = case_map_stage_create (dict); dict_delete_scratch_vars (dict); while (lex_match (lexer, T_SLASH)) @@ -271,7 +273,8 @@ cmd_save_translate (struct lexer *lexer, struct dataset *ds) goto error; fh_unref (handle); - map = case_map_from_dict (dict); + map = case_map_stage_get_case_map (stage); + case_map_stage_destroy (stage); if (map != NULL) writer = case_map_create_output_translator (map, writer); dict_destroy (dict); @@ -283,6 +286,7 @@ cmd_save_translate (struct lexer *lexer, struct dataset *ds) return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE; error: + case_map_stage_destroy (stage); fh_unref (handle); dict_destroy (dict); case_map_destroy (map); diff --git a/src/language/data-io/save.c b/src/language/data-io/save.c index b8031f71ea..e01a8c941e 100644 --- a/src/language/data-io/save.c +++ b/src/language/data-io/save.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -156,6 +156,7 @@ parse_write_command (struct lexer *lexer, struct dataset *ds, struct file_handle *handle; /* Output file. */ struct dictionary *dict; /* Dictionary for output file. */ struct casewriter *writer; /* Writer. */ + struct case_map_stage *stage; /* Preparation for 'map'. */ struct case_map *map; /* Map from input data to data for writer. */ /* Common options. */ @@ -172,11 +173,12 @@ parse_write_command (struct lexer *lexer, struct dataset *ds, handle = NULL; dict = dict_clone (dataset_dict (ds)); writer = NULL; + stage = NULL; map = NULL; sysfile_opts = sfm_writer_default_options (); porfile_opts = pfm_writer_default_options (); - case_map_prepare_dict (dict); + stage = case_map_stage_create (dict); dict_delete_scratch_vars (dict); lex_match (lexer, T_SLASH); @@ -301,7 +303,8 @@ parse_write_command (struct lexer *lexer, struct dataset *ds, if (writer == NULL) goto error; - map = case_map_from_dict (dict); + map = case_map_stage_get_case_map (stage); + case_map_stage_destroy (stage); if (map != NULL) writer = case_map_create_output_translator (map, writer); dict_destroy (dict); @@ -310,6 +313,7 @@ parse_write_command (struct lexer *lexer, struct dataset *ds, return writer; error: + case_map_stage_destroy (stage); fh_unref (handle); casewriter_destroy (writer); dict_destroy (dict);