X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fcaseproto.c;h=358d59eb3d37cb01dd2a13dc358461c8172d44d6;hb=e0cbdf0daefcca81be9572aab0deedf945687f5a;hp=1a40213a537d295f78241a0c35a0594ba3a6262a;hpb=4bd4ff4a47e70820ea55a37e27fe731e97cbbd14;p=pspp diff --git a/src/data/caseproto.c b/src/data/caseproto.c index 1a40213a53..358d59eb3d 100644 --- a/src/data/caseproto.c +++ b/src/data/caseproto.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2009 Free Software Foundation, Inc. + Copyright (C) 2009, 2011 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 @@ -16,46 +16,49 @@ #include -#include -#include -#include -#include -#include -#include +#include "data/caseproto.h" -#include "minmax.h" +#include "data/val-type.h" +#include "data/value.h" +#include "libpspp/array.h" +#include "libpspp/assertion.h" +#include "libpspp/pool.h" + +#include "gl/minmax.h" static struct caseproto *caseproto_unshare (struct caseproto *); -static bool try_init_long_strings (const struct caseproto *, +static bool try_init_strings (const struct caseproto *, size_t first, size_t last, union value[]); -static void init_long_strings (const struct caseproto *, +static void init_strings (const struct caseproto *, size_t first, size_t last, union value[]); -static void destroy_long_strings (const struct caseproto *, +static void destroy_strings (const struct caseproto *, size_t first, size_t last, union value[]); -static size_t count_long_strings (const struct caseproto *, +static size_t count_strings (const struct caseproto *, size_t idx, size_t count); -/* Returns the number of bytes to allocate for a struct caseproto - with room for N_WIDTHS elements in its widths[] array. */ -static inline size_t -caseproto_size (size_t n_widths) -{ - return (offsetof (struct caseproto, widths) - + n_widths * sizeof (((struct caseproto *) NULL)->widths[0])); -} - /* Creates and returns a case prototype that initially has no widths. */ struct caseproto * caseproto_create (void) { - enum { N_ALLOCATE = 4 }; - struct caseproto *proto = xmalloc (caseproto_size (N_ALLOCATE)); - proto->ref_cnt = 1; - proto->long_strings = NULL; - proto->n_long_strings = 0; - proto->n_widths = 0; - proto->allocated_widths = N_ALLOCATE; + struct caseproto *proto = xmalloc (sizeof *proto); + *proto = (struct caseproto) { + .ref_cnt = 1, + }; + return proto; +} + +struct caseproto * MALLOC_LIKE +caseproto_from_widths (short int *widths, size_t n) +{ + struct caseproto *proto = xmalloc (sizeof *proto); + *proto = (struct caseproto) { + .ref_cnt = 1, + .n_widths = n, + .allocated_widths = n, + .widths = widths, + }; + proto->n_strings = count_strings (proto, 0, n); return proto; } @@ -76,49 +79,35 @@ caseproto_ref_pool (const struct caseproto *proto_, struct pool *pool) return proto; } -/* Returns a replacement for PROTO that is unshared and has - enough room for at least N_WIDTHS widths before additional - memory is needed. */ -struct caseproto * -caseproto_reserve (struct caseproto *proto, size_t n_widths) -{ - proto = caseproto_unshare (proto); - if (n_widths > proto->allocated_widths) - { - proto->allocated_widths *= MAX (proto->allocated_widths * 2, n_widths); - proto = xrealloc (proto, caseproto_size (proto->allocated_widths)); - } - return proto; -} - /* Returns a replacement for PROTO with WIDTH appended. */ struct caseproto * caseproto_add_width (struct caseproto *proto, int width) { - assert (width >= -1 && width <= MAX_STRING); + assert (width >= 0 && width <= MAX_STRING); - proto = caseproto_reserve (proto, proto->n_widths + 1); + proto = caseproto_unshare (proto); + if (proto->n_widths >= proto->allocated_widths) + proto->widths = x2nrealloc (proto->widths, &proto->allocated_widths, + sizeof *proto->widths); proto->widths[proto->n_widths++] = width; - proto->n_long_strings += count_long_strings (proto, proto->n_widths - 1, 1); + if (width > 0) + proto->n_strings++; return proto; } -/* Returns a replacement for PROTO with the width at index IDX - replaced by WIDTH. IDX may be greater than the current number - of widths in PROTO, in which case any gap is filled in by - widths of -1. */ +/* Returns a replacement for PROTO with the width at index IDX replaced by + WIDTH. */ struct caseproto * caseproto_set_width (struct caseproto *proto, size_t idx, int width) { - assert (width >= -1 && width <= MAX_STRING); + assert (idx < proto->n_widths); + assert (width >= 0 && width <= MAX_STRING); - proto = caseproto_reserve (proto, idx + 1); - while (idx >= proto->n_widths) - proto->widths[proto->n_widths++] = -1; - proto->n_long_strings -= count_long_strings (proto, idx, 1); + proto = caseproto_unshare (proto); + proto->n_strings -= count_strings (proto, idx, 1); proto->widths[idx] = width; - proto->n_long_strings += count_long_strings (proto, idx, 1); + proto->n_strings += count_strings (proto, idx, 1); return proto; } @@ -129,10 +118,14 @@ caseproto_set_width (struct caseproto *proto, size_t idx, int width) struct caseproto * caseproto_insert_width (struct caseproto *proto, size_t before, int width) { + assert (width >= 0 && width <= MAX_STRING); assert (before <= proto->n_widths); - proto = caseproto_reserve (proto, proto->n_widths + 1); - proto->n_long_strings += value_needs_init (width); + proto = caseproto_unshare (proto); + if (proto->n_widths >= proto->allocated_widths) + proto->widths = x2nrealloc (proto->widths, &proto->allocated_widths, + sizeof *proto->widths); + proto->n_strings += value_needs_init (width); insert_element (proto->widths, proto->n_widths, sizeof *proto->widths, before); proto->widths[before] = width; @@ -141,35 +134,35 @@ caseproto_insert_width (struct caseproto *proto, size_t before, int width) return proto; } -/* Returns a replacement for PROTO with CNT widths removed +/* Returns a replacement for PROTO with N widths removed starting at index IDX. */ struct caseproto * -caseproto_remove_widths (struct caseproto *proto, size_t idx, size_t cnt) +caseproto_remove_widths (struct caseproto *proto, size_t idx, size_t n) { - assert (caseproto_range_is_valid (proto, idx, cnt)); + assert (caseproto_range_is_valid (proto, idx, n)); proto = caseproto_unshare (proto); - proto->n_long_strings -= count_long_strings (proto, idx, cnt); + proto->n_strings -= count_strings (proto, idx, n); remove_range (proto->widths, proto->n_widths, sizeof *proto->widths, - idx, cnt); - proto->n_widths -= cnt; + idx, n); + proto->n_widths -= n; return proto; } -/* Returns a replacement for PROTO in which the CNT widths +/* Returns a replacement for PROTO in which the N widths starting at index OLD_WIDTH now start at index NEW_WIDTH, with other widths shifting out of the way to make room. */ struct caseproto * caseproto_move_widths (struct caseproto *proto, size_t old_start, size_t new_start, - size_t cnt) + size_t n) { - assert (caseproto_range_is_valid (proto, old_start, cnt)); - assert (caseproto_range_is_valid (proto, new_start, cnt)); + assert (caseproto_range_is_valid (proto, old_start, n)); + assert (caseproto_range_is_valid (proto, new_start, n)); proto = caseproto_unshare (proto); move_range (proto->widths, proto->n_widths, sizeof *proto->widths, - old_start, new_start, cnt); + old_start, new_start, n); return proto; } @@ -206,9 +199,9 @@ caseproto_is_conformable (const struct caseproto *a, const struct caseproto *b) same as the N widths starting at B_START in B, false if any of the corresponding widths differ. */ bool -caseproto_equal (const struct caseproto *a, size_t a_start, - const struct caseproto *b, size_t b_start, - size_t n) +caseproto_range_equal (const struct caseproto *a, size_t a_start, + const struct caseproto *b, size_t b_start, + size_t n) { size_t i; @@ -220,6 +213,15 @@ caseproto_equal (const struct caseproto *a, size_t a_start, return true; } +/* Returns true if A and B have the same widths, false otherwise. */ +bool +caseproto_equal (const struct caseproto *a, const struct caseproto *b) +{ + return (a == b ? true + : a->n_widths != b->n_widths ? false + : caseproto_range_equal (a, 0, b, 0, a->n_widths)); +} + /* Returns true if an array of values that is to be used for data of the format specified in PROTO needs to be initialized by calling caseproto_init_values, false if that step may be @@ -230,7 +232,7 @@ caseproto_equal (const struct caseproto *a, size_t a_start, bool caseproto_needs_init_values (const struct caseproto *proto) { - return proto->n_long_strings > 0; + return proto->n_strings > 0; } /* Initializes the values in VALUES as required by PROTO, by @@ -245,7 +247,7 @@ caseproto_needs_init_values (const struct caseproto *proto) void caseproto_init_values (const struct caseproto *proto, union value values[]) { - init_long_strings (proto, 0, proto->n_long_strings, values); + init_strings (proto, 0, proto->n_strings, values); } /* Like caseproto_init_values, but returns false instead of @@ -253,7 +255,7 @@ caseproto_init_values (const struct caseproto *proto, union value values[]) bool caseproto_try_init_values (const struct caseproto *proto, union value values[]) { - return try_init_long_strings (proto, 0, proto->n_long_strings, values); + return try_init_strings (proto, 0, proto->n_strings, values); } /* Initializes the data in VALUES that are in NEW but not in OLD, @@ -272,15 +274,15 @@ void caseproto_reinit_values (const struct caseproto *old, const struct caseproto *new, union value values[]) { - size_t old_n_long = old->n_long_strings; - size_t new_n_long = new->n_long_strings; + size_t old_n_long = old->n_strings; + size_t new_n_long = new->n_strings; expensive_assert (caseproto_is_conformable (old, new)); if (new_n_long > old_n_long) - init_long_strings (new, old_n_long, new_n_long, values); + init_strings (new, old_n_long, new_n_long, values); else if (new_n_long < old_n_long) - destroy_long_strings (old, new_n_long, old_n_long, values); + destroy_strings (old, new_n_long, old_n_long, values); } /* Frees the values in VALUES as required by PROTO, by calling @@ -292,7 +294,7 @@ caseproto_reinit_values (const struct caseproto *old, void caseproto_destroy_values (const struct caseproto *proto, union value values[]) { - destroy_long_strings (proto, 0, proto->n_long_strings, values); + destroy_strings (proto, 0, proto->n_strings, values); } /* Copies COUNT values, whose widths are given by widths in PROTO @@ -313,62 +315,71 @@ caseproto_copy (const struct caseproto *proto, size_t idx, size_t count, void caseproto_free__ (struct caseproto *proto) { - free (proto->long_strings); + free (proto->strings); + free (proto->widths); free (proto); } void -caseproto_refresh_long_string_cache__ (const struct caseproto *proto_) +caseproto_refresh_string_cache__ (const struct caseproto *proto_) { - struct caseproto *proto = (struct caseproto *) proto_; + struct caseproto *proto = CONST_CAST (struct caseproto *, proto_); size_t n, i; - assert (proto->long_strings == NULL); - assert (proto->n_long_strings > 0); + assert (proto->strings == NULL); + assert (proto->n_strings > 0); - proto->long_strings = xmalloc (proto->n_long_strings - * sizeof *proto->long_strings); + proto->strings = xmalloc (proto->n_strings * sizeof *proto->strings); n = 0; for (i = 0; i < proto->n_widths; i++) - if (proto->widths[i] > MAX_SHORT_STRING) - proto->long_strings[n++] = i; - assert (n == proto->n_long_strings); + if (proto->widths[i] > 0) + proto->strings[n++] = i; + assert (n == proto->n_strings); } +/* Returns a caseproto that can be modified without affecting the contents of + any caseproto shared with OLD. + + The returned caseproto has no strings cache. This is helpful because the + caller might be about to invalidate it. */ static struct caseproto * caseproto_unshare (struct caseproto *old) { - struct caseproto *new; - if (old->ref_cnt > 1) + assert (old->ref_cnt > 0); + if (old->ref_cnt <= 1) { - new = xmemdup (old, caseproto_size (old->allocated_widths)); - new->ref_cnt = 1; - --old->ref_cnt; + free (old->strings); + old->strings = NULL; + return old; } - else - { - new = old; - free (new->long_strings); - } - new->long_strings = NULL; + + struct caseproto *new = xmalloc (sizeof *new); + *new = (struct caseproto) { + .ref_cnt = 1, + .n_strings = old->n_strings, + .n_widths = old->n_widths, + .allocated_widths = old->allocated_widths, + .widths = xmemdup (old->widths, old->allocated_widths * sizeof *old->widths), + }; + --old->ref_cnt; return new; } static bool -try_init_long_strings (const struct caseproto *proto, +try_init_strings (const struct caseproto *proto, size_t first, size_t last, union value values[]) { size_t i; - if (last > 0 && proto->long_strings == NULL) - caseproto_refresh_long_string_cache__ (proto); + if (last > 0 && proto->strings == NULL) + caseproto_refresh_string_cache__ (proto); for (i = first; i < last; i++) { - size_t idx = proto->long_strings[i]; + size_t idx = proto->strings[i]; if (!value_try_init (&values[idx], proto->widths[idx])) { - destroy_long_strings (proto, first, i, values); + destroy_strings (proto, first, i, values); return false; } } @@ -376,36 +387,36 @@ try_init_long_strings (const struct caseproto *proto, } static void -init_long_strings (const struct caseproto *proto, +init_strings (const struct caseproto *proto, size_t first, size_t last, union value values[]) { - if (!try_init_long_strings (proto, first, last, values)) + if (!try_init_strings (proto, first, last, values)) xalloc_die (); } static void -destroy_long_strings (const struct caseproto *proto, size_t first, size_t last, +destroy_strings (const struct caseproto *proto, size_t first, size_t last, union value values[]) { size_t i; - if (last > 0 && proto->long_strings == NULL) - caseproto_refresh_long_string_cache__ (proto); + if (last > 0 && proto->strings == NULL) + caseproto_refresh_string_cache__ (proto); for (i = first; i < last; i++) { - size_t idx = proto->long_strings[i]; + size_t idx = proto->strings[i]; value_destroy (&values[idx], proto->widths[idx]); } } static size_t -count_long_strings (const struct caseproto *proto, size_t idx, size_t count) +count_strings (const struct caseproto *proto, size_t idx, size_t count) { size_t n, i; n = 0; for (i = 0; i < count; i++) - n += proto->widths[idx + i] > MAX_SHORT_STRING; + n += proto->widths[idx + i] > 0; return n; }