From: Ben Pfaff Date: Wed, 7 Jan 2009 07:17:32 +0000 (-0800) Subject: Make cases simpler, faster, and easier to understand. X-Git-Tag: v0.7.1~13 X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cc57a28ef6796ae9a64ef80d453f72126956d49d;p=pspp-builds.git Make cases simpler, faster, and easier to understand. Cases (struct ccase) is reference-counted to avoid copying more data than necessary. But the existing implementation that uses separate structures for references to cases (struct ccase) and the cases themselves (struct case_data) has a number of issues: - The semantics of struct ccase are tricky to remember; one has to remember to treat struct ccase as essentially a pointer type. I get confused sometimes myself. (One of the symptoms of this was the existence of the case_nullify and case_is_null functions, which are exactly analogous to setting a pointer to null and comparing one against null, respectively.) - Every reference to data in a case involves two levels of indirection, which is one more than actually necessary. - The implementation is somewhat complicated. This commit simplifies things, by dropping a level of indirection. Now, a case is just a pointer to a struct ccase, which contains the actual data. Reference counting is still present, but it is simplified. The only thing that must be remembered is that, before modifying a case that may be shared, it must be passed through case_unshare() to make a new unshared copy if necessary. --- diff --git a/src/data/case-map.c b/src/data/case-map.c index 8d309580..cff621f3 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 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 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 @@ -38,7 +38,7 @@ struct case_map corresponding source index. */ }; -static void translate_case (struct ccase *, struct ccase *, void *map_); +static struct ccase *translate_case (struct ccase *, void *map_); static bool destroy_case_map (void *map_); /* Creates and returns an empty map. */ @@ -83,20 +83,30 @@ case_map_destroy (struct case_map *map) } } -/* Maps from SRC to DST, applying case map MAP. */ -void -case_map_execute (const struct case_map *map, - const struct ccase *src, struct ccase *dst) -{ - size_t dst_idx; +/* If MAP is nonnull, returns a new case that is the result of + applying case map MAP to SRC, and unrefs SRC. - case_create (dst, map->value_cnt); - for (dst_idx = 0; dst_idx < map->value_cnt; dst_idx++) + If MAP is null, returns SRC unchanged. */ +struct ccase * +case_map_execute (const struct case_map *map, struct ccase *src) +{ + if (map != NULL) { - int src_idx = map->map[dst_idx]; - if (src_idx != -1) - *case_data_rw_idx (dst, dst_idx) = *case_data_idx (src, src_idx); + struct ccase *dst; + size_t dst_idx; + + dst = case_create (map->value_cnt); + for (dst_idx = 0; dst_idx < map->value_cnt; dst_idx++) + { + int src_idx = map->map[dst_idx]; + if (src_idx != -1) + *case_data_rw_idx (dst, dst_idx) = *case_data_idx (src, src_idx); + } + case_unref (src); + return dst; } + else + return src; } /* Returns the number of `union value's in cases created by @@ -147,12 +157,11 @@ case_map_create_output_translator (struct case_map *map, } /* Casereader/casewriter translation callback. */ -static void -translate_case (struct ccase *input, struct ccase *output, void *map_) +static struct ccase * +translate_case (struct ccase *input, void *map_) { struct case_map *map = map_; - case_map_execute (map, input, output); - case_destroy (input); + return case_map_execute (map, input); } /* Casereader/casewriter destruction callback. */ diff --git a/src/data/case-map.h b/src/data/case-map.h index 1c8608c2..010dd487 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 Free Software Foundation, Inc. + 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 @@ -34,8 +34,7 @@ struct dictionary; struct case_map *case_map_create (void); void case_map_destroy (struct case_map *); -void case_map_execute (const struct case_map *, - const struct ccase *, struct ccase *); +struct ccase *case_map_execute (const struct case_map *, struct ccase *); size_t case_map_get_value_cnt (const struct case_map *); diff --git a/src/data/case-matcher.c b/src/data/case-matcher.c index 9cfc0083..a1251cb7 100644 --- a/src/data/case-matcher.c +++ b/src/data/case-matcher.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2008 Free Software Foundation, Inc. + Copyright (C) 2008, 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 @@ -30,7 +30,7 @@ struct case_matcher_input { struct subcase by_vars; - const struct ccase *data; + struct ccase **data; bool *is_minimal; }; @@ -55,13 +55,15 @@ case_matcher_create (void) /* Adds a new input file to case matcher CM. case_matcher_match() will compare the variables specified in - BY in case DATA and set *IS_MINIMAL appropriately. + BY in case *DATA and set *IS_MINIMAL appropriately. + (The caller may change the case that *DATA points to from one + call to the next.) All of the BY subcases provided to this function for a given CM must be conformable (see subcase_conformable()). */ void case_matcher_add_input (struct case_matcher *cm, const struct subcase *by, - const struct ccase *data, bool *is_minimal) + struct ccase **data, bool *is_minimal) { struct case_matcher_input *input; @@ -101,7 +103,7 @@ case_matcher_destroy (struct case_matcher *cm) static int compare_BY_3way (struct case_matcher_input *a, struct case_matcher_input *b) { - return subcase_compare_3way (&a->by_vars, a->data, &b->by_vars, b->data); + return subcase_compare_3way (&a->by_vars, *a->data, &b->by_vars, *b->data); } /* Compares the values of the BY variables in all of the nonnull @@ -121,7 +123,7 @@ case_matcher_match (struct case_matcher *cm, union value **by) min = NULL; for (file = cm->inputs; file < &cm->inputs[cm->n_inputs]; file++) - if (!case_is_null (file->data)) + if (*file->data != NULL) { int cmp = min != NULL ? compare_BY_3way (min, file) : 1; if (cmp < 0) @@ -140,7 +142,7 @@ case_matcher_match (struct case_matcher *cm, union value **by) { for (file = cm->inputs; file < min; file++) *file->is_minimal = false; - subcase_extract (&min->by_vars, min->data, cm->by_values); + subcase_extract (&min->by_vars, *min->data, cm->by_values); *by = cm->by_values; return true; } diff --git a/src/data/case-matcher.h b/src/data/case-matcher.h index d172f611..fa40781f 100644 --- a/src/data/case-matcher.h +++ b/src/data/case-matcher.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2008 Free Software Foundation, Inc. + Copyright (C) 2008, 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 @@ -25,7 +25,7 @@ union value; struct case_matcher *case_matcher_create (void); void case_matcher_add_input (struct case_matcher *, const struct subcase *, - const struct ccase *, bool *is_minimal); + struct ccase **, bool *is_minimal); void case_matcher_destroy (struct case_matcher *); bool case_matcher_match (struct case_matcher *, union value **by); diff --git a/src/data/case-tmpfile.c b/src/data/case-tmpfile.c index e6fc3de4..ca3a6a56 100644 --- a/src/data/case-tmpfile.c +++ b/src/data/case-tmpfile.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -198,25 +198,23 @@ case_tmpfile_get_values (const struct case_tmpfile *ctf, && do_read (ctf, sizeof *values * value_cnt, values)); } -/* Reads the case numbered CASE_IDX from CTF into C. - Returns true if successful, false if CTF is tainted or an I/O - error occurs during the operation. +/* Reads the case numbered CASE_IDX from CTF. + Returns the case if successful or a null pointer if CTF is + tainted or an I/O error occurs during the operation. The results of this function are undefined if the case read from CTF had not previously been written. */ -bool -case_tmpfile_get_case (const struct case_tmpfile *ctf, casenumber case_idx, - struct ccase *c) +struct ccase * +case_tmpfile_get_case (const struct case_tmpfile *ctf, casenumber case_idx) { - case_create (c, ctf->value_cnt); + struct ccase *c = case_create (ctf->value_cnt); if (case_tmpfile_get_values (ctf, case_idx, 0, case_data_all_rw (c), ctf->value_cnt)) - return true; + return c; else { - case_destroy (c); - case_nullify (c); - return false; + case_unref (c); + return NULL; } } @@ -246,7 +244,7 @@ case_tmpfile_put_case (struct case_tmpfile *ctf, casenumber case_idx, { bool ok = case_tmpfile_put_values (ctf, case_idx, 0, case_data_all (c), ctf->value_cnt); - case_destroy (c); + case_unref (c); return ok; } diff --git a/src/data/case-tmpfile.h b/src/data/case-tmpfile.h index 3a92debc..a5916249 100644 --- a/src/data/case-tmpfile.h +++ b/src/data/case-tmpfile.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -38,11 +38,10 @@ bool case_tmpfile_error (const struct case_tmpfile *); void case_tmpfile_force_error (struct case_tmpfile *); const struct taint *case_tmpfile_get_taint (const struct case_tmpfile *); -bool case_tmpfile_get_values (const struct case_tmpfile *, + bool case_tmpfile_get_values (const struct case_tmpfile *, casenumber, size_t start_value, union value[], size_t value_cnt); -bool case_tmpfile_get_case (const struct case_tmpfile *, - casenumber, struct ccase *); +struct ccase *case_tmpfile_get_case (const struct case_tmpfile *, casenumber); bool case_tmpfile_put_values (struct case_tmpfile *, casenumber, size_t start_value, diff --git a/src/data/case.c b/src/data/case.c index cec6f21e..8ae98900 100644 --- a/src/data/case.c +++ b/src/data/case.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2004, 2007 Free Software Foundation, Inc. + Copyright (C) 2004, 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 @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -29,212 +30,127 @@ #include "minmax.h" #include "xalloc.h" -/* Reference-counted case implementation. */ -struct case_data - { - size_t value_cnt; /* Number of values. */ - unsigned ref_cnt; /* Reference count. */ - union value values[1]; /* Values. */ - }; - -/* Ensures that C does not share data with any other case. */ -static void -case_unshare (struct ccase *c) -{ - if (c->case_data->ref_cnt > 1) - { - struct case_data *cd = c->case_data; - cd->ref_cnt--; - case_create (c, cd->value_cnt); - memcpy (c->case_data->values, cd->values, - sizeof *cd->values * cd->value_cnt); - } -} - -/* Returns the number of bytes needed by a case with VALUE_CNT +/* Returns the number of bytes needed by a case with N_VALUES values. */ static size_t -case_size (size_t value_cnt) +case_size (size_t n_values) { - return (offsetof (struct case_data, values) - + value_cnt * sizeof (union value)); + return offsetof (struct ccase, values) + n_values * sizeof (union value); } -/* Initializes C as a null case. */ -void -case_nullify (struct ccase *c) +/* Returns true if case C contains COUNT cases starting at index + OFS, false if any of those values are out of range for case + C. */ +static inline bool UNUSED +range_is_valid (const struct ccase *c, size_t ofs, size_t count) { - c->case_data = NULL; + return (count <= c->n_values + && ofs <= c->n_values + && ofs + count <= c->n_values); } -/* Returns true iff C is a null case. */ -bool -case_is_null (const struct ccase *c) -{ - return c->case_data == NULL; -} - -/* Initializes C as a new case that can store VALUE_CNT values. +/* Creates and returns a new case that can store N_VALUES values. The values have indeterminate contents until explicitly written. */ -void -case_create (struct ccase *c, size_t value_cnt) +struct ccase * +case_create (size_t n_values) { - if (!case_try_create (c, value_cnt)) + struct ccase *c = case_try_create (n_values); + if (c == NULL) xalloc_die (); + return c; } -/* Initializes CLONE as a copy of ORIG. */ -void -case_clone (struct ccase *clone, const struct ccase *orig) +/* Like case_create, but returns a null pointer if not enough + memory is available. */ +struct ccase * +case_try_create (size_t n_values) { - assert (orig->case_data->ref_cnt > 0); - - if (clone != orig) - *clone = *orig; - orig->case_data->ref_cnt++; -#ifdef DEBUGGING - case_unshare (clone); -#endif -} - -/* Replaces DST by SRC and nullifies SRC. - DST and SRC must be initialized cases at entry. */ -void -case_move (struct ccase *dst, struct ccase *src) -{ - assert (src->case_data->ref_cnt > 0); - - if (dst != src) + struct ccase *c = malloc (case_size (n_values)); + if (c) { - *dst = *src; - case_nullify (src); + c->n_values = n_values; + c->ref_cnt = 1; } + return c; } -/* Destroys case C. */ -void -case_destroy (struct ccase *c) +/* Resizes case C, which must not be shared, to N_VALUES union + values. If N_VALUES is greater than the current size of case + C, then the newly added values have indeterminate content that + the caller is responsible for initializing. Returns the new + case. */ +struct ccase * +case_resize (struct ccase *c, size_t n_values) { - struct case_data *cd; - - cd = c->case_data; - if (cd != NULL && --cd->ref_cnt == 0) + assert (!case_is_shared (c)); + if (n_values != c->n_values) { - memset (cd->values, 0xcc, sizeof *cd->values * cd->value_cnt); - cd->value_cnt = 0xdeadbeef; - free (cd); + c->n_values = n_values; + return xrealloc (c, case_size (n_values)); } + else + return c; } -/* Returns the number of union values in C. */ -size_t -case_get_value_cnt (const struct ccase *c) -{ - return c->case_data->value_cnt; -} +/* case_unshare_and_resize(C, N) is equivalent to + case_resize(case_unshare(C), N), but it is faster if case C is + shared. -/* Resizes case C to NEW_CNT union values. */ -void -case_resize (struct ccase *c, size_t new_cnt) + Returns the new case.*/ +struct ccase * +case_unshare_and_resize (struct ccase *c, size_t n_values) { - size_t old_cnt = case_get_value_cnt (c); - if (old_cnt != new_cnt) + if (!case_is_shared (c)) + return case_resize (c, n_values); + else { - struct ccase new; - - case_create (&new, new_cnt); - case_copy (&new, 0, c, 0, MIN (old_cnt, new_cnt)); - case_swap (&new, c); - case_destroy (&new); + struct ccase *new = case_create (n_values); + case_copy (new, 0, c, 0, MIN (n_values, c->n_values)); + c->ref_cnt--; + return new; } } -/* Swaps cases A and B. */ -void -case_swap (struct ccase *a, struct ccase *b) -{ - struct case_data *t = a->case_data; - a->case_data = b->case_data; - b->case_data = t; -} +/* Copies N_VALUES values from SRC (starting at SRC_IDX) to DST + (starting at DST_IDX). -/* Attempts to create C as a new case that holds VALUE_CNT - values. Returns true if successful, false if memory - allocation failed. */ -bool -case_try_create (struct ccase *c, size_t value_cnt) -{ - c->case_data = malloc (case_size (value_cnt)); - if (c->case_data != NULL) - { - c->case_data->value_cnt = value_cnt; - c->case_data->ref_cnt = 1; - return true; - } - - return false; -} - -/* Tries to initialize CLONE as a copy of ORIG. - Returns true if successful, false if memory allocation - failed. */ -bool -case_try_clone (struct ccase *clone, const struct ccase *orig) -{ - case_clone (clone, orig); - return true; -} - -/* Copies VALUE_CNT values from SRC (starting at SRC_IDX) to DST - (starting at DST_IDX). */ + DST must not be shared. */ void case_copy (struct ccase *dst, size_t dst_idx, const struct ccase *src, size_t src_idx, - size_t value_cnt) + size_t n_values) { - assert (dst->case_data->ref_cnt > 0); - assert (dst_idx + value_cnt <= dst->case_data->value_cnt); + assert (!case_is_shared (dst)); + assert (range_is_valid (dst, dst_idx, n_values)); + assert (range_is_valid (src, dst_idx, n_values)); - assert (src->case_data->ref_cnt > 0); - assert (src_idx + value_cnt <= src->case_data->value_cnt); - - if (dst->case_data != src->case_data || dst_idx != src_idx) - { - case_unshare (dst); - memmove (dst->case_data->values + dst_idx, - src->case_data->values + src_idx, - sizeof *dst->case_data->values * value_cnt); - } + if (dst != src || dst_idx != src_idx) + memmove (dst->values + dst_idx, src->values + src_idx, + sizeof *dst->values * n_values); } -/* Copies VALUE_CNT values out of case C to VALUES, starting at +/* Copies N_VALUES values out of case C to VALUES, starting at the given START_IDX. */ void case_copy_out (const struct ccase *c, - size_t start_idx, union value *values, size_t value_cnt) + size_t start_idx, union value *values, size_t n_values) { - assert (c->case_data->ref_cnt > 0); - assert (value_cnt <= c->case_data->value_cnt); - assert (start_idx + value_cnt <= c->case_data->value_cnt); - - memcpy (values, c->case_data->values + start_idx, - value_cnt * sizeof *values); + assert (range_is_valid (c, start_idx, n_values)); + memcpy (values, c->values + start_idx, n_values * sizeof *values); } -/* Copies VALUE_CNT values from VALUES into case C, staring at - the given START_IDX. */ +/* Copies N_VALUES values from VALUES into case C, starting at + the given START_IDX. + + C must not be shared. */ void case_copy_in (struct ccase *c, - size_t start_idx, const union value *values, size_t value_cnt) + size_t start_idx, const union value *values, size_t n_values) { - assert (c->case_data->ref_cnt > 0); - assert (value_cnt <= c->case_data->value_cnt); - assert (start_idx + value_cnt <= c->case_data->value_cnt); - - case_unshare (c); - memcpy (c->case_data->values + start_idx, values, - value_cnt * sizeof *values); + assert (!case_is_shared (c)); + assert (range_is_valid (c, start_idx, n_values)); + memcpy (c->values + start_idx, values, n_values * sizeof *values); } /* Returns a pointer to the `union value' used for the @@ -247,30 +163,21 @@ case_data (const struct ccase *c, const struct variable *v) return case_data_idx (c, var_get_case_index (v)); } -/* Returns the numeric value of the `union value' in C for - variable V. - Case C must be drawn from V's dictionary. */ -double -case_num (const struct ccase *c, const struct variable *v) +/* Returns a pointer to the `union value' used for the element of + C numbered IDX. The caller must not modify the returned + data. */ +const union value * +case_data_idx (const struct ccase *c, size_t idx) { - return case_num_idx (c, var_get_case_index (v)); + assert (idx < c->n_values); + return &c->values[idx]; } -/* Returns the string value of the `union value' in C for - variable V. - Case C must be drawn from V's dictionary. - (Note that the value is not null-terminated.) - The caller must not modify the return value. */ -const char * -case_str (const struct ccase *c, const struct variable *v) -{ - return case_str_idx (c, var_get_case_index (v)); -} +/* Returns a pointer to the `union value' used for the element of + C for variable V. Case C must be drawn from V's dictionary. + The caller is allowed to modify the returned data. -/* Returns a pointer to the `union value' used for the - element of C for variable V. - Case C must be drawn from V's dictionary. - The caller is allowed to modify the returned data. */ + Case C must not be shared. */ union value * case_data_rw (struct ccase *c, const struct variable *v) { @@ -279,14 +186,24 @@ case_data_rw (struct ccase *c, const struct variable *v) /* Returns a pointer to the `union value' used for the element of C numbered IDX. - The caller must not modify the returned data. */ -const union value * -case_data_idx (const struct ccase *c, size_t idx) + The caller is allowed to modify the returned data. + + Case C must not be shared. */ +union value * +case_data_rw_idx (struct ccase *c, size_t idx) { - assert (c->case_data->ref_cnt > 0); - assert (idx < c->case_data->value_cnt); + assert (!case_is_shared (c)); + assert (idx < c->n_values); + return &c->values[idx]; +} - return &c->case_data->values[idx]; +/* Returns the numeric value of the `union value' in C for + variable V. + Case C must be drawn from V's dictionary. */ +double +case_num (const struct ccase *c, const struct variable *v) +{ + return case_num_idx (c, var_get_case_index (v)); } /* Returns the numeric value of the `union value' in C numbered @@ -294,57 +211,53 @@ case_data_idx (const struct ccase *c, size_t idx) double case_num_idx (const struct ccase *c, size_t idx) { - assert (c->case_data->ref_cnt > 0); - assert (idx < c->case_data->value_cnt); - - return c->case_data->values[idx].f; + assert (idx < c->n_values); + return c->values[idx].f; } -/* Returns the string value of the `union value' in C numbered - IDX. - (Note that the value is not null-terminated.) - The caller must not modify the return value. */ +/* Returns the string value of the `union value' in C for + variable V. Case C must be drawn from V's dictionary. The + caller must not modify the return value. + + Like all "union value"s, the return value is not + null-terminated. */ const char * -case_str_idx (const struct ccase *c, size_t idx) +case_str (const struct ccase *c, const struct variable *v) { - assert (c->case_data->ref_cnt > 0); - assert (idx < c->case_data->value_cnt); - - return c->case_data->values[idx].s; + return case_str_idx (c, var_get_case_index (v)); } -/* Returns a pointer to the `union value' used for the - element of C numbered IDX. - The caller is allowed to modify the returned data. */ -union value * -case_data_rw_idx (struct ccase *c, size_t idx) -{ - assert (c->case_data->ref_cnt > 0); - assert (idx < c->case_data->value_cnt); +/* Returns the string value of the `union value' in C numbered + IDX. The caller must not modify the return value. - case_unshare (c); - return &c->case_data->values[idx]; + Like all "union value"s, the return value is not + null-terminated. */ +const char * +case_str_idx (const struct ccase *c, size_t idx) +{ + assert (idx < c->n_values); + return c->values[idx].s; } -/* Compares the values of the VAR_CNT variables in VP +/* Compares the values of the N_VARS variables in VP in cases A and B and returns a strcmp()-type result. */ int case_compare (const struct ccase *a, const struct ccase *b, - const struct variable *const *vp, size_t var_cnt) + const struct variable *const *vp, size_t n_vars) { - return case_compare_2dict (a, b, vp, vp, var_cnt); + return case_compare_2dict (a, b, vp, vp, n_vars); } -/* Compares the values of the VAR_CNT variables in VAP in case CA - to the values of the VAR_CNT variables in VBP in CB +/* Compares the values of the N_VARS variables in VAP in case CA + to the values of the N_VARS variables in VBP in CB and returns a strcmp()-type result. */ int case_compare_2dict (const struct ccase *ca, const struct ccase *cb, const struct variable *const *vap, - const struct variable *const *vbp, - size_t var_cnt) + const struct variable *const *vbp, + size_t n_vars) { - for (; var_cnt-- > 0; vap++, vbp++) + for (; n_vars-- > 0; vap++, vbp++) { const struct variable *va = *vap; const struct variable *vb = *vbp; @@ -375,26 +288,34 @@ case_compare_2dict (const struct ccase *ca, const struct ccase *cb, /* Returns a pointer to the array of `union value's used for C. The caller must *not* modify the returned data. - NOTE: This function breaks the case abstraction. It should - *not* be used often. Prefer the other case functions. */ + This function breaks the case abstraction. It should *not* be + commonly used. Prefer the other case functions. */ const union value * case_data_all (const struct ccase *c) { - assert (c->case_data->ref_cnt > 0); - - return c->case_data->values; + return c->values; } /* Returns a pointer to the array of `union value's used for C. The caller is allowed to modify the returned data. - NOTE: This function breaks the case abstraction. It should - *not* be used often. Prefer the other case functions. */ + Case C must not be shared. + + This function breaks the case abstraction. It should *not* be + commonly used. Prefer the other case functions. */ union value * case_data_all_rw (struct ccase *c) { - assert (c->case_data->ref_cnt > 0); + assert (!case_is_shared (c)); + return c->values; +} - case_unshare (c); - return c->case_data->values; +/* Internal helper function for case_unshare. */ +struct ccase * +case_unshare__ (struct ccase *old) +{ + struct ccase *new = case_create (old->n_values); + memcpy (new->values, old->values, old->n_values * sizeof old->values[0]); + --old->ref_cnt; + return new; } diff --git a/src/data/case.h b/src/data/case.h index aa5b9dd0..6f537726 100644 --- a/src/data/case.h +++ b/src/data/case.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2004, 2007 Free Software Foundation, Inc. + Copyright (C) 2004, 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 @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include "value.h" struct variable; @@ -29,57 +31,130 @@ struct variable; #define CASENUMBER_MAX LONG_MAX typedef long int casenumber; -/* Opaque structure that represents a case. Use accessor - functions instead of accessing any members directly. Use - case_move() or case_clone() instead of copying. */ +/* Reference-counted case implementation. + + A newly created case has a single owner (the code that created + it), represented by an initial reference count of 1. Other + code that receives the case may keep a virtual copy of it by + calling case_ref, which increments the case's reference count. + When this is done, the case becomes shared between its + original owner and each piece of code that incremented the + reference count. + + A shared case (one whose reference count is greater than 1) + must not be modified, because this would make the case change + in the view of every reference count holder, not just the one + that intended to change the case. Because the purpose of + keeping the reference count is to make a virtual copy of the + case, this is undesirable behavior. The case_unshare function + provides a solution, by making a new, unshared copy of a + shared case. */ struct ccase { - struct case_data *case_data; /* Actual data. */ + size_t n_values; /* Number of values. */ + size_t ref_cnt; /* Reference count. */ + union value values[1]; /* Values. */ }; -void case_nullify (struct ccase *); -bool case_is_null (const struct ccase *); +struct ccase *case_create (size_t n_values) MALLOC_LIKE; +struct ccase *case_try_create (size_t n_values) MALLOC_LIKE; -void case_create (struct ccase *, size_t value_cnt); -void case_clone (struct ccase *, const struct ccase *); -void case_move (struct ccase *, struct ccase *); -void case_destroy (struct ccase *); +static inline struct ccase *case_unshare (struct ccase *) WARN_UNUSED_RESULT; +static inline struct ccase *case_ref (const struct ccase *); +static inline void case_unref (struct ccase *); +static inline bool case_is_shared (const struct ccase *); -size_t case_get_value_cnt (const struct ccase *); +static inline size_t case_get_value_cnt (const struct ccase *); -void case_resize (struct ccase *, size_t new_cnt); -void case_swap (struct ccase *, struct ccase *); - -bool case_try_create (struct ccase *, size_t value_cnt); -bool case_try_clone (struct ccase *, const struct ccase *); +struct ccase *case_resize (struct ccase *, size_t new_cnt) WARN_UNUSED_RESULT; +struct ccase *case_unshare_and_resize (struct ccase *, size_t new_cnt) + WARN_UNUSED_RESULT; void case_copy (struct ccase *dst, size_t dst_idx, const struct ccase *src, size_t src_idx, size_t cnt); void case_copy_out (const struct ccase *, - size_t start_idx, union value *, size_t value_cnt); + size_t start_idx, union value *, size_t n_values); void case_copy_in (struct ccase *, - size_t start_idx, const union value *, size_t value_cnt); + size_t start_idx, const union value *, size_t n_values); const union value *case_data (const struct ccase *, const struct variable *); -double case_num (const struct ccase *, const struct variable *); -const char *case_str (const struct ccase *, const struct variable *); +const union value *case_data_idx (const struct ccase *, size_t idx); union value *case_data_rw (struct ccase *, const struct variable *); +union value *case_data_rw_idx (struct ccase *, size_t idx); -const union value *case_data_idx (const struct ccase *, size_t idx); +double case_num (const struct ccase *, const struct variable *); double case_num_idx (const struct ccase *, size_t idx); + +const char *case_str (const struct ccase *, const struct variable *); const char *case_str_idx (const struct ccase *, size_t idx); -union value *case_data_rw_idx (struct ccase *, size_t idx); int case_compare (const struct ccase *, const struct ccase *, - const struct variable *const *, size_t var_cnt); + const struct variable *const *, size_t n_vars); int case_compare_2dict (const struct ccase *, const struct ccase *, const struct variable *const *, const struct variable *const *, - size_t var_cnt); + size_t n_vars); const union value *case_data_all (const struct ccase *); union value *case_data_all_rw (struct ccase *); + +struct ccase *case_unshare__ (struct ccase *); + +/* If C is a shared case, that is, if it has a reference count + greater than 1, makes a new unshared copy and returns it, + decrementing C's reference count. If C is not shared (its + reference count is 1), returns C. + + This function should be used before attempting to modify any + of the data in a case that might be shared, e.g.: + c = case_unshare (c); // Make sure that C is not shared. + case_data_rw (c, myvar)->f = 1; // Modify data in C. +*/ +static inline struct ccase * +case_unshare (struct ccase *c) +{ + if (case_is_shared (c)) + c = case_unshare__ (c); + return c; +} + +/* Increments case C's reference count and returns C. Afterward, + case C is shared among its reference count holders. */ +static inline struct ccase * +case_ref (const struct ccase *c_) +{ + struct ccase *c = (struct ccase *) c_; + c->ref_cnt++; + return c; +} + +/* Decrements case C's reference count. Frees C if its + reference count drops to 0. + + If C is a null pointer, this function has no effect. */ +static inline void +case_unref (struct ccase *c) +{ + if (c != NULL && !--c->ref_cnt) + free (c); +} + +/* Returns true if case C is shared. A case that is shared + cannot be modified directly. Instead, an unshared copy must + first be made with case_unshare(). */ +static inline bool +case_is_shared (const struct ccase *c) +{ + return c->ref_cnt > 1; +} + +/* Returns the number of union values in C. */ +static inline size_t +case_get_value_cnt (const struct ccase *c) +{ + return c->n_values; +} #endif /* data/case.h */ diff --git a/src/data/casegrouper.c b/src/data/casegrouper.c index 75925650..86788ba7 100644 --- a/src/data/casegrouper.c +++ b/src/data/casegrouper.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -80,28 +80,26 @@ casegrouper_get_next_group (struct casegrouper *grouper, if (grouper->same_group != NULL) { struct casewriter *writer; - struct ccase group_case, tmp; + struct ccase *group_case, *tmp; - if (!casereader_read (grouper->reader, &group_case)) + group_case = casereader_read (grouper->reader); + if (group_case == NULL) { *reader = NULL; return false; } writer = autopaging_writer_create (casereader_get_value_cnt (grouper->reader)); - case_clone (&tmp, &group_case); - casewriter_write (writer, &tmp); + case_ref (group_case); + casewriter_write (writer, group_case); - while (casereader_peek (grouper->reader, 0, &tmp) - && grouper->same_group (&group_case, &tmp, grouper->aux)) + while ((tmp = casereader_peek (grouper->reader, 0)) != NULL + && grouper->same_group (group_case, tmp, grouper->aux)) { - struct ccase discard; - casereader_read (grouper->reader, &discard); - case_destroy (&discard); - casewriter_write (writer, &tmp); + case_unref (casereader_read (grouper->reader)); + casewriter_write (writer, tmp); } - case_destroy (&tmp); - case_destroy (&group_case); + case_unref (group_case); *reader = casewriter_make_reader (writer); return true; diff --git a/src/data/caseinit.c b/src/data/caseinit.c index f789244d..4f7ece7e 100644 --- a/src/data/caseinit.c +++ b/src/data/caseinit.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -247,7 +247,8 @@ caseinit_mark_for_init (struct caseinit *ci, const struct dictionary *d) init_list_mark (&ci->left_values, &ci->preinited_values, LEAVE_LEFT, d); } -/* Initializes variables in C as described by CI. */ +/* Initializes variables in *C as described by CI. + C must not be shared. */ void caseinit_init_vars (const struct caseinit *ci, struct ccase *c) { diff --git a/src/data/casereader-filter.c b/src/data/casereader-filter.c index fcd264e9..d387f5ea 100644 --- a/src/data/casereader-filter.c +++ b/src/data/casereader-filter.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -86,22 +86,22 @@ casereader_create_filter_func (struct casereader *subreader, } /* Internal read function for filtering casereader. */ -static bool -casereader_filter_read (struct casereader *reader UNUSED, void *filter_, - struct ccase *c) +static struct ccase * +casereader_filter_read (struct casereader *reader UNUSED, void *filter_) { struct casereader_filter *filter = filter_; for (;;) { - if (!casereader_read (filter->subreader, c)) - return false; + struct ccase *c = casereader_read (filter->subreader); + if (c == NULL) + return NULL; else if (filter->include (c, filter->aux)) - return true; + return c; else if (filter->exclude != NULL) casewriter_write (filter->exclude, c); else - case_destroy (c); + case_unref (c); } } @@ -115,12 +115,12 @@ casereader_filter_destroy (struct casereader *reader, void *filter_) casewriter, if there is one. */ if (filter->exclude != NULL) { - struct ccase c; - while (casereader_read (filter->subreader, &c)) - if (filter->include (&c, filter->aux)) - case_destroy (&c); + struct ccase *c; + while ((c = casereader_read (filter->subreader)) != NULL) + if (filter->include (c, filter->aux)) + case_unref (c); else - casewriter_write (filter->exclude, &c); + casewriter_write (filter->exclude, c); } casereader_destroy (filter->subreader); diff --git a/src/data/casereader-provider.h b/src/data/casereader-provider.h index 77220981..31d8a6d4 100644 --- a/src/data/casereader-provider.h +++ b/src/data/casereader-provider.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -43,20 +43,23 @@ struct casereader_class { /* Mandatory. - Reads the next case from READER into case C, which the - casereader must create and which the client is responsible - for destroying. If successful, returns true and advances - READER to the next case, so that the next call to this - function will read the next case. The case just read will - never be read again by a call to this function for READER. + Reads the next case from READER. If successful, returns + the case and advances READER, so that the next call to + this function will read the following case. The case just + read will never be read again by a call to this function + for READER. - At end of file or upon an I/O error, returns false. After - false is returned once, this function will not be called - again for the given READER. + If a case is successfully returned, the client is + responsible for calling case_unref upon it when it is no + longer needed. + + At end of file or upon an I/O error, returns a null + pointer. After null is returned once, this function will + not be called again for the given READER. If an I/O error occurs, this function should call casereader_force_error on READER. */ - bool (*read) (struct casereader *reader, void *aux, struct ccase *c); + struct ccase *(*read) (struct casereader *reader, void *aux); /* Mandatory. @@ -88,22 +91,23 @@ struct casereader_class (But it might be easier to use the random-access casereader wrapper instead.) - Reads the case at 0-based offset IDX from the beginning of - READER into case C, which the casereader must create and - which the client is responsible for destroying. + Reads and returns the case at 0-based offset IDX from the + beginning of READER. If a case is successfully returned, + the client is responsible for calling case_unref upon it + when it is no longer needed. - At end of file or upon an I/O error, returns false. If - this function returns false, then it will never be called - again for an equal or greater value of IDX, and the "read" - member function will never be called to advance as far as - IDX cases further into the casereader. That is, returning - false indicates that the casereader has fewer than IDX - cases left. + At end of file or upon an I/O error, returns a null + pointer. If this function returns null, then it will + never be called again for an equal or greater value of + IDX, and the "read" member function will never be called + to advance as far as IDX cases further into the + casereader. That is, returning null indicates that the + casereader has fewer than IDX cases left. If an I/O error occurs, this function should call casereader_force_error on READER. */ - bool (*peek) (struct casereader *reader, void *aux, casenumber idx, - struct ccase *c); + struct ccase *(*peek) (struct casereader *reader, void *aux, + casenumber idx); }; struct casereader * @@ -119,21 +123,22 @@ struct casereader_random_class /* Mandatory. Reads the case at 0-based offset IDX from the beginning of - READER into case C, which the casereader must create and - which the client is responsible for destroying. - - At end of file or upon an I/O error, returns false. If - this function returns false, then it will never be called - again for an equal or greater value of IDX, and the "read" - member function will never be called to advance as far as - IDX cases further into the casereader. That is, returning - false indicates that the casereader has fewer than IDX - cases. + READER. If a case is successfully returned, the client is + responsible for calling case_unref upon it when it is no + longer needed. + + At end of file or upon an I/O error, returns a null + pointer. If this function returns null, then it will + never be called again for an equal or greater value of + IDX, and the "read" member function will never be called + to advance as far as IDX cases further into the + casereader. That is, returning null indicates that the + casereader has fewer than IDX cases. If an I/O error occurs, this function should call casereader_force_error on READER. */ - bool (*read) (struct casereader *reader, void *aux, casenumber idx, - struct ccase *c); + struct ccase *(*read) (struct casereader *reader, void *aux, + casenumber idx); /* Mandatory. diff --git a/src/data/casereader-translator.c b/src/data/casereader-translator.c index ae22f129..d55e18e5 100644 --- a/src/data/casereader-translator.c +++ b/src/data/casereader-translator.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -32,7 +32,7 @@ struct casereader_translator { struct casereader *subreader; /* Source of input cases. */ - void (*translate) (struct ccase *input, struct ccase *output, void *aux); + struct ccase *(*translate) (struct ccase *input, void *aux); bool (*destroy) (void *aux); void *aux; }; @@ -41,9 +41,9 @@ static const struct casereader_class casereader_translator_class; /* Creates and returns a new casereader whose cases are produced by reading from SUBREADER and passing through TRANSLATE, which - must create case OUTPUT, with OUTPUT_VALUE_CNT values, and - populate it based on INPUT and auxiliary data AUX. TRANSLATE - must also destroy INPUT. + must return the translated case, with OUTPUT_VALUE_CNT values, + and populate it based on INPUT and auxiliary data AUX. + TRANSLATE must destroy its input case. When the translating casereader is destroyed, DESTROY will be called to allow any state maintained by TRANSLATE to be freed. @@ -54,9 +54,8 @@ static const struct casereader_class casereader_translator_class; struct casereader * casereader_create_translator (struct casereader *subreader, size_t output_value_cnt, - void (*translate) (struct ccase *input, - struct ccase *output, - void *aux), + struct ccase *(*translate) (struct ccase *input, + void *aux), bool (*destroy) (void *aux), void *aux) { @@ -75,20 +74,15 @@ casereader_create_translator (struct casereader *subreader, } /* Internal read function for translating casereader. */ -static bool +static struct ccase * casereader_translator_read (struct casereader *reader UNUSED, - void *ct_, struct ccase *c) + void *ct_) { struct casereader_translator *ct = ct_; - struct ccase tmp; - - if (casereader_read (ct->subreader, &tmp)) - { - ct->translate (&tmp, c, ct->aux); - return true; - } - else - return false; + struct ccase *tmp = casereader_read (ct->subreader); + if (tmp) + tmp = ct->translate (tmp, ct->aux); + return tmp; } /* Internal destroy function for translating casereader. */ @@ -123,8 +117,7 @@ struct casereader_append_numeric static bool can_destroy (void *can_); -static void can_translate (struct ccase *input, struct ccase *output, - void *can_); +static struct ccase *can_translate (struct ccase *, void *can_); /* Creates and returns a new casereader whose cases are produced by reading from SUBREADER and appending an additional value, @@ -152,15 +145,14 @@ casereader_create_append_numeric (struct casereader *subreader, } -static void -can_translate (struct ccase *input, struct ccase *output, void *can_) +static struct ccase * +can_translate (struct ccase *c, void *can_) { struct casereader_append_numeric *can = can_; - double new_value = can->func (input, can->n++, can->aux); - case_nullify (output); - case_move (output, input); - case_resize (output, can->value_ofs + 1); - case_data_rw_idx (output, can->value_ofs)->f = new_value; + double new_value = can->func (c, can->n++, can->aux); + c = case_unshare_and_resize (c, can->value_ofs + 1); + case_data_rw_idx (c, can->value_ofs)->f = new_value; + return c; } static bool @@ -231,8 +223,7 @@ struct casereader_append_rank static bool car_destroy (void *car_); -static void car_translate (struct ccase *input, struct ccase *output, - void *car_); +static struct ccase *car_translate (struct ccase *input, void *car_); /* Creates and returns a new casereader whose cases are produced by reading from SUBREADER and appending an additional value, @@ -293,9 +284,8 @@ car_destroy (void *car_) return true; } - -static void -car_translate (struct ccase *input, struct ccase *output, void *car_) +static struct ccase * +car_translate (struct ccase *input, void *car_) { struct casereader_append_rank *car = car_; @@ -321,16 +311,16 @@ car_translate (struct ccase *input, struct ccase *output, void *car_) do { - struct ccase c; - if ( ! casereader_peek (car->clone, car->n + ++k, &c)) + struct ccase *c = casereader_peek (car->clone, car->n + ++k); + if (c == NULL) break; - vxx = case_data (&c, car->var)->f; + vxx = case_data (c, car->var)->f; if ( vxx == value) { if (car->weight) { - double w = case_data (&c, car->weight)->f; + double w = case_data (c, car->weight)->f; if ( car->err && w < 0 ) *car->err |= RANK_ERR_NEGATIVE_WEIGHT; @@ -341,7 +331,7 @@ car_translate (struct ccase *input, struct ccase *output, void *car_) weight += 1.0; car->n_common++; } - case_destroy (&c); + case_unref (c); } while (vxx == value); car->mean_rank = car->cc + (weight + 1) / 2.0; @@ -355,11 +345,10 @@ car_translate (struct ccase *input, struct ccase *output, void *car_) car->n++; - case_nullify (output); - case_move (output, input); - case_resize (output, car->value_ofs + 1); - case_data_rw_idx (output, car->value_ofs)->f = car->mean_rank ; + input = case_unshare_and_resize (input, car->value_ofs + 1); + case_data_rw_idx (input, car->value_ofs)->f = car->mean_rank ; car->prev_value = value; + return input; } diff --git a/src/data/casereader.c b/src/data/casereader.c index ee7facb7..3d27a919 100644 --- a/src/data/casereader.c +++ b/src/data/casereader.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -43,18 +43,17 @@ struct casereader static void insert_shim (struct casereader *); -/* Creates a new case in C and reads the next case from READER - into it. The caller owns C and must destroy C when its data - is no longer needed. Return true if successful, false when - cases have been exhausted or upon detection of an I/O error. - In the latter case, C is set to the null case. +/* Reads and returns the next case from READER. The caller owns + the returned case and must call case_unref on it when its data + is no longer needed. Returns a null pointer if cases have + been exhausted or upon detection of an I/O error. The case returned is effectively consumed: it can never be read again through READER. If this is inconvenient, READER may be cloned in advance with casereader_clone, or casereader_peek may be used instead. */ -bool -casereader_read (struct casereader *reader, struct ccase *c) +struct ccase * +casereader_read (struct casereader *reader) { if (reader->case_cnt != 0) { @@ -69,17 +68,18 @@ casereader_read (struct casereader *reader, struct ccase *c) case_cnt after calling ->read, then this would actually drop two cases from case_cnt instead of one, and we'd lose the last case in the casereader. */ + struct ccase *c; if (reader->case_cnt != CASENUMBER_MAX) reader->case_cnt--; - if (reader->class->read (reader, reader->aux, c)) + c = reader->class->read (reader, reader->aux); + if (c != NULL) { assert (case_get_value_cnt (c) >= reader->value_cnt); - return true; + return c; } } reader->case_cnt = 0; - case_nullify (c); - return false; + return NULL; } /* Destroys READER. @@ -160,27 +160,27 @@ casereader_swap (struct casereader *a, struct casereader *b) } } -/* Creates a new case in C and reads the (IDX + 1)'th case from - READER into it. The caller owns C and must destroy C when its - data is no longer needed. Return true if successful, false - when cases have been exhausted or upon detection of an I/O - error. In the latter case, C is set to the null case. */ -bool -casereader_peek (struct casereader *reader, casenumber idx, struct ccase *c) +/* Reads and returns the (IDX + 1)'th case from READER. The + caller owns the returned case and must call case_unref on it + when it is no longer needed. Returns a null pointer if cases + have been exhausted or upon detection of an I/O error. */ +struct ccase * +casereader_peek (struct casereader *reader, casenumber idx) { if (idx < reader->case_cnt) { + struct ccase *c; if (reader->class->peek == NULL) insert_shim (reader); - if (reader->class->peek (reader, reader->aux, idx, c)) - return true; + c = reader->class->peek (reader, reader->aux, idx); + if (c != NULL) + return c; else if (casereader_error (reader)) reader->case_cnt = 0; } if (reader->case_cnt > idx) reader->case_cnt = idx; - case_nullify (c); - return false; + return NULL; } /* Returns true if no cases remain to be read from READER, or if @@ -191,13 +191,18 @@ casereader_peek (struct casereader *reader, casenumber idx, struct ccase *c) bool casereader_is_empty (struct casereader *reader) { - struct ccase c; - if (reader->case_cnt == 0 || !casereader_peek (reader, 0, &c)) + if (reader->case_cnt == 0) return true; else { - case_destroy (&c); - return false; + struct ccase *c = casereader_peek (reader, 0); + if (c == NULL) + return true; + else + { + case_unref (c); + return false; + } } } @@ -263,11 +268,11 @@ casereader_count_cases (struct casereader *reader) if (reader->case_cnt == CASENUMBER_MAX) { casenumber n_cases = 0; - struct ccase c; + struct ccase *c; struct casereader *clone = casereader_clone (reader); - for (; casereader_read (clone, &c); case_destroy (&c)) + for (; (c = casereader_read (clone)) != NULL; case_unref (c)) n_cases++; casereader_destroy (clone); @@ -289,12 +294,12 @@ casereader_get_value_cnt (struct casereader *reader) void casereader_transfer (struct casereader *reader, struct casewriter *writer) { - struct ccase c; + struct ccase *c; taint_propagate (casereader_get_taint (reader), casewriter_get_taint (writer)); - while (casereader_read (reader, &c)) - casewriter_write (writer, &c); + while ((c = casereader_read (reader)) != NULL) + casewriter_write (writer, c); casereader_destroy (reader); } @@ -475,22 +480,20 @@ advance_random_reader (struct casereader *reader, } /* struct casereader_class "read" function for random reader. */ -static bool -random_reader_read (struct casereader *reader, void *br_, struct ccase *c) +static struct ccase * +random_reader_read (struct casereader *reader, void *br_) { struct random_reader *br = br_; struct random_reader_shared *shared = br->shared; - - if (shared->class->read (reader, shared->aux, - br->offset - shared->min_offset, c)) + struct ccase *c = shared->class->read (reader, shared->aux, + br->offset - shared->min_offset); + if (c != NULL) { br->offset++; heap_changed (shared->readers, &br->heap_node); advance_random_reader (reader, shared); - return true; } - else - return false; + return c; } /* struct casereader_class "destroy" function for random @@ -529,15 +532,14 @@ random_reader_clone (struct casereader *reader, void *br_) } /* struct casereader_class "peek" function for random reader. */ -static bool -random_reader_peek (struct casereader *reader, void *br_, - casenumber idx, struct ccase *c) +static struct ccase * +random_reader_peek (struct casereader *reader, void *br_, casenumber idx) { struct random_reader *br = br_; struct random_reader_shared *shared = br->shared; return shared->class->read (reader, shared->aux, - br->offset - shared->min_offset + idx, c); + br->offset - shared->min_offset + idx); } /* Casereader class for random reader. */ @@ -607,24 +609,27 @@ prime_buffer (struct shim *b, casenumber case_cnt) { while (casewindow_get_case_cnt (b->window) < case_cnt) { - struct ccase tmp; - if (!casereader_read (b->subreader, &tmp)) + struct ccase *tmp = casereader_read (b->subreader); + if (tmp == NULL) return false; - casewindow_push_head (b->window, &tmp); + casewindow_push_head (b->window, tmp); } return true; } /* Reads the case at the given 0-based OFFSET from the front of - the window into C. Returns true if successful, false if - OFFSET is beyond the end of file or upon I/O error. */ -static bool + the window into C. Returns the case if successful, or a null + pointer if OFFSET is beyond the end of file or upon I/O error. + The caller must call case_unref() on the returned case when it + is no longer needed. */ +static struct ccase * shim_read (struct casereader *reader UNUSED, void *b_, - casenumber offset, struct ccase *c) + casenumber offset) { struct shim *b = b_; - return (prime_buffer (b, offset + 1) - && casewindow_get_case (b->window, offset, c)); + if (!prime_buffer (b, offset + 1)) + return NULL; + return casewindow_get_case (b->window, offset); } /* Destroys B. */ diff --git a/src/data/casereader.h b/src/data/casereader.h index 3df80cb0..deab5641 100644 --- a/src/data/casereader.h +++ b/src/data/casereader.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -59,7 +59,7 @@ struct dictionary; struct casereader; struct casewriter; -bool casereader_read (struct casereader *, struct ccase *); +struct ccase *casereader_read (struct casereader *); bool casereader_destroy (struct casereader *); struct casereader *casereader_clone (const struct casereader *); @@ -68,8 +68,7 @@ void casereader_split (struct casereader *, struct casereader *casereader_rename (struct casereader *); void casereader_swap (struct casereader *, struct casereader *); -bool casereader_peek (struct casereader *, casenumber, struct ccase *) - WARN_UNUSED_RESULT; +struct ccase *casereader_peek (struct casereader *, casenumber); bool casereader_is_empty (struct casereader *); bool casereader_error (const struct casereader *); @@ -107,9 +106,8 @@ casereader_create_counter (struct casereader *, casenumber *counter, struct casereader * casereader_create_translator (struct casereader *, size_t output_value_cnt, - void (*translate) (struct ccase *input, - struct ccase *output, - void *aux), + struct ccase *(*translate) (struct ccase *, + void *aux), bool (*destroy) (void *aux), void *aux); diff --git a/src/data/casewindow.c b/src/data/casewindow.c index 0d735c4d..d2be9cfa 100644 --- a/src/data/casewindow.c +++ b/src/data/casewindow.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -52,7 +52,7 @@ struct casewindow_class void (*destroy) (void *aux); void (*push_head) (void *aux, struct ccase *); void (*pop_tail) (void *aux, casenumber cnt); - bool (*get_case) (void *aux, casenumber ofs, struct ccase *); + struct ccase *(*get_case) (void *aux, casenumber ofs); casenumber (*get_case_cnt) (const void *aux); }; @@ -120,11 +120,11 @@ casewindow_to_disk (struct casewindow *old) new = do_casewindow_create (taint_clone (old->taint), old->value_cnt, 0); while (casewindow_get_case_cnt (old) > 0 && !casewindow_error (new)) { - struct ccase c; - if (!casewindow_get_case (old, 0, &c)) + struct ccase *c = casewindow_get_case (old, 0); + if (c == NULL) break; casewindow_pop_tail (old, 1); - casewindow_push_head (new, &c); + casewindow_push_head (new, c); } casewindow_swap (old, new); casewindow_destroy (new); @@ -147,7 +147,7 @@ casewindow_push_head (struct casewindow *cw, struct ccase *c) } } else - case_destroy (c); + case_unref (c); } /* Deletes CASE_CNT cases at the tail of casewindow CW. */ @@ -158,23 +158,19 @@ casewindow_pop_tail (struct casewindow *cw, casenumber case_cnt) cw->class->pop_tail (cw->aux, case_cnt); } -/* Copies the case that is CASE_IDX cases away from CW's tail - into C. Returns true if successful, false on an I/O error or - if CW is otherwise tainted. On failure, nullifies case C. */ -bool -casewindow_get_case (const struct casewindow *cw_, casenumber case_idx, - struct ccase *c) +/* Returns the case that is CASE_IDX cases away from CW's tail + into C, or a null pointer on an I/O error or if CW is + otherwise tainted. The caller must call case_unref() on the + returned case when it is no longer needed. */ +struct ccase * +casewindow_get_case (const struct casewindow *cw_, casenumber case_idx) { struct casewindow *cw = (struct casewindow *) cw_; assert (case_idx >= 0 && case_idx < casewindow_get_case_cnt (cw)); - if (!casewindow_error (cw)) - return cw->class->get_case (cw->aux, case_idx, c); - else - { - case_nullify (c); - return false; - } + if (casewindow_error (cw)) + return NULL; + return cw->class->get_case (cw->aux, case_idx); } /* Returns the number of cases in casewindow CW. */ @@ -218,7 +214,7 @@ casewindow_get_taint (const struct casewindow *cw) struct casewindow_memory { struct deque deque; - struct ccase *cases; + struct ccase **cases; }; static void * @@ -234,7 +230,7 @@ casewindow_memory_destroy (void *cwm_) { struct casewindow_memory *cwm = cwm_; while (!deque_is_empty (&cwm->deque)) - case_destroy (&cwm->cases[deque_pop_front (&cwm->deque)]); + case_unref (cwm->cases[deque_pop_front (&cwm->deque)]); free (cwm->cases); free (cwm); } @@ -245,7 +241,7 @@ casewindow_memory_push_head (void *cwm_, struct ccase *c) struct casewindow_memory *cwm = cwm_; if (deque_is_full (&cwm->deque)) cwm->cases = deque_expand (&cwm->deque, cwm->cases, sizeof *cwm->cases); - case_move (&cwm->cases[deque_push_back (&cwm->deque)], c); + cwm->cases[deque_push_back (&cwm->deque)] = c; } static void @@ -254,15 +250,14 @@ casewindow_memory_pop_tail (void *cwm_, casenumber case_cnt) struct casewindow_memory *cwm = cwm_; assert (deque_count (&cwm->deque) >= case_cnt); while (case_cnt-- > 0) - case_destroy (&cwm->cases[deque_pop_front (&cwm->deque)]); + case_unref (cwm->cases[deque_pop_front (&cwm->deque)]); } -static bool -casewindow_memory_get_case (void *cwm_, casenumber ofs, struct ccase *c) +static struct ccase * +casewindow_memory_get_case (void *cwm_, casenumber ofs) { struct casewindow_memory *cwm = cwm_; - case_clone (c, &cwm->cases[deque_front (&cwm->deque, ofs)]); - return true; + return case_ref (cwm->cases[deque_front (&cwm->deque, ofs)]); } static casenumber @@ -325,11 +320,11 @@ casewindow_file_pop_tail (void *cwf_, casenumber cnt) cwf->head = cwf->tail = 0; } -static bool -casewindow_file_get_case (void *cwf_, casenumber ofs, struct ccase *c) +static struct ccase * +casewindow_file_get_case (void *cwf_, casenumber ofs) { struct casewindow_file *cwf = cwf_; - return case_tmpfile_get_case (cwf->file, cwf->tail + ofs, c); + return case_tmpfile_get_case (cwf->file, cwf->tail + ofs); } static casenumber diff --git a/src/data/casewindow.h b/src/data/casewindow.h index c3971231..f0a200f4 100644 --- a/src/data/casewindow.h +++ b/src/data/casewindow.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -37,8 +37,8 @@ bool casewindow_destroy (struct casewindow *); void casewindow_push_head (struct casewindow *, struct ccase *); void casewindow_pop_tail (struct casewindow *, casenumber cnt); -bool casewindow_get_case (const struct casewindow *, casenumber case_idx, - struct ccase *); +struct ccase *casewindow_get_case (const struct casewindow *, + casenumber case_idx); size_t casewindow_get_value_cnt (const struct casewindow *); casenumber casewindow_get_case_cnt (const struct casewindow *); diff --git a/src/data/casewriter-provider.h b/src/data/casewriter-provider.h index 8298af46..1680fe28 100644 --- a/src/data/casewriter-provider.h +++ b/src/data/casewriter-provider.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2006 Free Software Foundation, Inc. + Copyright (C) 2006, 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 @@ -23,7 +23,8 @@ struct casewriter_class { /* Mandatory. - Writes case C to WRITER. Destroys C before returning. + Writes case C to WRITER. Ownership of C is transferred to + WRITER. If an I/O error occurs, this function should call casewriter_force_error on WRITER. Some I/O error diff --git a/src/data/casewriter-translator.c b/src/data/casewriter-translator.c index c630b44c..a19533d6 100644 --- a/src/data/casewriter-translator.c +++ b/src/data/casewriter-translator.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -29,7 +29,7 @@ struct casewriter_translator { struct casewriter *subwriter; - void (*translate) (struct ccase *input, struct ccase *output, void *aux); + struct ccase *(*translate) (struct ccase *, void *aux); bool (*destroy) (void *aux); void *aux; }; @@ -37,10 +37,15 @@ struct casewriter_translator static const struct casewriter_class casewriter_translator_class; /* Creates and returns a new casewriter whose cases are passed - through TRANSLATE, which must create case OUTPUT, with - OUTPUT_VALUE_CNT values, and populate it based on INPUT and - auxiliary data AUX. The translated cases are then written to - SUBWRITER. TRANSLATE must also destroy INPUT. + through TRANSLATE, which must return a case with + OUTPUT_VALUE_CNT values, based on INPUT and auxiliary data + AUX. (TRANSLATE may also return a null pointer, in which case + no case is written to the output.) The translated cases are + then written to SUBWRITER. + + TRANSLATE takes ownership of each case passed to it. Thus, it + should either unref each case and return a new case, or + (unshare and then) modify and return the same case. When the translating casewriter is destroyed, DESTROY will be called to allow any state maintained by TRANSLATE to be freed. @@ -51,9 +56,8 @@ static const struct casewriter_class casewriter_translator_class; struct casewriter * casewriter_create_translator (struct casewriter *subwriter, size_t translated_value_cnt, - void (*translate) (struct ccase *input, - struct ccase *output, - void *aux), + struct ccase *(*translate) (struct ccase *, + void *aux), bool (*destroy) (void *aux), void *aux) { @@ -75,10 +79,9 @@ casewriter_translator_write (struct casewriter *writer UNUSED, void *ct_, struct ccase *c) { struct casewriter_translator *ct = ct_; - struct ccase tmp; - - ct->translate (c, &tmp, ct->aux); - casewriter_write (ct->subwriter, &tmp); + c = ct->translate (c, ct->aux); + if (c != NULL) + casewriter_write (ct->subwriter, c); } static void diff --git a/src/data/casewriter.c b/src/data/casewriter.c index 4461d85e..56e6c291 100644 --- a/src/data/casewriter.c +++ b/src/data/casewriter.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -250,18 +250,19 @@ casewriter_window_convert_to_reader (struct casewriter *writer UNUSED, return reader; } -/* Reads the case at the given 0-based OFFSET from the front of - WINDOW into C. Returns true if successful, false if - OFFSET is beyond the end of file or upon I/O error. */ -static bool +/* Reads and returns the case at the given 0-based OFFSET from + the front of WINDOW into C. Returns a null pointer if OFFSET + is beyond the end of file or upon I/O error. The caller must + call case_unref() on the returned case when it is no longer + needed.*/ +static struct ccase * casereader_window_read (struct casereader *reader UNUSED, void *window_, - casenumber offset, struct ccase *c) + casenumber offset) { struct casewindow *window = window_; if (offset >= casewindow_get_case_cnt (window)) - return false; - else - return casewindow_get_case (window, offset, c); + return NULL; + return casewindow_get_case (window, offset); } /* Destroys casewindow reader WINDOW. */ diff --git a/src/data/casewriter.h b/src/data/casewriter.h index a92c4176..05ef7072 100644 --- a/src/data/casewriter.h +++ b/src/data/casewriter.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -43,9 +43,8 @@ struct casewriter *autopaging_writer_create (size_t value_cnt); struct casewriter * casewriter_create_translator (struct casewriter *, size_t translated_value_cnt, - void (*translate) (struct ccase *input, - struct ccase *output, - void *aux), + struct ccase *(*translate) (struct ccase *input, + void *aux), bool (*destroy) (void *aux), void *aux); diff --git a/src/data/datasheet.c b/src/data/datasheet.c index fd07ed30..83a2a677 100644 --- a/src/data/datasheet.c +++ b/src/data/datasheet.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -389,21 +389,22 @@ datasheet_move_columns (struct datasheet *ds, axis_move (ds->columns, old_start, new_start, cnt); } -/* Retrieves the contents of the given ROW in datasheet DS into - newly created case C. Returns true if successful, false on - I/O error. */ -bool -datasheet_get_row (const struct datasheet *ds, casenumber row, struct ccase *c) +/* Retrieves and returns the contents of the given ROW in + datasheet DS. The caller owns the returned case and must + unref it when it is no longer needed. Returns a null pointer + on I/O error. */ +struct ccase * +datasheet_get_row (const struct datasheet *ds, casenumber row) { size_t column_cnt = datasheet_get_column_cnt (ds); - case_create (c, column_cnt); + struct ccase *c = case_create (column_cnt); if (rw_case ((struct datasheet *) ds, OP_READ, row, 0, column_cnt, case_data_all_rw (c))) - return true; + return c; else { - case_destroy (c); - return false; + case_unref (c); + return NULL; } } @@ -417,7 +418,7 @@ datasheet_put_row (struct datasheet *ds, casenumber row, struct ccase *c) size_t column_cnt = datasheet_get_column_cnt (ds); bool ok = rw_case (ds, OP_WRITE, row, 0, column_cnt, (union value *) case_data_all (c)); - case_destroy (c); + case_unref (c); return ok; } @@ -445,13 +446,15 @@ datasheet_put_value (struct datasheet *ds, casenumber row, size_t column, (union value *) value); } -/* Inserts the CNT cases at C, which are destroyed, into - datasheet DS just before row BEFORE. Returns true if - successful, false on I/O error. On failure, datasheet DS is - not modified. */ +/* Inserts the CNT cases at C into datasheet DS just before row + BEFORE. Returns true if successful, false on I/O error. On + failure, datasheet DS is not modified. + + Regardless of success, this function unrefs all of the cases + in C. */ bool datasheet_insert_rows (struct datasheet *ds, - casenumber before, struct ccase c[], + casenumber before, struct ccase *c[], casenumber cnt) { casenumber added = 0; @@ -476,10 +479,10 @@ datasheet_insert_rows (struct datasheet *ds, /* Initialize the new rows. */ for (i = 0; i < phy_cnt; i++) - if (!datasheet_put_row (ds, before + i, &c[i])) + if (!datasheet_put_row (ds, before + i, c[i])) { while (++i < cnt) - case_destroy (&c[i]); + case_unref (c[i]); datasheet_delete_rows (ds, before - added, phy_cnt + added); return false; } @@ -540,20 +543,20 @@ datasheet_make_reader (struct datasheet *ds) } /* "read" function for the datasheet random casereader. */ -static bool +static struct ccase * datasheet_reader_read (struct casereader *reader UNUSED, void *ds_, - casenumber case_idx, struct ccase *c) + casenumber case_idx) { struct datasheet *ds = ds_; - if (case_idx >= datasheet_get_row_cnt (ds)) - return false; - else if (datasheet_get_row (ds, case_idx, c)) - return true; - else + if (case_idx < datasheet_get_row_cnt (ds)) { - taint_set_taint (ds->taint); - return false; + struct ccase *c = datasheet_get_row (ds, case_idx); + if (c == NULL) + taint_set_taint (ds->taint); + return c; } + else + return NULL; } /* "destroy" function for the datasheet random casereader. */ @@ -1136,15 +1139,12 @@ source_read (const struct source *source, return sparse_cases_read (source->data, row, column, values, value_cnt); else { - struct ccase c; - bool ok; - - assert (source->backing != NULL); - ok = casereader_peek (source->backing, row, &c); + struct ccase *c = casereader_peek (source->backing, row); + bool ok = c != NULL; if (ok) { - case_copy_out (&c, column, values, value_cnt); - case_destroy (&c); + case_copy_out (c, column, values, value_cnt); + case_unref (c); } return ok; } @@ -1169,9 +1169,10 @@ source_write (struct source *source, ok = sparse_cases_write (source->data, row, column, values, value_cnt); else { - struct ccase c; + struct ccase *c; + if (row < source->backing_rows) - ok = casereader_peek (source->backing, row, &c); + c = case_unshare (casereader_peek (source->backing, row)); else { /* It's not one of the backed rows. Ideally, this @@ -1182,15 +1183,16 @@ source_write (struct source *source, levels, so that we in fact usually write the full contents of new, unbacked rows in multiple calls to this function. Make this work. */ - case_create (&c, column_cnt); - ok = true; + c = case_create (column_cnt); } + ok = c != NULL; + if (ok) { - case_copy_in (&c, column, values, value_cnt); + case_copy_in (c, column, values, value_cnt); ok = sparse_cases_write (source->data, row, 0, - case_data_all (&c), column_cnt); - case_destroy (&c); + case_data_all (c), column_cnt); + case_unref (c); } } return ok; diff --git a/src/data/datasheet.h b/src/data/datasheet.h index 2a05fe0d..860f236e 100644 --- a/src/data/datasheet.h +++ b/src/data/datasheet.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -50,7 +50,7 @@ void datasheet_move_columns (struct datasheet *, /* Rows. */ casenumber datasheet_get_row_cnt (const struct datasheet *); bool datasheet_insert_rows (struct datasheet *, - casenumber before, struct ccase[], + casenumber before, struct ccase *[], casenumber cnt); void datasheet_delete_rows (struct datasheet *, casenumber first, casenumber cnt); @@ -59,7 +59,7 @@ void datasheet_move_rows (struct datasheet *, size_t cnt); /* Data. */ -bool datasheet_get_row (const struct datasheet *, casenumber, struct ccase *); +struct ccase *datasheet_get_row (const struct datasheet *, casenumber); bool datasheet_put_row (struct datasheet *, casenumber, struct ccase *); bool datasheet_get_value (const struct datasheet *, casenumber, size_t column, union value *, int width); diff --git a/src/data/gnumeric-reader.c b/src/data/gnumeric-reader.c index 52217664..5a0c75ed 100644 --- a/src/data/gnumeric-reader.c +++ b/src/data/gnumeric-reader.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -60,8 +60,7 @@ gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict) static void gnm_file_casereader_destroy (struct casereader *, void *); -static bool gnm_file_casereader_read (struct casereader *, void *, - struct ccase *); +static struct ccase *gnm_file_casereader_read (struct casereader *, void *); static const struct casereader_class gnm_file_casereader_class = { @@ -172,7 +171,7 @@ struct gnumeric_reader size_t value_cnt; struct dictionary *dict; - struct ccase first_case; + struct ccase *first_case; bool used_first_case; }; @@ -193,7 +192,7 @@ gnm_file_casereader_destroy (struct casereader *reader UNUSED, void *r_) xmlFreeTextReader (r->xtr); if ( ! r->used_first_case ) - case_destroy (&r->first_case); + case_unref (r->first_case); free (r); } @@ -537,15 +536,15 @@ gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict) goto error; } - case_create (&r->first_case, r->value_cnt); - memset (case_data_rw_idx (&r->first_case, 0)->s, + r->first_case = case_create (r->value_cnt); + memset (case_data_rw_idx (r->first_case, 0)->s, ' ', MAX_SHORT_STRING * r->value_cnt); for ( i = 0 ; i < n_var_specs ; ++i ) { const struct variable *var = dict_get_var (r->dict, i); - convert_xml_string_to_value (&r->first_case, var, + convert_xml_string_to_value (r->first_case, var, var_spec[i].first_value); } @@ -580,12 +579,12 @@ gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict) }; -/* Reads one case from READER's file into C. Returns true only - if successful. */ -static bool -gnm_file_casereader_read (struct casereader *reader UNUSED, void *r_, - struct ccase *c) +/* Reads and returns one case from READER's file. Returns a null + pointer on failure. */ +static struct ccase * +gnm_file_casereader_read (struct casereader *reader UNUSED, void *r_) { + struct ccase *c; int ret = 0; struct gnumeric_reader *r = r_; @@ -593,12 +592,11 @@ gnm_file_casereader_read (struct casereader *reader UNUSED, void *r_, if ( !r->used_first_case ) { - *c = r->first_case; r->used_first_case = true; - return true; + return r->first_case; } - case_create (c, r->value_cnt); + c = case_create (r->value_cnt); memset (case_data_rw_idx (c, 0)->s, ' ', MAX_SHORT_STRING * r->value_cnt); @@ -632,7 +630,13 @@ gnm_file_casereader_read (struct casereader *reader UNUSED, void *r_, } - return (ret == 1); + if (ret == 1) + return c; + else + { + case_unref (c); + return NULL; + } } diff --git a/src/data/lazy-casereader.c b/src/data/lazy-casereader.c index 2cb8911f..65d10aea 100644 --- a/src/data/lazy-casereader.c +++ b/src/data/lazy-casereader.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -117,13 +117,12 @@ instantiate_lazy_casereader (struct casereader *reader, casereader_destroy (subreader); } -static bool -lazy_casereader_read (struct casereader *reader, void *lc_, - struct ccase *c) +static struct ccase * +lazy_casereader_read (struct casereader *reader, void *lc_) { struct lazy_casereader *lc = lc_; instantiate_lazy_casereader (reader, lc); - return casereader_read (reader, c); + return casereader_read (reader); } static void @@ -143,13 +142,12 @@ lazy_casereader_clone (struct casereader *reader, void *lc_) return casereader_clone (reader); } -static bool -lazy_casereader_peek (struct casereader *reader, void *lc_, - casenumber idx, struct ccase *c) +static struct ccase * +lazy_casereader_peek (struct casereader *reader, void *lc_, casenumber idx) { struct lazy_casereader *lc = lc_; instantiate_lazy_casereader (reader, lc); - return casereader_peek (reader, idx, c); + return casereader_peek (reader, idx); } static const struct casereader_class lazy_casereader_class = diff --git a/src/data/por-file-reader.c b/src/data/por-file-reader.c index 52c0cc8e..7e65c28b 100644 --- a/src/data/por-file-reader.c +++ b/src/data/por-file-reader.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 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 @@ -814,28 +814,30 @@ read_documents (struct pfm_reader *r, struct dictionary *dict) } } -/* Reads one case from portable file R into C. */ -static bool -por_file_casereader_read (struct casereader *reader, void *r_, struct ccase *c) +/* Reads and returns one case from portable file R. Returns a + null pointer on failure. */ +static struct ccase * +por_file_casereader_read (struct casereader *reader, void *r_) { struct pfm_reader *r = r_; + struct ccase *volatile c; size_t i; size_t idx; - case_create (c, casereader_get_value_cnt (reader)); + c = case_create (casereader_get_value_cnt (reader)); setjmp (r->bail_out); if (!r->ok) { casereader_force_error (reader); - case_destroy (c); - return false; + case_unref (c); + return NULL; } /* Check for end of file. */ if (r->cc == 'Z') { - case_destroy (c); - return false; + case_unref (c); + return NULL; } idx = 0; @@ -857,7 +859,7 @@ por_file_casereader_read (struct casereader *reader, void *r_, struct ccase *c) } } - return true; + return c; } /* Returns true if FILE is an SPSS portable file, diff --git a/src/data/por-file-reader.h b/src/data/por-file-reader.h index f227fd9a..326514f9 100644 --- a/src/data/por-file-reader.h +++ b/src/data/por-file-reader.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 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 @@ -34,7 +34,6 @@ struct pfm_read_info struct dictionary; struct file_handle; -struct ccase; struct casereader *pfm_open_reader (struct file_handle *, struct dictionary **, struct pfm_read_info *); diff --git a/src/data/por-file-writer.c b/src/data/por-file-writer.c index 8a27f6b7..77396930 100644 --- a/src/data/por-file-writer.c +++ b/src/data/por-file-writer.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 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 @@ -463,7 +463,7 @@ por_file_casewriter_write (struct casewriter *writer, void *w_, else casewriter_force_error (writer); - case_destroy (c); + case_unref (c); } static void diff --git a/src/data/por-file-writer.h b/src/data/por-file-writer.h index b018a4f4..04eaaa2c 100644 --- a/src/data/por-file-writer.h +++ b/src/data/por-file-writer.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 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 @@ -38,7 +38,6 @@ struct pfm_write_options struct file_handle; struct dictionary; -struct ccase; struct casewriter *pfm_open_writer (struct file_handle *, struct dictionary *, struct pfm_write_options); struct pfm_write_options pfm_writer_default_options (void); diff --git a/src/data/procedure.c b/src/data/procedure.c index 98414a2b..91e185a4 100644 --- a/src/data/procedure.c +++ b/src/data/procedure.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006, 2007 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 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 @@ -79,7 +79,7 @@ struct dataset { /* Cases just before ("lagging") the current one. */ int n_lag; /* Number of cases to lag. */ struct deque lag; /* Deque of lagged cases. */ - struct ccase *lag_cases; /* Lagged cases managed by deque. */ + struct ccase **lag_cases; /* Lagged cases managed by deque. */ /* Procedure data. */ enum @@ -203,15 +203,15 @@ proc_is_open (const struct dataset *ds) } /* "read" function for procedure casereader. */ -static bool -proc_casereader_read (struct casereader *reader UNUSED, void *ds_, - struct ccase *c) +static struct ccase * +proc_casereader_read (struct casereader *reader UNUSED, void *ds_) { struct dataset *ds = ds_; enum trns_result retval = TRNS_DROP_CASE; + struct ccase *c; assert (ds->proc_state == PROC_OPEN); - for (;;) + for (; ; case_unref (c)) { casenumber case_nr; @@ -219,58 +219,47 @@ proc_casereader_read (struct casereader *reader UNUSED, void *ds_, if (retval == TRNS_ERROR) ds->ok = false; if (!ds->ok) - return false; + return NULL; /* Read a case from source. */ - if (!casereader_read (ds->source, c)) - return false; - case_resize (c, dict_get_next_value_idx (ds->dict)); + c = casereader_read (ds->source); + if (c == NULL) + return NULL; + c = case_unshare_and_resize (c, dict_get_next_value_idx (ds->dict)); caseinit_init_vars (ds->caseinit, c); /* Execute permanent transformations. */ case_nr = ds->cases_written + 1; retval = trns_chain_execute (ds->permanent_trns_chain, TRNS_CONTINUE, - c, case_nr); + &c, case_nr); caseinit_update_left_vars (ds->caseinit, c); if (retval != TRNS_CONTINUE) - { - case_destroy (c); - continue; - } + continue; /* Write case to collection of lagged cases. */ if (ds->n_lag > 0) { while (deque_count (&ds->lag) >= ds->n_lag) - case_destroy (&ds->lag_cases[deque_pop_back (&ds->lag)]); - case_clone (&ds->lag_cases[deque_push_front (&ds->lag)], c); + case_unref (ds->lag_cases[deque_pop_back (&ds->lag)]); + ds->lag_cases[deque_push_front (&ds->lag)] = case_ref (c); } /* Write case to replacement active file. */ ds->cases_written++; if (ds->sink != NULL) - { - struct ccase tmp; - if (ds->compactor != NULL) - case_map_execute (ds->compactor, c, &tmp); - else - case_clone (&tmp, c); - casewriter_write (ds->sink, &tmp); - } + casewriter_write (ds->sink, + case_map_execute (ds->compactor, case_ref (c))); /* Execute temporary transformations. */ if (ds->temporary_trns_chain != NULL) { retval = trns_chain_execute (ds->temporary_trns_chain, TRNS_CONTINUE, - c, ds->cases_written); + &c, ds->cases_written); if (retval != TRNS_CONTINUE) - { - case_destroy (c); - continue; - } + continue; } - return true; + return c; } } @@ -279,13 +268,13 @@ static void proc_casereader_destroy (struct casereader *reader, void *ds_) { struct dataset *ds = ds_; - struct ccase c; + struct ccase *c; /* Make sure transformations happen for every input case, in case they have side effects, and ensure that the replacement active file gets all the cases it should. */ - while (casereader_read (reader, &c)) - case_destroy (&c); + while ((c = casereader_read (reader)) != NULL) + case_unref (c); ds->proc_state = PROC_CLOSED; ds->ok = casereader_destroy (ds->source) && ds->ok; @@ -306,7 +295,7 @@ proc_commit (struct dataset *ds) /* Free memory for lagged cases. */ while (!deque_is_empty (&ds->lag)) - case_destroy (&ds->lag_cases[deque_pop_back (&ds->lag)]); + case_unref (ds->lag_cases[deque_pop_back (&ds->lag)]); free (ds->lag_cases); /* Dictionary from before TEMPORARY becomes permanent. */ @@ -361,14 +350,14 @@ update_last_proc_invocation (struct dataset *ds) /* Returns a pointer to the lagged case from N_BEFORE cases before the current one, or NULL if there haven't been that many cases yet. */ -struct ccase * +const struct ccase * lagged_case (const struct dataset *ds, int n_before) { assert (n_before >= 1); assert (n_before <= ds->n_lag); if (n_before <= deque_count (&ds->lag)) - return &ds->lag_cases[deque_front (&ds->lag, n_before - 1)]; + return ds->lag_cases[deque_front (&ds->lag, n_before - 1)]; else return NULL; } @@ -679,7 +668,7 @@ add_case_limit_trns (struct dataset *ds) *CASES_REMAINING. */ static int case_limit_trns_proc (void *cases_remaining_, - struct ccase *c UNUSED, casenumber case_nr UNUSED) + struct ccase **c UNUSED, casenumber case_nr UNUSED) { size_t *cases_remaining = cases_remaining_; if (*cases_remaining > 0) @@ -718,11 +707,11 @@ add_filter_trns (struct dataset *ds) /* FILTER transformation. */ static int filter_trns_proc (void *filter_var_, - struct ccase *c UNUSED, casenumber case_nr UNUSED) + struct ccase **c UNUSED, casenumber case_nr UNUSED) { struct variable *filter_var = filter_var_; - double f = case_num (c, filter_var); + double f = case_num (*c, filter_var); return (f != 0.0 && !var_is_num_missing (filter_var, f, MV_ANY) ? TRNS_CONTINUE : TRNS_DROP_CASE); } diff --git a/src/data/procedure.h b/src/data/procedure.h index 336725df..5d998030 100644 --- a/src/data/procedure.h +++ b/src/data/procedure.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006, 2007 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 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 @@ -82,7 +82,7 @@ struct dictionary *dataset_dict (const struct dataset *ds); const struct casereader *dataset_source (const struct dataset *ds); -struct ccase *lagged_case (const struct dataset *ds, int n_before); +const struct ccase *lagged_case (const struct dataset *ds, int n_before); void dataset_need_lag (struct dataset *ds, int n_before); #endif /* procedure.h */ diff --git a/src/data/psql-reader.c b/src/data/psql-reader.c index 244248a2..a54b9f8b 100644 --- a/src/data/psql-reader.c +++ b/src/data/psql-reader.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2008 Free Software Foundation, Inc. + Copyright (C) 2008, 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 @@ -75,8 +75,7 @@ psql_open_reader (struct psql_read_info *info UNUSED, struct dictionary **dict U static void psql_casereader_destroy (struct casereader *reader UNUSED, void *r_); -static bool psql_casereader_read (struct casereader *, void *, - struct ccase *); +static struct ccase *psql_casereader_read (struct casereader *, void *); static const struct casereader_class psql_casereader_class = { @@ -109,8 +108,7 @@ struct psql_reader }; -static bool set_value (struct psql_reader *r, - struct ccase *cc); +static struct ccase *set_value (struct psql_reader *r); @@ -546,9 +544,8 @@ psql_casereader_destroy (struct casereader *reader UNUSED, void *r_) -static bool -psql_casereader_read (struct casereader *reader UNUSED, void *r_, - struct ccase *cc) +static struct ccase * +psql_casereader_read (struct casereader *reader UNUSED, void *r_) { struct psql_reader *r = r_; @@ -558,24 +555,24 @@ psql_casereader_read (struct casereader *reader UNUSED, void *r_, return false; } - return set_value (r, cc); + return set_value (r); } -static bool -set_value (struct psql_reader *r, - struct ccase *c) +static struct ccase * +set_value (struct psql_reader *r) { - int i; + struct ccase *c; int n_vars; + int i; assert (r->res); n_vars = PQnfields (r->res); if ( r->tuple >= PQntuples (r->res)) - return false; + return NULL; - case_create (c, r->value_cnt); + c = case_create (r->value_cnt); memset (case_data_rw_idx (c, 0)->s, ' ', MAX_SHORT_STRING * r->value_cnt); @@ -870,7 +867,7 @@ set_value (struct psql_reader *r, r->tuple++; - return true; + return c; } #endif diff --git a/src/data/scratch-reader.h b/src/data/scratch-reader.h index 44531a49..a5ee005e 100644 --- a/src/data/scratch-reader.h +++ b/src/data/scratch-reader.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2006 Free Software Foundation, Inc. + Copyright (C) 2006, 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 @@ -21,7 +21,6 @@ struct dictionary; struct file_handle; -struct ccase; struct casereader *scratch_reader_open (struct file_handle *, struct dictionary **); diff --git a/src/data/scratch-writer.c b/src/data/scratch-writer.c index ed88af6d..952860cd 100644 --- a/src/data/scratch-writer.c +++ b/src/data/scratch-writer.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2006 Free Software Foundation, Inc. + Copyright (C) 2006, 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 @@ -99,15 +99,8 @@ scratch_writer_casewriter_write (struct casewriter *w UNUSED, void *writer_, struct ccase *c) { struct scratch_writer *writer = writer_; - struct ccase tmp; - if (writer->compactor) - { - case_map_execute (writer->compactor, c, &tmp); - case_destroy (c); - } - else - case_move (&tmp, c); - casewriter_write (writer->subwriter, &tmp); + casewriter_write (writer->subwriter, + case_map_execute (writer->compactor, c)); } /* Closes WRITER. */ diff --git a/src/data/scratch-writer.h b/src/data/scratch-writer.h index d2fda12a..a9c7a4d9 100644 --- a/src/data/scratch-writer.h +++ b/src/data/scratch-writer.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2006 Free Software Foundation, Inc. + Copyright (C) 2006, 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 @@ -21,7 +21,6 @@ struct dictionary; struct file_handle; -struct ccase; struct casewriter *scratch_writer_open (struct file_handle *, const struct dictionary *); diff --git a/src/data/sparse-cases.c b/src/data/sparse-cases.c index 1f3fb092..13fcf788 100644 --- a/src/data/sparse-cases.c +++ b/src/data/sparse-cases.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -49,7 +50,7 @@ sparse_cases_create (size_t column_cnt) sc->column_cnt = column_cnt; sc->default_columns = NULL; sc->max_memory_cases = settings_get_workspace_cases (column_cnt); - sc->memory = sparse_array_create (sizeof (struct ccase)); + sc->memory = sparse_array_create (sizeof (struct ccase *)); sc->disk = NULL; sc->disk_cases = NULL; return sc; @@ -76,12 +77,15 @@ sparse_cases_clone (const struct sparse_cases *old) 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_scan (old->memory, NULL, &idx); cp != NULL; + cp = sparse_array_scan (old->memory, &idx, &idx)) + { + struct ccase **ncp = sparse_array_insert (new->memory, idx); + *ncp = case_ref (*cp); + } } else new->memory = NULL; @@ -98,15 +102,16 @@ sparse_cases_clone (const struct sparse_cases *old) 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; - } + + for (idx = start; idx < end; idx++) + { + 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 @@ -127,10 +132,10 @@ sparse_cases_destroy (struct sparse_cases *sc) 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_scan (sc->memory, NULL, &idx); cp != NULL; + cp = sparse_array_scan (sc->memory, &idx, &idx)) + case_unref (*cp); sparse_array_destroy (sc->memory); } free (sc->default_columns); @@ -154,7 +159,7 @@ static bool 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); @@ -162,10 +167,10 @@ 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_scan (sc->memory, NULL, &idx); cp != NULL; + cp = sparse_array_scan (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; @@ -202,13 +207,20 @@ sparse_cases_read (struct sparse_cases *sc, casenumber row, size_t column, if (sparse_cases_contains_row (sc, row)) { - struct ccase c; + 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 **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 { @@ -225,20 +237,24 @@ 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; + 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); @@ -255,8 +271,11 @@ sparse_cases_write (struct sparse_cases *sc, casenumber row, size_t column, { 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) { @@ -265,8 +284,8 @@ sparse_cases_write (struct sparse_cases *sc, casenumber row, size_t column, 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); @@ -302,12 +321,15 @@ sparse_cases_write_columns (struct sparse_cases *sc, size_t start_column, /* Set individual rows. */ 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_scan (sc->memory, NULL, &idx); cp != NULL; + cp = sparse_array_scan (sc->memory, &idx, &idx)) + { + *cp = case_unshare (*cp); + case_copy_in (*cp, start_column, values, value_cnt); + } } else { diff --git a/src/data/subcase.c b/src/data/subcase.c index 3e019c7c..d4b13783 100644 --- a/src/data/subcase.c +++ b/src/data/subcase.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2008 Free Software Foundation, Inc. + Copyright (C) 2008, 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 @@ -168,7 +168,9 @@ subcase_inject (const struct subcase *sc, /* Copies the fields in SRC represented by SRC_SC into the corresponding fields in DST respresented by DST_SC. SRC_SC and DST_SC must be conformable (as tested by - subcase_conformable()). */ + subcase_conformable()). + + DST must not be shared. */ void subcase_copy (const struct subcase *src_sc, const struct ccase *src, const struct subcase *dst_sc, struct ccase *dst) diff --git a/src/data/sys-file-reader.c b/src/data/sys-file-reader.c index c80bd5f5..af09189e 100644 --- a/src/data/sys-file-reader.c +++ b/src/data/sys-file-reader.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006, 2007 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 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 @@ -1304,24 +1304,24 @@ static bool read_compressed_string (struct sfm_reader *, char *); static bool read_whole_strings (struct sfm_reader *, char *, size_t); static bool skip_whole_strings (struct sfm_reader *, size_t); -/* Reads one case from READER's file into C. Returns true only - if successful. */ -static bool -sys_file_casereader_read (struct casereader *reader, void *r_, - struct ccase *c) +/* Reads and returns one case from READER's file. Returns a null + pointer if not successful. */ +static struct ccase * +sys_file_casereader_read (struct casereader *reader, void *r_) { struct sfm_reader *r = r_; + struct ccase *volatile c; int i; if (r->error) - return false; + return NULL; - case_create (c, r->value_cnt); + c = case_create (r->value_cnt); if (setjmp (r->bail_out)) { casereader_force_error (reader); - case_destroy (c); - return false; + case_unref (c); + return NULL; } for (i = 0; i < r->sfm_var_cnt; i++) @@ -1342,15 +1342,15 @@ sys_file_casereader_read (struct casereader *reader, void *r_, partial_record (r); } } - return true; + return c; eof: - case_destroy (c); + case_unref (c); if (i != 0) partial_record (r); if (r->case_cnt != -1) read_error (reader, r); - return false; + return NULL; } /* Issues an error that R ends in a partial record. */ diff --git a/src/data/sys-file-reader.h b/src/data/sys-file-reader.h index eaf051fe..24285749 100644 --- a/src/data/sys-file-reader.h +++ b/src/data/sys-file-reader.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 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 @@ -47,7 +47,6 @@ struct sfm_read_info struct dictionary; struct file_handle; -struct ccase; struct casereader *sfm_open_reader (struct file_handle *, struct dictionary **, struct sfm_read_info *); diff --git a/src/data/sys-file-writer.c b/src/data/sys-file-writer.c index aa539a51..393be4e1 100644 --- a/src/data/sys-file-writer.c +++ b/src/data/sys-file-writer.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006, 2007 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 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 @@ -126,8 +126,9 @@ static void write_zeros (struct sfm_writer *, size_t); static void write_spaces (struct sfm_writer *, size_t); static void write_value (struct sfm_writer *, const union value *, int width); -static void write_case_uncompressed (struct sfm_writer *, struct ccase *); -static void write_case_compressed (struct sfm_writer *, struct ccase *); +static void write_case_uncompressed (struct sfm_writer *, + const struct ccase *); +static void write_case_compressed (struct sfm_writer *, const struct ccase *); static void flush_compressed (struct sfm_writer *); static void put_cmp_opcode (struct sfm_writer *, uint8_t); static void put_cmp_number (struct sfm_writer *, double); @@ -747,7 +748,7 @@ sys_file_casewriter_write (struct casewriter *writer, void *w_, if (ferror (w->file)) { casewriter_force_error (writer); - case_destroy (c); + case_unref (c); return; } @@ -758,7 +759,7 @@ sys_file_casewriter_write (struct casewriter *writer, void *w_, else write_case_compressed (w, c); - case_destroy (c); + case_unref (c); } /* Destroys system file writer W. */ @@ -836,7 +837,7 @@ static const struct casewriter_class sys_file_casewriter_class = /* Writes case C to system file W, without compressing it. */ static void -write_case_uncompressed (struct sfm_writer *w, struct ccase *c) +write_case_uncompressed (struct sfm_writer *w, const struct ccase *c) { size_t i; @@ -857,7 +858,7 @@ write_case_uncompressed (struct sfm_writer *w, struct ccase *c) /* Writes case C to system file W, with compression. */ static void -write_case_compressed (struct sfm_writer *w, struct ccase *c) +write_case_compressed (struct sfm_writer *w, const struct ccase *c) { size_t i; diff --git a/src/data/sys-file-writer.h b/src/data/sys-file-writer.h index c6128d45..fdff49fe 100644 --- a/src/data/sys-file-writer.h +++ b/src/data/sys-file-writer.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 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 @@ -31,7 +31,6 @@ struct sfm_write_options struct file_handle; struct dictionary; -struct ccase; struct casewriter *sfm_open_writer (struct file_handle *, struct dictionary *, struct sfm_write_options); struct sfm_write_options sfm_writer_default_options (void); diff --git a/src/data/transformations.c b/src/data/transformations.c index 08b43139..2a73cade 100644 --- a/src/data/transformations.c +++ b/src/data/transformations.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 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 @@ -178,14 +178,15 @@ trns_chain_next (struct trns_chain *chain) return chain->trns_cnt; } -/* Executes the given CHAIN of transformations on C, +/* Executes the given CHAIN of transformations on *C, passing CASE_NR as the case number. + *C may be replaced by a new case. Returns the result code that caused the transformations to terminate, or TRNS_CONTINUE if the transformations finished due to "falling off the end" of the set of transformations. */ enum trns_result trns_chain_execute (const struct trns_chain *chain, enum trns_result start, - struct ccase *c, casenumber case_nr) + struct ccase **c, casenumber case_nr) { size_t i; diff --git a/src/data/transformations.h b/src/data/transformations.h index 0a8c53e2..59001f11 100644 --- a/src/data/transformations.h +++ b/src/data/transformations.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 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 @@ -33,7 +33,7 @@ enum trns_result struct ccase; typedef void trns_finalize_func (void *); -typedef int trns_proc_func (void *, struct ccase *, casenumber); +typedef int trns_proc_func (void *, struct ccase **, casenumber); typedef bool trns_free_func (void *); /* Transformation chains. */ @@ -47,8 +47,9 @@ bool trns_chain_is_empty (const struct trns_chain *); void trns_chain_append (struct trns_chain *, trns_finalize_func *, trns_proc_func *, trns_free_func *, void *); size_t trns_chain_next (struct trns_chain *); -enum trns_result trns_chain_execute (const struct trns_chain *, enum trns_result, - struct ccase *, casenumber case_nr); +enum trns_result trns_chain_execute (const struct trns_chain *, + enum trns_result, struct ccase **, + casenumber case_nr); void trns_chain_splice (struct trns_chain *, struct trns_chain *); diff --git a/src/language/control/do-if.c b/src/language/control/do-if.c index 61c450a5..b3b6135f 100644 --- a/src/language/control/do-if.c +++ b/src/language/control/do-if.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 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 @@ -240,7 +240,7 @@ do_if_finalize_func (void *do_if_ UNUSED) Checks each clause and jumps to the appropriate transformation. */ static int -do_if_trns_proc (void *do_if_, struct ccase *c, casenumber case_num UNUSED) +do_if_trns_proc (void *do_if_, struct ccase **c, casenumber case_num UNUSED) { struct do_if_trns *do_if = do_if_; struct clause *clause; @@ -250,7 +250,7 @@ do_if_trns_proc (void *do_if_, struct ccase *c, casenumber case_num UNUSED) { if (clause->condition != NULL) { - double boolean = expr_evaluate_num (clause->condition, c, case_num); + double boolean = expr_evaluate_num (clause->condition, *c, case_num); if (boolean == 1.0) return clause->target_index; else if (boolean == SYSMIS) @@ -279,7 +279,8 @@ do_if_trns_free (void *do_if_) /* Breaks out of a DO IF construct. */ static int -break_trns_proc (void *do_if_, struct ccase *c UNUSED, casenumber case_num UNUSED) +break_trns_proc (void *do_if_, struct ccase **c UNUSED, + casenumber case_num UNUSED) { struct do_if_trns *do_if = do_if_; diff --git a/src/language/control/loop.c b/src/language/control/loop.c index 40a33c11..f5d205d4 100644 --- a/src/language/control/loop.c +++ b/src/language/control/loop.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 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 @@ -304,21 +304,22 @@ loop_trns_finalize (void *do_if_ UNUSED) /* Sets up LOOP for the first pass. */ static int -loop_trns_proc (void *loop_, struct ccase *c, casenumber case_num) +loop_trns_proc (void *loop_, struct ccase **c, casenumber case_num) { struct loop_trns *loop = loop_; if (loop->index_var != NULL) { /* Evaluate loop index expressions. */ - loop->cur = expr_evaluate_num (loop->first_expr, c, case_num); + loop->cur = expr_evaluate_num (loop->first_expr, *c, case_num); if (loop->by_expr != NULL) - loop->by = expr_evaluate_num (loop->by_expr, c, case_num); - loop->last = expr_evaluate_num (loop->last_expr, c, case_num); + loop->by = expr_evaluate_num (loop->by_expr, *c, case_num); + loop->last = expr_evaluate_num (loop->last_expr, *c, case_num); /* Even if the loop is never entered, set the index variable to the initial value. */ - case_data_rw (c, loop->index_var)->f = loop->cur; + *c = case_unshare (*c); + case_data_rw (*c, loop->index_var)->f = loop->cur; /* Throw out pathological cases. */ if (!isfinite (loop->cur) || !isfinite (loop->by) @@ -336,7 +337,7 @@ loop_trns_proc (void *loop_, struct ccase *c, casenumber case_num) /* Check condition. */ if (loop->loop_condition != NULL - && expr_evaluate_num (loop->loop_condition, c, case_num) != 1.0) + && expr_evaluate_num (loop->loop_condition, *c, case_num) != 1.0) goto zero_pass; return loop->past_LOOP_index; @@ -357,12 +358,12 @@ loop_trns_free (void *loop_) /* Finishes a pass through the loop and starts the next. */ static int -end_loop_trns_proc (void *loop_, struct ccase *c, casenumber case_num UNUSED) +end_loop_trns_proc (void *loop_, struct ccase **c, casenumber case_num UNUSED) { struct loop_trns *loop = loop_; if (loop->end_loop_condition != NULL - && expr_evaluate_num (loop->end_loop_condition, c, case_num) != 0.0) + && expr_evaluate_num (loop->end_loop_condition, *c, case_num) != 0.0) goto break_out; /* MXLOOPS limiter. */ @@ -380,11 +381,12 @@ end_loop_trns_proc (void *loop_, struct ccase *c, casenumber case_num UNUSED) if ((loop->by > 0.0 && loop->cur > loop->last) || (loop->by < 0.0 && loop->cur < loop->last)) goto break_out; - case_data_rw (c, loop->index_var)->f = loop->cur; + *c = case_unshare (*c); + case_data_rw (*c, loop->index_var)->f = loop->cur; } if (loop->loop_condition != NULL - && expr_evaluate_num (loop->loop_condition, c, case_num) != 1.0) + && expr_evaluate_num (loop->loop_condition, *c, case_num) != 1.0) goto break_out; return loop->past_LOOP_index; @@ -395,7 +397,8 @@ end_loop_trns_proc (void *loop_, struct ccase *c, casenumber case_num UNUSED) /* Executes BREAK. */ static int -break_trns_proc (void *loop_, struct ccase *c UNUSED, casenumber case_num UNUSED) +break_trns_proc (void *loop_, struct ccase **c UNUSED, + casenumber case_num UNUSED) { struct loop_trns *loop = loop_; diff --git a/src/language/data-io/combine-files.c b/src/language/data-io/combine-files.c index 1451743d..ccbe7679 100644 --- a/src/language/data-io/combine-files.c +++ b/src/language/data-io/combine-files.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006, 2007, 2008 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 2007, 2008, 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 @@ -72,7 +72,7 @@ struct comb_file struct file_handle *handle; /* Input file handle. */ struct dictionary *dict; /* Input file dictionary. */ struct casereader *reader; /* Input data source. */ - struct ccase data; /* The current input case. */ + struct ccase *data; /* The current input case. */ bool is_minimal; /* Does 'data' have minimum BY values across all input files? */ bool is_sorted; /* Is file presorted on the BY variables? */ @@ -98,8 +98,8 @@ struct comb_proc members used. */ struct variable *first; /* Variable specified on FIRST (if any). */ struct variable *last; /* Variable specified on LAST (if any). */ - struct ccase buffered_case; /* Case ready for output except that we don't - know the value for the LAST variable yet. */ + struct ccase *buffered_case; /* Case ready for output except that we don't + know the value for the LAST var yet. */ union value *prev_BY; /* Values of BY vars in buffered_case. */ }; @@ -165,7 +165,7 @@ combine_files (enum comb_command_type command, subcase_init_empty (&proc.by_vars); proc.first = NULL; proc.last = NULL; - case_nullify (&proc.buffered_case); + proc.buffered_case = NULL; proc.prev_BY = NULL; dict_set_case_limit (proc.dict, dict_get_case_limit (dataset_dict (ds))); @@ -198,7 +198,7 @@ combine_files (enum comb_command_type command, file->handle = NULL; file->dict = NULL; file->reader = NULL; - case_nullify (&file->data); + file->data = NULL; file->is_sorted = true; file->in_name[0] = '\0'; file->in_var = NULL; @@ -444,7 +444,7 @@ combine_files (enum comb_command_type command, if (!file->is_sorted) file->reader = sort_execute (file->reader, &file->by_vars); taint_propagate (casereader_get_taint (file->reader), taint); - casereader_read (file->reader, &file->data); + file->data = casereader_read (file->reader); if (file->type == COMB_FILE) case_matcher_add_input (proc.matcher, &file->by_vars, &file->data, &file->is_minimal); @@ -605,7 +605,7 @@ close_all_comb_files (struct comb_proc *proc) fh_unref (file->handle); dict_destroy (file->dict); casereader_destroy (file->reader); - case_destroy (&file->data); + case_unref (file->data); } free (proc->files); proc->files = NULL; @@ -621,12 +621,12 @@ free_comb_proc (struct comb_proc *proc) casewriter_destroy (proc->output); case_matcher_destroy (proc->matcher); subcase_destroy (&proc->by_vars); - case_destroy (&proc->buffered_case); + case_unref (proc->buffered_case); free (proc->prev_BY); } static bool scan_table (struct comb_file *, union value by[]); -static void create_output_case (const struct comb_proc *, struct ccase *); +static struct ccase *create_output_case (const struct comb_proc *); static void apply_case (const struct comb_file *, struct ccase *); static void apply_file_case_and_advance (struct comb_file *, struct ccase *, union value by[]); @@ -641,7 +641,6 @@ execute_add_files (struct comb_proc *proc) while (case_matcher_match (proc->matcher, &by)) { - struct ccase output; size_t i; for (i = 0; i < proc->n_files; i++) @@ -649,9 +648,9 @@ execute_add_files (struct comb_proc *proc) struct comb_file *file = &proc->files[i]; while (file->is_minimal) { - create_output_case (proc, &output); - apply_file_case_and_advance (file, &output, by); - output_case (proc, &output, by); + struct ccase *output = create_output_case (proc); + apply_file_case_and_advance (file, output, by); + output_case (proc, output, by); } } } @@ -666,25 +665,25 @@ execute_match_files (struct comb_proc *proc) while (case_matcher_match (proc->matcher, &by)) { - struct ccase output; + struct ccase *output; size_t i; - create_output_case (proc, &output); + output = create_output_case (proc); for (i = proc->n_files; i-- > 0; ) { struct comb_file *file = &proc->files[i]; if (file->type == COMB_FILE) { if (file->is_minimal) - apply_file_case_and_advance (file, &output, NULL); + apply_file_case_and_advance (file, output, NULL); } else { if (scan_table (file, by)) - apply_case (file, &output); + apply_case (file, output); } } - output_case (proc, &output, by); + output_case (proc, output, by); } output_buffered_case (proc); } @@ -699,15 +698,15 @@ execute_update (struct comb_proc *proc) while (case_matcher_match (proc->matcher, &by)) { struct comb_file *first, *file; - struct ccase output; + struct ccase *output; /* Find first nonnull case in array and make an output case from it. */ - create_output_case (proc, &output); + output = create_output_case (proc); for (first = &proc->files[0]; ; first++) if (first->is_minimal) break; - apply_file_case_and_advance (first, &output, by); + apply_file_case_and_advance (first, output, by); /* Read additional cases and update the output case from them. (Don't update the output case from any duplicate @@ -716,9 +715,9 @@ execute_update (struct comb_proc *proc) file < &proc->files[proc->n_files]; file++) { while (file->is_minimal) - apply_file_case_and_advance (file, &output, by); + apply_file_case_and_advance (file, output, by); } - casewriter_write (proc->output, &output); + casewriter_write (proc->output, output); /* Write duplicate cases in the master file directly to the output. */ @@ -727,9 +726,9 @@ execute_update (struct comb_proc *proc) n_duplicates++; while (first->is_minimal) { - create_output_case (proc, &output); - apply_file_case_and_advance (first, &output, by); - casewriter_write (proc->output, &output); + output = create_output_case (proc); + apply_file_case_and_advance (first, output, by); + casewriter_write (proc->output, output); } } } @@ -746,13 +745,13 @@ execute_update (struct comb_proc *proc) static bool scan_table (struct comb_file *file, union value by[]) { - while (!case_is_null (&file->data)) + while (file->data != NULL) { - int cmp = subcase_compare_3way_xc (&file->by_vars, by, &file->data); + int cmp = subcase_compare_3way_xc (&file->by_vars, by, file->data); if (cmp > 0) { - case_destroy (&file->data); - casereader_read (file->reader, &file->data); + case_unref (file->data); + file->data = casereader_read (file->reader); } else return cmp == 0; @@ -760,16 +759,17 @@ scan_table (struct comb_file *file, union value by[]) return false; } -/* Creates OUTPUT as an output case for PROC, by initializing each of - its values to system-missing or blanks, except that the values - of IN variables are set to 0. */ -static void -create_output_case (const struct comb_proc *proc, struct ccase *output) +/* Creates and returns an output case for PROC, initializing each + of its values to system-missing or blanks, except that the + values of IN variables are set to 0. */ +static struct ccase * +create_output_case (const struct comb_proc *proc) { size_t n_vars = dict_get_var_cnt (proc->dict); + struct ccase *output; size_t i; - case_create (output, dict_get_next_value_idx (proc->dict)); + output = case_create (dict_get_next_value_idx (proc->dict)); for (i = 0; i < n_vars; i++) { struct variable *v = dict_get_var (proc->dict, i); @@ -781,6 +781,7 @@ create_output_case (const struct comb_proc *proc, struct ccase *output) if (file->in_var != NULL) case_data_rw (output, file->in_var)->f = false; } + return output; } /* Copies the data from FILE's case into output case OUTPUT. @@ -788,7 +789,7 @@ create_output_case (const struct comb_proc *proc, struct ccase *output) static void apply_case (const struct comb_file *file, struct ccase *output) { - subcase_copy (&file->src, &file->data, &file->dst, output); + subcase_copy (&file->src, file->data, &file->dst, output); if (file->in_var != NULL) case_data_rw (output, file->in_var)->f = true; } @@ -802,11 +803,11 @@ apply_file_case_and_advance (struct comb_file *file, struct ccase *output, union value by[]) { apply_case (file, output); - case_destroy (&file->data); - casereader_read (file->reader, &file->data); + case_unref (file->data); + file->data = casereader_read (file->reader); if (by) - file->is_minimal = (!case_is_null (&file->data) - && subcase_equal_cx (&file->by_vars, &file->data, by)); + file->is_minimal = (file->data != NULL + && subcase_equal_cx (&file->by_vars, file->data, by)); } /* Writes OUTPUT, whose BY values has been extracted into BY, to @@ -828,15 +829,15 @@ output_case (struct comb_proc *proc, struct ccase *output, union value by[]) { new_BY = !subcase_equal_xx (&proc->by_vars, proc->prev_BY, by); if (proc->last != NULL) - case_data_rw (&proc->buffered_case, proc->last)->f = new_BY; - casewriter_write (proc->output, &proc->buffered_case); + case_data_rw (proc->buffered_case, proc->last)->f = new_BY; + casewriter_write (proc->output, proc->buffered_case); } else new_BY = true; - case_move (&proc->buffered_case, output); + proc->buffered_case = output; if (proc->first != NULL) - case_data_rw (&proc->buffered_case, proc->first)->f = new_BY; + case_data_rw (proc->buffered_case, proc->first)->f = new_BY; if (new_BY) { @@ -857,8 +858,8 @@ output_buffered_case (struct comb_proc *proc) if (proc->prev_BY != NULL) { if (proc->last != NULL) - case_data_rw (&proc->buffered_case, proc->last)->f = 1.0; - casewriter_write (proc->output, &proc->buffered_case); - case_nullify (&proc->buffered_case); + case_data_rw (proc->buffered_case, proc->last)->f = 1.0; + casewriter_write (proc->output, proc->buffered_case); + proc->buffered_case = NULL; } } diff --git a/src/language/data-io/data-list.c b/src/language/data-io/data-list.c index 7a2a074b..d07eae5c 100644 --- a/src/language/data-io/data-list.c +++ b/src/language/data-io/data-list.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006, 2007 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 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 @@ -463,14 +463,15 @@ data_list_trns_free (void *trns_) return true; } -/* Handle DATA LIST transformation TRNS, parsing data into C. */ +/* Handle DATA LIST transformation TRNS, parsing data into *C. */ static int -data_list_trns_proc (void *trns_, struct ccase *c, casenumber case_num UNUSED) +data_list_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED) { struct data_list_trns *trns = trns_; int retval; - if (data_parser_parse (trns->parser, trns->reader, c)) + *c = case_unshare (*c); + if (data_parser_parse (trns->parser, trns->reader, *c)) retval = TRNS_CONTINUE; else if (dfm_reader_error (trns->reader) || dfm_eof (trns->reader) > 1) { @@ -484,7 +485,7 @@ data_list_trns_proc (void *trns_, struct ccase *c, casenumber case_num UNUSED) /* If there was an END subcommand handle it. */ if (trns->end != NULL) { - double *end = &case_data_rw (c, trns->end)->f; + double *end = &case_data_rw (*c, trns->end)->f; if (retval == TRNS_END_FILE) { *end = 1.0; diff --git a/src/language/data-io/data-parser.c b/src/language/data-io/data-parser.c index dfc04be4..87fd1b79 100644 --- a/src/language/data-io/data-parser.c +++ b/src/language/data-io/data-parser.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -364,14 +364,17 @@ static bool parse_delimited_no_span (const struct data_parser *, static bool parse_fixed (const struct data_parser *, struct dfm_reader *, struct ccase *); -/* Reads a case from DFM into C, parsing it with PARSER. - Returns true if successful, false at end of file or on I/O error. */ +/* Reads a case from DFM into C, parsing it with PARSER. Returns + true if successful, false at end of file or on I/O error. + + Case C must not be shared. */ bool data_parser_parse (struct data_parser *parser, struct dfm_reader *reader, struct ccase *c) { bool retval; + assert (!case_is_shared (c)); assert (data_parser_any_fields (parser)); /* Skip the requested number of records before reading the @@ -746,18 +749,18 @@ data_parser_make_active_file (struct data_parser *parser, struct dataset *ds, proc_set_active_file (ds, casereader, dict); } -static bool -data_parser_casereader_read (struct casereader *reader UNUSED, void *r_, - struct ccase *c) +static struct ccase * +data_parser_casereader_read (struct casereader *reader UNUSED, void *r_) { struct data_parser_casereader *r = r_; - bool ok; - - case_create (c, r->value_cnt); - ok = data_parser_parse (r->parser, r->reader, c); - if (!ok) - case_destroy (c); - return ok; + struct ccase *c = case_create (r->value_cnt); + if (data_parser_parse (r->parser, r->reader, c)) + return c; + else + { + case_unref (c); + return NULL; + } } static void diff --git a/src/language/data-io/inpt-pgm.c b/src/language/data-io/inpt-pgm.c index 609c9b2c..c2e5dc0f 100644 --- a/src/language/data-io/inpt-pgm.c +++ b/src/language/data-io/inpt-pgm.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 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 @@ -180,35 +180,34 @@ is_valid_state (enum trns_result state) || state >= 0); } -/* Reads one case into C. - Returns true if successful, false at end of file or if an +/* Reads and returns one case. + Returns the case if successful, null at end of file or if an I/O error occurred. */ -static bool -input_program_casereader_read (struct casereader *reader UNUSED, void *inp_, - struct ccase *c) +static struct ccase * +input_program_casereader_read (struct casereader *reader UNUSED, void *inp_) { struct input_program_pgm *inp = inp_; - - case_create (c, inp->value_cnt); + struct ccase *c = case_create (inp->value_cnt); do { assert (is_valid_state (inp->restart)); if (inp->restart == TRNS_ERROR || inp->restart == TRNS_END_FILE) { - case_destroy (c); - return false; + case_unref (c); + return NULL; } + c = case_unshare (c); caseinit_init_vars (inp->init, c); inp->restart = trns_chain_execute (inp->trns_chain, inp->restart, - c, inp->case_nr); + &c, inp->case_nr); assert (is_valid_state (inp->restart)); caseinit_update_left_vars (inp->init, c); } while (inp->restart < 0); - return true; + return c; } static void @@ -251,7 +250,7 @@ cmd_end_case (struct lexer *lexer, struct dataset *ds UNUSED) /* Outputs the current case */ int -end_case_trns_proc (void *inp_, struct ccase *c UNUSED, +end_case_trns_proc (void *inp_, struct ccase **c UNUSED, casenumber case_nr UNUSED) { struct input_program_pgm *inp = inp_; @@ -323,7 +322,7 @@ cmd_reread (struct lexer *lexer, struct dataset *ds) /* Executes a REREAD transformation. */ static int -reread_trns_proc (void *t_, struct ccase *c, casenumber case_num) +reread_trns_proc (void *t_, struct ccase **c, casenumber case_num) { struct reread_trns *t = t_; @@ -331,7 +330,7 @@ reread_trns_proc (void *t_, struct ccase *c, casenumber case_num) dfm_reread_record (t->reader, 1); else { - double column = expr_evaluate_num (t->column, c, case_num); + double column = expr_evaluate_num (t->column, *c, case_num); if (!isfinite (column) || column < 1) { msg (SE, _("REREAD: Column numbers must be positive finite " @@ -368,7 +367,7 @@ cmd_end_file (struct lexer *lexer, struct dataset *ds) /* Executes an END FILE transformation. */ static int -end_file_trns_proc (void *trns_ UNUSED, struct ccase *c UNUSED, +end_file_trns_proc (void *trns_ UNUSED, struct ccase **c UNUSED, casenumber case_num UNUSED) { return TRNS_END_FILE; diff --git a/src/language/data-io/list.q b/src/language/data-io/list.q index 8e8bba9b..28820a85 100644 --- a/src/language/data-io/list.q +++ b/src/language/data-io/list.q @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 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 @@ -83,7 +83,7 @@ static unsigned n_chars_width (struct outp_driver *d); static void write_line (struct outp_driver *d, const char *s); /* Other functions. */ -static void list_case (struct ccase *, casenumber case_idx, +static void list_case (const struct ccase *, casenumber case_idx, const struct dataset *); static void determine_layout (void); static void clean_up (void); @@ -236,15 +236,15 @@ cmd_list (struct lexer *lexer, struct dataset *ds) casegrouper_get_next_group (grouper, &group); casereader_destroy (group)) { - struct ccase c; + struct ccase *c; write_all_headers (group, ds); - for (; casereader_read (group, &c); case_destroy (&c)) + for (; (c = casereader_read (group)) != NULL; case_unref (c)) { case_idx++; if (case_idx >= cmd.first && case_idx <= cmd.last && (case_idx - cmd.first) % cmd.step == 0) - list_case (&c, case_idx, ds); + list_case (c, case_idx, ds); } } ok = casegrouper_destroy (grouper); @@ -265,12 +265,13 @@ static void write_all_headers (struct casereader *input, const struct dataset *ds) { struct outp_driver *d; - struct ccase c; + struct ccase *c; - if (!casereader_peek (input, 0, &c)) + c = casereader_peek (input, 0); + if (c == NULL) return; - output_split_file_values (ds, &c); - case_destroy (&c); + output_split_file_values (ds, c); + case_unref (c); for (d = outp_drivers (NULL); d; d = outp_drivers (d)) { @@ -649,7 +650,8 @@ determine_layout (void) /* Writes case C to output. */ static void -list_case (struct ccase *c, casenumber case_idx, const struct dataset *ds) +list_case (const struct ccase *c, casenumber case_idx, + const struct dataset *ds) { struct dictionary *dict = dataset_dict (ds); struct outp_driver *d; diff --git a/src/language/data-io/print-space.c b/src/language/data-io/print-space.c index c3a2e09a..3f73ee25 100644 --- a/src/language/data-io/print-space.c +++ b/src/language/data-io/print-space.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2006 Free Software Foundation, Inc. + Copyright (C) 2006, 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 @@ -102,7 +102,7 @@ cmd_print_space (struct lexer *lexer, struct dataset *ds) /* Executes a PRINT SPACE transformation. */ static int -print_space_trns_proc (void *t_, struct ccase *c, +print_space_trns_proc (void *t_, struct ccase **c, casenumber case_num UNUSED) { struct print_space_trns *trns = t_; @@ -111,7 +111,7 @@ print_space_trns_proc (void *t_, struct ccase *c, n = 1; if (trns->expr) { - double f = expr_evaluate_num (trns->expr, c, case_num); + double f = expr_evaluate_num (trns->expr, *c, case_num); if (f == SYSMIS) msg (SW, _("The expression on PRINT SPACE evaluated to the " "system-missing value.")); diff --git a/src/language/data-io/print.c b/src/language/data-io/print.c index 408224af..ab25ec75 100644 --- a/src/language/data-io/print.c +++ b/src/language/data-io/print.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 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 @@ -450,7 +450,7 @@ static void flush_records (struct print_trns *, int target_record, /* Performs the transformation inside print_trns T on case C. */ static int -print_trns_proc (void *trns_, struct ccase *c, casenumber case_num UNUSED) +print_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED) { struct print_trns *trns = trns_; bool eject = trns->eject; @@ -467,7 +467,7 @@ print_trns_proc (void *trns_, struct ccase *c, casenumber case_num UNUSED) ds_set_length (&trns->line, spec->first_column, encoded_space); if (spec->type == PRT_VAR) { - const union value *input = case_data (c, spec->var); + const union value *input = case_data (*c, spec->var); char *output = ds_put_uninit (&trns->line, spec->format.w); if (!spec->sysmis_as_spaces || input->f != SYSMIS) data_out_legacy (input, trns->encoding, &spec->format, output); diff --git a/src/language/data-io/save.c b/src/language/data-io/save.c index e94c020b..c34d4462 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 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 2007, 2008, 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 @@ -326,14 +326,12 @@ parse_write_command (struct lexer *lexer, struct dataset *ds, return NULL; } -/* Writes case C to the system file specified on XSAVE or XEXPORT. */ +/* Writes case *C to the system file specified on XSAVE or XEXPORT. */ static int -output_trns_proc (void *trns_, struct ccase *c, casenumber case_num UNUSED) +output_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED) { struct output_trns *t = trns_; - struct ccase tmp; - case_clone (&tmp, c); - casewriter_write (t->writer, &tmp); + casewriter_write (t->writer, case_ref (*c)); return TRNS_CONTINUE; } diff --git a/src/language/expressions/evaluate.c b/src/language/expressions/evaluate.c index fc5b74a3..91b9c842 100644 --- a/src/language/expressions/evaluate.c +++ b/src/language/expressions/evaluate.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006, 2007 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 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 @@ -170,12 +170,9 @@ cmd_debug_evaluate (struct lexer *lexer, struct dataset *dsother UNUSED) } if (c == NULL) - { - c = xmalloc (sizeof *c); - case_create (c, dict_get_next_value_idx (d)); - } + c = case_create (dict_get_next_value_idx (d)); else - case_resize (c, dict_get_next_value_idx (d)); + c = case_resize (c, dict_get_next_value_idx (d)); if (lex_is_number (lexer)) case_data_rw (c, v)->f = lex_tokval (lexer); @@ -255,11 +252,7 @@ cmd_debug_evaluate (struct lexer *lexer, struct dataset *dsother UNUSED) if (ds) destroy_dataset (ds); - if (c != NULL) - { - case_destroy (c); - free (c); - } + case_unref (c); return retval; } diff --git a/src/language/expressions/operations.def b/src/language/expressions/operations.def index ea640e18..2d31bd47 100644 --- a/src/language/expressions/operations.def +++ b/src/language/expressions/operations.def @@ -1,7 +1,7 @@ // -*- c -*- // // PSPP - a program for statistical analysis. -// Copyright (C) 2005, 2006 Free Software Foundation, Inc. +// Copyright (C) 2005, 2006, 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 @@ -988,7 +988,7 @@ no_opt string operator STR_VAR () no_opt perm_only function LAG (num_var v, pos_int n_before) dataset ds; { - struct ccase *c = lagged_case (ds, n_before); + const struct ccase *c = lagged_case (ds, n_before); if (c != NULL) { double x = case_num (c, v); @@ -1001,7 +1001,7 @@ no_opt perm_only function LAG (num_var v, pos_int n_before) no_opt perm_only function LAG (num_var v) dataset ds; { - struct ccase *c = lagged_case (ds, 1); + const struct ccase *c = lagged_case (ds, 1); if (c != NULL) { double x = case_num (c, v); @@ -1015,7 +1015,7 @@ no_opt perm_only string function LAG (str_var v, pos_int n_before) expression e; dataset ds; { - struct ccase *c = lagged_case (ds, n_before); + const struct ccase *c = lagged_case (ds, n_before); if (c != NULL) return copy_string (e, case_str (c, v), var_get_width (v)); else @@ -1026,7 +1026,7 @@ no_opt perm_only string function LAG (str_var v) expression e; dataset ds; { - struct ccase *c = lagged_case (ds, 1); + const struct ccase *c = lagged_case (ds, 1); if (c != NULL) return copy_string (e, case_str (c, v), var_get_width (v)); else diff --git a/src/language/stats/aggregate.c b/src/language/stats/aggregate.c index 02257f94..c2173109 100644 --- a/src/language/stats/aggregate.c +++ b/src/language/stats/aggregate.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006, 2008 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 2008, 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 @@ -146,7 +146,7 @@ struct agr_proc struct subcase sort; /* Sort criteria (break variables). */ const struct variable **break_vars; /* Break variables. */ size_t break_var_cnt; /* Number of break variables. */ - struct ccase break_case; /* Last values of break variables. */ + struct ccase *break_case; /* Last values of break variables. */ enum missing_treatment missing; /* How to treat missing values. */ struct agr_var *agr_vars; /* First aggregate variable. */ @@ -187,7 +187,7 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) memset(&agr, 0 , sizeof (agr)); agr.missing = ITEMWISE; - case_nullify (&agr.break_case); + agr.break_case = NULL; agr.dict = dict_create (); agr.src_dict = dict; @@ -295,18 +295,17 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) casegrouper_get_next_group (grouper, &group); casereader_destroy (group)) { - struct ccase c; - - if (!casereader_peek (group, 0, &c)) + struct ccase *c = casereader_peek (group, 0); + if (c == NULL) { casereader_destroy (group); continue; } - initialize_aggregate_info (&agr, &c); - case_destroy (&c); + initialize_aggregate_info (&agr, c); + case_unref (c); - for (; casereader_read (group, &c); case_destroy (&c)) - accumulate_aggregate_info (&agr, &c); + for (; (c = casereader_read (group)) != NULL; case_unref (c)) + accumulate_aggregate_info (&agr, c); dump_aggregate_info (&agr, output); } if (!casegrouper_destroy (grouper)) @@ -694,7 +693,7 @@ agr_destroy (struct agr_proc *agr) subcase_destroy (&agr->sort); free (agr->break_vars); - case_destroy (&agr->break_case); + case_unref (agr->break_case); for (iter = agr->agr_vars; iter; iter = next) { next = iter->next; @@ -770,20 +769,18 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) case MEDIAN: { double wv ; - struct ccase cout; - case_create (&cout, 2); + struct ccase *cout = case_create (2); - case_data_rw (&cout, iter->subject)->f = - case_data (input, iter->src)->f; + case_data_rw (cout, iter->subject)->f + = case_data (input, iter->src)->f; wv = dict_get_case_weight (agr->src_dict, input, NULL); - case_data_rw (&cout, iter->weight)->f = wv; + case_data_rw (cout, iter->weight)->f = wv; iter->cc += wv; - casewriter_write (iter->writer, &cout); - case_destroy (&cout); + casewriter_write (iter->writer, cout); } break; case SD: @@ -916,9 +913,7 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) static void dump_aggregate_info (struct agr_proc *agr, struct casewriter *output) { - struct ccase c; - - case_create (&c, dict_get_next_value_idx (agr->dict)); + struct ccase *c = case_create (dict_get_next_value_idx (agr->dict)); { int value_idx = 0; @@ -928,8 +923,8 @@ dump_aggregate_info (struct agr_proc *agr, struct casewriter *output) { const struct variable *v = agr->break_vars[i]; size_t value_cnt = var_get_value_cnt (v); - memcpy (case_data_rw_idx (&c, value_idx), - case_data (&agr->break_case, v), + memcpy (case_data_rw_idx (c, value_idx), + case_data (agr->break_case, v), sizeof (union value) * value_cnt); value_idx += value_cnt; } @@ -940,7 +935,7 @@ dump_aggregate_info (struct agr_proc *agr, struct casewriter *output) for (i = agr->agr_vars; i; i = i->next) { - union value *v = case_data_rw (&c, i->dest); + union value *v = case_data_rw (c, i->dest); if (agr->missing == COLUMNWISE && i->saw_missing @@ -1067,7 +1062,7 @@ dump_aggregate_info (struct agr_proc *agr, struct casewriter *output) } } - casewriter_write (output, &c); + casewriter_write (output, c); } /* Resets the state for all the aggregate functions. */ @@ -1076,8 +1071,8 @@ initialize_aggregate_info (struct agr_proc *agr, const struct ccase *input) { struct agr_var *iter; - case_destroy (&agr->break_case); - case_clone (&agr->break_case, input); + case_unref (agr->break_case); + agr->break_case = case_ref (input); for (iter = agr->agr_vars; iter; iter = iter->next) { diff --git a/src/language/stats/autorecode.c b/src/language/stats/autorecode.c index af9280b5..de941682 100644 --- a/src/language/stats/autorecode.c +++ b/src/language/stats/autorecode.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 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 @@ -103,7 +103,7 @@ cmd_autorecode (struct lexer *lexer, struct dataset *ds) { struct autorecode_pgm arc; struct casereader *input; - struct ccase c; + struct ccase *c; size_t dst_cnt; size_t i; bool ok; @@ -189,15 +189,15 @@ cmd_autorecode (struct lexer *lexer, struct dataset *ds) } input = proc_open (ds); - for (; casereader_read (input, &c); case_destroy (&c)) + for (; (c = casereader_read (input)) != NULL; case_unref (c)) for (i = 0; i < arc.var_cnt; i++) { union arc_value v, *vp, **vpp; if (var_is_numeric (arc.src_vars[i])) - v.f = case_num (&c, arc.src_vars[i]); + v.f = case_num (c, arc.src_vars[i]); else - v.c = (char *) case_str (&c, arc.src_vars[i]); + v.c = (char *) case_str (c, arc.src_vars[i]); vpp = (union arc_value **) hsh_probe (arc.src_values[i], &v); if (*vpp == NULL) @@ -300,11 +300,13 @@ recode (struct dataset *ds, const struct autorecode_pgm *arc) /* Executes an AUTORECODE transformation. */ static int -autorecode_trns_proc (void *trns_, struct ccase *c, casenumber case_idx UNUSED) +autorecode_trns_proc (void *trns_, struct ccase **c, + casenumber case_idx UNUSED) { struct autorecode_trns *trns = trns_; size_t i; + *c = case_unshare (*c); for (i = 0; i < trns->spec_cnt; i++) { struct arc_spec *spec = &trns->specs[i]; @@ -312,12 +314,12 @@ autorecode_trns_proc (void *trns_, struct ccase *c, casenumber case_idx UNUSED) union arc_value v; if (var_is_numeric (spec->src)) - v.f = case_num (c, spec->src); + v.f = case_num (*c, spec->src); else - v.c = (char *) case_str (c, spec->src); + v.c = (char *) case_str (*c, spec->src); item = hsh_force_find (spec->items, &v); - case_data_rw (c, spec->dest)->f = item->to; + case_data_rw (*c, spec->dest)->f = item->to; } return TRNS_CONTINUE; } diff --git a/src/language/stats/binomial.c b/src/language/stats/binomial.c index 35e619bd..15d0e403 100644 --- a/src/language/stats/binomial.c +++ b/src/language/stats/binomial.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2006 Free Software Foundation, Inc. + Copyright (C) 2006, 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 @@ -98,17 +98,17 @@ do_binomial (const struct dictionary *dict, bool warn = true; const struct one_sample_test *ost = (const struct one_sample_test *) bst; - struct ccase c; + struct ccase *c; - while (casereader_read(input, &c)) + while ((c = casereader_read(input)) != NULL) { int v; - double w = dict_get_case_weight (dict, &c, &warn); + double w = dict_get_case_weight (dict, c, &warn); for (v = 0 ; v < ost->n_vars ; ++v ) { const struct variable *var = ost->vars[v]; - const union value *value = case_data (&c, var); + const union value *value = case_data (c, var); int width = var_get_width (var); if (var_is_value_missing (var, value, exclude)) @@ -132,7 +132,7 @@ do_binomial (const struct dictionary *dict, msg (ME, _("Variable %s is not dichotomous"), var_get_name (var)); } - case_destroy (&c); + case_unref (c); } return casereader_destroy (input); } diff --git a/src/language/stats/chisquare.c b/src/language/stats/chisquare.c index ed143824..19496d7e 100644 --- a/src/language/stats/chisquare.c +++ b/src/language/stats/chisquare.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2006, 2007 Free Software Foundation, Inc. + Copyright (C) 2006, 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 @@ -57,7 +57,7 @@ create_freq_hash_with_range (const struct dictionary *dict, { bool warn = true; float i_d; - struct ccase c; + struct ccase *c; struct hsh_table *freq_hash = hsh_create (4, compare_freq, hash_freq, @@ -78,21 +78,21 @@ create_freq_hash_with_range (const struct dictionary *dict, hsh_insert (freq_hash, fr); } - while (casereader_read (input, &c)) + while ((c = casereader_read (input)) != NULL) { union value obs_value; struct freq **existing_fr; struct freq *fr = xmalloc(sizeof (*fr)); - fr->value = case_data (&c, var); + fr->value = case_data (c, var); - fr->count = dict_get_case_weight (dict, &c, &warn); + fr->count = dict_get_case_weight (dict, c, &warn); obs_value.f = trunc (fr->value->f); if ( obs_value.f < lo || obs_value.f > hi) { free (fr); - case_destroy (&c); + case_unref (c); continue; } @@ -107,7 +107,7 @@ create_freq_hash_with_range (const struct dictionary *dict, (*existing_fr)->count += fr->count; free (fr); - case_destroy (&c); + case_unref (c); } if (casereader_destroy (input)) return freq_hash; @@ -130,20 +130,20 @@ create_freq_hash (const struct dictionary *dict, const struct variable *var) { bool warn = true; - struct ccase c; + struct ccase *c; struct hsh_table *freq_hash = hsh_create (4, compare_freq, hash_freq, free_freq_mutable_hash, (void *) var); - for (; casereader_read (input, &c); case_destroy (&c)) + for (; (c = casereader_read (input)) != NULL; case_unref (c)) { struct freq **existing_fr; struct freq *fr = xmalloc(sizeof (*fr)); - fr->value = case_data (&c, var); + fr->value = case_data (c, var); - fr->count = dict_get_case_weight (dict, &c, &warn); + fr->count = dict_get_case_weight (dict, c, &warn); existing_fr = (struct freq **) hsh_probe (freq_hash, fr); if ( *existing_fr) diff --git a/src/language/stats/crosstabs.q b/src/language/stats/crosstabs.q index 801b128b..60d2faee 100644 --- a/src/language/stats/crosstabs.q +++ b/src/language/stats/crosstabs.q @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 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 @@ -177,8 +177,8 @@ static struct pool *pl_col; /* For column data. */ static int internal_cmd_crosstabs (struct lexer *lexer, struct dataset *ds); static void precalc (struct casereader *, const struct dataset *); -static void calc_general (struct ccase *, const struct dataset *); -static void calc_integer (struct ccase *, const struct dataset *); +static void calc_general (const struct ccase *, const struct dataset *); +static void calc_integer (const struct ccase *, const struct dataset *); static void postcalc (void); static void submit (struct tab_table *); @@ -305,16 +305,16 @@ internal_cmd_crosstabs (struct lexer *lexer, struct dataset *ds) grouper = casegrouper_create_splits (input, dataset_dict (ds)); while (casegrouper_get_next_group (grouper, &group)) { - struct ccase c; + struct ccase *c; precalc (group, ds); - for (; casereader_read (group, &c); case_destroy (&c)) + for (; (c = casereader_read (group)) != NULL; case_unref (c)) { if (mode == GENERAL) - calc_general (&c, ds); + calc_general (c, ds); else - calc_integer (&c, ds); + calc_integer (c, ds); } casereader_destroy (group); @@ -518,12 +518,13 @@ static unsigned hash_table_entry (const void *, const void *); static void precalc (struct casereader *input, const struct dataset *ds) { - struct ccase c; + struct ccase *c; - if (casereader_peek (input, 0, &c)) + c = casereader_peek (input, 0); + if (c != NULL) { - output_split_file_values (ds, &c); - case_destroy (&c); + output_split_file_values (ds, c); + case_unref (c); } if (mode == GENERAL) @@ -598,7 +599,7 @@ precalc (struct casereader *input, const struct dataset *ds) /* Form crosstabulations for general mode. */ static void -calc_general (struct ccase *c, const struct dataset *ds) +calc_general (const struct ccase *c, const struct dataset *ds) { /* Missing values to exclude. */ enum mv_class exclude = (cmd.miss == CRS_TABLE ? MV_ANY @@ -672,7 +673,7 @@ calc_general (struct ccase *c, const struct dataset *ds) } static void -calc_integer (struct ccase *c, const struct dataset *ds) +calc_integer (const struct ccase *c, const struct dataset *ds) { bool bad_warn = true; diff --git a/src/language/stats/descriptives.c b/src/language/stats/descriptives.c index 72f7476a..68b19300 100644 --- a/src/language/stats/descriptives.c +++ b/src/language/stats/descriptives.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 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 @@ -583,7 +583,7 @@ dump_z_table (struct dsc_proc *dsc) (either system or user-missing values that weren't included). */ static int -descriptives_trns_proc (void *trns_, struct ccase * c, +descriptives_trns_proc (void *trns_, struct ccase **c, casenumber case_idx UNUSED) { struct dsc_trns *t = trns_; @@ -596,7 +596,7 @@ descriptives_trns_proc (void *trns_, struct ccase * c, assert(t->vars); for (vars = t->vars; vars < t->vars + t->var_cnt; vars++) { - double score = case_num (c, *vars); + double score = case_num (*c, *vars); if (var_is_num_missing (*vars, score, t->exclude)) { all_sysmis = 1; @@ -605,10 +605,11 @@ descriptives_trns_proc (void *trns_, struct ccase * c, } } + *c = case_unshare (*c); for (z = t->z_scores; z < t->z_scores + t->z_score_cnt; z++) { - double input = case_num (c, z->src_var); - double *output = &case_data_rw (c, z->z_var)->f; + double input = case_num (*c, z->src_var); + double *output = &case_data_rw (*c, z->z_var)->f; if (z->mean == SYSMIS || z->std_dev == SYSMIS || all_sysmis || var_is_num_missing (z->src_var, input, t->exclude)) @@ -695,16 +696,17 @@ calc_descriptives (struct dsc_proc *dsc, struct casereader *group, struct dataset *ds) { struct casereader *pass1, *pass2; - struct ccase c; + struct ccase *c; size_t i; - if (!casereader_peek (group, 0, &c)) + c = casereader_peek (group, 0); + if (c == NULL) { casereader_destroy (group); return; } - output_split_file_values (ds, &c); - case_destroy (&c); + output_split_file_values (ds, c); + case_unref (c); group = casereader_create_filter_weight (group, dataset_dict (ds), NULL, NULL); @@ -726,12 +728,12 @@ calc_descriptives (struct dsc_proc *dsc, struct casereader *group, dsc->valid = 0.; /* First pass to handle most of the work. */ - for (; casereader_read (pass1, &c); case_destroy (&c)) + for (; (c = casereader_read (pass1)) != NULL; case_unref (c)) { - double weight = dict_get_case_weight (dataset_dict (ds), &c, NULL); + double weight = dict_get_case_weight (dataset_dict (ds), c, NULL); /* Check for missing values. */ - if (listwise_missing (dsc, &c)) + if (listwise_missing (dsc, c)) { dsc->missing_listwise += weight; if (dsc->missing_type == DSC_LISTWISE) @@ -742,7 +744,7 @@ calc_descriptives (struct dsc_proc *dsc, struct casereader *group, for (i = 0; i < dsc->var_cnt; i++) { struct dsc_var *dv = &dsc->vars[i]; - double x = case_num (&c, dv->v); + double x = case_num (c, dv->v); if (var_is_num_missing (dv->v, x, dsc->exclude)) { @@ -768,18 +770,18 @@ calc_descriptives (struct dsc_proc *dsc, struct casereader *group, /* Second pass for higher-order moments. */ if (dsc->max_moment > MOMENT_MEAN) { - for (; casereader_read (pass2, &c); case_destroy (&c)) + for (; (c = casereader_read (pass2)) != NULL; case_unref (c)) { - double weight = dict_get_case_weight (dataset_dict (ds), &c, NULL); + double weight = dict_get_case_weight (dataset_dict (ds), c, NULL); /* Check for missing values. */ - if (dsc->missing_type == DSC_LISTWISE && listwise_missing (dsc, &c)) + if (dsc->missing_type == DSC_LISTWISE && listwise_missing (dsc, c)) continue; for (i = 0; i < dsc->var_cnt; i++) { struct dsc_var *dv = &dsc->vars[i]; - double x = case_num (&c, dv->v); + double x = case_num (c, dv->v); if (var_is_num_missing (dv->v, x, dsc->exclude)) continue; diff --git a/src/language/stats/examine.q b/src/language/stats/examine.q index 312547f3..b564ba44 100644 --- a/src/language/stats/examine.q +++ b/src/language/stats/examine.q @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2004, 2008 Free Software Foundation, Inc. + Copyright (C) 2004, 2008, 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 @@ -369,14 +369,14 @@ np_plot (struct np *np, const char *label) chart_write_yscale (dnp_chart, np->dns_min, np->dns_max, 5); { - struct ccase c; struct casereader *reader = casewriter_make_reader (np->writer); - while (casereader_read (reader, &c)) + struct ccase *c; + while ((c = casereader_read (reader)) != NULL) { - chart_datum (np_chart, 0, case_data_idx (&c, NP_IDX_Y)->f, case_data_idx (&c, NP_IDX_NS)->f); - chart_datum (dnp_chart, 0, case_data_idx (&c, NP_IDX_Y)->f, case_data_idx (&c, NP_IDX_DNS)->f); + chart_datum (np_chart, 0, case_data_idx (c, NP_IDX_Y)->f, case_data_idx (c, NP_IDX_NS)->f); + chart_datum (dnp_chart, 0, case_data_idx (c, NP_IDX_Y)->f, case_data_idx (c, NP_IDX_DNS)->f); - case_destroy (&c); + case_unref (c); } casereader_destroy (reader); } @@ -866,7 +866,7 @@ static void examine_group (struct cmd_examine *cmd, struct casereader *reader, int level, const struct dictionary *dict, struct xfactor *factor) { - struct ccase c; + struct ccase *c; const struct variable *wv = dict_get_weight (dict); int v; int n_extrema = 1; @@ -878,20 +878,21 @@ examine_group (struct cmd_examine *cmd, struct casereader *reader, int level, n_extrema = cmd->st_n; - if (casereader_peek (reader, 0, &c)) + c = casereader_peek (reader, 0); + if (c != NULL) { if ( level > 0) { result->value[0] = - value_dup (case_data (&c, factor->indep_var[0]), + value_dup (case_data (c, factor->indep_var[0]), var_get_width (factor->indep_var[0])); if ( level > 1) result->value[1] = - value_dup (case_data (&c, factor->indep_var[1]), + value_dup (case_data (c, factor->indep_var[1]), var_get_width (factor->indep_var[1])); } - case_destroy (&c); + case_unref (c); } for (v = 0; v < n_dependent_vars; ++v) @@ -927,33 +928,33 @@ examine_group (struct cmd_examine *cmd, struct casereader *reader, int level, /* Sort or just iterate, whilst calculating moments etc */ - while (casereader_read (input, &c)) + while ((c = casereader_read (input)) != NULL) { const casenumber loc = - case_data_idx (&c, casereader_get_value_cnt (reader) - 1)->f; + case_data_idx (c, casereader_get_value_cnt (reader) - 1)->f; - const double weight = wv ? case_data (&c, wv)->f : 1.0; + const double weight = wv ? case_data (c, wv)->f : 1.0; if (weight != SYSMIS) minimize (&result->metrics[v].cmin, weight); moments1_add (result->metrics[v].moments, - case_data (&c, dependent_vars[v])->f, + case_data (c, dependent_vars[v])->f, weight); result->metrics[v].n += weight; extrema_add (result->metrics[v].maxima, - case_data (&c, dependent_vars[v])->f, + case_data (c, dependent_vars[v])->f, weight, loc); extrema_add (result->metrics[v].minima, - case_data (&c, dependent_vars[v])->f, + case_data (c, dependent_vars[v])->f, weight, loc); - casewriter_write (writer, &c); + casewriter_write (writer, c); } casereader_destroy (input); result->metrics[v].up_reader = casewriter_make_reader (writer); @@ -1028,7 +1029,7 @@ examine_group (struct cmd_examine *cmd, struct casereader *reader, int level, /* FIXME: Do this in the above loop */ if ( cmd->a_plot[XMN_PLT_HISTOGRAM] ) { - struct ccase c; + struct ccase *c; struct casereader *input = casereader_clone (reader); for (v = 0; v < n_dependent_vars; ++v) @@ -1059,18 +1060,18 @@ examine_group (struct cmd_examine *cmd, struct casereader *reader, int level, metric->histogram = histogram_create (10, min->value, max->value); } - while (casereader_read (input, &c)) + while ((c = casereader_read (input)) != NULL) { - const double weight = wv ? case_data (&c, wv)->f : 1.0; + const double weight = wv ? case_data (c, wv)->f : 1.0; for (v = 0; v < n_dependent_vars; ++v) { struct factor_metrics *metric = &result->metrics[v]; if ( metric->histogram) histogram_add ((struct histogram *) metric->histogram, - case_data (&c, dependent_vars[v])->f, weight); + case_data (c, dependent_vars[v])->f, weight); } - case_destroy (&c); + case_unref (c); } casereader_destroy (input); } @@ -1106,17 +1107,18 @@ run_examine (struct cmd_examine *cmd, struct casereader *input, { struct ll *ll; const struct dictionary *dict = dataset_dict (ds); - struct ccase c; + struct ccase *c; struct casereader *level0 = casereader_clone (input); - if (!casereader_peek (input, 0, &c)) + c = casereader_peek (input, 0); + if (c == NULL) { casereader_destroy (input); return; } - output_split_file_values (ds, &c); - case_destroy (&c); + output_split_file_values (ds, c); + case_unref (c); ll_init (&level0_factor.result_list); diff --git a/src/language/stats/flip.c b/src/language/stats/flip.c index ccb84dd8..7583374b 100644 --- a/src/language/stats/flip.c +++ b/src/language/stats/flip.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 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 @@ -88,7 +88,7 @@ cmd_flip (struct lexer *lexer, struct dataset *ds) struct flip_pgm *flip; struct casereader *input, *reader; union value *output_buf; - struct ccase c; + struct ccase *c; size_t i; bool ok; @@ -169,10 +169,10 @@ cmd_flip (struct lexer *lexer, struct dataset *ds) proc_discard_output (ds); input = proc_open (ds); - while (casereader_read (input, &c)) + while ((c = casereader_read (input)) != NULL) { - write_flip_case (flip, &c); - case_destroy (&c); + write_flip_case (flip, c); + case_unref (c); } ok = casereader_destroy (input); ok = proc_commit (ds) && ok; @@ -464,26 +464,25 @@ flip_file (struct flip_pgm *flip) return true; } -/* Reads one case into C. - Returns true if successful, false at end of file or if an - I/O error occurred. */ -static bool -flip_casereader_read (struct casereader *reader UNUSED, void *flip_, - struct ccase *c) +/* Reads and returns one case. + Returns a null pointer at end of file or if an I/O error occurred. */ +static struct ccase * +flip_casereader_read (struct casereader *reader UNUSED, void *flip_) { struct flip_pgm *flip = flip_; + struct ccase *c; size_t i; if (flip->error || flip->cases_read >= flip->var_cnt) - return false; + return NULL; - case_create (c, flip->case_cnt); + c = case_create (flip->case_cnt); for (i = 0; i < flip->case_cnt; i++) { double in; if (fread (&in, sizeof in, 1, flip->file) != 1) { - case_destroy (c); + case_unref (c); if (ferror (flip->file)) msg (SE, _("Error reading FLIP temporary file: %s."), strerror (errno)); @@ -492,14 +491,14 @@ flip_casereader_read (struct casereader *reader UNUSED, void *flip_, else NOT_REACHED (); flip->error = true; - return false; + return NULL; } case_data_rw_idx (c, i)->f = in; } flip->cases_read++; - return true; + return c; } /* Destroys the source. diff --git a/src/language/stats/frequencies.q b/src/language/stats/frequencies.q index 94b2bcf9..cd370be8 100644 --- a/src/language/stats/frequencies.q +++ b/src/language/stats/frequencies.q @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2007 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 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 @@ -376,11 +376,11 @@ internal_cmd_frequencies (struct lexer *lexer, struct dataset *ds) for (; casegrouper_get_next_group (grouper, &group); casereader_destroy (group)) { - struct ccase c; + struct ccase *c; precalc (group, ds); - for (; casereader_read (group, &c); case_destroy (&c)) - calc (&c, ds); + for (; (c = casereader_read (group)) != NULL; case_unref (c)) + calc (c, ds); postcalc (); } ok = casegrouper_destroy (grouper); @@ -535,13 +535,14 @@ calc (const struct ccase *c, const struct dataset *ds) static void precalc (struct casereader *input, struct dataset *ds) { - struct ccase c; + struct ccase *c; size_t i; - if (casereader_peek (input, 0, &c)) + c = casereader_peek (input, 0); + if (c != NULL) { - output_split_file_values (ds, &c); - case_destroy (&c); + output_split_file_values (ds, c); + case_unref (c); } pool_destroy (data_pool); diff --git a/src/language/stats/glm.q b/src/language/stats/glm.q index d6b4952c..07ee7ab5 100644 --- a/src/language/stats/glm.q +++ b/src/language/stats/glm.q @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -184,20 +184,21 @@ run_glm (struct casereader *input, int n_indep = 0; pspp_linreg_cache *model = NULL; pspp_linreg_opts lopts; - struct ccase c; + struct ccase *c; size_t i; size_t n_all_vars; size_t n_data; /* Number of valid cases. */ struct casereader *reader; struct covariance_matrix *cov; - if (!casereader_peek (input, 0, &c)) + c = casereader_peek (input, 0); + if (c == NULL) { casereader_destroy (input); return true; } - output_split_file_values (ds, &c); - case_destroy (&c); + output_split_file_values (ds, c); + case_unref (c); if (!v_dependent) { @@ -237,12 +238,12 @@ run_glm (struct casereader *input, cov = covariance_matrix_init (n_all_vars, all_vars, ONE_PASS, PAIRWISE, MV_ANY); reader = casereader_create_counter (reader, &row, -1); - for (; casereader_read (reader, &c); case_destroy (&c)) + for (; (c = casereader_read (reader)) != NULL; case_unref (c)) { /* Accumulate the covariance matrix. */ - covariance_matrix_accumulate (cov, &c); + covariance_matrix_accumulate (cov, c); n_data++; } covariance_matrix_compute (cov); diff --git a/src/language/stats/npar-summary.c b/src/language/stats/npar-summary.c index c752d503..04c83e1a 100644 --- a/src/language/stats/npar-summary.c +++ b/src/language/stats/npar-summary.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2006 Free Software Foundation, Inc. + Copyright (C) 2006, 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 @@ -45,7 +45,7 @@ npar_summary_calc_descriptives (struct descriptives *desc, double maximum = -DBL_MAX; double var; struct moments1 *moments = moments1_create (MOMENT_VARIANCE); - struct ccase c; + struct ccase *c; const struct variable *v = *vv++; struct casereader *pass; @@ -54,14 +54,14 @@ npar_summary_calc_descriptives (struct descriptives *desc, &v, 1, filter, NULL, NULL); pass = casereader_create_filter_weight (pass, dict, NULL, NULL); - while (casereader_read(pass, &c)) + while ((c = casereader_read (pass)) != NULL) { - double val = case_num (&c, v); - double w = dict_get_case_weight (dict, &c, NULL); + double val = case_num (c, v); + double w = dict_get_case_weight (dict, c, NULL); minimum = MIN (minimum, val); maximum = MAX (maximum, val); moments1_add (moments, val, w); - case_destroy (&c); + case_unref (c); } casereader_destroy (pass); diff --git a/src/language/stats/oneway.q b/src/language/stats/oneway.q index b2e77f45..be57eb24 100644 --- a/src/language/stats/oneway.q +++ b/src/language/stats/oneway.q @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2007 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 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 @@ -894,15 +894,16 @@ run_oneway (struct cmd_oneway *cmd, struct dictionary *dict = dataset_dict (ds); enum mv_class exclude; struct casereader *reader; - struct ccase c; + struct ccase *c; - if (!casereader_peek (input, 0, &c)) + c = casereader_peek (input, 0); + if (c == NULL) { casereader_destroy (input); return; } - output_split_file_values (ds, &c); - case_destroy (&c); + output_split_file_values (ds, c); + case_unref (c); taint = taint_clone (casereader_get_taint (input)); @@ -923,13 +924,13 @@ run_oneway (struct cmd_oneway *cmd, input = casereader_create_filter_weight (input, dict, NULL, NULL); reader = casereader_clone (input); - for (; casereader_read (reader, &c); case_destroy (&c)) + for (; (c = casereader_read (reader)) != NULL; case_unref (c)) { size_t i; - const double weight = dict_get_case_weight (dict, &c, NULL); + const double weight = dict_get_case_weight (dict, c, NULL); - const union value *indep_val = case_data (&c, indep_var); + const union value *indep_val = case_data (c, indep_var); void **p = hsh_probe (global_group_hash, indep_val); if (*p == NULL) *p = value_dup (indep_val, var_get_width (indep_var)); @@ -938,7 +939,7 @@ run_oneway (struct cmd_oneway *cmd, { const struct variable *v = vars[i]; - const union value *val = case_data (&c, v); + const union value *val = case_data (c, v); struct group_proc *gp = group_proc_get (vars[i]); struct hsh_table *group_hash = gp->group_hash; diff --git a/src/language/stats/rank.q b/src/language/stats/rank.q index d3ee3707..3bbd39d1 100644 --- a/src/language/stats/rank.q +++ b/src/language/stats/rank.q @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc. + Copyright (C) 2005, 2006, 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 @@ -476,7 +476,7 @@ rank_sorted_file (struct casereader *input, { struct casereader *pass1, *pass2, *pass2_1; struct casegrouper *tie_grouper; - struct ccase c; + struct ccase *c; double w = 0.0; double cc = 0.0; int tie_group = 1; @@ -489,8 +489,8 @@ rank_sorted_file (struct casereader *input, casereader_split (input, &pass1, &pass2); /* Pass 1: Get total group weight. */ - for (; casereader_read (pass1, &c); case_destroy (&c)) - w += dict_get_case_weight (dict, &c, NULL); + for (; (c = casereader_read (pass1)) != NULL; case_unref (c)) + w += dict_get_case_weight (dict, c, NULL); casereader_destroy (pass1); /* Pass 2: Do ranking. */ @@ -507,21 +507,22 @@ rank_sorted_file (struct casereader *input, casewriter_get_taint (output)); /* Pass 2.1: Sum up weight for tied cases. */ - for (; casereader_read (pass2_1, &c); case_destroy (&c)) - tw += dict_get_case_weight (dict, &c, NULL); + for (; (c = casereader_read (pass2_1)) != NULL; case_unref (c)) + tw += dict_get_case_weight (dict, c, NULL); cc += tw; casereader_destroy (pass2_1); /* Pass 2.2: Rank tied cases. */ - while (casereader_read (pass2_2, &c)) + while ((c = casereader_read (pass2_2)) != NULL) { + c = case_unshare (c); for (i = 0; i < n_rank_specs; ++i) { const struct variable *dst_var = rs[i].destvars[dest_idx]; - double *dst_value = &case_data_rw (&c, dst_var)->f; + double *dst_value = &case_data_rw (c, dst_var)->f; *dst_value = rank_func[rs[i].rfunc] (tw, cc, cc_1, tie_group, w); } - casewriter_write (output, &c); + casewriter_write (output, c); } casereader_destroy (pass2_2); @@ -532,11 +533,12 @@ rank_sorted_file (struct casereader *input, /* Transformation function to enumerate all the cases */ static int -create_resort_key (void *key_var_, struct ccase *cc, casenumber case_num) +create_resort_key (void *key_var_, struct ccase **cc, casenumber case_num) { struct variable *key_var = key_var_; - case_data_rw(cc, key_var)->f = case_num; + *cc = case_unshare (*cc); + case_data_rw (*cc, key_var)->f = case_num; return TRNS_CONTINUE; } diff --git a/src/language/stats/regression.q b/src/language/stats/regression.q index 4f6f0b86..595e7e75 100644 --- a/src/language/stats/regression.q +++ b/src/language/stats/regression.q @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 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 @@ -542,7 +542,7 @@ regression_trns_free (void *t_) Gets the predicted values. */ static int -regression_trns_pred_proc (void *t_, struct ccase *c, +regression_trns_pred_proc (void *t_, struct ccase **c, casenumber case_idx UNUSED) { size_t i; @@ -563,12 +563,12 @@ regression_trns_pred_proc (void *t_, struct ccase *c, n_vals = (*model->get_vars) (model, vars); vals = xnmalloc (n_vals, sizeof (*vals)); - output = case_data_rw (c, model->pred); - assert (output != NULL); + *c = case_unshare (*c); + output = case_data_rw (*c, model->pred); for (i = 0; i < n_vals; i++) { - vals[i] = case_data (c, vars[i]); + vals[i] = case_data (*c, vars[i]); } output->f = (*model->predict) ((const struct variable **) vars, vals, model, n_vals); @@ -581,7 +581,7 @@ regression_trns_pred_proc (void *t_, struct ccase *c, Gets the residuals. */ static int -regression_trns_resid_proc (void *t_, struct ccase *c, +regression_trns_resid_proc (void *t_, struct ccase **c, casenumber case_idx UNUSED) { size_t i; @@ -603,14 +603,15 @@ regression_trns_resid_proc (void *t_, struct ccase *c, n_vals = (*model->get_vars) (model, vars); vals = xnmalloc (n_vals, sizeof (*vals)); - output = case_data_rw (c, model->resid); + *c = case_unshare (*c); + output = case_data_rw (*c, model->resid); assert (output != NULL); for (i = 0; i < n_vals; i++) { - vals[i] = case_data (c, vars[i]); + vals[i] = case_data (*c, vars[i]); } - obs = case_data (c, model->depvar); + obs = case_data (*c, model->depvar); output->f = (*model->residual) ((const struct variable **) vars, vals, obs, model, n_vals); free (vals); @@ -821,7 +822,7 @@ prepare_categories (struct casereader *input, struct moments_var *mom) { int n_data; - struct ccase c; + struct ccase *c; size_t i; assert (vars != NULL); @@ -832,7 +833,7 @@ prepare_categories (struct casereader *input, cat_stored_values_create (vars[i]); n_data = 0; - for (; casereader_read (input, &c); case_destroy (&c)) + for (; (c = casereader_read (input)) != NULL; case_unref (c)) { /* The second condition ensures the program will run even if @@ -841,7 +842,7 @@ prepare_categories (struct casereader *input, */ for (i = 0; i < n_vars; i++) { - const union value *val = case_data (&c, vars[i]); + const union value *val = case_data (c, vars[i]); if (var_is_alpha (vars[i])) cat_value_update (vars[i], val); else @@ -868,7 +869,7 @@ run_regression (struct casereader *input, struct cmd_regression *cmd, size_t i; int n_indep = 0; int k; - struct ccase c; + struct ccase *c; const struct variable **indep_vars; struct design_matrix *X; struct moments_var *mom; @@ -878,13 +879,14 @@ run_regression (struct casereader *input, struct cmd_regression *cmd, assert (models != NULL); - if (!casereader_peek (input, 0, &c)) + c = casereader_peek (input, 0); + if (c == NULL) { casereader_destroy (input); return true; } - output_split_file_values (ds, &c); - case_destroy (&c); + output_split_file_values (ds, c); + case_unref (c); if (!v_variables) { @@ -916,7 +918,7 @@ run_regression (struct casereader *input, struct cmd_regression *cmd, const struct variable *dep_var; struct casereader *reader; casenumber row; - struct ccase c; + struct ccase *c; size_t n_data; /* Number of valid cases. */ dep_var = cmd->v_dependent[k]; @@ -955,18 +957,18 @@ run_regression (struct casereader *input, struct cmd_regression *cmd, The second pass fills the design matrix. */ reader = casereader_create_counter (reader, &row, -1); - for (; casereader_read (reader, &c); case_destroy (&c)) + for (; (c = casereader_read (reader)) != NULL; case_unref (c)) { for (i = 0; i < n_indep; ++i) { const struct variable *v = indep_vars[i]; - const union value *val = case_data (&c, v); + const union value *val = case_data (c, v); if (var_is_alpha (v)) design_matrix_set_categorical (X, row, v, val); else design_matrix_set_numeric (X, row, v, val); } - gsl_vector_set (Y, row, case_num (&c, dep_var)); + gsl_vector_set (Y, row, case_num (c, dep_var)); } /* Now that we know the number of coefficients, allocate space diff --git a/src/language/stats/reliability.q b/src/language/stats/reliability.q index 8384bb35..25aff211 100644 --- a/src/language/stats/reliability.q +++ b/src/language/stats/reliability.q @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2008 Free Software Foundation, Inc. + Copyright (C) 2008, 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 @@ -304,7 +304,7 @@ run_reliability (struct casereader *input, struct dataset *ds UNUSED, { int i; int si; - struct ccase c; + struct ccase *c; casenumber n_missing ; casenumber n_valid = 0; @@ -338,7 +338,7 @@ run_reliability (struct casereader *input, struct dataset *ds UNUSED, s, NULL); } - for (; casereader_read (input, &c); case_destroy (&c)) + for (; (c = casereader_read (input)) != NULL; case_unref (c)) { double weight = 1.0; n_valid ++; @@ -348,9 +348,9 @@ run_reliability (struct casereader *input, struct dataset *ds UNUSED, struct cronbach *s = &rel->sc[si]; for (i = 0 ; i < s->n_items ; ++i ) - moments1_add (s->m[i], case_data (&c, s->items[i])->f, weight); + moments1_add (s->m[i], case_data (c, s->items[i])->f, weight); - moments1_add (s->total, case_data_idx (&c, s->totals_idx)->f, weight); + moments1_add (s->total, case_data_idx (c, s->totals_idx)->f, weight); } } casereader_destroy (input); diff --git a/src/language/stats/t-test.q b/src/language/stats/t-test.q index 6d6dfd56..bc6023c7 100644 --- a/src/language/stats/t-test.q +++ b/src/language/stats/t-test.q @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 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 @@ -1799,17 +1799,18 @@ calculate (struct cmd_t_test *cmd, struct casereader *pass1, *pass2, *pass3; struct taint *taint; - struct ccase c; + struct ccase *c; enum mv_class exclude = cmd->miss != TTS_INCLUDE ? MV_ANY : MV_SYSTEM; - if (!casereader_peek (input, 0, &c)) + c = casereader_peek (input, 0); + if (c == NULL) { casereader_destroy (input); return; } - output_split_file_values (ds, &c); - case_destroy (&c); + output_split_file_values (ds, c); + case_unref (c); if ( cmd->miss == TTS_LISTWISE ) input = casereader_create_filter_missing (input, @@ -1823,8 +1824,8 @@ calculate (struct cmd_t_test *cmd, casereader_split (input, &pass1, &pass2); common_precalc (cmd); - for (; casereader_read (pass1, &c); case_destroy (&c)) - common_calc (dict, &c, cmd, exclude); + for (; (c = casereader_read (pass1)) != NULL; case_unref (c)) + common_calc (dict, c, cmd, exclude); casereader_destroy (pass1); common_postcalc (cmd); @@ -1832,22 +1833,22 @@ calculate (struct cmd_t_test *cmd, { case T_1_SAMPLE: one_sample_precalc (cmd); - for (; casereader_read (pass2, &c); case_destroy (&c)) - one_sample_calc (dict, &c, cmd, exclude); + for (; (c = casereader_read (pass2)) != NULL; case_unref (c)) + one_sample_calc (dict, c, cmd, exclude); one_sample_postcalc (cmd); break; case T_PAIRED: paired_precalc (cmd); - for (; casereader_read (pass2, &c); case_destroy (&c)) - paired_calc (dict, &c, cmd, exclude); + for (; (c = casereader_read (pass2)) != NULL; case_unref (c)) + paired_calc (dict, c, cmd, exclude); paired_postcalc (cmd); break; case T_IND_SAMPLES: pass3 = casereader_clone (pass2); group_precalc (cmd); - for (; casereader_read (pass2, &c); case_destroy (&c)) - group_calc (dict, &c, cmd, exclude); + for (; (c = casereader_read (pass2)) != NULL; case_unref (c)) + group_calc (dict, c, cmd, exclude); group_postcalc (cmd); levene (dict, pass3, indep_var, cmd->n_variables, cmd->v_variables, diff --git a/src/language/stats/wilcoxon.c b/src/language/stats/wilcoxon.c index 2f5bbea8..2a05f5d9 100644 --- a/src/language/stats/wilcoxon.c +++ b/src/language/stats/wilcoxon.c @@ -1,5 +1,5 @@ /* Pspp - a program for statistical analysis. - Copyright (C) 2008 Free Software Foundation, Inc. + Copyright (C) 2008, 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 @@ -88,7 +88,7 @@ wilcoxon_execute (const struct dataset *ds, { struct casereader *r = casereader_clone (input); struct casewriter *writer; - struct ccase c; + struct ccase *c; struct subcase ordering; variable_pair *vp = &t2s->pairs[i]; @@ -105,41 +105,37 @@ wilcoxon_execute (const struct dataset *ds, writer = sort_create_writer (&ordering, reader_width); subcase_destroy (&ordering); - while (casereader_read (r, &c)) + for (; (c = casereader_read (r)) != NULL; case_unref (c)) { - struct ccase output; - double d = append_difference (&c, 0, vp); - - case_create (&output, reader_width); + struct ccase *output = case_create (reader_width); + double d = append_difference (c, 0, vp); if (d > 0) { - case_data_rw (&output, ws[i].sign)->f = 1.0; + case_data_rw (output, ws[i].sign)->f = 1.0; } else if (d < 0) { - case_data_rw (&output, ws[i].sign)->f = -1.0; + case_data_rw (output, ws[i].sign)->f = -1.0; } else { double w = 1.0; if (weight) - w = case_data (&c, weight)->f; + w = case_data (c, weight)->f; /* Central point values should be dropped */ ws[i].n_zeros += w; - case_destroy (&c); - continue; + continue; } - case_data_rw (&output, ws[i].absdiff)->f = fabs (d); + case_data_rw (output, ws[i].absdiff)->f = fabs (d); if (weight) - case_data_rw (&output, weightx)->f = case_data (&c, weight)->f; + case_data_rw (output, weightx)->f = case_data (c, weight)->f; - casewriter_write (writer, &output); - case_destroy (&c); + casewriter_write (writer, output); } casereader_destroy (r); ws[i].reader = casewriter_make_reader (writer); @@ -148,7 +144,7 @@ wilcoxon_execute (const struct dataset *ds, for (i = 0 ; i < t2s->n_pairs; ++i ) { struct casereader *rr ; - struct ccase c; + struct ccase *c; enum rank_error err = 0; rr = casereader_create_append_rank (ws[i].reader, ws[i].absdiff, @@ -156,13 +152,13 @@ wilcoxon_execute (const struct dataset *ds, distinct_callback, &ws[i] ); - while (casereader_read (rr, &c)) + for (; (c = casereader_read (rr)) != NULL; case_unref (c)) { - double sign = case_data (&c, ws[i].sign)->f; - double rank = case_data_idx (&c, weight ? 3 : 2)->f; + double sign = case_data (c, ws[i].sign)->f; + double rank = case_data_idx (c, weight ? 3 : 2)->f; double w = 1.0; if (weight) - w = case_data (&c, weightx)->f; + w = case_data (c, weightx)->f; if ( sign > 0 ) { @@ -176,8 +172,6 @@ wilcoxon_execute (const struct dataset *ds, } else NOT_REACHED (); - - case_destroy (&c); } casereader_destroy (rr); diff --git a/src/language/tests/datasheet-check.c b/src/language/tests/datasheet-check.c index b3b2856d..ccfee805 100644 --- a/src/language/tests/datasheet-check.c +++ b/src/language/tests/datasheet-check.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -80,14 +80,15 @@ check_datasheet_casereader (struct mc *mc, struct casereader *reader, casereader_get_value_cnt (reader), column_cnt); else { - struct ccase c; + struct ccase *c; size_t row; for (row = 0; row < row_cnt; row++) { size_t col; - if (!casereader_read (reader, &c)) + c = casereader_read (reader); + if (c == NULL) { mc_error (mc, "casereader_read failed reading row %zu of %zu " "(%zu columns)", row, row_cnt, column_cnt); @@ -95,16 +96,17 @@ check_datasheet_casereader (struct mc *mc, struct casereader *reader, } for (col = 0; col < column_cnt; col++) - if (case_num_idx (&c, col) != array[row][col]) + if (case_num_idx (c, col) != array[row][col]) mc_error (mc, "element %zu,%zu (of %zu,%zu) differs: " "%g != %g", row, col, row_cnt, column_cnt, - case_num_idx (&c, col), array[row][col]); + case_num_idx (c, col), array[row][col]); - case_destroy (&c); + case_unref (c); } - if (casereader_read (reader, &c)) + c = casereader_read (reader); + if (c != NULL) mc_error (mc, "casereader has extra cases (expected %zu)", row_cnt); } } @@ -253,17 +255,17 @@ datasheet_mc_init (struct mc *mc) writer = mem_writer_create (params->backing_cols); for (row = 0; row < params->backing_rows; row++) { - struct ccase c; + struct ccase *c; int col; - case_create (&c, params->backing_cols); + c = case_create (params->backing_cols); for (col = 0; col < params->backing_cols; col++) { double value = params->next_value++; data[row][col] = value; - case_data_rw_idx (&c, col)->f = value; + case_data_rw_idx (c, col)->f = value; } - casewriter_write (writer, &c); + casewriter_write (writer, c); } reader = casewriter_make_reader (writer); assert (reader != NULL); @@ -371,7 +373,7 @@ datasheet_mc_mutate (struct mc *mc, const void *ods_) if (mc_include_state (mc)) { struct datasheet *ds; - struct ccase c[MAX_ROWS]; + struct ccase *c[MAX_ROWS]; size_t i, j; clone_model (ods, odata, &ds, data); @@ -379,15 +381,15 @@ datasheet_mc_mutate (struct mc *mc, const void *ods_) for (i = 0; i < cnt; i++) { - case_create (&c[i], column_cnt); + c[i] = case_create (column_cnt); for (j = 0; j < column_cnt; j++) - case_data_rw_idx (&c[i], j)->f = params->next_value++; + case_data_rw_idx (c[i], j)->f = params->next_value++; } insert_range (data, row_cnt, sizeof data[pos], pos, cnt); for (i = 0; i < cnt; i++) for (j = 0; j < column_cnt; j++) - data[i + pos][j] = case_num_idx (&c[i], j); + data[i + pos][j] = case_num_idx (c[i], j); if (!datasheet_insert_rows (ds, pos, c, cnt)) mc_error (mc, "datasheet_insert_rows failed"); diff --git a/src/language/tests/datasheet-check.h b/src/language/tests/datasheet-check.h index bd0e492d..d5a1c096 100644 --- a/src/language/tests/datasheet-check.h +++ b/src/language/tests/datasheet-check.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -51,7 +51,7 @@ void datasheet_move_columns (struct datasheet *, /* Rows. */ casenumber datasheet_get_row_cnt (const struct datasheet *); bool datasheet_insert_rows (struct datasheet *, - casenumber before, struct ccase[], + casenumber before, struct ccase *rows[], casenumber cnt); void datasheet_delete_rows (struct datasheet *, casenumber first, casenumber cnt); @@ -60,7 +60,7 @@ void datasheet_move_rows (struct datasheet *, size_t cnt); /* Data. */ -bool datasheet_get_row (const struct datasheet *, casenumber, struct ccase *); +struct ccase *datasheet_get_row (const struct datasheet *, casenumber); bool datasheet_put_row (struct datasheet *, casenumber, struct ccase *); bool datasheet_get_value (const struct datasheet *, casenumber, size_t column, union value *, int width); diff --git a/src/language/xforms/compute.c b/src/language/xforms/compute.c index f17798f7..9f65491e 100644 --- a/src/language/xforms/compute.c +++ b/src/language/xforms/compute.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 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 @@ -112,14 +112,17 @@ cmd_compute (struct lexer *lexer, struct dataset *ds) /* Handle COMPUTE or IF with numeric target variable. */ static int -compute_num (void *compute_, struct ccase *c, casenumber case_num) +compute_num (void *compute_, struct ccase **c, casenumber case_num) { struct compute_trns *compute = compute_; if (compute->test == NULL - || expr_evaluate_num (compute->test, c, case_num) == 1.0) - case_data_rw (c, compute->variable)->f - = expr_evaluate_num (compute->rvalue, c, case_num); + || expr_evaluate_num (compute->test, *c, case_num) == 1.0) + { + *c = case_unshare (*c); + case_data_rw (*c, compute->variable)->f + = expr_evaluate_num (compute->rvalue, *c, case_num); + } return TRNS_CONTINUE; } @@ -127,17 +130,17 @@ compute_num (void *compute_, struct ccase *c, casenumber case_num) /* Handle COMPUTE or IF with numeric vector element target variable. */ static int -compute_num_vec (void *compute_, struct ccase *c, casenumber case_num) +compute_num_vec (void *compute_, struct ccase **c, casenumber case_num) { struct compute_trns *compute = compute_; if (compute->test == NULL - || expr_evaluate_num (compute->test, c, case_num) == 1.0) + || expr_evaluate_num (compute->test, *c, case_num) == 1.0) { double index; /* Index into the vector. */ int rindx; /* Rounded index value. */ - index = expr_evaluate_num (compute->element, c, case_num); + index = expr_evaluate_num (compute->element, *c, case_num); rindx = floor (index + EPSILON); if (index == SYSMIS || rindx < 1 || rindx > vector_get_var_cnt (compute->vector)) @@ -152,8 +155,10 @@ compute_num_vec (void *compute_, struct ccase *c, casenumber case_num) index, vector_get_name (compute->vector)); return TRNS_CONTINUE; } - case_data_rw (c, vector_get_var (compute->vector, rindx - 1))->f - = expr_evaluate_num (compute->rvalue, c, case_num); + + *c = case_unshare (*c); + case_data_rw (*c, vector_get_var (compute->vector, rindx - 1))->f + = expr_evaluate_num (compute->rvalue, *c, case_num); } return TRNS_CONTINUE; @@ -161,14 +166,18 @@ compute_num_vec (void *compute_, struct ccase *c, casenumber case_num) /* Handle COMPUTE or IF with string target variable. */ static int -compute_str (void *compute_, struct ccase *c, casenumber case_num) +compute_str (void *compute_, struct ccase **c, casenumber case_num) { struct compute_trns *compute = compute_; if (compute->test == NULL - || expr_evaluate_num (compute->test, c, case_num) == 1.0) - expr_evaluate_str (compute->rvalue, c, case_num, - case_data_rw (c, compute->variable)->s, compute->width); + || expr_evaluate_num (compute->test, *c, case_num) == 1.0) + { + *c = case_unshare (*c); + expr_evaluate_str (compute->rvalue, *c, case_num, + case_data_rw (*c, compute->variable)->s, + compute->width); + } return TRNS_CONTINUE; } @@ -176,18 +185,18 @@ compute_str (void *compute_, struct ccase *c, casenumber case_num) /* Handle COMPUTE or IF with string vector element target variable. */ static int -compute_str_vec (void *compute_, struct ccase *c, casenumber case_num) +compute_str_vec (void *compute_, struct ccase **c, casenumber case_num) { struct compute_trns *compute = compute_; if (compute->test == NULL - || expr_evaluate_num (compute->test, c, case_num) == 1.0) + || expr_evaluate_num (compute->test, *c, case_num) == 1.0) { double index; /* Index into the vector. */ int rindx; /* Rounded index value. */ struct variable *vr; /* Variable reference by indexed vector. */ - index = expr_evaluate_num (compute->element, c, case_num); + index = expr_evaluate_num (compute->element, *c, case_num); rindx = floor (index + EPSILON); if (index == SYSMIS) { @@ -205,8 +214,9 @@ compute_str_vec (void *compute_, struct ccase *c, casenumber case_num) } vr = vector_get_var (compute->vector, rindx - 1); - expr_evaluate_str (compute->rvalue, c, case_num, - case_data_rw (c, vr)->s, + *c = case_unshare (*c); + expr_evaluate_str (compute->rvalue, *c, case_num, + case_data_rw (*c, vr)->s, var_get_width (vr)); } diff --git a/src/language/xforms/count.c b/src/language/xforms/count.c index 1c9b4d65..6e234c4b 100644 --- a/src/language/xforms/count.c +++ b/src/language/xforms/count.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 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 @@ -268,8 +268,8 @@ parse_string_criteria (struct lexer *lexer, struct pool *pool, struct criteria * /* Transformation. */ /* Counts the number of values in case C matching CRIT. */ -static inline int -count_numeric (struct criteria *crit, struct ccase *c) +static int +count_numeric (struct criteria *crit, const struct ccase *c) { int counter = 0; size_t i; @@ -302,8 +302,8 @@ count_numeric (struct criteria *crit, struct ccase *c) } /* Counts the number of values in case C matching CRIT. */ -static inline int -count_string (struct criteria *crit, struct ccase *c) +static int +count_string (struct criteria *crit, const struct ccase *c) { int counter = 0; size_t i; @@ -325,12 +325,13 @@ count_string (struct criteria *crit, struct ccase *c) /* Performs the COUNT transformation T on case C. */ static int -count_trns_proc (void *trns_, struct ccase *c, +count_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED) { struct count_trns *trns = trns_; struct dst_var *dv; + *c = case_unshare (*c); for (dv = trns->dst_vars; dv; dv = dv->next) { struct criteria *crit; @@ -339,10 +340,10 @@ count_trns_proc (void *trns_, struct ccase *c, counter = 0; for (crit = dv->crit; crit; crit = crit->next) if (var_is_numeric (crit->vars[0])) - counter += count_numeric (crit, c); + counter += count_numeric (crit, *c); else - counter += count_string (crit, c); - case_data_rw (c, dv->var)->f = counter; + counter += count_string (crit, *c); + case_data_rw (*c, dv->var)->f = counter; } return TRNS_CONTINUE; } diff --git a/src/language/xforms/fail.c b/src/language/xforms/fail.c index ad3425c8..d1cfabf6 100644 --- a/src/language/xforms/fail.c +++ b/src/language/xforms/fail.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -24,14 +24,14 @@ #include #include -static int trns_fail (void *x, struct ccase *c, casenumber n); +static int trns_fail (void *x, struct ccase **c, casenumber n); /* A transformation which is guaranteed to fail. */ static int -trns_fail (void *x UNUSED, struct ccase *c UNUSED, +trns_fail (void *x UNUSED, struct ccase **c UNUSED, casenumber n UNUSED) { return TRNS_ERROR; diff --git a/src/language/xforms/recode.c b/src/language/xforms/recode.c index bdff1ac5..e2074823 100644 --- a/src/language/xforms/recode.c +++ b/src/language/xforms/recode.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 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 @@ -647,18 +647,19 @@ find_src_string (struct recode_trns *trns, const char *value, const struct varia /* Performs RECODE transformation. */ static int -recode_trns_proc (void *trns_, struct ccase *c, casenumber case_idx UNUSED) +recode_trns_proc (void *trns_, struct ccase **c, casenumber case_idx UNUSED) { struct recode_trns *trns = trns_; size_t i; + *c = case_unshare (*c); for (i = 0; i < trns->var_cnt; i++) { const struct variable *src_var = trns->src_vars[i]; const struct variable *dst_var = trns->dst_vars[i]; - const union value *src_data = case_data (c, src_var); - union value *dst_data = case_data_rw (c, dst_var); + const union value *src_data = case_data (*c, src_var); + union value *dst_data = case_data_rw (*c, dst_var); const struct map_out *out; diff --git a/src/language/xforms/sample.c b/src/language/xforms/sample.c index 632009ed..6fbc758c 100644 --- a/src/language/xforms/sample.c +++ b/src/language/xforms/sample.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 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 @@ -116,7 +116,7 @@ cmd_sample (struct lexer *lexer, struct dataset *ds) /* Executes a SAMPLE transformation. */ static int -sample_trns_proc (void *t_, struct ccase *c UNUSED, +sample_trns_proc (void *t_, struct ccase **c UNUSED, casenumber case_num UNUSED) { struct sample_trns *t = t_; diff --git a/src/language/xforms/select-if.c b/src/language/xforms/select-if.c index 5576c420..85f616d5 100644 --- a/src/language/xforms/select-if.c +++ b/src/language/xforms/select-if.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 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 @@ -70,11 +70,11 @@ cmd_select_if (struct lexer *lexer, struct dataset *ds) /* Performs the SELECT IF transformation T on case C. */ static int -select_if_proc (void *t_, struct ccase *c, +select_if_proc (void *t_, struct ccase **c, casenumber case_num) { struct select_if_trns *t = t_; - return (expr_evaluate_num (t->e, c, case_num) == 1.0 + return (expr_evaluate_num (t->e, *c, case_num) == 1.0 ? TRNS_CONTINUE : TRNS_DROP_CASE); } diff --git a/src/math/levene.c b/src/math/levene.c index 3f8ddb29..7bd58210 100644 --- a/src/math/levene.c +++ b/src/math/levene.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 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 @@ -118,7 +118,7 @@ levene(const struct dictionary *dict, enum mv_class exclude) { struct casereader *pass1, *pass2; - struct ccase c; + struct ccase *c; struct levene_info l; l.n_dep = n_dep; @@ -131,14 +131,14 @@ levene(const struct dictionary *dict, casereader_split (reader, &pass1, &pass2); levene_precalc (&l); - for (; casereader_read (pass1, &c); case_destroy (&c)) - levene_calc (dict, &c, &l); + for (; (c = casereader_read (pass1)) != NULL; case_unref (c)) + levene_calc (dict, c, &l); casereader_destroy (pass1); levene_postcalc (&l); levene2_precalc(&l); - for (; casereader_read (pass2, &c); case_destroy (&c)) - levene2_calc (dict, &c, &l); + for (; (c = casereader_read (pass2)) != NULL; case_unref (c)) + levene2_calc (dict, c, &l); casereader_destroy (pass2); levene2_postcalc (&l); diff --git a/src/math/merge.c b/src/math/merge.c index b8412298..2ff57c6e 100644 --- a/src/math/merge.c +++ b/src/math/merge.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + 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 @@ -36,7 +36,7 @@ struct merge_input { struct casereader *reader; - struct ccase c; + struct ccase *c; }; struct merge @@ -111,7 +111,8 @@ read_input_case (struct merge *m, size_t idx) { struct merge_input *i = &m->inputs[idx]; - if (casereader_read (i->reader, &i->c)) + i->c = casereader_read (i->reader); + if (i->c) return true; else { @@ -144,11 +145,11 @@ do_merge (struct merge *m) min = 0; for (i = 1; i < m->input_cnt; i++) - if (subcase_compare_3way (&m->ordering, &m->inputs[i].c, - &m->ordering, &m->inputs[min].c) < 0) + if (subcase_compare_3way (&m->ordering, m->inputs[i].c, + &m->ordering, m->inputs[min].c) < 0) min = i; - casewriter_write (w, &m->inputs[min].c); + casewriter_write (w, m->inputs[min].c); read_input_case (m, min); } diff --git a/src/math/np.c b/src/math/np.c index e189b470..99584a51 100644 --- a/src/math/np.c +++ b/src/math/np.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2008 Free Software Foundation, Inc. + Copyright (C) 2008, 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 @@ -37,7 +37,7 @@ static void acc (struct statistic *s, const struct ccase *cx UNUSED, double c, double cc, double y) { - struct ccase cp; + struct ccase *cp; struct np *np = (struct np *) s; double rank = np->prev_cc + (c + 1) / 2.0; @@ -56,13 +56,11 @@ acc (struct statistic *s, const struct ccase *cx UNUSED, maximize (&np->y_max, y); minimize (&np->y_min, y); - case_create (&cp, n_NP_IDX); - - case_data_rw_idx (&cp, NP_IDX_Y)->f = y; - case_data_rw_idx (&cp, NP_IDX_NS)->f = ns; - case_data_rw_idx (&cp, NP_IDX_DNS)->f = dns; - - casewriter_write (np->writer, &cp); + cp = case_create (n_NP_IDX); + case_data_rw_idx (cp, NP_IDX_Y)->f = y; + case_data_rw_idx (cp, NP_IDX_NS)->f = ns; + case_data_rw_idx (cp, NP_IDX_DNS)->f = dns; + casewriter_write (np->writer, cp); np->prev_cc = cc; } diff --git a/src/math/order-stats.c b/src/math/order-stats.c index ca4160f4..1b6aa131 100644 --- a/src/math/order-stats.c +++ b/src/math/order-stats.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2008 Free Software Foundation, Inc. + Copyright (C) 2008, 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 @@ -113,44 +113,42 @@ order_stats_accumulate (struct order_stats **os, size_t nos, const struct variable *var, enum mv_class exclude) { - struct ccase cx; - struct ccase prev_cx; + struct ccase *cx; + struct ccase *prev_cx = NULL; double prev_value = -DBL_MAX; double cc_i = 0; double c_i = 0; - case_nullify (&prev_cx); - - for (; casereader_read (reader, &cx); case_destroy (&cx)) + for (; (cx = casereader_read (reader)) != NULL; case_unref (cx)) { - const double weight = wv ? case_data (&cx, wv)->f : 1.0; - const double this_value = case_data (&cx, var)->f; + const double weight = wv ? case_data (cx, wv)->f : 1.0; + const double this_value = case_data (cx, var)->f; /* The casereader MUST be sorted */ assert (this_value >= prev_value); - if ( var_is_value_missing (var, case_data (&cx, var), exclude)) + if ( var_is_value_missing (var, case_data (cx, var), exclude)) continue; - case_destroy (&prev_cx); + case_unref (prev_cx); if ( prev_value == -DBL_MAX || prev_value == this_value) c_i += weight; if ( prev_value > -DBL_MAX && this_value > prev_value) { - update_k_values (&prev_cx, prev_value, c_i, cc_i, os, nos); + update_k_values (prev_cx, prev_value, c_i, cc_i, os, nos); c_i = weight; } cc_i += weight; prev_value = this_value; - case_clone (&prev_cx, &cx); + prev_cx = case_ref (cx); } - update_k_values (&prev_cx, prev_value, c_i, cc_i, os, nos); - case_destroy (&prev_cx); + update_k_values (prev_cx, prev_value, c_i, cc_i, os, nos); + case_unref (prev_cx); casereader_destroy (reader); } diff --git a/src/math/sort.c b/src/math/sort.c index 9e860c46..67aa32d2 100644 --- a/src/math/sort.c +++ b/src/math/sort.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 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 @@ -48,7 +48,7 @@ struct sort_writer struct casewriter *run; casenumber run_id; - struct ccase run_end; + struct ccase *run_end; }; static struct casewriter_class sort_casewriter_class; @@ -58,7 +58,7 @@ static void pqueue_destroy (struct pqueue *); static bool pqueue_is_full (const struct pqueue *); static bool pqueue_is_empty (const struct pqueue *); static void pqueue_push (struct pqueue *, struct ccase *, casenumber); -static void pqueue_pop (struct pqueue *, struct ccase *, casenumber *); +static struct ccase *pqueue_pop (struct pqueue *, casenumber *); static void output_record (struct sort_writer *); @@ -74,7 +74,7 @@ sort_create_writer (const struct subcase *ordering, size_t value_cnt) sort->pqueue = pqueue_create (ordering, value_cnt); sort->run = NULL; sort->run_id = 0; - case_nullify (&sort->run_end); + sort->run_end = NULL; return casewriter_create (value_cnt, &sort_casewriter_class, sort); } @@ -89,9 +89,9 @@ sort_casewriter_write (struct casewriter *writer UNUSED, void *sort_, if (pqueue_is_full (sort->pqueue)) output_record (sort); - next_run = (case_is_null (&sort->run_end) + next_run = (sort->run_end == NULL || subcase_compare_3way (&sort->ordering, c, - &sort->ordering, &sort->run_end) < 0); + &sort->ordering, sort->run_end) < 0); pqueue_push (sort->pqueue, c, sort->run_id + (next_run ? 1 : 0)); } @@ -104,7 +104,7 @@ sort_casewriter_destroy (struct casewriter *writer UNUSED, void *sort_) merge_destroy (sort->merge); pqueue_destroy (sort->pqueue); casewriter_destroy (sort->run); - case_destroy (&sort->run_end); + case_unref (sort->run_end); free (sort); } @@ -134,12 +134,12 @@ sort_casewriter_convert_to_reader (struct casewriter *writer, void *sort_) static void output_record (struct sort_writer *sort) { - struct ccase min_case; + struct ccase *min_case; casenumber min_run_id; - pqueue_pop (sort->pqueue, &min_case, &min_run_id); + min_case = pqueue_pop (sort->pqueue, &min_run_id); #if 0 - printf ("\toutput: %f to run %d\n", case_num_idx (&min_case, 0), min_run_id); + printf ("\toutput: %f to run %d\n", case_num_idx (min_case, 0), min_run_id); #endif if (sort->run_id != min_run_id && sort->run != NULL) @@ -153,10 +153,9 @@ output_record (struct sort_writer *sort) sort->run_id = min_run_id; } - case_destroy (&sort->run_end); - case_clone (&sort->run_end, &min_case); - - casewriter_write (sort->run, &min_case); + case_unref (sort->run_end); + sort->run_end = case_ref (min_case); + casewriter_write (sort->run, min_case); } static struct casewriter_class sort_casewriter_class = @@ -204,7 +203,7 @@ struct pqueue struct pqueue_record { casenumber id; - struct ccase c; + struct ccase *c; casenumber idx; }; @@ -238,10 +237,9 @@ pqueue_destroy (struct pqueue *pq) { while (!pqueue_is_empty (pq)) { - struct ccase c; casenumber id; - pqueue_pop (pq, &c, &id); - case_destroy (&c); + struct ccase *c = pqueue_pop (pq, &id); + case_unref (c); } subcase_destroy (&pq->ordering); free (pq->records); @@ -270,15 +268,15 @@ pqueue_push (struct pqueue *pq, struct ccase *c, casenumber id) r = &pq->records[pq->record_cnt++]; r->id = id; - case_move (&r->c, c); + r->c = c; r->idx = pq->idx++; push_heap (pq->records, pq->record_cnt, sizeof *pq->records, compare_pqueue_records_minheap, pq); } -static void -pqueue_pop (struct pqueue *pq, struct ccase *c, casenumber *id) +static struct ccase * +pqueue_pop (struct pqueue *pq, casenumber *id) { struct pqueue_record *r; @@ -289,7 +287,7 @@ pqueue_pop (struct pqueue *pq, struct ccase *c, casenumber *id) r = &pq->records[pq->record_cnt]; *id = r->id; - case_move (c, &r->c); + return r->c; } /* Compares record-run tuples A and B on id, then on case data, @@ -303,8 +301,7 @@ compare_pqueue_records_minheap (const void *a_, const void *b_, const struct pqueue *pq = pq_; int result = a->id < b->id ? -1 : a->id > b->id; if (result == 0) - result = subcase_compare_3way (&pq->ordering, &a->c, - &pq->ordering, &b->c); + result = subcase_compare_3way (&pq->ordering, a->c, &pq->ordering, b->c); if (result == 0) result = a->idx < b->idx ? -1 : a->idx > b->idx; return -result; diff --git a/src/ui/gui/psppire-data-editor.c b/src/ui/gui/psppire-data-editor.c index 00e227ec..735d4328 100644 --- a/src/ui/gui/psppire-data-editor.c +++ b/src/ui/gui/psppire-data-editor.c @@ -1,5 +1,5 @@ /* PSPPIRE - a graphical user interface for PSPP. - Copyright (C) 2008 Free Software Foundation, Inc. + Copyright (C) 2008, 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 @@ -1607,16 +1607,9 @@ data_sheet_set_clip (PsppireSheet *sheet) writer = autopaging_writer_create (dict_get_next_value_idx (clip_dict)); for (i = range.row0; i <= range.rowi ; ++i ) { - struct ccase old; - - if (psppire_data_store_get_case (ds, i, &old)) - { - struct ccase new; - - case_map_execute (map, &old, &new); - case_destroy (&old); - casewriter_write (writer, &new); - } + struct ccase *old = psppire_data_store_get_case (ds, i); + if (old != NULL) + casewriter_write (writer, case_map_execute (map, old)); else casewriter_force_error (writer); } @@ -1667,8 +1660,10 @@ clip_to_text (void) for (r = 0 ; r < case_cnt ; ++r ) { int c; - struct ccase cc; - if ( ! casereader_peek (clip_datasheet, r, &cc)) + struct ccase *cc; + + cc = casereader_peek (clip_datasheet, r); + if (cc == NULL) { g_warning ("Clipboard seems to have inexplicably shrunk"); break; @@ -1677,7 +1672,7 @@ clip_to_text (void) for (c = 0 ; c < var_cnt ; ++c) { const struct variable *v = dict_get_var (clip_dict, c); - data_out_g_string (string, v, &cc); + data_out_g_string (string, v, cc); if ( c < val_cnt - 1 ) g_string_append (string, "\t"); } @@ -1685,7 +1680,7 @@ clip_to_text (void) if ( r < case_cnt) g_string_append (string, "\n"); - case_destroy (&cc); + case_unref (cc); } return string; @@ -1710,8 +1705,8 @@ clip_to_html (void) for (r = 0 ; r < case_cnt ; ++r ) { int c; - struct ccase cc; - if ( ! casereader_peek (clip_datasheet, r, &cc)) + struct ccase *cc = casereader_peek (clip_datasheet, r); + if (cc == NULL) { g_warning ("Clipboard seems to have inexplicably shrunk"); break; @@ -1722,13 +1717,13 @@ clip_to_html (void) { const struct variable *v = dict_get_var (clip_dict, c); g_string_append (string, ""); - data_out_g_string (string, v, &cc); + data_out_g_string (string, v, cc); g_string_append (string, "\n"); } g_string_append (string, "\n"); - case_destroy (&cc); + case_unref (cc); } g_string_append (string, "\n"); diff --git a/src/ui/gui/psppire-data-store.c b/src/ui/gui/psppire-data-store.c index 37747e07..71d7d5f5 100644 --- a/src/ui/gui/psppire-data-store.c +++ b/src/ui/gui/psppire-data-store.c @@ -1,5 +1,5 @@ /* PSPPIRE - a graphical user interface for PSPP. - Copyright (C) 2006, 2008 Free Software Foundation + Copyright (C) 2006, 2008, 2009 Free Software Foundation 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 @@ -531,7 +531,7 @@ psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn) { gboolean result; gint val_cnt, v; - struct ccase cc; + struct ccase *cc; g_return_val_if_fail (ds, FALSE); val_cnt = datasheet_get_column_cnt (ds->datasheet) ; @@ -540,9 +540,9 @@ psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn) g_return_val_if_fail (posn <= psppire_data_store_get_case_count (ds), FALSE); - case_create (&cc, val_cnt); + cc = case_create (val_cnt); - memset ( case_data_rw_idx (&cc, 0), 0, val_cnt * MAX_SHORT_STRING); + memset ( case_data_rw_idx (cc, 0), 0, val_cnt * MAX_SHORT_STRING); for (v = 0 ; v < psppire_dict_get_var_cnt (ds->dict) ; ++v) { @@ -550,12 +550,12 @@ psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn) if ( var_is_alpha (pv)) continue; - case_data_rw (&cc, pv)->f = SYSMIS; + case_data_rw (cc, pv)->f = SYSMIS; } - result = psppire_data_store_insert_case (ds, &cc, posn); + result = psppire_data_store_insert_case (ds, cc, posn); - case_destroy (&cc); + case_unref (cc); return result; } @@ -837,18 +837,16 @@ get_column_justification (const PsppireSheetModel *model, gint col) -/* Fills C with the CASENUMth case. - Returns true on success, false otherwise. +/* Returns the CASENUMth case, or a null pointer on failure. */ -gboolean +struct ccase * psppire_data_store_get_case (const PsppireDataStore *ds, - casenumber casenum, - struct ccase *c) + casenumber casenum) { g_return_val_if_fail (ds, FALSE); g_return_val_if_fail (ds->datasheet, FALSE); - return datasheet_get_row (ds->datasheet, casenum, c); + return datasheet_get_row (ds->datasheet, casenum); } @@ -879,14 +877,13 @@ psppire_data_store_insert_case (PsppireDataStore *ds, struct ccase *cc, casenumber posn) { - struct ccase tmp; bool result ; g_return_val_if_fail (ds, FALSE); g_return_val_if_fail (ds->datasheet, FALSE); - case_clone (&tmp, cc); - result = datasheet_insert_rows (ds->datasheet, posn, &tmp, 1); + case_ref (cc); + result = datasheet_insert_rows (ds->datasheet, posn, &cc, 1); if ( result ) { diff --git a/src/ui/gui/psppire-data-store.h b/src/ui/gui/psppire-data-store.h index 44b11725..5ffd85d6 100644 --- a/src/ui/gui/psppire-data-store.h +++ b/src/ui/gui/psppire-data-store.h @@ -1,5 +1,5 @@ /* PSPPIRE - a graphical user interface for PSPP. - Copyright (C) 2006 Free Software Foundation + Copyright (C) 2006, 2009 Free Software Foundation 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 @@ -122,9 +122,8 @@ size_t psppire_data_store_get_value_count (const PsppireDataStore *ds); -gboolean psppire_data_store_get_case (const PsppireDataStore *ds, - casenumber casenum, - struct ccase *c); +struct ccase *psppire_data_store_get_case (const PsppireDataStore *ds, + casenumber casenum);