diff src/oct-stream.cc @ 4944:44046bbaa52c

[project @ 2004-08-31 05:30:46 by jwe]
author jwe
date Tue, 31 Aug 2004 05:30:47 +0000
parents b7732e23965b
children 48a39e2b2ab7
line wrap: on
line diff
--- a/src/oct-stream.cc	Tue Aug 31 00:51:31 2004 +0000
+++ b/src/oct-stream.cc	Tue Aug 31 05:30:47 2004 +0000
@@ -31,6 +31,13 @@
 #include <fstream>
 #include <string>
 
+#include <Array.h>
+#include <Array2.h>
+#include <Array3.h>
+
+#include <Array.cc>
+
+#include "byte-swap.h"
 #include "lo-ieee.h"
 #include "lo-mappers.h"
 #include "lo-sstream.h"
@@ -1032,48 +1039,6 @@
   return do_gets (max_len, err, false, who);
 }
 
-octave_value
-octave_base_stream::read (const Array<double>& size,
-			  oct_data_conv::data_type dt, int skip,
-			  oct_mach_info::float_format ffmt,
-			  int& char_count)
-{
-  Matrix retval;
-
-  char_count = 0;
-
-  std::istream *isp = input_stream ();
-
-  if (isp)
-    {
-      std::istream& is = *isp;
-
-      int nr = -1;
-      int nc = -1;
-
-      bool ignore;
-
-      get_size (size, nr, nc, ignore, "fread");
-
-      if (! error_state)
-	{
-	  if (ffmt == oct_mach_info::flt_fmt_unknown)
-	    ffmt = float_format ();
-
-	  int tmp = retval.read (is, nr, nc, dt, skip, ffmt);
-
-	  if (tmp < 0)
-	    error ("fread: read error");
-	  else
-	    char_count = tmp;
-	}
-    }
-  else
-    invalid_operation ("fread", "reading");
-
-  return retval;
-}
-
 #if defined (__GNUG__) && ! defined (CXX_ISO_COMPLIANT_LIBRARY)
 
 #define OCTAVE_SCAN(is, fmt, arg) is.scan ((fmt).text, arg)
@@ -2092,49 +2057,6 @@
   return retval;
 }
 
-int
-octave_base_stream::write (const octave_value& data,
-			   oct_data_conv::data_type dt, int skip,
-			   oct_mach_info::float_format ffmt)
-{
-  int retval = -1;
-
-  std::ostream *osp = output_stream ();
-
-  if (osp)
-    {
-      std::ostream& os = *osp;
-
-      int status = 0;
-
-      // XXX FIXME XXX -- the octave_value class should probably have
-      // a write method that would handle the dispatch for us?
-      //
-      // If DATA is a character matrix, then it is a bit of a kluge to
-      // force it to be a double matrix and then write it out as uchar
-      // data, but this is the quick fix...
-
-      Matrix mval = data.matrix_value (true);
-
-      if (! error_state)
-	{
-	  if (ffmt == oct_mach_info::flt_fmt_unknown)
-	    ffmt = float_format ();
-
-	  status = mval.write (os, dt, skip, ffmt);
-
-	  if (status < 0)
-	    error ("fwrite: write error");
-	  else
-	    retval = status;
-	}
-    }
-  else
-    invalid_operation ("fwrite", "writing");
-
-  return retval;
-}
-
 class
 printf_value_cache
 {
@@ -2848,32 +2770,646 @@
     rep->close ();
 }
 
