X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fcasereader.c;h=97b7ceff3d1b7eb19e8ac6243aef08eb961a0f6b;hb=13d91b755ed1045e2c1183874b3752b07489b922;hp=5ae5a0a8ea4431019660c60e1d56d9d68ed8c3fa;hpb=cb586666724d5fcbdb658ce471b85484f0a7babe;p=pspp-builds.git diff --git a/src/data/casereader.c b/src/data/casereader.c index 5ae5a0a8..97b7ceff 100644 --- a/src/data/casereader.c +++ b/src/data/casereader.c @@ -257,6 +257,20 @@ casereader_get_case_cnt (struct casereader *reader) return reader->case_cnt; } +static casenumber +casereader_count_cases__ (const struct casereader *reader, + casenumber max_cases) +{ + struct casereader *clone; + casenumber n_cases; + + clone = casereader_clone (reader); + n_cases = casereader_advance (clone, max_cases); + casereader_destroy (clone); + + return n_cases; +} + /* Returns the number of cases that will be read by successive calls to casereader_read for READER, assuming that no errors occur. Upon an error condition, the case count drops to 0, so @@ -267,25 +281,30 @@ casereader_get_case_cnt (struct casereader *reader) of the contents of a clone of READER. Thus, the return value is always correct in the absence of I/O errors. */ casenumber -casereader_count_cases (struct casereader *reader) +casereader_count_cases (const struct casereader *reader) { if (reader->case_cnt == CASENUMBER_MAX) { - casenumber n_cases = 0; - struct ccase *c; - - struct casereader *clone = casereader_clone (reader); - - for (; (c = casereader_read (clone)) != NULL; case_unref (c)) - n_cases++; - - casereader_destroy (clone); - reader->case_cnt = n_cases; + struct casereader *reader_rw = CONST_CAST (struct casereader *, reader); + reader_rw->case_cnt = casereader_count_cases__ (reader, CASENUMBER_MAX); } - return reader->case_cnt; } +/* Truncates READER to at most N cases. */ +void +casereader_truncate (struct casereader *reader, casenumber n) +{ + /* This could be optimized, if it ever becomes too expensive, by adding a + "max_cases" member to struct casereader. We could also add a "truncate" + function to the casereader implementation, to allow the casereader to + throw away data that cannot ever be read. */ + if (reader->case_cnt == CASENUMBER_MAX) + reader->case_cnt = casereader_count_cases__ (reader, n); + if (reader->case_cnt > n) + reader->case_cnt = n; +} + /* Returns the prototype for the cases in READER. The caller must not unref the returned prototype. */ const struct caseproto * @@ -294,6 +313,26 @@ casereader_get_proto (const struct casereader *reader) return reader->proto; } +/* Skips past N cases in READER, stopping when the last case in + READER has been read or on an input error. Returns the number + of cases successfully skipped. */ +casenumber +casereader_advance (struct casereader *reader, casenumber n) +{ + casenumber i; + + for (i = 0; i < n; i++) + { + struct ccase *c = casereader_read (reader); + if (c == NULL) + break; + case_unref (c); + } + + return i; +} + + /* Copies all the cases in READER to WRITER, propagating errors appropriately. */ void @@ -664,3 +703,42 @@ static const struct casereader_random_class shim_class = shim_destroy, shim_advance, }; + +static const struct casereader_class casereader_null_class; + +/* Returns a casereader with no cases. The casereader has the prototype + specified by PROTO. PROTO may be specified as a null pointer, in which case + the casereader has no variables. */ +struct casereader * +casereader_create_empty (const struct caseproto *proto_) +{ + struct casereader *reader; + struct caseproto *proto; + + proto = proto_ != NULL ? caseproto_ref (proto_) : caseproto_create (); + reader = casereader_create_sequential (NULL, proto, 0, + &casereader_null_class, NULL); + caseproto_unref (proto); + + return reader; +} + +static struct ccase * +casereader_null_read (struct casereader *reader UNUSED, void *aux UNUSED) +{ + return NULL; +} + +static void +casereader_null_destroy (struct casereader *reader UNUSED, void *aux UNUSED) +{ + /* Nothing to do. */ +} + +static const struct casereader_class casereader_null_class = + { + casereader_null_read, + casereader_null_destroy, + NULL, /* clone */ + NULL, /* peek */ + };