changeset 17439:6690dba6078a

improve efficiency of fwrite * oct-stream.h, oct-stream.cc (write_int, do_write): Delete. (convert_ints, convert_data, octave_stream::write_bytes octave_stream::skip_bytes): New functions. (octave_stream::write): Improve efficiency by writing data in larger chunks. * oct-stream.cc: Delete unnecessary template instantiations. * data-conv.h, data-conv.cc (is_equivalent_type): New template. Provide specializations for core Octave data types. (oct_data_conv::data_type_size): New function. (oct_data_conv::data_type_to_string): Correct spelling of unsigned.
author John W. Eaton <jwe@octave.org>
date Fri, 13 Sep 2013 23:31:11 -0400
parents 3856298f1ff8
children 9289bb0ff4dd
files libinterp/corefcn/file-io.cc libinterp/corefcn/oct-stream.cc libinterp/corefcn/oct-stream.h liboctave/util/data-conv.cc liboctave/util/data-conv.h
diffstat 5 files changed, 471 insertions(+), 322 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/file-io.cc
+++ b/libinterp/corefcn/file-io.cc
@@ -1556,10 +1556,6 @@
 IEEE little endian.\n\
 @end table\n\
 \n\
-@noindent\n\
-Conversions are currently only supported for @qcode{\"ieee-be\"} and\n\
-@qcode{\"ieee-le\"} formats.\n\
-\n\
 The data read from the file is returned in @var{val}, and the number of\n\
 values read is returned in @code{count}\n\
 @seealso{fwrite, fgets, fgetl, fscanf, fopen}\n\
--- a/libinterp/corefcn/oct-stream.cc
+++ b/libinterp/corefcn/oct-stream.cc
@@ -1189,29 +1189,6 @@
   return is >> valptr;
 }
 
-template std::istream&
-octave_scan (std::istream&, const scanf_format_elt&, int*);
-
-template std::istream&
-octave_scan (std::istream&, const scanf_format_elt&, long int*);
-
-template std::istream&
-octave_scan (std::istream&, const scanf_format_elt&, short int*);
-
-template std::istream&
-octave_scan (std::istream&, const scanf_format_elt&, unsigned int*);
-
-template std::istream&
-octave_scan (std::istream&, const scanf_format_elt&, unsigned long int*);
-
-template std::istream&
-octave_scan (std::istream&, const scanf_format_elt&, unsigned short int*);
-
-#if 0
-template std::istream&
-octave_scan (std::istream&, const scanf_format_elt&, float*);
-#endif
-
 template<>
 std::istream&
 octave_scan<> (std::istream& is, const scanf_format_elt& fmt, double* valptr)
@@ -1278,36 +1255,6 @@
 }
 
 template void
-do_scanf_conv (std::istream&, const scanf_format_elt&, int*,
-               Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool);
-
-template void
-do_scanf_conv (std::istream&, const scanf_format_elt&, long int*,
-               Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool);
-
-template void
-do_scanf_conv (std::istream&, const scanf_format_elt&, short int*,
-               Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool);
-
-template void
-do_scanf_conv (std::istream&, const scanf_format_elt&, unsigned int*,
-               Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool);
-
-template void
-do_scanf_conv (std::istream&, const scanf_format_elt&, unsigned long int*,
-               Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool);
-
-template void
-do_scanf_conv (std::istream&, const scanf_format_elt&, unsigned short int*,
-               Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool);
-
-#if 0
-template void
-do_scanf_conv (std::istream&, const scanf_format_elt&, float*,
-               Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool);
-#endif
-
-template void
 do_scanf_conv (std::istream&, const scanf_format_elt&, double*,
                Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool);
 
@@ -2402,30 +2349,6 @@
   return retval;
 }
 
