Line data Source code
1 : /** \file binVector.hpp
2 : * \author Jared R. Males
3 : * \brief A utility to read/write vectors of data from/to a binary file.
4 : * \ingroup utils_files
5 : */
6 :
7 : //***********************************************************************//
8 : // Copyright 2015, 2016, 2017 Jared R. Males (jaredmales@gmail.com)
9 : //
10 : // This file is part of mxlib.
11 : //
12 : // mxlib is free software: you can redistribute it and/or modify
13 : // it under the terms of the GNU General Public License as published by
14 : // the Free Software Foundation, either version 3 of the License, or
15 : // (at your option) any later version.
16 : //
17 : // mxlib is distributed in the hope that it will be useful,
18 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 : // GNU General Public License for more details.
21 : //
22 : // You should have received a copy of the GNU General Public License
23 : // along with mxlib. If not, see <http://www.gnu.org/licenses/>.
24 : //***********************************************************************//
25 :
26 : #ifndef binVector_hpp
27 : #define binVector_hpp
28 :
29 : #include <vector>
30 : #include <complex>
31 : #include <cstdint>
32 :
33 : #include "../mxlib.hpp"
34 :
35 : namespace mx
36 : {
37 : namespace ioutils
38 : {
39 :
40 : /** \defgroup binvector binVector Binary File Format
41 : * \ingroup ioutils
42 : * \brief A simple binary file format for storing vectors of data on disk.
43 : *
44 : * The binVector file format is very simple: the first 8 bytes contain a unit64_t integer which specifies
45 : * the type of the data. The second 8 bytes contain a uint64_t integer which specifies the length L of the data vector.
46 : * The remaining L*sizeof(dataT) bytes contain the data.
47 : *
48 : * The suggested extension for BinVector files is ".binv".
49 : *
50 : *
51 : */
52 :
53 : /// The type used for binVector sizes.
54 : /** \ingroup binvector
55 : */
56 : typedef uint64_t binVSizeT;
57 :
58 : /// The type of binVector type codes.
59 : /** \ingroup binvector
60 : */
61 : typedef uint64_t binVTypeT;
62 :
63 : /// Namespace fo the bin-vector type-codes.
64 : /** \ingroup binvector
65 : */
66 : namespace binVTypes
67 : {
68 :
69 : /// The pre-defined type codes for binVector.
70 : /** \ingroup binvector
71 : */
72 : enum : binVTypeT
73 : {
74 : Bool = 0,
75 : SChar = 1,
76 : UChar = 2,
77 : Char = 3,
78 : WChar = 4,
79 : Char16 = 5,
80 : Char32 = 6,
81 : Int = 7,
82 : UInt = 8,
83 : SInt = 9,
84 : SUInt = 10,
85 : LInt = 11,
86 : LUInt = 12,
87 : LLInt = 13,
88 : LLUInt = 14,
89 : Float = 15,
90 : Double = 16,
91 : LDouble = 17,
92 : Quad = 18,
93 : CFloat = 19,
94 : CDouble = 20,
95 : };
96 :
97 : } // namespace binVTypes
98 :
99 : /// Get the integer type code corresponding to the type.
100 : /**
101 : * \returns an integer which uniquely identifies the type.
102 : *
103 : * \tparam dataT is the type
104 : *
105 : * \ingroup binvector
106 : */
107 : template <typename dataT>
108 : binVTypeT binVectorTypeCode();
109 :
110 : template <>
111 0 : binVTypeT binVectorTypeCode<bool>()
112 : {
113 0 : return binVTypes::Bool;
114 : }
115 :
116 : template <>
117 0 : binVTypeT binVectorTypeCode<signed char>()
118 : {
119 0 : return binVTypes::SChar;
120 : }
121 :
122 : template <>
123 0 : binVTypeT binVectorTypeCode<unsigned char>()
124 : {
125 0 : return binVTypes::UChar;
126 : }
127 :
128 : template <>
129 0 : binVTypeT binVectorTypeCode<char>()
130 : {
131 0 : return binVTypes::Char;
132 : }
133 :
134 : template <>
135 0 : binVTypeT binVectorTypeCode<wchar_t>()
136 : {
137 0 : return binVTypes::WChar;
138 : }
139 :
140 : template <>
141 0 : binVTypeT binVectorTypeCode<char16_t>()
142 : {
143 0 : return binVTypes::Char16;
144 : }
145 :
146 : template <>
147 0 : binVTypeT binVectorTypeCode<char32_t>()
148 : {
149 0 : return binVTypes::Char32;
150 : }
151 :
152 : template <>
153 0 : binVTypeT binVectorTypeCode<int>()
154 : {
155 0 : return binVTypes::Int;
156 : }
157 :
158 : template <>
159 0 : binVTypeT binVectorTypeCode<unsigned int>()
160 : {
161 0 : return binVTypes::UInt;
162 : }
163 :
164 : template <>
165 0 : binVTypeT binVectorTypeCode<short int>()
166 : {
167 0 : return binVTypes::SInt;
168 : }
169 :
170 : template <>
171 0 : binVTypeT binVectorTypeCode<short unsigned int>()
172 : {
173 0 : return binVTypes::SUInt;
174 : }
175 :
176 : template <>
177 0 : binVTypeT binVectorTypeCode<long int>()
178 : {
179 0 : return binVTypes::LInt;
180 : }
181 :
182 : template <>
183 0 : binVTypeT binVectorTypeCode<long unsigned int>()
184 : {
185 0 : return binVTypes::LUInt;
186 : }
187 :
188 : template <>
189 0 : binVTypeT binVectorTypeCode<long long int>()
190 : {
191 0 : return binVTypes::LLInt;
192 : }
193 :
194 : template <>
195 0 : binVTypeT binVectorTypeCode<long long unsigned int>()
196 : {
197 0 : return binVTypes::LLUInt;
198 : }
199 :
200 : template <>
201 0 : binVTypeT binVectorTypeCode<float>()
202 : {
203 0 : return binVTypes::Float;
204 : }
205 :
206 : template <>
207 1 : binVTypeT binVectorTypeCode<double>()
208 : {
209 1 : return binVTypes::Double;
210 : }
211 :
212 : template <>
213 0 : binVTypeT binVectorTypeCode<long double>()
214 : {
215 0 : return binVTypes::LDouble;
216 : }
217 :
218 : template <>
219 0 : binVTypeT binVectorTypeCode<std::complex<float>>()
220 : {
221 0 : return binVTypes::CFloat;
222 : }
223 :
224 : template <>
225 0 : binVTypeT binVectorTypeCode<std::complex<double>>()
226 : {
227 0 : return binVTypes::CDouble;
228 : }
229 :
230 : /// Read a BinVector file from disk.
231 : /**
232 : * \note dataT must match what was stored in the file.
233 : *
234 : * \returns 0 on success.
235 : * \returns -1 if an error occurs.
236 : *
237 : * \ingroup binvector
238 : */
239 : template <typename dataT>
240 0 : int readBinVector( std::vector<dataT> &vec, ///< [out] vec is a vector which will be resized and populated.
241 : const std::string &fname ///< [in] fname is the name (full-path) of the file.
242 : )
243 : {
244 : FILE *fin;
245 : binVTypeT typecode;
246 : binVSizeT sz;
247 : size_t nrd;
248 :
249 0 : fin = fopen( fname.c_str(), "r" );
250 0 : if( fin == 0 )
251 : {
252 0 : internal::mxlib_error_report( errno2error_t( errno ), "Error from fopen [" + fname + "]" );
253 0 : return -1;
254 : }
255 :
256 0 : errno = 0;
257 0 : nrd = fread( &typecode, sizeof( binVTypeT ), 1, fin );
258 :
259 0 : if( nrd != 1 )
260 : {
261 : // Have to handle case where EOF reached but no error.
262 0 : if( errno != 0 )
263 : {
264 0 : internal::mxlib_error_report( errno2error_t( errno ), "Error reading data size [" + fname + "]" );
265 : }
266 : else
267 : {
268 0 : internal::mxlib_error_report( error_t::filererr,
269 0 : "Error reading data size, did not read enough bytes. [" + fname + "]" );
270 : }
271 0 : fclose( fin );
272 0 : return -1;
273 : }
274 :
275 0 : if( typecode != binVectorTypeCode<dataT>() )
276 : {
277 0 : internal::mxlib_error_report( error_t::sizeerr,
278 0 : "Mismatch between type dataT and type in file [" + fname + "]" );
279 0 : fclose( fin );
280 0 : return -1;
281 : }
282 :
283 0 : errno = 0;
284 0 : nrd = fread( &sz, sizeof( binVSizeT ), 1, fin );
285 :
286 0 : if( nrd != 1 )
287 : {
288 : // Have to handle case where EOF reached but no error.
289 0 : if( errno != 0 )
290 : {
291 0 : internal::mxlib_error_report( errno2error_t( errno ), "Error reading vector size [" + fname + "]" );
292 : }
293 : else
294 : {
295 0 : internal::mxlib_error_report( error_t::filererr,
296 0 : "Error reading vector size, did not read enough bytes [" + fname + "]" );
297 : }
298 0 : fclose( fin );
299 0 : return -1;
300 : }
301 :
302 0 : vec.resize( sz );
303 :
304 0 : errno = 0;
305 0 : nrd = fread( vec.data(), sizeof( dataT ), sz, fin );
306 :
307 0 : if( nrd != sz )
308 : {
309 : // Have to handle case where EOF reached but no error.
310 0 : if( errno != 0 )
311 : {
312 0 : internal::mxlib_error_report( errno2error_t( errno ), "Error reading data [" + fname + "]" );
313 : }
314 : else
315 : {
316 0 : internal::mxlib_error_report( error_t::filererr, "Did not read enough data [" + fname + "]" );
317 : }
318 0 : fclose( fin );
319 0 : return -1;
320 : }
321 :
322 0 : fclose( fin );
323 :
324 0 : return 0;
325 : }
326 :
327 : /// Write a BinVector file to disk.
328 : /**
329 : *
330 : * \returns 0 on success.
331 : * \returns -1 if an error occurs.
332 : *
333 : * \ingroup binvector
334 : */
335 : template <typename dataT>
336 1 : int writeBinVector( const std::string &fname, ///< [in] fname is the name (full-path) of the file.
337 : std::vector<dataT> &vec ///< [in] vec is the vector which will be written to disk.
338 : )
339 : {
340 :
341 : FILE *fout;
342 : size_t nwr;
343 1 : binVTypeT typecode = binVectorTypeCode<dataT>();
344 1 : binVSizeT sz = vec.size();
345 :
346 1 : fout = fopen( fname.c_str(), "wb" );
347 1 : if( fout == 0 )
348 : {
349 0 : internal::mxlib_error_report( errno2error_t( errno ), "Error from fopen [" + fname + "]" );
350 0 : return -1;
351 : }
352 :
353 1 : nwr = fwrite( &typecode, sizeof( binVTypeT ), 1, fout );
354 1 : if( nwr != 1 )
355 : {
356 0 : internal::mxlib_error_report( errno2error_t( errno ), "Error writing typecode [" + fname + "]" );
357 0 : fclose( fout );
358 0 : return -1;
359 : }
360 :
361 1 : nwr = fwrite( &sz, sizeof( binVSizeT ), 1, fout );
362 1 : if( nwr != 1 )
363 : {
364 0 : internal::mxlib_error_report( errno2error_t( errno ), "Error writing vector size [" + fname + "]" );
365 0 : fclose( fout );
366 0 : return -1;
367 : }
368 :
369 1 : nwr = fwrite( vec.data(), sizeof( dataT ), vec.size(), fout );
370 1 : if( nwr != sz )
371 : {
372 0 : internal::mxlib_error_report( errno2error_t( errno ), "Error writing data [" + fname + "]" );
373 0 : fclose( fout );
374 0 : return -1;
375 : }
376 :
377 1 : fclose( fout );
378 :
379 1 : return 0;
380 : }
381 :
382 : } // namespace ioutils
383 : } // namespace mx
384 :
385 : #endif // binVector_hpp
|