core/vsl/vsl_block_binary.cxx
Go to the documentation of this file.
00001 // This is core/vsl/vsl_block_binary.cxx
00002 //:
00003 // \file
00004 // \brief Set of functions to do binary IO on a block of values.
00005 // \author Ian Scott, ISBE Manchester, Feb 2003
00006 
00007 #include "vsl_block_binary.h"
00008 #include <vcl_cstddef.h>
00009 #include <vcl_new.h>
00010 #include <vcl_algorithm.h>
00011 #include <vcl_cstdlib.h>
00012 #include <vcl_cassert.h>
00013 
00014 struct vsl_block_t
00015 {
00016   char * ptr;
00017   vcl_size_t size;
00018 };
00019 
00020 vsl_block_t allocate_up_to(vcl_size_t nbytes)
00021 {
00022   vsl_block_t block = {0, nbytes};
00023   while (true)
00024   {
00025 #if VCL_HAS_EXCEPTIONS
00026     try
00027     {
00028       block.ptr = new char[block.size];
00029     }
00030     catch (const vcl_bad_alloc& )
00031     {
00032     }
00033 #else
00034     //use malloc because gcc's new still tries to throw a bad alloc even with -fno_exceptions
00035     block.ptr = (char *)vcl_malloc(block.size);
00036 #endif
00037     if (block.ptr)
00038       return block;
00039     block.size /= 2;
00040   }
00041 }
00042 
00043 
00044 //: Error checking.
00045 void vsl_block_binary_read_confirm_specialisation(vsl_b_istream &is, bool specialised)
00046 {
00047   if (!is) return;
00048   bool b;
00049   vsl_b_read(is, b);
00050   if (b != specialised)
00051   {
00052     vcl_cerr << "I/O ERROR: vsl_block_binary_read()\n";
00053     if (specialised)
00054       vcl_cerr << "           Data was saved using unspecialised slow form and is being loaded\n"
00055                << "           using specialised fast form.\n\n";
00056     else
00057       vcl_cerr << "           Data was saved using specialised fast form and is being loaded\n"
00058                << "           using unspecialised slow form.\n\n";
00059 
00060     is.is().clear(vcl_ios::badbit); // Set an unrecoverable IO error on stream
00061   }
00062 }
00063 
00064 
00065 /////////////////////////////////////////////////////////////////////////
00066 
00067 //: Write a block of floats to a vsl_b_ostream
00068 template <class T>
00069 void vsl_block_binary_write_float_impl(vsl_b_ostream &os, const T* begin, vcl_size_t nelems)
00070 {
00071   vsl_b_write(os, true); // Error check that this is a specialised version
00072 
00073   const vcl_size_t wanted = sizeof(T) * nelems;
00074   vsl_block_t block = allocate_up_to(wanted);
00075 
00076   // multiple-block version works equally efficiently with single block
00077   const vcl_size_t items_per_block = block.size / sizeof(T);
00078 
00079   // convert and save the data from the start.
00080   while (nelems > 0)
00081   {
00082     vcl_size_t items = vcl_min(items_per_block, nelems);
00083     vcl_size_t bytes = sizeof(T) * items;
00084     vsl_swap_bytes_to_buffer((const char *)begin, (char *)block.ptr, sizeof(T), items);
00085     os.os().write( block.ptr, bytes);
00086     begin += items;
00087     nelems -= items;
00088   }
00089 #if VCL_HAS_EXCEPTIONS
00090    delete [] block.ptr;
00091 #else
00092   vcl_free(block.ptr);
00093 #endif
00094 }
00095 
00096 //: Read a block of floats from a vsl_b_ostream
00097 template <class T>
00098 void vsl_block_binary_read_float_impl(vsl_b_istream &is, T* begin, vcl_size_t nelems)
00099 {
00100   // There are no complications here, to deal with low memory,
00101   // because the byte swapping can be done in place.
00102   vsl_block_binary_read_confirm_specialisation(is, true);
00103   if (!is) return;
00104   is.is().read((char*) begin, nelems*sizeof(T));
00105   vsl_swap_bytes((char *)begin, sizeof(T), nelems);
00106 }
00107 
00108 /////////////////////////////////////////////////////////////////////////
00109 //: Write a block of signed ints to a vsl_b_ostream
00110 template <class T>
00111 void vsl_block_binary_write_int_impl(vsl_b_ostream &os, const T* begin, vcl_size_t nelems)
00112 {
00113 
00114   vsl_b_write(os, true); // Error check that this is a specialised version
00115 
00116   const vcl_size_t wanted = VSL_MAX_ARBITRARY_INT_BUFFER_LENGTH(sizeof(T)) * nelems;
00117   vsl_block_t block = allocate_up_to(wanted  );
00118 
00119   if (block.size == wanted)
00120   {
00121     // Do simple single block version
00122     vcl_size_t nbytes = vsl_convert_to_arbitrary_length(begin,
00123                                                         (unsigned char *)block.ptr, nelems);
00124     vsl_b_write(os, nbytes);
00125     os.os().write( block.ptr, nbytes);
00126   }
00127   else
00128   {
00129     // Do multiple-block version
00130     const vcl_size_t items_per_block = block.size / VSL_MAX_ARBITRARY_INT_BUFFER_LENGTH(sizeof(T));
00131     vcl_size_t n=nelems; //Number of items still to be converted.
00132     const T* p=begin; //Pointer to next block of data to be converted.
00133     assert (n > items_per_block);
00134     // Convert the data - just counting bytes for now.
00135     vcl_size_t n_bytes=0;
00136     while (n > 0)
00137     {
00138       vcl_size_t items = vcl_min(items_per_block, n);
00139       n_bytes += vsl_convert_to_arbitrary_length(p,
00140                                                  (unsigned char *)block.ptr, items);
00141       p += items;
00142       n -= items;
00143     }
00144 
00145     vsl_b_write(os, n_bytes);
00146     n=nelems;
00147     p=begin;
00148 
00149     // Now convert and save the data from the start.
00150     while (n > 0)
00151     {
00152       vcl_size_t items = vcl_min(items_per_block, n);
00153       vcl_size_t bytes = vsl_convert_to_arbitrary_length(p,
00154                                                          (unsigned char *)block.ptr, items );
00155       os.os().write( block.ptr, bytes);
00156       p += items;
00157       n -= items;
00158     }
00159   }
00160 #if VCL_HAS_EXCEPTIONS
00161    delete [] block.ptr;
00162 #else
00163   vcl_free(block.ptr);
00164 #endif
00165 }
00166 
00167 /////////////////////////////////////////////////////////////////////////
00168 
00169 //: Read a block of signed ints from a vsl_b_istream
00170 template <class T>
00171 void vsl_block_binary_read_int_impl(vsl_b_istream &is, T* begin, vcl_size_t nelems)
00172 {
00173   vsl_block_binary_read_confirm_specialisation(is, true);
00174   if (!is) return;
00175   vcl_size_t nbytes;
00176   vsl_b_read(is, nbytes);
00177   if (nbytes==0) return;
00178 
00179 
00180   vsl_block_t block = allocate_up_to(nbytes);
00181 
00182   vcl_size_t n_bytes_converted = 0;
00183   if (block.size == nbytes)
00184   {
00185     // Do simple single block version
00186     is.is().read(block.ptr, block.size);
00187     n_bytes_converted =
00188       vsl_convert_from_arbitrary_length((unsigned char *)block.ptr, begin, nelems);
00189   }
00190   else    // Do multi-block version
00191   {
00192     vcl_size_t offset=0;
00193     vcl_size_t bytes_left = nbytes;
00194     vcl_size_t bytes_read = 0;
00195     while (nelems > 0)
00196     {
00197       assert (offset < block.size);
00198 
00199       // fill block beyond offset with as much as possible.
00200       vcl_size_t bytes = vcl_min((vcl_size_t)nbytes-bytes_read, block.size-offset);
00201       is.is().read(block.ptr+offset, bytes);
00202       bytes_read += bytes;
00203 
00204       if (!is) break;
00205 
00206       // count number of ints in block.
00207       vcl_size_t elems=0;
00208       for (unsigned char *p = (unsigned char *)block.ptr, *p_end=p+bytes+offset; p!=p_end; ++p)
00209         elems += *p >> 7;
00210 
00211       if (elems > nelems)
00212       {
00213         vcl_cerr << "\nI/O ERROR: vsl_block_binary_read(.., int*,..)"
00214                  << " Corrupted data stream\n";
00215         is.is().clear(vcl_ios::badbit); // Set an unrecoverable IO error on stream
00216         break;
00217       }
00218 
00219       // convert ints;
00220       vcl_size_t bytes_converted =
00221         vsl_convert_from_arbitrary_length((unsigned char *)block.ptr, begin, elems);
00222       nelems -= elems;
00223       begin += elems;
00224 
00225       offset = (bytes + offset) - bytes_converted; // avoid overflow.
00226       n_bytes_converted += bytes_converted;
00227       bytes_left -= bytes_converted;
00228 
00229       // shift remaining (offset) bytes to front of block.
00230       vcl_memcpy(block.ptr, block.ptr + bytes_converted, offset);
00231     }
00232     if (bytes_left != 0 || nelems != 0 || bytes_read != nbytes)
00233     {
00234       vcl_cerr << "\nI/O ERROR: vsl_block_binary_read(.., int*,..)"
00235                << " Corrupted data stream\n";
00236       is.is().clear(vcl_ios::badbit); // Set an unrecoverable IO error on stream
00237     }
00238   }
00239   if (n_bytes_converted != nbytes)
00240   {
00241     vcl_cerr << "\nI/O ERROR: vsl_block_binary_read(.., int*,..)"
00242              << " Corrupted data stream\n";
00243     is.is().clear(vcl_ios::badbit); // Set an unrecoverable IO error on stream
00244   }
00245 #if VCL_HAS_EXCEPTIONS
00246    delete [] block.ptr;
00247 #else
00248   vcl_free(block.ptr);
00249 #endif
00250 }
00251 
00252 /////////////////////////////////////////////////////////////////////////
00253 
00254 //: Write a block of bytes to a vsl_b_ostream
00255 template <class T>
00256 void vsl_block_binary_write_byte_impl(vsl_b_ostream &os, const T* begin, vcl_size_t nelems)
00257 {
00258   vsl_b_write(os, true); // Error check that this is a specialised version
00259   os.os().write((char*) begin, nelems);
00260 }
00261 
00262 //: Read a block of bytes from a vsl_b_ostream
00263 template <class T>
00264 void vsl_block_binary_read_byte_impl(vsl_b_istream &is, T* begin, vcl_size_t nelems)
00265 {
00266   // There are no complications here, to deal with low memory,
00267   // because the load is done in place.
00268   vsl_block_binary_read_confirm_specialisation(is, true);
00269   if (!is) return;
00270   is.is().read((char*) begin, nelems);
00271 }
00272 
00273 
00274 // Instantiate templates for POD types.
00275 
00276 template void vsl_block_binary_write_float_impl(vsl_b_ostream &, const double*, vcl_size_t);
00277 template void vsl_block_binary_write_float_impl(vsl_b_ostream &, const float*, vcl_size_t);
00278 
00279 template void vsl_block_binary_read_float_impl(vsl_b_istream &, double*, vcl_size_t);
00280 template void vsl_block_binary_read_float_impl(vsl_b_istream &, float*, vcl_size_t);
00281 
00282 template void vsl_block_binary_write_int_impl(vsl_b_ostream &, const long*, vcl_size_t);
00283 template void vsl_block_binary_write_int_impl(vsl_b_ostream &, const unsigned long*, vcl_size_t);
00284 template void vsl_block_binary_write_int_impl(vsl_b_ostream &, const int*, vcl_size_t);
00285 template void vsl_block_binary_write_int_impl(vsl_b_ostream &, const unsigned int*, vcl_size_t);
00286 template void vsl_block_binary_write_int_impl(vsl_b_ostream &, const short*, vcl_size_t);
00287 template void vsl_block_binary_write_int_impl(vsl_b_ostream &, const unsigned short*, vcl_size_t);
00288 
00289 template void vsl_block_binary_read_int_impl(vsl_b_istream &, long*, vcl_size_t);
00290 template void vsl_block_binary_read_int_impl(vsl_b_istream &, unsigned long*, vcl_size_t);
00291 template void vsl_block_binary_read_int_impl(vsl_b_istream &, int*, vcl_size_t);
00292 template void vsl_block_binary_read_int_impl(vsl_b_istream &, unsigned int*, vcl_size_t);
00293 template void vsl_block_binary_read_int_impl(vsl_b_istream &, short*, vcl_size_t);
00294 template void vsl_block_binary_read_int_impl(vsl_b_istream &, unsigned short*, vcl_size_t);
00295 
00296 template void vsl_block_binary_write_byte_impl(vsl_b_ostream &, const signed char*, vcl_size_t);
00297 template void vsl_block_binary_write_byte_impl(vsl_b_ostream &, const unsigned char*, vcl_size_t);
00298 
00299 template void vsl_block_binary_read_byte_impl(vsl_b_istream &, signed char*, vcl_size_t);
00300 template void vsl_block_binary_read_byte_impl(vsl_b_istream &, unsigned char*, vcl_size_t);
00301 
00302 #if VXL_HAS_INT_64 && !VXL_INT_64_IS_LONG
00303 template void vsl_block_binary_write_int_impl(vsl_b_ostream &, const vxl_int_64*, vcl_size_t);
00304 template void vsl_block_binary_write_int_impl(vsl_b_ostream &, const vxl_uint_64*, vcl_size_t);
00305 template void vsl_block_binary_read_int_impl(vsl_b_istream &, vxl_int_64*, vcl_size_t);
00306 template void vsl_block_binary_read_int_impl(vsl_b_istream &, vxl_uint_64*, vcl_size_t);
00307 #endif //VXL_HAS_INT_64 && !VXL_INT_64_IS_LONG