-template int
-do_printf_conv (std::ostream&, const char*, int, int, int, int,
-                const std::string&);
-
-template int
-do_printf_conv (std::ostream&, const char*, int, int, int, long,
-                const std::string&);
-
-template int
-do_printf_conv (std::ostream&, const char*, int, int, int, unsigned int,
-                const std::string&);
-
-template int
-do_printf_conv (std::ostream&, const char*, int, int, int, unsigned long,
-                const std::string&);
-
-template int
-do_printf_conv (std::ostream&, const char*, int, int, int, double,
-                const std::string&);
-
-template int
-do_printf_conv (std::ostream&, const char*, int, int, int, const char*,
-                const std::string&);
-
 #define DO_DOUBLE_CONV(TQUAL) \
   do \
     { \
@@ -3199,44 +3122,11 @@
   return retval;
 }
 
-#define DO_READ_VAL_TEMPLATE(RET_T, READ_T) \
-  template octave_value \
-  do_read<RET_T, READ_T> (octave_stream&, octave_idx_type, octave_idx_type, octave_idx_type, octave_idx_type, bool, bool, \
-                          oct_mach_info::float_format, octave_idx_type&)
-
-// FIXME -- should we only have float if it is a different
-// size from double?
-
-#define INSTANTIATE_DO_READ(VAL_T) \
-  DO_READ_VAL_TEMPLATE (VAL_T, octave_int8); \
-  DO_READ_VAL_TEMPLATE (VAL_T, octave_uint8); \
-  DO_READ_VAL_TEMPLATE (VAL_T, octave_int16); \
-  DO_READ_VAL_TEMPLATE (VAL_T, octave_uint16); \
-  DO_READ_VAL_TEMPLATE (VAL_T, octave_int32); \
-  DO_READ_VAL_TEMPLATE (VAL_T, octave_uint32); \
-  DO_READ_VAL_TEMPLATE (VAL_T, octave_int64); \
-  DO_READ_VAL_TEMPLATE (VAL_T, octave_uint64); \
-  DO_READ_VAL_TEMPLATE (VAL_T, float); \
-  DO_READ_VAL_TEMPLATE (VAL_T, double); \
-  DO_READ_VAL_TEMPLATE (VAL_T, char); \
-  DO_READ_VAL_TEMPLATE (VAL_T, signed char); \
-  DO_READ_VAL_TEMPLATE (VAL_T, unsigned char)
-
-INSTANTIATE_DO_READ (int8NDArray);
-INSTANTIATE_DO_READ (uint8NDArray);
-INSTANTIATE_DO_READ (int16NDArray);
-INSTANTIATE_DO_READ (uint16NDArray);
-INSTANTIATE_DO_READ (int32NDArray);
-INSTANTIATE_DO_READ (uint32NDArray);
-INSTANTIATE_DO_READ (int64NDArray);
-INSTANTIATE_DO_READ (uint64NDArray);
-INSTANTIATE_DO_READ (FloatNDArray);
-INSTANTIATE_DO_READ (NDArray);
-INSTANTIATE_DO_READ (charNDArray);
-INSTANTIATE_DO_READ (boolNDArray);
-
-typedef octave_value (*read_fptr) (octave_stream&, octave_idx_type, octave_idx_type, octave_idx_type, octave_idx_type, bool, bool,
-                                   oct_mach_info::float_format ffmt, octave_idx_type&);
+typedef octave_value (*read_fptr) (octave_stream&, octave_idx_type,
+                                   octave_idx_type, octave_idx_type,
+                                   octave_idx_type, bool, bool, 
+                                   oct_mach_info::float_format ffmt,
+                                   octave_idx_type&);
 
 #define FILL_TABLE_ROW(R, VAL_T) \
   read_fptr_table[R][oct_data_conv::dt_int8] = do_read<VAL_T, octave_int8>; \
@@ -3381,103 +3271,106 @@
   return retval;
 }
 
