vsl_block_binary.cxx
Go to the documentation of this file.
1 // This is core/vsl/vsl_block_binary.cxx
2 //:
3 // \file
4 // \brief Set of functions to do binary IO on a block of values.
5 // \author Ian Scott, ISBE Manchester, Feb 2003
6 
7 #include <cstddef>
8 #include <new>
9 #include <algorithm>
10 #include <cstdlib>
11 #include "vsl_block_binary.h"
12 #ifdef _MSC_VER
13 # include <vcl_msvc_warnings.h>
14 #endif
15 #include <cassert>
16 
18 {
19  char * ptr;
20  std::size_t size;
21 };
22 
23 vsl_block_t allocate_up_to(std::size_t nbytes)
24 {
25  vsl_block_t block = {nullptr, nbytes};
26  while (true)
27  {
28  try
29  {
30  block.ptr = new char[block.size];
31  }
32  catch (const std::bad_alloc& )
33  {
34  }
35  if (block.ptr)
36  return block;
37  block.size /= 2;
38  }
39 }
40 
41 
42 //: Error checking.
44 {
45  if (!is) return;
46  bool b;
47  vsl_b_read(is, b);
48  if (b != specialised)
49  {
50  std::cerr << "I/O ERROR: vsl_block_binary_read()\n";
51  if (specialised)
52  std::cerr << " Data was saved using unspecialised slow form and is being loaded\n"
53  << " using specialised fast form.\n\n";
54  else
55  std::cerr << " Data was saved using specialised fast form and is being loaded\n"
56  << " using unspecialised slow form.\n\n";
57 
58  is.is().clear(std::ios::badbit); // Set an unrecoverable IO error on stream
59  }
60 }
61 
62 
63 /////////////////////////////////////////////////////////////////////////
64 
65 //: Write a block of floats to a vsl_b_ostream
66 template <class T>
67 void vsl_block_binary_write_float_impl(vsl_b_ostream &os, const T* begin, std::size_t nelems)
68 {
69  vsl_b_write(os, true); // Error check that this is a specialised version
70 
71  const std::size_t wanted = sizeof(T) * nelems;
72  vsl_block_t block = allocate_up_to(wanted);
73 
74  // multiple-block version works equally efficiently with single block
75  const std::size_t items_per_block = block.size / sizeof(T);
76 
77  // convert and save the data from the start.
78  while (nelems > 0)
79  {
80  std::size_t items = std::min(items_per_block, nelems);
81  std::size_t bytes = sizeof(T) * items;
82  vsl_swap_bytes_to_buffer((const char *)begin, (char *)block.ptr, sizeof(T), items);
83  os.os().write( block.ptr, bytes);
84  begin += items;
85  nelems -= items;
86  }
87  delete [] block.ptr;
88 }
89 
90 //: Read a block of floats from a vsl_b_ostream
91 template <class T>
92 void vsl_block_binary_read_float_impl(vsl_b_istream &is, T* begin, std::size_t nelems)
93 {
94  // There are no complications here, to deal with low memory,
95  // because the byte swapping can be done in place.
97  if (!is) return;
98  is.is().read((char*) begin, nelems*sizeof(T));
99  vsl_swap_bytes((char *)begin, sizeof(T), nelems);
100 }
101 
102 /////////////////////////////////////////////////////////////////////////
103 //: Write a block of signed ints to a vsl_b_ostream
104 template <class T>
105 void vsl_block_binary_write_int_impl(vsl_b_ostream &os, const T* begin, std::size_t nelems)
106 {
107 
108  vsl_b_write(os, true); // Error check that this is a specialised version
109 
110  const std::size_t wanted = VSL_MAX_ARBITRARY_INT_BUFFER_LENGTH(sizeof(T)) * nelems;
111  vsl_block_t block = allocate_up_to(wanted );
112 
113  if (block.size == wanted)
114  {
115  // Do simple single block version
116  std::size_t nbytes = vsl_convert_to_arbitrary_length(begin,
117  (unsigned char *)block.ptr, nelems);
118  vsl_b_write(os, nbytes);
119  os.os().write( block.ptr, nbytes);
120  }
121  else
122  {
123  // Do multiple-block version
124  const std::size_t items_per_block = block.size / VSL_MAX_ARBITRARY_INT_BUFFER_LENGTH(sizeof(T));
125  std::size_t n=nelems; //Number of items still to be converted.
126  const T* p=begin; //Pointer to next block of data to be converted.
127  assert (n > items_per_block);
128  // Convert the data - just counting bytes for now.
129  std::size_t n_bytes=0;
130  while (n > 0)
131  {
132  std::size_t items = std::min(items_per_block, n);
133  n_bytes += vsl_convert_to_arbitrary_length(p,
134  (unsigned char *)block.ptr, items);
135  p += items;
136  n -= items;
137  }
138 
139  vsl_b_write(os, n_bytes);
140  n=nelems;
141  p=begin;
142 
143  // Now convert and save the data from the start.
144  while (n > 0)
145  {
146  std::size_t items = std::min(items_per_block, n);
147  std::size_t bytes = vsl_convert_to_arbitrary_length(p,
148  (unsigned char *)block.ptr, items );
149  os.os().write( block.ptr, bytes);
150  p += items;
151  n -= items;
152  }
153  }
154  delete [] block.ptr;
155 }
156 
157 /////////////////////////////////////////////////////////////////////////
158 
159 //: Read a block of signed ints from a vsl_b_istream
160 template <class T>
161 void vsl_block_binary_read_int_impl(vsl_b_istream &is, T* begin, std::size_t nelems)
162 {
164  if (!is) return;
165  std::size_t nbytes;
166  vsl_b_read(is, nbytes);
167  if (nbytes==0) return;
168 
169 
170  vsl_block_t block = allocate_up_to(nbytes);
171 
172  std::size_t n_bytes_converted = 0;
173  if (block.size == nbytes)
174  {
175  // Do simple single block version
176  is.is().read(block.ptr, block.size);
177  n_bytes_converted =
178  vsl_convert_from_arbitrary_length((unsigned char *)block.ptr, begin, nelems);
179  }
180  else // Do multi-block version
181  {
182  std::size_t offset=0;
183  std::size_t bytes_left = nbytes;
184  std::size_t bytes_read = 0;
185  while (nelems > 0)
186  {
187  assert (offset < block.size);
188 
189  // fill block beyond offset with as much as possible.
190  std::size_t bytes = std::min((std::size_t)nbytes-bytes_read, block.size-offset);
191  is.is().read(block.ptr+offset, bytes);
192  bytes_read += bytes;
193 
194  if (!is) break;
195 
196  // count number of ints in block.
197  std::size_t elems=0;
198  for (unsigned char *p = (unsigned char *)block.ptr, *p_end=p+bytes+offset; p!=p_end; ++p)
199  elems += *p >> 7;
200 
201  if (elems > nelems)
202  {
203  std::cerr << "\nI/O ERROR: vsl_block_binary_read(.., int*,..)"
204  << " Corrupted data stream\n";
205  is.is().clear(std::ios::badbit); // Set an unrecoverable IO error on stream
206  break;
207  }
208 
209  // convert ints;
210  std::size_t bytes_converted =
211  vsl_convert_from_arbitrary_length((unsigned char *)block.ptr, begin, elems);
212  nelems -= elems;
213  begin += elems;
214 
215  offset = (bytes + offset) - bytes_converted; // avoid overflow.
216  n_bytes_converted += bytes_converted;
217  bytes_left -= bytes_converted;
218 
219  // shift remaining (offset) bytes to front of block.
220  std::memcpy(block.ptr, block.ptr + bytes_converted, offset);
221  }
222  if (bytes_left != 0 || nelems != 0 || bytes_read != nbytes)
223  {
224  std::cerr << "\nI/O ERROR: vsl_block_binary_read(.., int*,..)"
225  << " Corrupted data stream\n";
226  is.is().clear(std::ios::badbit); // Set an unrecoverable IO error on stream
227  }
228  }
229  if (n_bytes_converted != nbytes)
230  {
231  std::cerr << "\nI/O ERROR: vsl_block_binary_read(.., int*,..)"
232  << " Corrupted data stream\n";
233  is.is().clear(std::ios::badbit); // Set an unrecoverable IO error on stream
234  }
235  delete [] block.ptr;
236 }
237 
238 /////////////////////////////////////////////////////////////////////////
239 
240 //: Write a block of bytes to a vsl_b_ostream
241 template <class T>
242 void vsl_block_binary_write_byte_impl(vsl_b_ostream &os, const T* begin, std::size_t nelems)
243 {
244  vsl_b_write(os, true); // Error check that this is a specialised version
245  os.os().write((char*) begin, nelems);
246 }
247 
248 //: Read a block of bytes from a vsl_b_ostream
249 template <class T>
250 void vsl_block_binary_read_byte_impl(vsl_b_istream &is, T* begin, std::size_t nelems)
251 {
252  // There are no complications here, to deal with low memory,
253  // because the load is done in place.
255  if (!is) return;
256  is.is().read((char*) begin, nelems);
257 }
258 
259 
260 // Instantiate templates for POD types.
261 
262 template void vsl_block_binary_write_float_impl(vsl_b_ostream &, const double*, std::size_t);
263 template void vsl_block_binary_write_float_impl(vsl_b_ostream &, const float*, std::size_t);
264 
265 template void vsl_block_binary_read_float_impl(vsl_b_istream &, double*, std::size_t);
266 template void vsl_block_binary_read_float_impl(vsl_b_istream &, float*, std::size_t);
267 
268 template void vsl_block_binary_write_int_impl(vsl_b_ostream &, const long*, std::size_t);
269 template void vsl_block_binary_write_int_impl(vsl_b_ostream &, const unsigned long*, std::size_t);
270 template void vsl_block_binary_write_int_impl(vsl_b_ostream &, const int*, std::size_t);
271 template void vsl_block_binary_write_int_impl(vsl_b_ostream &, const unsigned int*, std::size_t);
272 template void vsl_block_binary_write_int_impl(vsl_b_ostream &, const short*, std::size_t);
273 template void vsl_block_binary_write_int_impl(vsl_b_ostream &, const unsigned short*, std::size_t);
274 
275 template void vsl_block_binary_read_int_impl(vsl_b_istream &, long*, std::size_t);
276 template void vsl_block_binary_read_int_impl(vsl_b_istream &, unsigned long*, std::size_t);
277 template void vsl_block_binary_read_int_impl(vsl_b_istream &, int*, std::size_t);
278 template void vsl_block_binary_read_int_impl(vsl_b_istream &, unsigned int*, std::size_t);
279 template void vsl_block_binary_read_int_impl(vsl_b_istream &, short*, std::size_t);
280 template void vsl_block_binary_read_int_impl(vsl_b_istream &, unsigned short*, std::size_t);
281 
282 template void vsl_block_binary_write_byte_impl(vsl_b_ostream &, const signed char*, std::size_t);
283 template void vsl_block_binary_write_byte_impl(vsl_b_ostream &, const unsigned char*, std::size_t);
284 
285 template void vsl_block_binary_read_byte_impl(vsl_b_istream &, signed char*, std::size_t);
286 template void vsl_block_binary_read_byte_impl(vsl_b_istream &, unsigned char*, std::size_t);
287 
288 #if VXL_HAS_INT_64 && !VXL_INT_64_IS_LONG
289 template void vsl_block_binary_write_int_impl(vsl_b_ostream &, const vxl_int_64*, std::size_t);
290 template void vsl_block_binary_write_int_impl(vsl_b_ostream &, const vxl_uint_64*, std::size_t);
291 template void vsl_block_binary_read_int_impl(vsl_b_istream &, vxl_int_64*, std::size_t);
292 template void vsl_block_binary_read_int_impl(vsl_b_istream &, vxl_uint_64*, std::size_t);
293 #endif //VXL_HAS_INT_64 && !VXL_INT_64_IS_LONG
void vsl_block_binary_write_byte_impl(vsl_b_ostream &os, const T *begin, std::size_t nelems)
Write a block of bytes to a vsl_b_ostream.
A binary output adaptor for any std::ostream.
Definition: vsl_binary_io.h:37
Set of functions to do binary IO on a block of values.
void vsl_b_write(vsl_b_ostream &os, char n)
Write char to vsl_b_ostream.
void vsl_swap_bytes(char *ptr, unsigned nbyte, std::size_t nelem=1)
Perform byte swapping in situ.
void vsl_block_binary_write_float_impl(vsl_b_ostream &os, const T *begin, std::size_t nelems)
Write a block of floats to a vsl_b_ostream.
void vsl_block_binary_read_byte_impl(vsl_b_istream &is, T *begin, std::size_t nelems)
Read a block of bytes from a vsl_b_ostream.
std::istream & is() const
A reference to the adaptor's stream.
vsl_block_t allocate_up_to(std::size_t nbytes)
std::size_t vsl_convert_from_arbitrary_length(const unsigned char *buffer, unsigned long *ints, std::size_t count=1)
Decode a buffer of arbitrary length integers.
void vsl_block_binary_read_confirm_specialisation(vsl_b_istream &is, bool specialised)
Error checking.
std::size_t size
#define VSL_MAX_ARBITRARY_INT_BUFFER_LENGTH(size_of_type)
The maximum length of buffer to use with arbitrary length integers.
void vsl_block_binary_write_int_impl(vsl_b_ostream &os, const T *begin, std::size_t nelems)
Write a block of signed ints to a vsl_b_ostream.
void vsl_b_read(vsl_b_istream &is, char &n)
Read char from vsl_b_istream.
An adaptor for any std::istream to make it suitable for binary input.
std::size_t vsl_convert_to_arbitrary_length(const unsigned long *ints, unsigned char *buffer, std::size_t count=1)
Encode an array of ints into an arbitrary length format.
void vsl_block_binary_read_int_impl(vsl_b_istream &is, T *begin, std::size_t nelems)
Read a block of signed ints from a vsl_b_istream.
void vsl_block_binary_read_float_impl(vsl_b_istream &is, T *begin, std::size_t nelems)
Read a block of floats from a vsl_b_ostream.
std::ostream & os() const
A reference to the adaptor's stream.
void vsl_swap_bytes_to_buffer(const char *source, char *dest, unsigned nbyte, std::size_t nelem=1)
Perform byte swapping to a buffer.