treewide: Replace <name>_cnt by n_<name>s and <name>_cap by allocated_<name>.
[pspp] / src / data / datasheet.c
index fa24d8ce77014e980cb79e4700ffc63832c5d061..74da1116a579e539178461917c5561259b557544 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2010, 2011, 2012, 2013 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/datasheet.h>
+#include "data/datasheet.h"
 
 #include <stdlib.h>
 #include <string.h>
 
-#include <data/casereader-provider.h>
-#include <data/casereader.h>
-#include <data/casewriter.h>
-#include <data/lazy-casereader.h>
-#include <data/settings.h>
-#include <libpspp/array.h>
-#include <libpspp/assertion.h>
-#include <libpspp/misc.h>
-#include <libpspp/range-map.h>
-#include <libpspp/range-set.h>
-#include <libpspp/sparse-xarray.h>
-#include <libpspp/taint.h>
-#include <libpspp/tower.h>
-
-#include "minmax.h"
-#include "md4.h"
-#include "xalloc.h"
+#include "data/casereader-provider.h"
+#include "data/casereader.h"
+#include "data/casewriter.h"
+#include "data/lazy-casereader.h"
+#include "data/settings.h"
+#include "libpspp/array.h"
+#include "libpspp/assertion.h"
+#include "libpspp/misc.h"
+#include "libpspp/range-map.h"
+#include "libpspp/range-set.h"
+#include "libpspp/sparse-xarray.h"
+#include "libpspp/taint.h"
+#include "libpspp/tower.h"
+
+#include "gl/minmax.h"
+#include "gl/md4.h"
+#include "gl/xalloc.h"
 
 struct column;
 
@@ -80,9 +80,10 @@ static int source_allocate_column (struct source *, int width);
 static void source_release_column (struct source *, int ofs, int width);
 static bool source_in_use (const struct source *);
 
-static bool source_read (const struct column *, casenumber row, union value *);
+static bool source_read (const struct column *, casenumber row, union value *,
+                         size_t n);
 static bool source_write (const struct column *, casenumber row,
-                          const union value *);
+                          const union value *, size_t n);
 static bool source_write_column (struct column *, const union value *);
 static bool source_has_backing (const struct source *);
 
@@ -174,7 +175,7 @@ value_to_data (const union value *value_, int width)
   if (width == 0)
     return &value->f;
   else
-    return value_str_rw (value, width);
+    return value->s;
 }
 
 /* Returns the number of bytes needed to store all the values in
@@ -275,7 +276,7 @@ datasheet_destroy (struct datasheet *ds)
 const struct caseproto *
 datasheet_get_proto (const struct datasheet *ds_)
 {
-  struct datasheet *ds = (struct datasheet *) ds_;
+  struct datasheet *ds = CONST_CAST (struct datasheet *, ds_);
   if (ds->proto == NULL)
     {
       size_t i;
@@ -360,6 +361,8 @@ datasheet_insert_column (struct datasheet *ds,
 {
   struct column *col;
 
+  assert (before <= ds->n_columns);
+
   ds->columns = xnrealloc (ds->columns,
                            ds->n_columns + 1, sizeof *ds->columns);
   insert_element (ds->columns, ds->n_columns, sizeof *ds->columns, before);
@@ -382,6 +385,8 @@ datasheet_insert_column (struct datasheet *ds,
 void
 datasheet_delete_columns (struct datasheet *ds, size_t start, size_t n)
 {
+  assert (start + n <= ds->n_columns);
+
   if (n > 0)
     {
       size_t i;
@@ -411,6 +416,9 @@ datasheet_move_columns (struct datasheet *ds,
                         size_t old_start, size_t new_start,
                         size_t n)
 {
+  assert (old_start + n <= ds->n_columns);
+  assert (new_start + n <= ds->n_columns);
+
   move_range (ds->columns, ds->n_columns, sizeof *ds->columns,
               old_start, new_start, n);
 
@@ -424,8 +432,8 @@ struct resize_datasheet_value_aux
     size_t src_ofs;
     int src_width;
 
-    void (*resize_cb) (const union value *, union value *, void *aux);
-    void *resize_cb_aux;
+    void (*resize_cb) (const union value *, union value *, const void *aux);
+    const void *resize_cb_aux;
 
     union value dst_value;
     size_t dst_ofs;
@@ -453,8 +461,8 @@ resize_datasheet_value (const void *src, void *dst, void *aux_)
 bool
 datasheet_resize_column (struct datasheet *ds, size_t column, int new_width,
                          void (*resize_cb) (const union value *,
-                                            union value *, void *aux),
-                         void *resize_cb_aux)
+                                            union value *, const void *aux),
+                         const void *resize_cb_aux)
 {
   struct column old_col;
   struct column *col;
@@ -499,18 +507,22 @@ datasheet_resize_column (struct datasheet *ds, size_t column, int new_width,
       for (lrow = 0; lrow < n_rows; lrow++)
         {
           unsigned long int prow = axis_map (ds->rows, lrow);
-          if (!source_read (&old_col, prow, &src))
+          if (!source_read (&old_col, prow, &src, 1))
             {
               /* FIXME: back out col changes. */