-template <class T>
-void
-write_int (std::ostream& os, bool swap, const T& val)
+template <class T, class V>
+static void
+convert_ints (const T *data, void *conv_data, octave_idx_type n_elts,
+              bool swap)
 {
-  typename T::val_type tmp = val.value ();
-
-  if (swap)
-    swap_bytes<sizeof (typename T::val_type)> (&tmp);
-
-  os.write (reinterpret_cast<const char *> (&tmp),
-            sizeof (typename T::val_type));
+  typedef typename V::val_type val_type;
+
+  val_type *vt_data = static_cast <val_type *> (conv_data);
+
+  for (octave_idx_type i = 0; i < n_elts; i++)
+    {
+      V val (data[i]);
+
+      vt_data[i] = val.value ();
+
+      if (swap)
+        swap_bytes<sizeof (val_type)> (&vt_data[i]);
+    }
 }
 
-template void write_int (std::ostream&, bool, const octave_int8&);
-template void write_int (std::ostream&, bool, const octave_uint8&);
-template void write_int (std::ostream&, bool, const octave_int16&);
-template void write_int (std::ostream&, bool, const octave_uint16&);
-template void write_int (std::ostream&, bool, const octave_int32&);
-template void write_int (std::ostream&, bool, const octave_uint32&);
-template void write_int (std::ostream&, bool, const octave_int64&);
-template void write_int (std::ostream&, bool, const octave_uint64&);
-
 template <class T>