+// XXX FIXME XXX -- these trait classes probably belong somehwere else...
+
+template <typename T>
+class
+octave_type_traits
+{
+public:
+  typedef T val_type;
+};
+
+#define OCTAVE_TYPE_TRAIT(T, VAL_T) \
+  template <> \
+  class \
+  octave_type_traits<T> \
+  { \
+  public: \
+    typedef VAL_T val_type; \
+  }
+
+OCTAVE_TYPE_TRAIT (octave_int8, octave_int8::val_type);
+OCTAVE_TYPE_TRAIT (octave_uint8, octave_uint8::val_type);
+OCTAVE_TYPE_TRAIT (octave_int16, octave_int16::val_type);
+OCTAVE_TYPE_TRAIT (octave_uint16, octave_uint16::val_type);
+OCTAVE_TYPE_TRAIT (octave_int32, octave_int32::val_type);
+OCTAVE_TYPE_TRAIT (octave_uint32, octave_uint32::val_type);
+OCTAVE_TYPE_TRAIT (octave_int64, octave_int64::val_type);
+OCTAVE_TYPE_TRAIT (octave_uint64, octave_uint64::val_type);
+
+template <typename T>
+class octave_array_type_traits
+{
+public:
+  typedef T element_type;
+};
+
+#define OCTAVE_ARRAY_TYPE_TRAIT(T, ELT_T) \
+  template <> \
+  class \
+  octave_array_type_traits<T> \
+  { \
+  public: \
+    typedef ELT_T element_type; \
+  }
+
+OCTAVE_ARRAY_TYPE_TRAIT (charNDArray, char);
+OCTAVE_ARRAY_TYPE_TRAIT (int8NDArray, octave_int8);
+OCTAVE_ARRAY_TYPE_TRAIT (uint8NDArray, octave_uint8);
+OCTAVE_ARRAY_TYPE_TRAIT (int16NDArray, octave_int16);
+OCTAVE_ARRAY_TYPE_TRAIT (uint16NDArray, octave_uint16);
+OCTAVE_ARRAY_TYPE_TRAIT (int32NDArray, octave_int32);
+OCTAVE_ARRAY_TYPE_TRAIT (uint32NDArray, octave_uint32);
+OCTAVE_ARRAY_TYPE_TRAIT (int64NDArray, octave_int64);
+OCTAVE_ARRAY_TYPE_TRAIT (uint64NDArray, octave_uint64);
+OCTAVE_ARRAY_TYPE_TRAIT (NDArray, double);
+
+template <class RET_T, class READ_T>
 octave_value
