X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fcase.c;h=1384791c82665c359eb3755e37516641c41f788d;hb=a29bbbe97388bb6f9c9b4df36b448dfe5023363c;hp=6c427df5bc4dedcbdca0413cb62357b2300fe257;hpb=06f9ee45954e5e71fa7f6262dbf37defa1dbf996;p=pspp diff --git a/src/case.c b/src/case.c index 6c427df5bc..1384791c82 100644 --- a/src/case.c +++ b/src/case.c @@ -14,8 +14,8 @@ 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., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ #include #include "case.h" @@ -24,14 +24,22 @@ #include "val.h" #include "alloc.h" #include "str.h" +#include "var.h" #ifdef GLOBAL_DEBUGGING #undef NDEBUG #else +#ifndef NDEBUG #define NDEBUG #endif +#endif #include +/* Changes C not to share data with any other case. + C must be a case with a reference count greater than 1. + There should be no reason for external code to call this + function explicitly. It will be called automatically when + needed. */ void case_unshare (struct ccase *c) { @@ -49,6 +57,8 @@ case_unshare (struct ccase *c) sizeof *cd->values * cd->value_cnt); } +/* Returns the number of bytes needed by a case with VALUE_CNT + values. */ static inline size_t case_size (size_t value_cnt) { @@ -57,6 +67,7 @@ case_size (size_t value_cnt) } #ifdef GLOBAL_DEBUGGING +/* Initializes C as a null case. */ void case_nullify (struct ccase *c) { @@ -66,6 +77,7 @@ case_nullify (struct ccase *c) #endif /* GLOBAL_DEBUGGING */ #ifdef GLOBAL_DEBUGGING +/* Returns true iff C is a null case. */ int case_is_null (const struct ccase *c) { @@ -73,14 +85,18 @@ case_is_null (const struct ccase *c) } #endif /* GLOBAL_DEBUGGING */ +/* Initializes C as a new case that can store VALUE_CNT values. + The values have indeterminate contents until explicitly + written. */ void case_create (struct ccase *c, size_t value_cnt) { if (!case_try_create (c, value_cnt)) - out_of_memory (); + xalloc_die (); } #ifdef GLOBAL_DEBUGGING +/* Initializes CLONE as a copy of ORIG. */ void case_clone (struct ccase *clone, const struct ccase *orig) { @@ -100,6 +116,8 @@ case_clone (struct ccase *clone, const struct ccase *orig) #endif /* GLOBAL_DEBUGGING */ #ifdef GLOBAL_DEBUGGING +/* 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) { @@ -116,6 +134,7 @@ case_move (struct ccase *dst, struct ccase *src) #endif /* GLOBAL_DEBUGGING */ #ifdef GLOBAL_DEBUGGING +/* Destroys case C. */ void case_destroy (struct ccase *c) { @@ -134,6 +153,30 @@ case_destroy (struct ccase *c) } #endif /* GLOBAL_DEBUGGING */ +/* Resizes case C from OLD_CNT to NEW_CNT values. */ +void +case_resize (struct ccase *c, size_t old_cnt, size_t new_cnt) +{ + struct ccase new; + + case_create (&new, new_cnt); + case_copy (&new, 0, c, 0, old_cnt < new_cnt ? old_cnt : new_cnt); + case_swap (&new, c); + case_destroy (&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; +} + +/* Attempts to create C as a new case that holds VALUE_CNT + values. Returns nonzero if successful, zero if memory + allocation failed. */ int case_try_create (struct ccase *c, size_t value_cnt) { @@ -156,6 +199,9 @@ case_try_create (struct ccase *c, size_t value_cnt) } } +/* Tries to initialize CLONE as a copy of ORIG. + Returns nonzero if successful, zero if memory allocation + failed. */ int case_try_clone (struct ccase *clone, const struct ccase *orig) { @@ -164,6 +210,8 @@ case_try_clone (struct ccase *clone, const struct ccase *orig) } #ifdef GLOBAL_DEBUGGING +/* Copies VALUE_CNT values from SRC (starting at SRC_IDX) to DST + (starting at DST_IDX). */ void case_copy (struct ccase *dst, size_t dst_idx, const struct ccase *src, size_t src_idx, @@ -191,50 +239,51 @@ case_copy (struct ccase *dst, size_t dst_idx, #endif /* GLOBAL_DEBUGGING */ #ifdef GLOBAL_DEBUGGING -size_t -case_serial_size (size_t value_cnt) -{ - return value_cnt * sizeof (union value); -} -#endif /* GLOBAL_DEBUGGING */ - -#ifdef GLOBAL_DEBUGGING +/* Copies case C to OUTPUT. + OUTPUT_SIZE is the number of `union values' in OUTPUT, + which must match the number of `union values' in C. */ void -case_serialize (const struct ccase *c, void *output, +case_to_values (const struct ccase *c, union value *output, size_t output_size UNUSED) { assert (c != NULL); assert (c->this == c); assert (c->case_data != NULL); assert (c->case_data->ref_cnt > 0); - assert (output_size == case_serial_size (c->case_data->value_cnt)); + assert (output_size == c->case_data->value_cnt); assert (output != NULL || output_size == 0); memcpy (output, c->case_data->values, - case_serial_size (c->case_data->value_cnt)); + c->case_data->value_cnt * sizeof *output); } #endif /* GLOBAL_DEBUGGING */ #ifdef GLOBAL_DEBUGGING +/* Copies INPUT into case C. + INPUT_SIZE is the number of `union values' in INPUT, + which must match the number of `union values' in C. */ void -case_unserialize (struct ccase *c, const void *input, +case_from_values (struct ccase *c, const union value *input, size_t input_size UNUSED) { assert (c != NULL); assert (c->this == c); assert (c->case_data != NULL); assert (c->case_data->ref_cnt > 0); - assert (input_size == case_serial_size (c->case_data->value_cnt)); + assert (input_size == c->case_data->value_cnt); assert (input != NULL || input_size == 0); if (c->case_data->ref_cnt > 1) case_unshare (c); memcpy (c->case_data->values, input, - case_serial_size (c->case_data->value_cnt)); + c->case_data->value_cnt * sizeof *input); } #endif /* GLOBAL_DEBUGGING */ #ifdef GLOBAL_DEBUGGING +/* 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 (const struct ccase *c, size_t idx) { @@ -249,6 +298,8 @@ case_data (const struct ccase *c, size_t idx) #endif /* GLOBAL_DEBUGGING */ #ifdef GLOBAL_DEBUGGING +/* Returns the numeric value of the `union value' in C numbered + IDX. */ double case_num (const struct ccase *c, size_t idx) { @@ -263,6 +314,10 @@ case_num (const struct ccase *c, size_t idx) #endif /* GLOBAL_DEBUGGING */ #ifdef GLOBAL_DEBUGGING +/* 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. */ const char * case_str (const struct ccase *c, size_t idx) { @@ -277,6 +332,9 @@ case_str (const struct ccase *c, size_t idx) #endif /* GLOBAL_DEBUGGING */ #ifdef GLOBAL_DEBUGGING +/* 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 (struct ccase *c, size_t idx) { @@ -291,3 +349,83 @@ case_data_rw (struct ccase *c, size_t idx) return &c->case_data->values[idx]; } #endif /* GLOBAL_DEBUGGING */ + +/* Compares the values of the VAR_CNT 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, + struct variable *const *vp, size_t var_cnt) +{ + return case_compare_2dict (a, b, vp, vp, var_cnt); +} + +/* 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 + and returns a strcmp()-type result. */ +int +case_compare_2dict (const struct ccase *ca, const struct ccase *cb, + struct variable *const *vap, struct variable *const *vbp, + size_t var_cnt) +{ + for (; var_cnt-- > 0; vap++, vbp++) + { + const struct variable *va = *vap; + const struct variable *vb = *vbp; + + assert (va->type == vb->type); + assert (va->width == vb->width); + + if (va->width == 0) + { + double af = case_num (ca, va->fv); + double bf = case_num (cb, vb->fv); + + if (af != bf) + return af > bf ? 1 : -1; + } + else + { + const char *as = case_str (ca, va->fv); + const char *bs = case_str (cb, vb->fv); + int cmp = memcmp (as, bs, va->width); + + if (cmp != 0) + return cmp; + } + } + return 0; +} + +/* 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. */ +const union value * +case_data_all (const struct ccase *c) +{ + assert (c != NULL); + assert (c->this == c); + assert (c->case_data != NULL); + assert (c->case_data->ref_cnt > 0); + + return c->case_data->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. */ +union value * +case_data_all_rw (struct ccase *c) +{ + assert (c != NULL); + assert (c->this == c); + assert (c->case_data != NULL); + assert (c->case_data->ref_cnt > 0); + + if (c->case_data->ref_cnt > 1) + case_unshare (c); + return c->case_data->values; +}