X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fsparse-cases.c;h=7abe429147a893af7a48bf88eb5db99cb25313ae;hb=07623ede4f56d27643c0c0ac978c089690f350c0;hp=8a4a263fd920db8f44380171bd3bda8b55acaad9;hpb=1b2982dce3a196a0c9011c6c836d57a9763fcfc3;p=pspp-builds.git diff --git a/src/data/sparse-cases.c b/src/data/sparse-cases.c index 8a4a263f..7abe4291 100644 --- a/src/data/sparse-cases.c +++ b/src/data/sparse-cases.c @@ -1,20 +1,18 @@ -/* PSPP - computes sample statistics. - Copyright (C) 2007 Free Software Foundation, Inc. +/* PSPP - a program for statistical analysis. + Copyright (C) 2007, 2009 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 the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. + 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 + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. */ + along with this program. If not, see . */ #include @@ -23,6 +21,7 @@ #include #include +#include #include #include #include @@ -32,7 +31,7 @@ #include "xalloc.h" /* A sparse array of cases. */ -struct sparse_cases +struct sparse_cases { size_t column_cnt; /* Number of values per case. */ union value *default_columns; /* Defaults for unwritten cases. */ @@ -45,13 +44,13 @@ struct sparse_cases /* Creates and returns a new sparse array of cases with COLUMN_CNT values per case. */ struct sparse_cases * -sparse_cases_create (size_t column_cnt) +sparse_cases_create (size_t column_cnt) { struct sparse_cases *sc = xmalloc (sizeof *sc); sc->column_cnt = column_cnt; sc->default_columns = NULL; - sc->max_memory_cases = get_workspace_cases (column_cnt); - sc->memory = sparse_array_create (sizeof (struct ccase)); + sc->max_memory_cases = settings_get_workspace_cases (column_cnt); + sc->memory = sparse_array_create (sizeof (struct ccase *)); sc->disk = NULL; sc->disk_cases = NULL; return sc; @@ -60,7 +59,7 @@ sparse_cases_create (size_t column_cnt) /* Creates and returns a new sparse array of cases that contains the same data as OLD. */ struct sparse_cases * -sparse_cases_clone (const struct sparse_cases *old) +sparse_cases_clone (const struct sparse_cases *old) { struct sparse_cases *new = xmalloc (sizeof *new); @@ -75,64 +74,68 @@ sparse_cases_clone (const struct sparse_cases *old) new->max_memory_cases = old->max_memory_cases; - if (old->memory != NULL) + if (old->memory != NULL) { unsigned long int idx; - struct ccase *c; + struct ccase **cp; - new->memory = sparse_array_create (sizeof (struct ccase)); - for (c = sparse_array_scan (old->memory, NULL, &idx); c != NULL; - c = sparse_array_scan (old->memory, &idx, &idx)) - case_clone (sparse_array_insert (new->memory, idx), c); + new->memory = sparse_array_create (sizeof (struct ccase *)); + for (cp = sparse_array_first (old->memory, &idx); cp != NULL; + cp = sparse_array_next (old->memory, idx, &idx)) + { + struct ccase **ncp = sparse_array_insert (new->memory, idx); + *ncp = case_ref (*cp); + } } else new->memory = NULL; - if (old->disk != NULL) + if (old->disk != NULL) { const struct range_set_node *node; - + new->disk = case_tmpfile_create (old->column_cnt); new->disk_cases = range_set_create (); for (node = range_set_first (old->disk_cases); node != NULL; - node = range_set_next (old->disk_cases, node)) + node = range_set_next (old->disk_cases, node)) { unsigned long int start = range_set_node_get_start (node); unsigned long int end = range_set_node_get_end (node); unsigned long int idx; - struct ccase c; for (idx = start; idx < end; idx++) - if (!case_tmpfile_get_case (old->disk, idx, &c) - || !case_tmpfile_put_case (new->disk, idx, &c)) - { - sparse_cases_destroy (new); - return NULL; - } + { + struct ccase *c = case_tmpfile_get_case (old->disk, idx); + if (c == NULL || !case_tmpfile_put_case (new->disk, idx, c)) + { + sparse_cases_destroy (new); + return NULL; + } + } } } - else + else { new->disk = NULL; new->disk_cases = NULL; } - + return new; } /* Destroys sparse array of cases SC. */ void -sparse_cases_destroy (struct sparse_cases *sc) +sparse_cases_destroy (struct sparse_cases *sc) { - if (sc != NULL) + if (sc != NULL) { - if (sc->memory != NULL) + if (sc->memory != NULL) { unsigned long int idx; - struct ccase *c; - for (c = sparse_array_scan (sc->memory, NULL, &idx); c != NULL; - c = sparse_array_scan (sc->memory, &idx, &idx)) - case_destroy (c); + struct ccase **cp; + for (cp = sparse_array_first (sc->memory, &idx); cp != NULL; + cp = sparse_array_next (sc->memory, idx, &idx)) + case_unref (*cp); sparse_array_destroy (sc->memory); } free (sc->default_columns); @@ -144,19 +147,19 @@ sparse_cases_destroy (struct sparse_cases *sc) /* Returns the number of `union value's in each case in SC. */ size_t -sparse_cases_get_value_cnt (const struct sparse_cases *sc) +sparse_cases_get_value_cnt (const struct sparse_cases *sc) { return sc->column_cnt; } /* Dumps the cases in SC, which must currently be stored in memory, to disk. Returns true if successful, false on I/O - error. */ + error. */ static bool -dump_sparse_cases_to_disk (struct sparse_cases *sc) +dump_sparse_cases_to_disk (struct sparse_cases *sc) { unsigned long int idx; - struct ccase *c; + struct ccase **cp; assert (sc->memory != NULL); assert (sc->disk == NULL); @@ -164,18 +167,18 @@ dump_sparse_cases_to_disk (struct sparse_cases *sc) sc->disk = case_tmpfile_create (sc->column_cnt); sc->disk_cases = range_set_create (); - for (c = sparse_array_scan (sc->memory, NULL, &idx); c != NULL; - c = sparse_array_scan (sc->memory, &idx, &idx)) + for (cp = sparse_array_first (sc->memory, &idx); cp != NULL; + cp = sparse_array_next (sc->memory, idx, &idx)) { - if (!case_tmpfile_put_case (sc->disk, idx, c)) - { + if (!case_tmpfile_put_case (sc->disk, idx, *cp)) + { case_tmpfile_destroy (sc->disk); sc->disk = NULL; range_set_destroy (sc->disk_cases); sc->disk_cases = NULL; return false; } - range_set_insert (sc->disk_cases, idx, 1); + range_set_insert (sc->disk_cases, idx, 1); } sparse_array_destroy (sc->memory); sc->memory = NULL; @@ -185,7 +188,7 @@ dump_sparse_cases_to_disk (struct sparse_cases *sc) /* Returns true if any data has ever been written to ROW in SC, false otherwise. */ bool -sparse_cases_contains_row (const struct sparse_cases *sc, casenumber row) +sparse_cases_contains_row (const struct sparse_cases *sc, casenumber row) { return (sc->memory != NULL ? sparse_array_get (sc->memory, row) != NULL @@ -197,22 +200,29 @@ sparse_cases_contains_row (const struct sparse_cases *sc, casenumber row) Returns true if successful, false on I/O error. */ bool sparse_cases_read (struct sparse_cases *sc, casenumber row, size_t column, - union value values[], size_t value_cnt) + union value values[], size_t value_cnt) { assert (value_cnt <= sc->column_cnt); assert (column + value_cnt <= sc->column_cnt); - if (sparse_cases_contains_row (sc, row)) + if (sparse_cases_contains_row (sc, row)) { - struct ccase c; - if (sc->memory != NULL) - case_clone (&c, sparse_array_get (sc->memory, row)); - else if (!case_tmpfile_get_case (sc->disk, row, &c)) - return false; - case_copy_out (&c, column, values, value_cnt); - case_destroy (&c); + struct ccase *c; + if (sc->memory != NULL) + { + struct ccase **cp = sparse_array_get (sc->memory, row); + c = case_ref (*cp); + } + else + { + c = case_tmpfile_get_case (sc->disk, row); + if (c == NULL) + return false; + } + case_copy_out (c, column, values, value_cnt); + case_unref (c); } - else + else { assert (sc->default_columns != NULL); memcpy (values, sc->default_columns + column, @@ -227,23 +237,27 @@ static bool write_disk_case (struct sparse_cases *sc, casenumber row, size_t column, const union value values[], size_t value_cnt) { - struct ccase c; + struct ccase *c; bool ok; /* Get current case data. */ - if (column == 0 && value_cnt == sc->column_cnt) - case_create (&c, sc->column_cnt); - else if (!case_tmpfile_get_case (sc->disk, row, &c)) - return false; + if (column == 0 && value_cnt == sc->column_cnt) + c = case_create (sc->column_cnt); + else + { + c = case_tmpfile_get_case (sc->disk, row); + if (c == NULL) + return false; + } /* Copy in new data. */ - case_copy_in (&c, column, values, value_cnt); + case_copy_in (c, column, values, value_cnt); /* Write new case. */ - ok = case_tmpfile_put_case (sc->disk, row, &c); + ok = case_tmpfile_put_case (sc->disk, row, c); if (ok) range_set_insert (sc->disk_cases, row, 1); - + return ok; } @@ -253,22 +267,25 @@ write_disk_case (struct sparse_cases *sc, casenumber row, size_t column, Returns true if successful, false on I/O error. */ bool sparse_cases_write (struct sparse_cases *sc, casenumber row, size_t column, - const union value values[], size_t value_cnt) + const union value values[], size_t value_cnt) { if (sc->memory != NULL) { - struct ccase *c = sparse_array_get (sc->memory, row); - if (c == NULL) + struct ccase *c, **cp; + cp = sparse_array_get (sc->memory, row); + if (cp != NULL) + c = *cp = case_unshare (*cp); + else { - if (sparse_array_count (sc->memory) >= sc->max_memory_cases) + if (sparse_array_count (sc->memory) >= sc->max_memory_cases) { if (!dump_sparse_cases_to_disk (sc)) return false; return write_disk_case (sc, row, column, values, value_cnt); } - - c = sparse_array_insert (sc->memory, row); - case_create (c, sc->column_cnt); + + cp = sparse_array_insert (sc->memory, row); + c = *cp = case_create (sc->column_cnt); if (sc->default_columns != NULL && (column != 0 || value_cnt != sc->column_cnt)) case_copy_in (c, 0, sc->default_columns, sc->column_cnt); @@ -282,7 +299,7 @@ sparse_cases_write (struct sparse_cases *sc, casenumber row, size_t column, /* Writes the VALUE_CNT values in VALUES to columns START_COLUMN...(START_COLUMN + VALUE_CNT), exclusive, in every - row in SC, even those rows that have not yet been written. + row in SC, even those rows that have not yet been written. Returns true if successful, false on I/O error. The runtime of this function is linear in the number of rows @@ -302,31 +319,34 @@ sparse_cases_write_columns (struct sparse_cases *sc, size_t start_column, value_cnt * sizeof *sc->default_columns); /* Set individual rows. */ - if (sc->memory != NULL) + if (sc->memory != NULL) { - struct ccase *c; + struct ccase **cp; unsigned long int idx; - - for (c = sparse_array_scan (sc->memory, NULL, &idx); c != NULL; - c = sparse_array_scan (sc->memory, &idx, &idx)) - case_copy_in (c, start_column, values, value_cnt); + + for (cp = sparse_array_first (sc->memory, &idx); cp != NULL; + cp = sparse_array_next (sc->memory, idx, &idx)) + { + *cp = case_unshare (*cp); + case_copy_in (*cp, start_column, values, value_cnt); + } } - else + else { const struct range_set_node *node; for (node = range_set_first (sc->disk_cases); node != NULL; - node = range_set_next (sc->disk_cases, node)) + node = range_set_next (sc->disk_cases, node)) { unsigned long int start = range_set_node_get_start (node); unsigned long int end = range_set_node_get_end (node); unsigned long int row; - for (row = start; row < end; row++) + for (row = start; row < end; row++) case_tmpfile_put_values (sc->disk, row, start_column, values, value_cnt); } - + if (case_tmpfile_error (sc->disk)) return false; }