-octave_stream::read (const Array<double>& size,
-		     oct_data_conv::data_type dt, int skip,
-		     oct_mach_info::float_format flt_fmt, int& count)
+do_read (octave_stream& strm, int nr, int nc, int block_size,
+	 int skip, bool do_float_fmt_conv,
+	 oct_mach_info::float_format from_flt_fmt, int& count)
 {
   octave_value retval;
 
+  RET_T nda;
+
+  bool ok = true;
+
+  count = 0;
+
+  typename octave_array_type_traits<RET_T>::element_type elt_zero
+    = typename octave_array_type_traits<RET_T>::element_type ();
+
+  typename octave_array_type_traits<RET_T>::element_type *dat = 0;
+
+  int max_size = 0;
+
+  int final_nr = 0;
+  int final_nc = 0;
+
+  if (nr > 0)
+    {
+      if (nc > 0)
+	{
+	  nda.resize (dim_vector (nr, nc), elt_zero);
+	  dat = nda.fortran_vec ();
+	  max_size = nr * nc;
+	}
+      else
+	{
+	  nda.resize (dim_vector (nr, 32), elt_zero);
+	  dat = nda.fortran_vec ();
+	  max_size = nr * 32;
+	}
+    }
+  else
+    {
+      nda.resize (dim_vector (32, 1), elt_zero);
+      dat = nda.fortran_vec ();
+      max_size = 32;
+    }
+
+  // XXX FIXME XXX -- byte order for Cray?
+
+  bool swap = false;
+
+  if (oct_mach_info::words_big_endian ())
+    swap = (from_flt_fmt == oct_mach_info::flt_fmt_ieee_little_endian
+	    || from_flt_fmt == oct_mach_info::flt_fmt_vax_g
+	    || from_flt_fmt == oct_mach_info::flt_fmt_vax_g);
+  else
+    swap = (from_flt_fmt == oct_mach_info::flt_fmt_ieee_big_endian);
+
+  union
+  {
+    char buf[sizeof (typename octave_type_traits<READ_T>::val_type)];
+    typename octave_type_traits<READ_T>::val_type val;
+  } u;
+
+  std::istream *isp = strm.input_stream ();
+
+  if (isp)
+    {
+      std::istream& is = *isp;
+
+      int elts_read = 0;
+
+      for (;;)
+	{
+	  // XXX FIXME XXX -- maybe there should be a special case for
+	  // skip == 0.
+
+	  if (is)
+	    {
+	      if (nr > 0 && nc > 0 && count == max_size)
+		{
+		  final_nr = nr;
+		  final_nc = nc;
+
+		  break;
+		}
+
+	      is.read (u.buf, sizeof (typename octave_type_traits<READ_T>::val_type));
+
+	      // We only swap bytes for integer types.  For float
+	      // types, the format conversion will also handle byte
+	      // swapping.
+
+	      if (swap)
+		swap_bytes<sizeof (typename octave_type_traits<READ_T>::val_type)> (u.buf);
+	      else if (do_float_fmt_conv)
+		do_float_format_conversion
+		  (u.buf,
+		   sizeof (typename octave_type_traits<READ_T>::val_type),
+		   1, from_flt_fmt, oct_mach_info::float_format ());
+
+	      typename octave_array_type_traits<RET_T>::element_type tmp
+		= static_cast <typename octave_array_type_traits<RET_T>::element_type> (u.val);
+
+	      if (ok)
+		{
+		  if (is)
+		    {
+		      if (count == max_size)
+			{
+			  max_size *= 2;
+
+			  if (nr > 0)
+			    nda.resize (dim_vector (nr, max_size / nr),
+					elt_zero);
+			  else
+			    nda.resize (dim_vector (max_size, 1), elt_zero);
+
+			  dat = nda.fortran_vec ();
+			}
+
+		      dat[count++] = tmp;
+
+		      elts_read++;
+		    }
+
+		  if (skip != 0 && elts_read == block_size)
+		    {
+		      strm.seek (skip, SEEK_CUR);
+		      elts_read = 0;
+		    }
+
+		  if (is.eof ())
+		    {
+		      if (nr > 0)
+			{
+			  if (count > nr)
+			    {
+			      final_nr = nr;
+			      final_nc = (count - 1) / nr + 1;
+			    }
+			  else
+			    {
+			      final_nr = count;
+			      final_nc = 1;
+			    }
+			}
+		      else
+			{
+			  final_nr = count;
+			  final_nc = 1;
+			}
+
+		      break;
+		    }
+		}
+	      else
+		{
+		  ok = false;
+		  break;
+		}
+	    }
+	  else
+	    {
+	      ok = false;
+	      break;
+	    }
+	}
+    }
+
+  if (ok)
+    {
+      nda.resize (dim_vector (final_nr, final_nc), elt_zero);
+
+      retval = nda;
+    }
+
+  return retval;
+}
+
+#define DO_READ_VAL_TEMPLATE(RET_T, READ_T) \
+  template octave_value \
+  do_read<RET_T, READ_T> (octave_stream&, int, int, int, int, bool, \
+			  oct_mach_info::float_format, int&)
+
+// XXX FIXME XXX -- 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);
+
+typedef octave_value (*read_fptr) (octave_stream&, int, int, int, int, bool,
+				   oct_mach_info::float_format ffmt, int&);
+
+INSTANTIATE_ARRAY (read_fptr);
+template class Array2<read_fptr>;
+
+#define FILL_TABLE_ROW(R, VAL_T) \
+  read_fptr_table(R,oct_data_conv::dt_int8) = do_read<VAL_T, octave_int8>; \
+  read_fptr_table(R,oct_data_conv::dt_uint8) = do_read<VAL_T, octave_uint8>; \
+  read_fptr_table(R,oct_data_conv::dt_int16) = do_read<VAL_T, octave_int16>; \
+  read_fptr_table(R,oct_data_conv::dt_uint16) = do_read<VAL_T, octave_uint16>; \
+  read_fptr_table(R,oct_data_conv::dt_int32) = do_read<VAL_T, octave_int32>; \
+  read_fptr_table(R,oct_data_conv::dt_uint32) = do_read<VAL_T, octave_uint32>; \
+  read_fptr_table(R,oct_data_conv::dt_int64) = do_read<VAL_T, octave_int64>; \
+  read_fptr_table(R,oct_data_conv::dt_uint64) = do_read<VAL_T, octave_uint64>; \
+  read_fptr_table(R,oct_data_conv::dt_single) = do_read<VAL_T, float>; \
+  read_fptr_table(R,oct_data_conv::dt_double) = do_read<VAL_T, double>; \
+  read_fptr_table(R,oct_data_conv::dt_char) = do_read<VAL_T, char>; \
+  read_fptr_table(R,oct_data_conv::dt_schar) = do_read<VAL_T, signed char>; \
+  read_fptr_table(R,oct_data_conv::dt_uchar) = do_read<VAL_T, unsigned char>
+
+octave_value
+octave_stream::read (const Array<double>& size, int block_size,
+		     oct_data_conv::data_type input_type,
+		     oct_data_conv::data_type output_type,
+		     int skip, oct_mach_info::float_format ffmt,
+		     int& char_count)
+{
+  static bool initialized = false;
+
+  // Table function pointers for return types x read types.
+
+  static Array2<read_fptr> read_fptr_table (oct_data_conv::dt_unknown, 13, 0);
+
+  if (! initialized)
+    {
+      FILL_TABLE_ROW (oct_data_conv::dt_int8, int8NDArray);
+      FILL_TABLE_ROW (oct_data_conv::dt_uint8, uint8NDArray);
+      FILL_TABLE_ROW (oct_data_conv::dt_int16, int16NDArray);
+      FILL_TABLE_ROW (oct_data_conv::dt_uint16, uint16NDArray);
+      FILL_TABLE_ROW (oct_data_conv::dt_int32, int32NDArray);
+      FILL_TABLE_ROW (oct_data_conv::dt_uint32, uint32NDArray);
+      FILL_TABLE_ROW (oct_data_conv::dt_int64, int64NDArray);
+      FILL_TABLE_ROW (oct_data_conv::dt_uint64, uint64NDArray);
+      FILL_TABLE_ROW (oct_data_conv::dt_double, NDArray);
+      FILL_TABLE_ROW (oct_data_conv::dt_char, charNDArray);
+      FILL_TABLE_ROW (oct_data_conv::dt_schar, charNDArray);
+      FILL_TABLE_ROW (oct_data_conv::dt_uchar, charNDArray);
+
+      initialized = true;
+    }
+
+  octave_value retval;
+
   if (stream_ok ("fread"))
-    retval = rep->read (size, dt, skip, flt_fmt, count);
+    {
+      // XXX FIXME XXX -- we may eventually want to make this extensible.
+
+      // XXX FIXME XXX -- we need a better way to ensure that this
+      // numbering stays consistent with the order of the elements in the
+      // data_type enum in the oct_data_conv class.
+
+      char_count = 0;
+
+      int nr = -1;
+      int nc = -1;
+
+      bool ignore;
+
+      get_size (size, nr, nc, ignore, "fread");
+
+      if (! error_state)
+	{
+	  if (nr == 0 || nc == 0)
+	    retval = Matrix (nr, nc);
+	  else
+	    {
+	      if (ffmt == oct_mach_info::flt_fmt_unknown)
+		ffmt = float_format ();
+
+	      read_fptr fcn = read_fptr_table (output_type, input_type);
+
+	      bool do_float_fmt_conv = ((input_type == oct_data_conv::dt_double
+					 || input_type == oct_data_conv::dt_single)
+					&& ffmt != float_format ());
+
+	      if (fcn)
+		{
+		  retval = (*fcn) (*this, nr, nc, block_size, skip,
+				   do_float_fmt_conv, ffmt, char_count);
+
+		  // XXX FIXME XXX -- kluge!
+
+		  if (! error_state
+		      && (output_type == oct_data_conv::dt_char
+			  || output_type == oct_data_conv::dt_schar
+			  || output_type == oct_data_conv::dt_uchar))
+		    retval = octave_value (retval.char_matrix_value (), true);
+		}
+	      else
+		error ("fread: unable to read and convert requested types");
+	    }
+	}
+      else
+	invalid_operation ("fread", "reading");
+    }
 
   return retval;
 }
 
 int