-static inline bool
-do_write (std::ostream& os, const T& val, oct_data_conv::data_type output_type,
-          oct_mach_info::float_format flt_fmt, bool swap,
-          bool do_float_conversion)
+static bool
+convert_data (const T *data, void *conv_data, octave_idx_type n_elts,
+              oct_data_conv::data_type output_type,
+              oct_mach_info::float_format flt_fmt)
 {
   bool retval = true;
 
-  // For compatibility, Octave converts to the output type, then
-  // writes.  This means that truncation happens on the conversion.
-  // For example, the following program prints 0:
-  //
-  //   x = int8 (-1)
-  //   f = fopen ("foo.dat", "w");
-  //   fwrite (f, x, "unsigned char");
-  //   fclose (f);
-  //   f = fopen ("foo.dat", "r");
-  //   y = fread (f, 1, "unsigned char");
-  //   printf ("%d\n", y);
+  bool swap
+    = ((oct_mach_info::words_big_endian ()
+        && flt_fmt == oct_mach_info::flt_fmt_ieee_little_endian)
+       || flt_fmt == oct_mach_info::flt_fmt_ieee_big_endian);
+
+  bool do_float_conversion =  flt_fmt != oct_mach_info::float_format ();
+
+  // We use octave_intN classes here instead of converting directly to
+  // intN_t so that we get integer saturation semantics.
 
   switch (output_type)
     {
     case oct_data_conv::dt_char:
     case oct_data_conv::dt_schar:
     case oct_data_conv::dt_int8:
-      write_int (os, swap, octave_int8 (val));
+      convert_ints<T, octave_int8> (data, conv_data, n_elts, swap);
       break;
 
     case oct_data_conv::dt_uchar:
     case oct_data_conv::dt_uint8:
-      write_int (os, swap, octave_uint8 (val));
+      convert_ints<T, octave_uint8> (data, conv_data, n_elts, swap);
       break;
 
     case oct_data_conv::dt_int16:
-      write_int (os, swap, octave_int16 (val));
+      convert_ints<T, octave_int16> (data, conv_data, n_elts, swap);
       break;
 
     case oct_data_conv::dt_uint16:
-      write_int (os, swap, octave_uint16 (val));
+      convert_ints<T, octave_uint16> (data, conv_data, n_elts, swap);
       break;
 
     case oct_data_conv::dt_int32:
-      write_int (os, swap, octave_int32 (val));
+      convert_ints<T, octave_int32> (data, conv_data, n_elts, swap);
       break;
 
     case oct_data_conv::dt_uint32:
-      write_int (os, swap, octave_uint32 (val));
+      convert_ints<T, octave_uint32> (data, conv_data, n_elts, swap);
       break;
 
     case oct_data_conv::dt_int64:
-      write_int (os, swap, octave_int64 (val));
+      convert_ints<T, octave_int64> (data, conv_data, n_elts, swap);
       break;
 
     case oct_data_conv::dt_uint64:
-      write_int (os, swap, octave_uint64 (val));
+      convert_ints<T, octave_uint64> (data, conv_data, n_elts, swap);
       break;
 
     case oct_data_conv::dt_single:
       {
-        float f = static_cast<float> (val);
-
-        if (do_float_conversion)
-          do_float_format_conversion (&f, 1, flt_fmt);
-
-        os.write (reinterpret_cast<const char *> (&f), sizeof (float));
+        float *vt_data = static_cast <float *> (conv_data);
+
+        for (octave_idx_type i = 0; i < n_elts; i++)
+          {
+            vt_data[i] = data[i];
+
+            if (do_float_conversion)
+              do_float_format_conversion (&vt_data[i], 1, flt_fmt);
+          }
       }
       break;
 
     case oct_data_conv::dt_double:
       {
-        double d = static_cast<double> (val);
-        if (do_float_conversion)
-          do_double_format_conversion (&d, 1, flt_fmt);
-
-        os.write (reinterpret_cast<const char *> (&d), sizeof (double));
+        double *vt_data = static_cast <double *> (conv_data);
+
+        for (octave_idx_type i = 0; i < n_elts; i++)
+          {
+            vt_data[i] = data[i];
+
+            if (do_float_conversion)
+              do_double_format_conversion (&vt_data[i], 1, flt_fmt);
+          }
       }
       break;
 
@@ -3491,162 +3384,174 @@
   return retval;
 }
 
+bool
+octave_stream::write_bytes (const void *data, size_t nbytes)
+{
+  bool status = false;
+
+  std::ostream *osp = output_stream ();
+
+  if (osp)
+    {
+      std::ostream& os = *osp;
+
+      if (os)
+        {
+          os.write (static_cast<const char *> (data), nbytes);
+
+          if (os)
+            status = true;
+        }
+    }
+
+  return status;
+}
+
+bool
+octave_stream::skip_bytes (size_t skip)
+{
+  bool status = false;
+
+  std::ostream *osp = output_stream ();
+
+  if (osp)
+    {
+      std::ostream& os = *osp;
+
+      // Seek to skip when inside bounds of existing file.
+      // Otherwise, write NUL to skip.
+
+      off_t orig_pos = tell ();
+
+      seek (0, SEEK_END);
+
+      off_t eof_pos = tell ();
+
+      // Is it possible for this to fail to return us to the
+      // original position?
+      seek (orig_pos, SEEK_SET);
+
+      size_t remaining = eof_pos - orig_pos;
+
+      if (remaining < skip)
+        {
+          seek (0, SEEK_END);
+
+          // FIXME -- probably should try to write larger blocks...
+
+          unsigned char zero = 0;
+          for (size_t j = 0; j < skip - remaining; j++)
+            os.write (reinterpret_cast<const char *> (&zero), 1);
+        }
+      else
+        seek (skip, SEEK_CUR);
+
+      if (os)
+        status = true;
+    }
+
+  return status;
+}
+
 template <class T>
 octave_idx_type
 octave_stream::write (const Array<T>& data, octave_idx_type block_size,
                       oct_data_conv::data_type output_type,
-                      octave_idx_type skip, oct_mach_info::float_format flt_fmt)
+                      octave_idx_type skip,
+                      oct_mach_info::float_format flt_fmt)
 {
-  octave_idx_type retval = -1;
-
-  bool status = true;
-
-  octave_idx_type count = 0;
-
-  const T *d = data.data ();
-
-  octave_idx_type n = data.length ();
-
-  oct_mach_info::float_format native_flt_fmt
-    = oct_mach_info::float_format ();
-
-  bool do_float_conversion = (flt_fmt != native_flt_fmt);
-
-  bool swap = false;
-
-  if (oct_mach_info::words_big_endian ())
-    swap = (flt_fmt == oct_mach_info::flt_fmt_ieee_little_endian);
+  bool swap
+    = ((oct_mach_info::words_big_endian ()
+        && flt_fmt == oct_mach_info::flt_fmt_ieee_little_endian)
+       || flt_fmt == oct_mach_info::flt_fmt_ieee_big_endian);
+
+  bool do_data_conversion
+    = (swap || ! is_equivalent_type<T> (output_type) 
+       || flt_fmt != oct_mach_info::float_format ());
+
+  octave_idx_type nel = data.numel ();
+
+  octave_idx_type chunk_size;
+
+  if (skip != 0)
+    chunk_size = block_size;
+  else if (do_data_conversion)
+    chunk_size = 1024 * 1024;
   else
-    swap = (flt_fmt == oct_mach_info::flt_fmt_ieee_big_endian);
-
-  for (octave_idx_type i = 0; i < n; i++)
+    chunk_size = nel;
+
+  octave_idx_type i = 0;
+
+  const T *pdata = data.data ();
+
+  while (i < nel)
     {
-      std::ostream *osp = output_stream ();
-
-      if (osp)
+      if (skip != 0)
         {
-          std::ostream& os = *osp;
-
-          if (skip != 0 && (i % block_size) == 0)
-            {
-              // Seek to skip when inside bounds of existing file.
-              // Otherwise, write NUL to skip.
-
-              off_t orig_pos = tell ();
-
-              seek (0, SEEK_END);
-
-              off_t eof_pos = tell ();
-
-              // Is it possible for this to fail to return us to the
-              // original position?
-              seek (orig_pos, SEEK_SET);
-
-              off_t remaining = eof_pos - orig_pos;
-
-              if (remaining < skip)
-                {
-                  seek (0, SEEK_END);
-
-                  // FIXME -- probably should try to write larger
-                  // blocks...
-
-                  unsigned char zero = 0;
-                  for (octave_idx_type j = 0; j < skip - remaining; j++)
-                    os.write (reinterpret_cast<const char *> (&zero), 1);
-                }
-              else
-                seek (skip, SEEK_CUR);
-            }
-
-          if (os)
-            {
-              status = do_write (os, d[i], output_type, flt_fmt, swap,
-                                 do_float_conversion);
-
-              if (os && status)
-                count++;
-              else
-                break;
-            }
-          else
-            {
-              status = false;
-              break;
-            }
+          if (! skip_bytes (skip))
+            return -1;
+        }
+
+      octave_idx_type remaining_nel = nel - i;
+
+      if (chunk_size > remaining_nel)
+        chunk_size = remaining_nel;
+
+      bool status = false;
+
+      if (do_data_conversion)
+        {
+          size_t output_size
+            = chunk_size * oct_data_conv::data_type_size (output_type);
+
+          OCTAVE_LOCAL_BUFFER (unsigned char, conv_data, output_size);
+
+          status = convert_data (&pdata[i], conv_data, chunk_size,
+                                 output_type, flt_fmt);
+
+          if (status)
+            status = write_bytes (conv_data, output_size);
         }
       else
-        {
-          status = false;
-          break;
-        }
+        status = write_bytes (pdata, sizeof (T) * chunk_size);
+
+      if (! status)
+        return -1;
+
+      i += chunk_size;
     }
 
-  if (status)
-    retval = count;
-
-  return retval;
+  return nel;
 }
 
