26#ifndef __readColumns_hpp__
27#define __readColumns_hpp__
39#define MX_READCOL_MISSINGVALSTR "-99"
46#ifndef ioutils_readColumns_detail_hpp
47#define ioutils_readColumns_detail_hpp
48namespace readColumnsDetail
61using operationHookT = void ( * )( operation, std::ifstream & );
64inline void noOperationFailure( operation, std::ifstream & )
69inline operationHookT &operationHook()
71 static operationHookT hook = noOperationFailure;
79#ifdef MXLIBTEST_NAMESPACE
80namespace MXLIBTEST_NAMESPACE
84struct readColSpaceDelim
86 static constexpr char delim =
' ';
87 static constexpr char strDelim =
'"';
88 static constexpr char eol =
'\n';
89 static constexpr char comment =
'#';
90 static constexpr const char *missingValStr = MX_READCOL_MISSINGVALSTR;
93struct readColCommaDelim
95 static constexpr char delim =
',';
96 static constexpr char strdelim =
'"';
97 static constexpr char eol =
'\n';
98 static constexpr char comment =
'#';
99 static constexpr const char *missingValStr = MX_READCOL_MISSINGVALSTR;
102template <
class delimT,
class verboseT>
103error_t readcol( [[maybe_unused]]
const char *sin, [[maybe_unused]]
int sz, [[maybe_unused]]
int &colno )
105 return error_t::noerror;
108template <
class delimT,
class verboseT,
typename arrT,
typename... arrTs>
109error_t readcol(
const char *sin,
int sz,
int &colno, arrT &array, arrTs &...arrays )
116 int l = strlen( sin );
120 return error_t::noerror;
124 while( i < l && std::isspace(
static_cast<unsigned char>( sin[i] ) ) && sin[i] != delimT::eol )
135 array.push_back( stoT<typename arrT::value_type>(
"", &errc ) );
139 return internal::mxlib_error_report<verboseT>( errc, std::format(
"processing column {}", colno ) );
145 std::stringstream sinstr( sin );
147 std::getline( sinstr, str, delimT::delim );
150 if( !str.empty() && str[str.size() - 1] == delimT::eol )
152 str.erase( str.size() - 1 );
156 if( str.size() == 0 )
158 array.push_back( stoT<typename arrT::value_type>( MX_READCOL_MISSINGVALSTR, &errc ) );
162 array.push_back( stoT<typename arrT::value_type>( str, &errc ) );
167 return internal::mxlib_error_report<verboseT>( errc, std::format(
"processing column {}", colno ) );
170 sin += ( str.size() + 1 ) *
sizeof( char );
171 sz -= ( str.size() + 1 ) *
sizeof( char );
173 catch(
const std::invalid_argument &e )
176 return internal::mxlib_error_report<verboseT>( error_t::std_invalid_argument,
177 std::format(
"processing column {}: {}", colno, e.what() ) );
179 catch(
const std::out_of_range &e )
182 return internal::mxlib_error_report<verboseT>( error_t::std_out_of_range,
183 std::format(
"processing column {}: {}", colno, e.what() ) );
185 catch(
const std::bad_alloc &e )
189 #if defined( MXLIB_CATCH_ALL_EXCEPTIONS )
190 return internal::mxlib_error_report<verboseT>( error_t::std_bad_alloc,
191 std::format(
"processing column {}: {}", colno, e.what() ) );
194 std::format(
"processing column {}: {}", colno, e.what() ) ));
198 catch(
const std::exception &e )
201 #if defined( MXLIB_CATCH_ALL_EXCEPTIONS ) || defined( MXLIB_CATCH_NONALLOC_EXCEPTIONS )
202 return internal::mxlib_error_report<verboseT>( error_t::std_exception,
203 std::format(
"processing column {}: {}", colno, e.what() ) );
207 std::format(
"processing column {}: {}", colno, e.what() ) ));
215 #if defined( MXLIB_CATCH_ALL_EXCEPTIONS ) || defined( MXLIB_CATCH_NONALLOC_EXCEPTIONS )
216 return internal::mxlib_error_report<verboseT>( error_t::exception,
217 std::format(
"processing column {}", colno) );
221 std::format(
"processing column {}", colno) ));
227 return readcol<delimT, verboseT>( sin, sz, colno, arrays... );
259template <
class delimT = readColSpaceDelim,
class verboseT = verbose::d,
typename... arrTs>
270 readColumnsDetail::operationHook()( readColumnsDetail::operation::afterOpen, fin );
296 std::getline( fin, line, delimT::eol );
297 readColumnsDetail::operationHook()( readColumnsDetail::operation::afterReadLine, fin );
299 catch(
const std::bad_alloc &e )
303 #if defined( MXLIB_CATCH_ALL_EXCEPTIONS )
305 std::format(
"Reading from {} at line {}: {}.",
306 fname, lineno, e.what() ) );
310 std::format(
"Reading from {} at line {}: {}.",
311 fname, lineno, e.what() ) ) );
315 catch(
const std::exception &e )
319 #if defined( MXLIB_CATCH_ALL_EXCEPTIONS ) || defined(MXLIB_CATCH_NONALLOC_EXCEPTIONS)
322 std::format(
"Reading from {} at line {}: {}.",
328 std::format(
"Reading from {} at line {}: {}.",
329 fname, lineno, e.what() ) ) );
337 #if defined( MXLIB_CATCH_ALL_EXCEPTIONS ) || defined(MXLIB_CATCH_NONALLOC_EXCEPTIONS)
340 std::format(
"Reading from {} at line {}",
345 std::format(
"Reading from {} at line {}",
356 if( line.size() == 0 )
363 bool nonspace =
false;
364 while( i < line.size() && line[i] != delimT::comment )
366 if( !nonspace && !std::isspace(
static_cast<unsigned char>( line[i] ) ) )
374 if( i == 0 || !nonspace )
379 if( i < line.size() )
381 line.erase( line.begin() + i, line.end() );
385 error_t errc = readcol<delimT, verboseT>( line.c_str(), line.size(), colno, arrays... );
391 std::format(
"Reading from {} at line {} column {}", fname, lineno + 1, colno + 1 ) );
414 readColumnsDetail::operationHook()( readColumnsDetail::operation::afterClose, fin );
449 template <
typename T>
450 void push_back(
const T &arg )
456#ifdef MXLIBTEST_NAMESPACE
Augments an exception with the source file and line.
error_t readColumns(const std::string &fname, arrTs &...arrays)
Read in columns from a text file.
error_t
The mxlib error codes.
static constexpr error_t errno2error_t(const int &err)
Convert an errno code to error_t.
@ noerror
No error has occurred.
@ std_exception
An exception was thrown.
@ filererr
An error occurred while reading from a file.
@ exception
An exception was thrown.
@ std_bad_alloc
A bad allocation exception was thrown.
@ filecerr
An error occurred while closing a file.
@ fileoerr
An error occurred while opening a file.
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.
Declarations of some libarary wide utilities.
Utilities for working with strings.
A dummy class to allow mx::readColumns to skip a column(s) in a file without requiring memory allocat...
std::string value_type
value_type is defined as std::string so that no conversions take place.