-octave_stream::write (const octave_value& data,
-		      oct_data_conv::data_type dt, int skip,
+octave_stream::write (const octave_value& data, int block_size,
+		      oct_data_conv::data_type output_type, int skip,
 		      oct_mach_info::float_format flt_fmt)
 {
   int retval = -1;
 
   if (stream_ok ("fwrite"))
-    retval = rep->write (data, dt, skip, flt_fmt);
+    {
+      if (! error_state)
+	{
+	  if (flt_fmt == oct_mach_info::flt_fmt_unknown)
+	    flt_fmt = float_format ();
+
+	  int status = data.write (*this, block_size, output_type,
+				   skip, flt_fmt);
+
+	  if (status < 0)
+	    error ("fwrite: write error");
+	  else
+	    retval = status;
+	}
+      else
+	invalid_operation ("fwrite", "writing");
+    }
 
   return retval;
 }
 
+template <class T>
+void
+write_int (std::ostream& os, bool swap, const T& val)
+{
+  typename octave_type_traits<T>::val_type tmp = val.value ();
+
+  if (swap)
+    swap_bytes<sizeof (typename octave_type_traits<T>::val_type)> (&tmp);
+
+  os.write (reinterpret_cast<const char *> (&tmp),
+	    sizeof (typename octave_type_traits<T>::val_type));
+}
+
+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)
+{
+  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);
+
+  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));
+      break;
+
+    case oct_data_conv::dt_uchar:
+    case oct_data_conv::dt_uint8:
+      write_int (os, swap, octave_uint8 (val));
+      break;
+
+    case oct_data_conv::dt_int16:
+      write_int (os, swap, octave_int16 (val));
+      break;
+
+    case oct_data_conv::dt_uint16:
+      write_int (os, swap, octave_uint16 (val));
+      break;
+
+    case oct_data_conv::dt_int32:
+      write_int (os, swap, octave_int32 (val));
+      break;
+
+    case oct_data_conv::dt_uint32:
+      write_int (os, swap, octave_uint32 (val));
+      break;
+
+    case oct_data_conv::dt_int64:
+      write_int (os, swap, octave_int64 (val));
+      break;
+
+    case oct_data_conv::dt_uint64:
+      write_int (os, swap, octave_uint64 (val));
+      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));
+      }
+      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));
+      }
+      break;
+
+    default:
+      retval = false;
+      (*current_liboctave_error_handler)
+	("write: invalid type specification");
+      break;
+    }
+
+  return retval;
+}
+
+template <class T>
+int
+octave_stream::write (const Array<T>& data, int block_size,
+		      oct_data_conv::data_type output_type,
+		      int skip, oct_mach_info::float_format flt_fmt)
+{
+  int retval = -1;
+
+  bool status = true;
+
+  int count = 0;
+
+  const T *d = data.data ();
+
+  int 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);
+
+  // XXX FIXME XXX -- byte order for Cray?
+
+  bool swap = false;
+
+  if (oct_mach_info::words_big_endian ())
+    swap = (flt_fmt == oct_mach_info::flt_fmt_ieee_little_endian
+	    || flt_fmt == oct_mach_info::flt_fmt_vax_g
+	    || flt_fmt == oct_mach_info::flt_fmt_vax_g);
+  else
+    swap = (flt_fmt == oct_mach_info::flt_fmt_ieee_big_endian);
+
+  for (int i = 0; i < n; i++)
+    {
+      std::ostream *osp = output_stream ();
+
+      if (osp)
+	{
+	  std::ostream& os = *osp;
+
+	  if (skip != 0 && (i % block_size) == 0)
+	    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;
+	    }
+	}
+      else
+	{
+	  status = false;
+	  break;
+	}
+    }
+
+  if (status)
+    retval = count;
+
+  return retval;
+}
+
+template int
+octave_stream::write (const Array<char>&, int,
+		      oct_data_conv::data_type,
+		      int, oct_mach_info::float_format);
+
+template int
+octave_stream::write (const Array<double>&, int,
+		      oct_data_conv::data_type,
+		      int, oct_mach_info::float_format);
+
+template int
+octave_stream::write (const Array<octave_int8>&, int,
+		      oct_data_conv::data_type,
+		      int, oct_mach_info::float_format);
+
+template int
+octave_stream::write (const Array<octave_uint8>&, int,
+		      oct_data_conv::data_type,
+		      int, oct_mach_info::float_format);
+
+template int
+octave_stream::write (const Array<octave_int16>&, int,
+		      oct_data_conv::data_type,
+		      int, oct_mach_info::float_format);
+
+template int
+octave_stream::write (const Array<octave_uint16>&, int,
+		      oct_data_conv::data_type,
+		      int, oct_mach_info::float_format);
+
+template int
+octave_stream::write (const Array<octave_int32>&, int,
+		      oct_data_conv::data_type,
+		      int, oct_mach_info::float_format);
+
+template int
+octave_stream::write (const Array<octave_uint32>&, int,
+		      oct_data_conv::data_type,
+		      int, oct_mach_info::float_format);
+
+template int
+octave_stream::write (const Array<octave_int64>&, int,
+		      oct_data_conv::data_type,
+		      int, oct_mach_info::float_format);
+
+template int
+octave_stream::write (const Array<octave_uint64>&, int,
+		      oct_data_conv::data_type,
+		      int, oct_mach_info::float_format);
+
 octave_value
 octave_stream::scanf (const std::string& fmt, const Array<double>& size,
 		      int& count, const std::string& who)