-template octave_idx_type
-octave_stream::write (const Array<char>&, octave_idx_type,
-                      oct_data_conv::data_type,
-                      octave_idx_type, oct_mach_info::float_format);
-
-template octave_idx_type
-octave_stream::write (const Array<bool>&, octave_idx_type,
-                      oct_data_conv::data_type,
-                      octave_idx_type, oct_mach_info::float_format);
-
-template octave_idx_type
-octave_stream::write (const Array<double>&, octave_idx_type,
-                      oct_data_conv::data_type,
-                      octave_idx_type, oct_mach_info::float_format);
-
-template octave_idx_type
-octave_stream::write (const Array<float>&, octave_idx_type,
-                      oct_data_conv::data_type,
-                      octave_idx_type, oct_mach_info::float_format);
-
-template octave_idx_type
-octave_stream::write (const Array<octave_int8>&, octave_idx_type,
-                      oct_data_conv::data_type,
-                      octave_idx_type, oct_mach_info::float_format);
-
-template octave_idx_type
-octave_stream::write (const Array<octave_uint8>&, octave_idx_type,
-                      oct_data_conv::data_type,
-                      octave_idx_type, oct_mach_info::float_format);
-
-template octave_idx_type
-octave_stream::write (const Array<octave_int16>&, octave_idx_type,
-                      oct_data_conv::data_type,
-                      octave_idx_type, oct_mach_info::float_format);
-
-template octave_idx_type
-octave_stream::write (const Array<octave_uint16>&, octave_idx_type,
-                      oct_data_conv::data_type,
-                      octave_idx_type, oct_mach_info::float_format);
-
-template octave_idx_type
-octave_stream::write (const Array<octave_int32>&, octave_idx_type,
-                      oct_data_conv::data_type,
-                      octave_idx_type, oct_mach_info::float_format);
-
-template octave_idx_type
-octave_stream::write (const Array<octave_uint32>&, octave_idx_type,
-                      oct_data_conv::data_type,
-                      octave_idx_type, oct_mach_info::float_format);
-
-template octave_idx_type
-octave_stream::write (const Array<octave_int64>&, octave_idx_type,
-                      oct_data_conv::data_type,
-                      octave_idx_type, oct_mach_info::float_format);
-
-template octave_idx_type
-octave_stream::write (const Array<octave_uint64>&, octave_idx_type,
-                      oct_data_conv::data_type,
-                      octave_idx_type, oct_mach_info::float_format);
+#define INSTANTIATE_WRITE(T) \
+  template \
+  octave_idx_type \
+  octave_stream::write (const Array<T>& data, octave_idx_type block_size, \
+                        oct_data_conv::data_type output_type, \
+                        octave_idx_type skip, \
+                        oct_mach_info::float_format flt_fmt)
+
+INSTANTIATE_WRITE (octave_int8);
+INSTANTIATE_WRITE (octave_uint8);
+INSTANTIATE_WRITE (octave_int16);
+INSTANTIATE_WRITE (octave_uint16);
+INSTANTIATE_WRITE (octave_int32);
+INSTANTIATE_WRITE (octave_uint32);
+INSTANTIATE_WRITE (octave_int64);
+INSTANTIATE_WRITE (octave_uint64);
+INSTANTIATE_WRITE (int8_t);
+INSTANTIATE_WRITE (uint8_t);
+INSTANTIATE_WRITE (int16_t);
+INSTANTIATE_WRITE (uint16_t);
+INSTANTIATE_WRITE (int32_t);
+INSTANTIATE_WRITE (uint32_t);
+INSTANTIATE_WRITE (int64_t);
+INSTANTIATE_WRITE (uint64_t);
+INSTANTIATE_WRITE (bool);
+INSTANTIATE_WRITE (char);
+INSTANTIATE_WRITE (float);
+INSTANTIATE_WRITE (double);
 
 octave_value
 octave_stream::scanf (const std::string& fmt, const Array<double>& size,
--- a/libinterp/corefcn/oct-stream.h
+++ b/libinterp/corefcn/oct-stream.h
@@ -37,6 +37,7 @@
 #include "data-conv.h"
 #include "lo-utils.h"
 #include "mach-info.h"
+#include "oct-locbuf.h"
 #include "oct-refcount.h"
 
 class
@@ -539,13 +540,19 @@
                      octave_idx_type& count);
 
   octave_idx_type write (const octave_value& data, octave_idx_type block_size,
-             oct_data_conv::data_type output_type,
-             octave_idx_type skip, oct_mach_info::float_format flt_fmt);
+                         oct_data_conv::data_type output_type,
+                         octave_idx_type skip,
+                         oct_mach_info::float_format flt_fmt);
+
+  bool write_bytes (const void *data, size_t n_elts);
+
+  bool skip_bytes (size_t n_elts);
 
   template <class T>
