case: Introduce new functions for numbers and substrings in cases.
[pspp] / src / data / case.c
index dc4029268ebf981bc10d96ecccf7c88eb53dd71a..742d1f0f22ca46e6743f0c0a6d808b6fd28250a6 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2007, 2009, 2010, 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
 
 #include <config.h>
 
-#include <data/case.h>
+#include "data/case.h"
 
 #include <limits.h>
 #include <stddef.h>
 #include <stdlib.h>
 
-#include <data/value.h>
-#include <data/variable.h>
-#include <libpspp/assertion.h>
-#include <libpspp/str.h>
+#include "data/value.h"
+#include "data/variable.h"
+#include "libpspp/assertion.h"
+#include "libpspp/str.h"
 
-#include "minmax.h"
-#include "xalloc.h"
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
+
+/* Set this flag to 1 to copy cases instead of ref counting them.
+   This is sometimes helpful in debugging situations. */
+#define DEBUG_CASEREFS 0
+
+#if DEBUG_CASEREFS
+#warning "Caseref debug enabled.  CASES ARE NOT BEING SHARED!!"
+#endif
 
 static size_t case_size (const struct caseproto *);
-static bool variable_matches_case (const struct ccase *,
+static void assert_variable_matches_case (const struct ccase *,
                                    const struct variable *);
 static void copy_forward (struct ccase *dst, size_t dst_idx,
                           const struct ccase *src, size_t src_idx,
@@ -80,6 +88,19 @@ case_clone (const struct ccase *c)
   return case_unshare (case_ref (c));
 }
 
+/* Increments case C's reference count and returns C.  Afterward,
+   case C is shared among its reference count holders. */
+struct ccase *
+case_ref (const struct ccase *c_)
+{
+  struct ccase *c = CONST_CAST (struct ccase *, c_);
+  c->ref_cnt++;
+#if DEBUG_CASEREFS
+  c = case_unshare__ (c);
+#endif
+  return c;
+}
+
 /* Returns an estimate of the number of bytes of memory that
    would be consumed in creating a case based on PROTO.  The
    estimate includes typical overhead from malloc() in addition
@@ -89,7 +110,7 @@ case_get_cost (const struct caseproto *proto)
 {
   /* FIXME: improve approximation? */
   return (1 + caseproto_get_n_widths (proto)
-          + 3 * caseproto_get_n_long_strings (proto)) * sizeof (union value);
+          + 3 * caseproto_get_n_strings (proto)) * sizeof (union value);
 }
 
 /* Changes the prototype for case C, which must not be shared.
@@ -185,7 +206,7 @@ case_copy (struct ccase *dst, size_t dst_idx,
 
   if (dst != src)
     {
-      if (!dst->proto->n_long_strings || !src->proto->n_long_strings)
+      if (!dst->proto->n_strings || !src->proto->n_strings)
         memcpy (&dst->values[dst_idx], &src->values[src_idx],
                 sizeof dst->values[0] * n_values);
       else
@@ -193,7 +214,7 @@ case_copy (struct ccase *dst, size_t dst_idx,
     }
   else if (dst_idx != src_idx)
     {
-      if (!dst->proto->n_long_strings)
+      if (!dst->proto->n_strings)
         memmove (&dst->values[dst_idx], &src->values[src_idx],
                  sizeof dst->values[0] * n_values);
       else if (dst_idx < src_idx)
@@ -243,7 +264,7 @@ case_copy_in (struct ccase *c,
 const union value *
 case_data (const struct ccase *c, const struct variable *v)
 {
-  assert (variable_matches_case (c, v));
+  assert_variable_matches_case (c, v);
   return &c->values[var_get_case_index (v)];
 }
 
@@ -265,7 +286,7 @@ case_data_idx (const struct ccase *c, size_t idx)
 union value *
 case_data_rw (struct ccase *c, const struct variable *v)
 {
-  assert (variable_matches_case (c, v));
+  assert_variable_matches_case (c, v);
   assert (!case_is_shared (c));
   return &c->values[var_get_case_index (v)];
 }
@@ -289,7 +310,7 @@ case_data_rw_idx (struct ccase *c, size_t idx)
 double
 case_num (const struct ccase *c, const struct variable *v)
 {
-  assert (variable_matches_case (c, v));
+  assert_variable_matches_case (c, v);
   return c->values[var_get_case_index (v)].f;
 }
 
@@ -302,6 +323,29 @@ case_num_idx (const struct ccase *c, size_t idx)
   return c->values[idx].f;
 }
 
+/* Returns a pointer to the `double' in the `union value' in C for variable V.
+   The caller is allowed to modify the returned data.
+
+   Case C must be drawn from V's dictionary and must not be shared. */
+double *
+case_num_rw (struct ccase *c, const struct variable *v)
+{
+  assert_variable_matches_case (c, v);
+  assert (!case_is_shared (c));
+  return &c->values[var_get_case_index (v)].f;
+}
+
+/* Returns a pointer to the `double' in the `union value' in C numbered IDX.
+   The caller is allowed to modify the returned data.
+
+   Case C must not be shared. */
+double *
+case_num_rw_idx (struct ccase *c, size_t idx)
+{
+  assert (!case_is_shared (c));
+  return &c->values[idx].f;
+}
+
 /* 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.
@@ -311,9 +355,8 @@ case_num_idx (const struct ccase *c, size_t idx)
 const uint8_t *
 case_str (const struct ccase *c, const struct variable *v)
 {
-  size_t idx = var_get_case_index (v);
-  assert (variable_matches_case (c, v));
-  return value_str (&c->values[idx], caseproto_get_width (c->proto, idx));
+  assert_variable_matches_case (c, v);
+  return c->values[var_get_case_index (v)].s;
 }
 
 /* Returns the string value of the `union value' in C numbered
@@ -325,7 +368,27 @@ const uint8_t *
 case_str_idx (const struct ccase *c, size_t idx)
 {
   assert (idx < c->proto->n_widths);
-  return value_str (&c->values[idx], caseproto_get_width (c->proto, idx));
+  return c->values[idx].s;
+}
+
+/* Returns a substring for the `union value' in C for variable V.  Case C must
+   be drawn from V's dictionary. */
+struct substring
+case_ss (const struct ccase *c, const struct variable *v)
+{
+  assert_variable_matches_case (c, v);
+  return ss_buffer (CHAR_CAST (char *, c->values[var_get_case_index (v)].s),
+                    var_get_width (v));
+}
+
+/* Returns a substring for the `union value' in C numbered IDX.  WIDTH must be
+   the value's width. */
+struct substring
+case_ss_idx (const struct ccase *c, size_t width, size_t idx)
+{
+  assert (width > 0);
+  assert (idx < c->proto->n_widths);
+  return ss_buffer (CHAR_CAST (char *, c->values[idx].s), width);
 }
 
 /* Returns the string value of the `union value' in C for
@@ -339,10 +402,10 @@ case_str_idx (const struct ccase *c, size_t idx)
 uint8_t *
 case_str_rw (struct ccase *c, const struct variable *v)
 {
+  assert_variable_matches_case (c, v);
   size_t idx = var_get_case_index (v);
-  assert (variable_matches_case (c, v));
   assert (!case_is_shared (c));
-  return value_str_rw (&c->values[idx], caseproto_get_width (c->proto, idx));
+  return c->values[idx].s;
 }
 
 /* Returns the string value of the `union value' in C numbered
@@ -357,7 +420,7 @@ case_str_rw_idx (struct ccase *c, size_t idx)
 {
   assert (idx < c->proto->n_widths);
   assert (!case_is_shared (c));
-  return value_str_rw (&c->values[idx], caseproto_get_width (c->proto, idx));
+  return c->values[idx].s;
 }
 
 /* Compares the values of the N_VARS variables in VP
@@ -384,7 +447,7 @@ case_compare_2dict (const struct ccase *ca, const struct ccase *cb,
       const union value *va = case_data (ca, *vap);
       const union value *vb = case_data (cb, *vbp);
       assert (var_get_width (*vap) == var_get_width (*vbp));
-      cmp = value_compare_3way (va, vb, var_get_width (*vap)); 
+      cmp = value_compare_3way (va, vb, var_get_width (*vap));
     }
   return cmp;
 }
@@ -447,12 +510,12 @@ case_size (const struct caseproto *proto)
    or write data in C.
 
    Useful in assertions. */
-static bool UNUSED
-variable_matches_case (const struct ccase *c, const struct variable *v)
+static void
+assert_variable_matches_case (const struct ccase *c, const struct variable *v)
 {
   size_t case_idx = var_get_case_index (v);
-  return (case_idx < caseproto_get_n_widths (c->proto)
-          && caseproto_get_width (c->proto, case_idx) == var_get_width (v));
+  assert (case_idx < caseproto_get_n_widths (c->proto));
+  assert (caseproto_get_width (c->proto, case_idx) == var_get_width (v));
 }
 
 /* Internal helper function for case_copy(). */
@@ -476,7 +539,7 @@ copy_backward (struct ccase *dst, size_t dst_idx,
 {
   size_t i;
 
-  for (i = n_values; i-- != 0; )
+  for (i = n_values; i-- != 0;)
     value_copy (&dst->values[dst_idx + i], &src->values[src_idx + i],
                 caseproto_get_width (dst->proto, dst_idx + i));
 }