mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
binVector.hpp
Go to the documentation of this file.
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
35namespace mx
36{
37namespace 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 */
56typedef uint64_t binVSizeT;
57
58/// The type of binVector type codes.
59/** \ingroup binvector
60 */
61typedef uint64_t binVTypeT;
62
63/// Namespace fo the bin-vector type-codes.
64/** \ingroup binvector
65 */
66namespace binVTypes
67{
68
69/// The pre-defined type codes for binVector.
70/** \ingroup binvector
71 */
72enum : 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 */
107template <typename dataT>
109
110template <>
111binVTypeT binVectorTypeCode<bool>()
112{
113 return binVTypes::Bool;
114}
115
116template <>
117binVTypeT binVectorTypeCode<signed char>()
118{
119 return binVTypes::SChar;
120}
121
122template <>
123binVTypeT binVectorTypeCode<unsigned char>()
124{
125 return binVTypes::UChar;
126}
127
128template <>
129binVTypeT binVectorTypeCode<char>()
130{
131 return binVTypes::Char;
132}
133
134template <>
135binVTypeT binVectorTypeCode<wchar_t>()
136{
137 return binVTypes::WChar;
138}
139
140template <>
141binVTypeT binVectorTypeCode<char16_t>()
142{
143 return binVTypes::Char16;
144}
145
146template <>
147binVTypeT binVectorTypeCode<char32_t>()
148{
149 return binVTypes::Char32;
150}
151
152template <>
153binVTypeT binVectorTypeCode<int>()
154{
155 return binVTypes::Int;
156}
157
158template <>
159binVTypeT binVectorTypeCode<unsigned int>()
160{
161 return binVTypes::UInt;
162}
163
164template <>
165binVTypeT binVectorTypeCode<short int>()
166{
167 return binVTypes::SInt;
168}
169
170template <>
171binVTypeT binVectorTypeCode<short unsigned int>()
172{
173 return binVTypes::SUInt;
174}
175
176template <>
177binVTypeT binVectorTypeCode<long int>()
178{
179 return binVTypes::LInt;
180}
181
182template <>
183binVTypeT binVectorTypeCode<long unsigned int>()
184{
185 return binVTypes::LUInt;
186}
187
188template <>
189binVTypeT binVectorTypeCode<long long int>()
190{
191 return binVTypes::LLInt;
192}
193
194template <>
195binVTypeT binVectorTypeCode<long long unsigned int>()
196{
197 return binVTypes::LLUInt;
198}
199
200template <>
201binVTypeT binVectorTypeCode<float>()
202{
203 return binVTypes::Float;
204}
205
206template <>
207binVTypeT binVectorTypeCode<double>()
208{
209 return binVTypes::Double;
210}
211
212template <>
213binVTypeT binVectorTypeCode<long double>()
214{
215 return binVTypes::LDouble;
216}
217
218template <>
219binVTypeT binVectorTypeCode<std::complex<float>>()
220{
221 return binVTypes::CFloat;
222}
223
224template <>
225binVTypeT binVectorTypeCode<std::complex<double>>()
226{
227 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 */
239template <typename dataT>
240int 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 fin = fopen( fname.c_str(), "r" );
250 if( fin == 0 )
251 {
252 internal::mxlib_error_report( errno2error_t( errno ), "Error from fopen [" + fname + "]" );
253 return -1;
254 }
255
256 errno = 0;
257 nrd = fread( &typecode, sizeof( binVTypeT ), 1, fin );
258
259 if( nrd != 1 )
260 {
261 // Have to handle case where EOF reached but no error.
262 if( errno != 0 )
263 {
264 internal::mxlib_error_report( errno2error_t( errno ), "Error reading data size [" + fname + "]" );
265 }
266 else
267 {
269 "Error reading data size, did not read enough bytes. [" + fname + "]" );
270 }
271 fclose( fin );
272 return -1;
273 }
274
275 if( typecode != binVectorTypeCode<dataT>() )
276 {
278 "Mismatch between type dataT and type in file [" + fname + "]" );
279 fclose( fin );
280 return -1;
281 }
282
283 errno = 0;
284 nrd = fread( &sz, sizeof( binVSizeT ), 1, fin );
285
286 if( nrd != 1 )
287 {
288 // Have to handle case where EOF reached but no error.
289 if( errno != 0 )
290 {
291 internal::mxlib_error_report( errno2error_t( errno ), "Error reading vector size [" + fname + "]" );
292 }
293 else
294 {
296 "Error reading vector size, did not read enough bytes [" + fname + "]" );
297 }
298 fclose( fin );
299 return -1;
300 }
301
302 vec.resize( sz );
303
304 errno = 0;
305 nrd = fread( vec.data(), sizeof( dataT ), sz, fin );
306
307 if( nrd != sz )
308 {
309 // Have to handle case where EOF reached but no error.
310 if( errno != 0 )
311 {
312 internal::mxlib_error_report( errno2error_t( errno ), "Error reading data [" + fname + "]" );
313 }
314 else
315 {
316 internal::mxlib_error_report( error_t::filererr, "Did not read enough data [" + fname + "]" );
317 }
318 fclose( fin );
319 return -1;
320 }
321
322 fclose( fin );
323
324 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 */
335template <typename dataT>
336int 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 binVTypeT typecode = binVectorTypeCode<dataT>();
344 binVSizeT sz = vec.size();
345
346 fout = fopen( fname.c_str(), "wb" );
347 if( fout == 0 )
348 {
349 internal::mxlib_error_report( errno2error_t( errno ), "Error from fopen [" + fname + "]" );
350 return -1;
351 }
352
353 nwr = fwrite( &typecode, sizeof( binVTypeT ), 1, fout );
354 if( nwr != 1 )
355 {
356 internal::mxlib_error_report( errno2error_t( errno ), "Error writing typecode [" + fname + "]" );
357 fclose( fout );
358 return -1;
359 }
360
361 nwr = fwrite( &sz, sizeof( binVSizeT ), 1, fout );
362 if( nwr != 1 )
363 {
364 internal::mxlib_error_report( errno2error_t( errno ), "Error writing vector size [" + fname + "]" );
365 fclose( fout );
366 return -1;
367 }
368
369 nwr = fwrite( vec.data(), sizeof( dataT ), vec.size(), fout );
370 if( nwr != sz )
371 {
372 internal::mxlib_error_report( errno2error_t( errno ), "Error writing data [" + fname + "]" );
373 fclose( fout );
374 return -1;
375 }
376
377 fclose( fout );
378
379 return 0;
380}
381
382} // namespace ioutils
383} // namespace mx
384
385#endif // binVector_hpp
uint64_t binVSizeT
The type used for binVector sizes.
Definition binVector.hpp:56
int writeBinVector(const std::string &fname, std::vector< dataT > &vec)
Write a BinVector file to disk.
binVTypeT binVectorTypeCode()
Get the integer type code corresponding to the type.
uint64_t binVTypeT
The type of binVector type codes.
Definition binVector.hpp:61
int readBinVector(std::vector< dataT > &vec, const std::string &fname)
Read a BinVector file from disk.
static constexpr error_t errno2error_t(const int &err)
Convert an errno code to error_t.
Definition error_t.hpp:2006
@ filererr
An error occurred while reading from a file.
@ sizeerr
A size was invalid or calculated incorrectly.
error_t mxlib_error_report(const error_t &code, const std::string &expl, const std::source_location &loc=std::source_location::current())
Print a report to stderr given an mxlib error_t code and explanation and return the code.
Definition error.hpp:331
The mxlib c++ namespace.
Definition mxlib.hpp:37