-  octave_idx_type write (const Array<T>&, octave_idx_type block_size,
-             oct_data_conv::data_type output_type,
-             octave_idx_type skip, oct_mach_info::float_format flt_fmt);
+  octave_idx_type write (const Array<T>& data, octave_idx_type block_size,
+                         oct_data_conv::data_type output_type,
+                         octave_idx_type skip,
+                         oct_mach_info::float_format flt_fmt);
 
   octave_value scanf (const std::string& fmt, const Array<double>& size,
                       octave_idx_type& count, const std::string& who /* = "scanf" */);
--- a/liboctave/util/data-conv.cc
+++ b/liboctave/util/data-conv.cc
@@ -174,6 +174,111 @@
     } \
   while (0)
 
+size_t
+oct_data_conv::data_type_size (data_type dt)
+{
+  size_t retval = -1;
+
+  switch (dt)
+    {
+    case oct_data_conv::dt_int8:
+      retval = sizeof (int8_t);
+      break;
+
+    case oct_data_conv::dt_uint8:
+      retval = sizeof (uint8_t);
+      break;
+
+    case oct_data_conv::dt_int16:
+      retval = sizeof (int16_t);
+      break;
+
+    case oct_data_conv::dt_uint16:
+      retval = sizeof (uint16_t);
+      break;
+
+    case oct_data_conv::dt_int32:
+      retval = sizeof (int32_t);
+      break;
+
+    case oct_data_conv::dt_uint32:
+      retval = sizeof (uint32_t);
+      break;
+
+    case oct_data_conv::dt_int64:
+      retval = sizeof (int64_t);
+      break;
+
+    case oct_data_conv::dt_uint64:
+      retval = sizeof (uint64_t);
+      break;
+
+    case oct_data_conv::dt_float:
+    case oct_data_conv::dt_single:
+      retval = sizeof (float);
+      break;
+
+    case oct_data_conv::dt_double:
+      retval = sizeof (double);
+      break;
+
+    case oct_data_conv::dt_char:
+      retval = sizeof (char);
+      break;
+
+    case oct_data_conv::dt_schar:
+      retval = sizeof (signed char);
+      break;
+
+    case oct_data_conv::dt_uchar:
+      retval = sizeof (unsigned char);
+      break;
+
+    case oct_data_conv::dt_short:
+      retval = sizeof (short);
+      break;
+
+    case oct_data_conv::dt_ushort:
+      retval = sizeof (unsigned short);
+      break;
+
+    case oct_data_conv::dt_int:
+      retval = sizeof (int);
+      break;
+
+    case oct_data_conv::dt_uint:
+      retval = sizeof (unsigned int);
+      break;
+
+    case oct_data_conv::dt_long:
+      retval = sizeof (long);
+      break;
+
+    case oct_data_conv::dt_ulong:
+      retval = sizeof (unsigned long);
+      break;
+
+    case oct_data_conv::dt_longlong:
+      retval = sizeof (long long);
+      break;
+
+    case oct_data_conv::dt_ulonglong:
+      retval = sizeof (unsigned long long);
+      break;
+
+    case oct_data_conv::dt_logical:
+      retval = sizeof (bool);
+      break;
+
+    case oct_data_conv::dt_unknown:
+    default:
+      abort ();
+      break;
+    }
+
+  return retval;
+}
+
 oct_data_conv::data_type
 oct_data_conv::string_to_data_type (const std::string& str)
 {
@@ -426,7 +531,7 @@
       break;
 
     case oct_data_conv::dt_uchar:
-      retval = "usigned char";
+      retval = "unsigned char";
       break;
 
     case oct_data_conv::dt_short:
@@ -442,7 +547,7 @@
       break;
 
     case oct_data_conv::dt_uint:
-      retval = "usigned int";
+      retval = "unsigned int";
       break;
 
     case oct_data_conv::dt_long:
@@ -450,7 +555,7 @@
       break;
 
     case oct_data_conv::dt_ulong:
-      retval = "usigned long";
+      retval = "unsigned long";
       break;
 
     case oct_data_conv::dt_longlong:
--- a/liboctave/util/data-conv.h
+++ b/liboctave/util/data-conv.h
@@ -26,6 +26,7 @@
 #include <limits>
 
 #include "mach-info.h"
+#include "oct-inttypes.h"
 
 class
 OCTAVE_API
@@ -61,6 +62,8 @@
       dt_unknown   = 23 // Must be last, have largest value!
     };
 
