X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fcasewindow.c;h=9b04b9413c61bbace1e5b189d68e65eebe152482;hb=edf539fc797fedcdf7a71894f707d3c9728335d6;hp=71a7c1bd2fe87aa6d6127622e9803510df1367ed;hpb=5aa037d0c36fcaf2a1ad3995bffe5c32fd201124;p=pspp-builds.git diff --git a/src/data/casewindow.c b/src/data/casewindow.c index 71a7c1bd..9b04b941 100644 --- a/src/data/casewindow.c +++ b/src/data/casewindow.c @@ -1,20 +1,18 @@ -/* PSPP - computes sample statistics. - Copyright (C) 2007 Free Software Foundation, Inc. +/* PSPP - a program for statistical analysis. + Copyright (C) 2007, 2009 Free Software Foundation, Inc. - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. */ + along with this program. If not, see . */ /* This casewindow implementation in terms of an class interface is undoubtedly a form of over-abstraction. However, it works @@ -35,26 +33,26 @@ #include "xalloc.h" /* A queue of cases. */ -struct casewindow +struct casewindow { /* Common data. */ - size_t value_cnt; /* Number of values per case. */ + struct caseproto *proto; /* Prototype of cases in window. */ casenumber max_in_core_cases; /* Max cases before dumping to disk. */ struct taint *taint; /* Taint status. */ /* Implementation data. */ - const struct casewindow_class *class; + const struct casewindow_class *class; void *aux; }; /* Implementation of a casewindow. */ -struct casewindow_class +struct casewindow_class { - void *(*create) (struct taint *, size_t value_cnt); + void *(*create) (struct taint *, const struct caseproto *); 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); }; @@ -65,41 +63,44 @@ static const struct casewindow_class casewindow_file_class; /* Creates and returns a new casewindow using the given parameters. */ static struct casewindow * -do_casewindow_create (struct taint *taint, - size_t value_cnt, casenumber max_in_core_cases) +do_casewindow_create (struct taint *taint, const struct caseproto *proto, + casenumber max_in_core_cases) { struct casewindow *cw = xmalloc (sizeof *cw); cw->class = (max_in_core_cases ? &casewindow_memory_class : &casewindow_file_class); - cw->aux = cw->class->create (taint, value_cnt); - cw->value_cnt = value_cnt; + cw->aux = cw->class->create (taint, proto); + cw->proto = caseproto_ref (proto); cw->max_in_core_cases = max_in_core_cases; cw->taint = taint; return cw; } -/* Creates and returns a new casewindow for cases with VALUE_CNT - values each. If the casewindow holds more than +/* Creates and returns a new casewindow for cases that take the + form specified by PROTO. If the casewindow holds more than MAX_IN_CORE_CASES cases at any time, its cases will be dumped - to disk; otherwise, its cases will be held in memory. */ + to disk; otherwise, its cases will be held in memory. + + The caller retains its reference to PROTO. */ struct casewindow * -casewindow_create (size_t value_cnt, casenumber max_in_core_cases) +casewindow_create (const struct caseproto *proto, casenumber max_in_core_cases) { - return do_casewindow_create (taint_create (), value_cnt, max_in_core_cases); + return do_casewindow_create (taint_create (), proto, max_in_core_cases); } /* Destroys casewindow CW. Returns true if CW was tainted, which is caused by an I/O error or by taint propagation to the casewindow. */ bool -casewindow_destroy (struct casewindow *cw) +casewindow_destroy (struct casewindow *cw) { bool ok = true; - if (cw != NULL) + if (cw != NULL) { cw->class->destroy (cw->aux); ok = taint_destroy (cw->taint); + caseproto_unref (cw->proto); free (cw); } return ok; @@ -107,7 +108,7 @@ casewindow_destroy (struct casewindow *cw) /* Swaps the contents of casewindows A and B. */ static void -casewindow_swap (struct casewindow *a, struct casewindow *b) +casewindow_swap (struct casewindow *a, struct casewindow *b) { struct casewindow tmp = *a; *a = *b; @@ -116,17 +117,17 @@ casewindow_swap (struct casewindow *a, struct casewindow *b) /* Dumps the contents of casewindow OLD to disk. */ static void -casewindow_to_disk (struct casewindow *old) +casewindow_to_disk (struct casewindow *old) { struct casewindow *new; - new = do_casewindow_create (taint_clone (old->taint), old->value_cnt, 0); + new = do_casewindow_create (taint_clone (old->taint), old->proto, 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); @@ -135,7 +136,7 @@ casewindow_to_disk (struct casewindow *old) /* Pushes case C at the head of casewindow CW. Case C becomes owned by the casewindow. */ void -casewindow_push_head (struct casewindow *cw, struct ccase *c) +casewindow_push_head (struct casewindow *cw, struct ccase *c) { if (!casewindow_error (cw)) { @@ -145,86 +146,84 @@ casewindow_push_head (struct casewindow *cw, struct ccase *c) casenumber case_cnt = cw->class->get_case_cnt (cw->aux); if (case_cnt > cw->max_in_core_cases && cw->class == &casewindow_memory_class) - casewindow_to_disk (cw); + casewindow_to_disk (cw); } } else - case_destroy (c); + case_unref (c); } /* Deletes CASE_CNT cases at the tail of casewindow CW. */ void -casewindow_pop_tail (struct casewindow *cw, casenumber case_cnt) +casewindow_pop_tail (struct casewindow *cw, casenumber case_cnt) { - if (!casewindow_error (cw)) + if (!casewindow_error (cw)) 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. */ casenumber -casewindow_get_case_cnt (const struct casewindow *cw) +casewindow_get_case_cnt (const struct casewindow *cw) { return cw->class->get_case_cnt (cw->aux); } -/* Returns the number of values per case in casewindow CW. */ -size_t -casewindow_get_value_cnt (const struct casewindow *cw) +/* Returns the case prototype for the cases in casewindow CW. + The caller must not unref the returned prototype. */ +const struct caseproto * +casewindow_get_proto (const struct casewindow *cw) { - return cw->value_cnt; + return cw->proto; } /* Returns true if casewindow CW is tainted. A casewindow is tainted by an I/O error or by taint propagation to the casewindow. */ bool -casewindow_error (const struct casewindow *cw) +casewindow_error (const struct casewindow *cw) { return taint_is_tainted (cw->taint); } /* Marks casewindow CW tainted. */ void -casewindow_force_error (struct casewindow *cw) +casewindow_force_error (struct casewindow *cw) { taint_set_taint (cw->taint); } /* Returns casewindow CW's taint object. */ const struct taint * -casewindow_get_taint (const struct casewindow *cw) +casewindow_get_taint (const struct casewindow *cw) { return cw->taint; } /* In-memory casewindow data. */ -struct casewindow_memory +struct casewindow_memory { struct deque deque; - struct ccase *cases; + struct ccase **cases; }; static void * -casewindow_memory_create (struct taint *taint UNUSED, size_t value_cnt UNUSED) +casewindow_memory_create (struct taint *taint UNUSED, + const struct caseproto *proto UNUSED) { struct casewindow_memory *cwm = xmalloc (sizeof *cwm); cwm->cases = deque_init (&cwm->deque, 4, sizeof *cwm->cases); @@ -232,11 +231,11 @@ casewindow_memory_create (struct taint *taint UNUSED, size_t value_cnt UNUSED) } static void -casewindow_memory_destroy (void *cwm_) +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)]); + while (!deque_is_empty (&cwm->deque)) + case_unref (cwm->cases[deque_pop_front (&cwm->deque)]); free (cwm->cases); free (cwm); } @@ -247,7 +246,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 @@ -255,26 +254,25 @@ 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)]); + while (case_cnt-- > 0) + 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 -casewindow_memory_get_case_cnt (const void *cwm_) +casewindow_memory_get_case_cnt (const void *cwm_) { const struct casewindow_memory *cwm = cwm_; return deque_count (&cwm->deque); } -static const struct casewindow_class casewindow_memory_class = +static const struct casewindow_class casewindow_memory_class = { casewindow_memory_create, casewindow_memory_destroy, @@ -285,24 +283,24 @@ static const struct casewindow_class casewindow_memory_class = }; /* On-disk casewindow data. */ -struct casewindow_file +struct casewindow_file { struct case_tmpfile *file; casenumber head, tail; }; static void * -casewindow_file_create (struct taint *taint, size_t value_cnt) +casewindow_file_create (struct taint *taint, const struct caseproto *proto) { struct casewindow_file *cwf = xmalloc (sizeof *cwf); - cwf->file = case_tmpfile_create (value_cnt); + cwf->file = case_tmpfile_create (proto); cwf->head = cwf->tail = 0; taint_propagate (case_tmpfile_get_taint (cwf->file), taint); return cwf; } static void -casewindow_file_destroy (void *cwf_) +casewindow_file_destroy (void *cwf_) { struct casewindow_file *cwf = cwf_; case_tmpfile_destroy (cwf->file); @@ -310,15 +308,15 @@ casewindow_file_destroy (void *cwf_) } static void -casewindow_file_push_head (void *cwf_, struct ccase *c) +casewindow_file_push_head (void *cwf_, struct ccase *c) { struct casewindow_file *cwf = cwf_; - if (case_tmpfile_put_case (cwf->file, cwf->head, c)) + if (case_tmpfile_put_case (cwf->file, cwf->head, c)) cwf->head++; } static void -casewindow_file_pop_tail (void *cwf_, casenumber cnt) +casewindow_file_pop_tail (void *cwf_, casenumber cnt) { struct casewindow_file *cwf = cwf_; assert (cnt <= cwf->head - cwf->tail); @@ -327,21 +325,21 @@ 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 -casewindow_file_get_case_cnt (const void *cwf_) +casewindow_file_get_case_cnt (const void *cwf_) { const struct casewindow_file *cwf = cwf_; return cwf->head - cwf->tail; } -static const struct casewindow_class casewindow_file_class = +static const struct casewindow_class casewindow_file_class = { casewindow_file_create, casewindow_file_destroy,