-              return false;
+              break;
             }
           resize_cb (&src, &dst, resize_cb_aux);
-          if (!source_write (col, prow, &dst))
+          if (!source_write (col, prow, &dst, 1))
             {
               /* FIXME: back out col changes. */
-              return false;
+              break;
             }
         }
+      value_destroy (&src, old_width);
+      value_destroy (&dst, new_width);
+      if (lrow < n_rows)
+       return false;
 
       release_source (ds, old_col.source);
     }
@@ -548,7 +560,7 @@ datasheet_get_row (const struct datasheet *ds, casenumber row)
 {
   size_t n_columns = datasheet_get_n_columns (ds);
   struct ccase *c = case_create (datasheet_get_proto (ds));
-  if (rw_case ((struct datasheet *) ds, OP_READ,
+  if (rw_case (CONST_CAST (struct datasheet *, ds), OP_READ,
                row, 0, n_columns, case_data_all_rw (c)))
     return c;
   else
@@ -582,7 +594,8 @@ datasheet_get_value (const struct datasheet *ds, casenumber row,
                      size_t column, union value *value)
 {
   assert (row >= 0);
-  return rw_case ((struct datasheet *) ds, OP_READ, row, column, 1, value);
+  return rw_case (CONST_CAST (struct datasheet *, ds), OP_READ,
+                  row, column, 1, value);
 }
 
 /* Stores VALUE into DS in the given ROW and COLUMN.  VALUE must
@@ -591,8 +604,8 @@ datasheet_get_value (const struct datasheet *ds, casenumber row,
    successful, false on I/O error.  On failure, ROW might be
    partially modified or corrupted. */
 bool
-datasheet_put_value (struct datasheet *ds UNUSED, casenumber row UNUSED,
-                     size_t column UNUSED, const union value *value UNUSED)
+datasheet_put_value (struct datasheet *ds, casenumber row,
+                     size_t column, const union value *value)
 {
   return rw_case (ds, OP_WRITE, row, column, 1, (union value *) value);
 }
@@ -612,37 +625,37 @@ datasheet_insert_rows (struct datasheet *ds,
   while (cnt > 0)
     {
       unsigned long first_phy;
-      unsigned long phy_cnt;
+      unsigned long n_phys;
       unsigned long i;
 
       /* Allocate physical rows from the pool of available
          rows. */
-      if (!axis_allocate (ds->rows, cnt, &first_phy, &phy_cnt))
+      if (!axis_allocate (ds->rows, cnt, &first_phy, &n_phys))
         {
           /* No rows were available.  Extend the row axis to make
              some new ones available. */
-          phy_cnt = cnt;
+          n_phys = cnt;
           first_phy = axis_extend (ds->rows, cnt);
         }
 
       /* Insert the new rows into the row mapping. */
-      axis_insert (ds->rows, before, first_phy, phy_cnt);
+      axis_insert (ds->rows, before, first_phy, n_phys);
 
       /* Initialize the new rows. */
-      for (i = 0; i < phy_cnt; i++)
+      for (i = 0; i < n_phys; i++)
         if (!datasheet_put_row (ds, before + i, c[i]))
           {
             while (++i < cnt)
               case_unref (c[i]);
-            datasheet_delete_rows (ds, before - added, phy_cnt + added);
+            datasheet_delete_rows (ds, before - added, n_phys + added);
             return false;
           }
 
       /* Advance. */
-      c += phy_cnt;
-      cnt -= phy_cnt;
-      before += phy_cnt;
-      added += phy_cnt;
+      c += n_phys;
+      cnt -= n_phys;
+      before += n_phys;
+      added += n_phys;
     }
   return true;
 }
@@ -721,10 +734,10 @@ datasheet_reader_destroy (struct casereader *reader UNUSED, void *ds_)
 /* "advance" function for the datasheet random casereader. */
 static void
 datasheet_reader_advance (struct casereader *reader UNUSED, void *ds_,
-                          casenumber case_cnt)
+                          casenumber n_cases)
 {
   struct datasheet *ds = ds_;
-  datasheet_delete_rows (ds, 0, case_cnt);
+  datasheet_delete_rows (ds, 0, n_cases);
 }
 
 /* Random casereader class for a datasheet. */
@@ -797,6 +810,7 @@ rw_case (struct datasheet *ds, enum rw_op op,
          casenumber lrow, size_t start_column, size_t n_columns,
          union value data[])
 {
+  struct column *columns = &ds->columns[start_column];
   casenumber prow;
   size_t i;
 
@@ -805,24 +819,34 @@ rw_case (struct datasheet *ds, enum rw_op op,
   assert (start_column + n_columns <= datasheet_get_n_columns (ds));
 
   prow = axis_map (ds->rows, lrow);
-  for (i = 0; i < n_columns; i++)
+  for (i = 0; i < n_columns;)
     {
-      struct column *c = &ds->columns[start_column + i];
-      if (c->width >= 0)
+      struct source *source = columns[i].source;
+      size_t j;
+      bool ok;
+
+      if (columns[i].width < 0)
         {
-          bool ok;
+          i++;
+          continue;
+        }
 
-          if (op == OP_READ)
-            ok = source_read (c, prow, &data[i]);
-          else
-            ok = source_write (c, prow, &data[i]);
+      for (j = i + 1; j < n_columns; j++)
+        if (columns[j].width < 0 || columns[j].source != source)
+          break;
 
-          if (!ok)
-            {
-              taint_set_taint (ds->taint);
-              return false;
-            }
+      if (op == OP_READ)
+        ok = source_read (&columns[i], prow, &data[i], j - i);
+      else
+        ok = source_write (&columns[i], prow, &data[i], j - i);
+
+      if (!ok)
+        {
+          taint_set_taint (ds->taint);
+          return false;
         }
+
+      i = j;
     }
   return true;
 }
@@ -918,8 +942,7 @@ axis_hash (const struct axis *axis, struct md4_ctx *ctx)
       md4_process_bytes (&size, sizeof size, ctx);
     }
 
-  for (rsn = range_set_first (axis->available); rsn != NULL;
-       rsn = range_set_next (axis->available, rsn))
+  RANGE_SET_FOR_EACH (rsn, axis->available)
     {
       unsigned long int start = range_set_node_get_start (rsn);
       unsigned long int end = range_set_node_get_end (rsn);
@@ -970,7 +993,7 @@ static void
 axis_make_available (struct axis *axis,
                      unsigned long int start, unsigned long int width)
 {
-  range_set_insert (axis->available, start, width);
+  range_set_set1 (axis->available, start, width);
 }
 
 /* Extends the total physical length of AXIS by WIDTH and returns
@@ -1220,7 +1243,7 @@ source_create_empty (size_t n_bytes)
   size_t row_size = n_bytes + 4 * sizeof (void *);
   size_t max_memory_rows = settings_get_workspace () / row_size;
   source->avail = range_set_create ();
-  range_set_insert (source->avail, 0, n_bytes);
+  range_set_set1 (source->avail, 0, n_bytes);
   source->data = sparse_xarray_create (n_bytes, MAX (max_memory_rows, 4));
   source->backing = NULL;
   source->backing_rows = 0;
@@ -1239,7 +1262,7 @@ source_create_casereader (struct casereader *reader)
   size_t n_columns;
   size_t i;
 
-  range_set_delete (source->avail, 0, n_bytes);
+  range_set_set0 (source->avail, 0, n_bytes);
   source->backing = reader;
   source->backing_rows = casereader_count_cases (reader);
 
@@ -1293,7 +1316,7 @@ static void
 source_release_column (struct source *source, int ofs, int width)
 {
   assert (width >= 0);
-  range_set_insert (source->avail, ofs, width_to_n_bytes (width));
+  range_set_set1 (source->avail, ofs, width_to_n_bytes (width));
   if (source->backing != NULL)
     source->n_used--;
 }
@@ -1328,30 +1351,39 @@ source_get_backing_n_rows (const struct source *source)
   return source->backing_rows;
 }
 
-/* Reads the given COLUMN from SOURCE in the given ROW, into
-   VALUE.  Returns true if successful, false on I/O error.
+/* Reads the N COLUMNS in the given ROW, into the N VALUES.  Returns true if
+   successful, false on I/O error.
+
+   All of the COLUMNS must have the same source.
 
-   The caller must have initialized VALUE with the proper
-   width. */
+   The caller must have initialized VALUES with the proper width. */
 static bool
-source_read (const struct column *column, casenumber row, union value *value)
+source_read (const struct column columns[], casenumber row,
+             union value values[], size_t n)
 {
-  struct source *source = column->source;
+  struct source *source = columns[0].source;
+  size_t i;
 
-  assert (column->width >= 0);
   if (source->backing == NULL
       || sparse_xarray_contains_row (source->data, row))
-    return sparse_xarray_read (source->data, row, column->byte_ofs,
-                               width_to_n_bytes (column->width),
-                               value_to_data (value, column->width));
+    {
+      bool ok = true;
+
+      for (i = 0; i < n && ok; i++)
+        ok = sparse_xarray_read (source->data, row, columns[i].byte_ofs,
+                                 width_to_n_bytes (columns[i].width),
+                                 value_to_data (&values[i], columns[i].width));
+      return ok;
+    }
   else
     {
       struct ccase *c = casereader_peek (source->backing, row);
       bool ok = c != NULL;
       if (ok)
         {
-          value_copy (value, case_data_idx (c, column->value_ofs),
-                      column->width);
+          for (i = 0; i < n; i++)
+            value_copy (&values[i], case_data_idx (c, columns[i].value_ofs),
+                        columns[i].width);
           case_unref (c);
         }
       return ok;
@@ -1383,18 +1415,20 @@ copy_case_into_source (struct source *source, struct ccase *c, casenumber row)
   return true;
 }
 
-/* Writes VALUE to SOURCE in the given ROW and COLUMN.  Returns
-   true if successful, false on I/O error.  On error, the row's
-   data may be completely or partially corrupted, both inside and
-   outside the region to be written.  */
+/* Writes the N VALUES to their source in the given ROW and COLUMNS.  Returns
+   true if successful, false on I/O error.  On error, the row's data may be
+   completely or partially corrupted, both inside and outside the region to be
+   written.
+
+   All of the COLUMNS must have the same source. */
 static bool
-source_write (const struct column *column, casenumber row,
-              const union value *value)
+source_write (const struct column columns[], casenumber row,
+              const union value values[], size_t n)
 {
-  struct source *source = column->source;
+  struct source *source = columns[0].source;
   struct casereader *backing = source->backing;
+  size_t i;
 
-  assert (column->width >= 0);
   if (backing != NULL
       && !sparse_xarray_contains_row (source->data, row)
       && row < source->backing_rows)
@@ -1412,9 +1446,12 @@ source_write (const struct column *column, casenumber row,
         return false;
     }
 
-  return sparse_xarray_write (source->data, row, column->byte_ofs,
-                              width_to_n_bytes (column->width),
-                              value_to_data (value, column->width));
+  for (i = 0; i < n; i++)
+    if (!sparse_xarray_write (source->data, row, columns[i].byte_ofs,
+                              width_to_n_bytes (columns[i].width),
+                              value_to_data (&values[i], columns[i].width)))
+      return false;
+  return true;
 }
 
 /* Within SOURCE, which must not have a backing casereader,