+  static size_t data_type_size (data_type dt);
+
   static data_type string_to_data_type (const std::string& s);
 
   static void string_to_data_type (const std::string& s, int& block_size,
@@ -125,4 +128,137 @@
 write_floats (std::ostream& os, const float *data, save_type type,
               octave_idx_type len);
 
+template <typename T>
+inline bool
+is_equivalent_type (oct_data_conv::data_type)
+{
+  return false;
+}
+
+template <>
+inline bool
+is_equivalent_type<int8_t> (oct_data_conv::data_type t)
+{
+  return t == oct_data_conv::dt_int8;
+}
+
+template <>
+inline bool
+is_equivalent_type<int16_t> (oct_data_conv::data_type t)
+{
+  return t == oct_data_conv::dt_int16;
+}
+
+template <>
+inline bool
+is_equivalent_type<int32_t> (oct_data_conv::data_type t)
+{
+  return t == oct_data_conv::dt_int32;
+}
+
+template <>
+inline bool
+is_equivalent_type<int64_t> (oct_data_conv::data_type t)
+{
+  return t == oct_data_conv::dt_int64;
+}
+
+template <>
+inline bool
+is_equivalent_type<uint8_t> (oct_data_conv::data_type t)
+{
+  return t == oct_data_conv::dt_uint8;
+}
+
+template <>
+inline bool
+is_equivalent_type<uint16_t> (oct_data_conv::data_type t)
+{
+  return t == oct_data_conv::dt_uint16;
+}
+
+template <>
+inline bool
+is_equivalent_type<uint32_t> (oct_data_conv::data_type t)
+{
+  return t == oct_data_conv::dt_uint32;
+}
+
+template <>
+inline bool
+is_equivalent_type<uint64_t> (oct_data_conv::data_type t)
+{
+  return t == oct_data_conv::dt_uint64;
+}
+
+template <>
+inline bool
+is_equivalent_type<octave_int8> (oct_data_conv::data_type t)
+{
+  return t == oct_data_conv::dt_int8;
+}
+
+template <>
+inline bool
+is_equivalent_type<octave_int16> (oct_data_conv::data_type t)
+{
+  return t == oct_data_conv::dt_int16;
+}
+
+template <>
+inline bool
+is_equivalent_type<octave_int32> (oct_data_conv::data_type t)
+{
+  return t == oct_data_conv::dt_int32;
+}
+
+template <>
+inline bool
+is_equivalent_type<octave_int64> (oct_data_conv::data_type t)
+{
+  return t == oct_data_conv::dt_int64;
+}
+
+template <>
+inline bool
+is_equivalent_type<octave_uint8> (oct_data_conv::data_type t)
+{
+  return t == oct_data_conv::dt_uint8;
+}
+
+template <>
+inline bool
+is_equivalent_type<octave_uint16> (oct_data_conv::data_type t)
+{
+  return t == oct_data_conv::dt_uint16;
+}
+
+template <>
+inline bool
+is_equivalent_type<octave_uint32> (oct_data_conv::data_type t)
+{
+  return t == oct_data_conv::dt_uint32;
+}
+
+template <>
+inline bool
+is_equivalent_type<octave_uint64> (oct_data_conv::data_type t)
+{
+  return t == oct_data_conv::dt_uint64;
+}
+
+template <>
+inline bool
+is_equivalent_type<double> (oct_data_conv::data_type t)
+{
+  return t == oct_data_conv::dt_double;
+}
+
+template <>
+inline bool
+is_equivalent_type<float> (oct_data_conv::data_type t)
+{
+  return t == oct_data_conv::dt_single || t == oct_data_conv::dt_float;
+}
+
 #endif