42 #ifndef CSV_IO_NO_THREAD 45 #include <condition_variable> 58 struct base : std::exception{
59 virtual void format_error_message()
const = 0;
61 const char*what()const noexcept
override{
62 format_error_message();
63 return error_message_buffer;
66 mutable char error_message_buffer[512];
69 const int max_file_name_length = 255;
71 struct with_file_name{
73 std::memset(file_name, 0,
sizeof(file_name));
76 void set_file_name(
const char*file_name){
77 if(file_name !=
nullptr){
78 strncpy(this->file_name, file_name,
sizeof(this->file_name));
79 this->file_name[
sizeof(this->file_name)-1] =
'\0';
81 this->file_name[0] =
'\0';
85 char file_name[max_file_name_length+1];
88 struct with_file_line{
93 void set_file_line(
int file_line){
94 this->file_line = file_line;
105 void set_errno(
int errno_value){
106 this->errno_value = errno_value;
112 struct can_not_open_file :
116 void format_error_message()
const override{
118 std::snprintf(error_message_buffer,
sizeof(error_message_buffer),
119 "Can not open file \"%s\" because \"%s\"." 120 , file_name, std::strerror(errno_value));
122 std::snprintf(error_message_buffer,
sizeof(error_message_buffer),
123 "Can not open file \"%s\"." 128 struct line_length_limit_exceeded :
132 void format_error_message()
const override{
133 std::snprintf(error_message_buffer,
sizeof(error_message_buffer),
134 "Line number %d in file \"%s\" exceeds the maximum length of 2^24-1." 135 , file_line, file_name);
140 class ByteSourceBase{
142 virtual int read(
char*buffer,
int size)=0;
143 virtual ~ByteSourceBase(){}
148 class OwningStdIOByteSourceBase :
public ByteSourceBase{
150 explicit OwningStdIOByteSourceBase(FILE*file):file(file){
152 std::setvbuf(file, 0, _IONBF, 0);
155 int read(
char*buffer,
int size){
156 return std::fread(buffer, 1, size, file);
159 ~OwningStdIOByteSourceBase(){
167 class NonOwningIStreamByteSource :
public ByteSourceBase{
169 explicit NonOwningIStreamByteSource(std::istream&in):in(in){}
171 int read(
char*buffer,
int size){
172 in.read(buffer, size);
176 ~NonOwningIStreamByteSource(){}
182 class NonOwningStringByteSource :
public ByteSourceBase{
184 NonOwningStringByteSource(
const char*str,
long long size):str(str), remaining_byte_count(size){}
186 int read(
char*buffer,
int desired_byte_count){
187 int to_copy_byte_count = desired_byte_count;
188 if(remaining_byte_count < to_copy_byte_count)
189 to_copy_byte_count = remaining_byte_count;
190 std::memcpy(buffer, str, to_copy_byte_count);
191 remaining_byte_count -= to_copy_byte_count;
192 str += to_copy_byte_count;
193 return to_copy_byte_count;
196 ~NonOwningStringByteSource(){}
200 long long remaining_byte_count;
203 #ifndef CSV_IO_NO_THREAD 204 class AsynchronousReader{
206 void init(std::unique_ptr<ByteSourceBase>arg_byte_source){
207 std::unique_lock<std::mutex>guard(lock);
208 byte_source = std::move(arg_byte_source);
209 desired_byte_count = -1;
210 termination_requested =
false;
211 worker = std::thread(
213 std::unique_lock<std::mutex>guard(lock);
216 read_requested_condition.wait(
219 return desired_byte_count != -1 || termination_requested;
222 if(termination_requested)
225 read_byte_count = byte_source->read(buffer, desired_byte_count);
226 desired_byte_count = -1;
227 if(read_byte_count == 0)
229 read_finished_condition.notify_one();
232 read_error = std::current_exception();
234 read_finished_condition.notify_one();
239 bool is_valid()
const{
240 return byte_source !=
nullptr;
243 void start_read(
char*arg_buffer,
int arg_desired_byte_count){
244 std::unique_lock<std::mutex>guard(lock);
246 desired_byte_count = arg_desired_byte_count;
247 read_byte_count = -1;
248 read_requested_condition.notify_one();
252 std::unique_lock<std::mutex>guard(lock);
253 read_finished_condition.wait(
256 return read_byte_count != -1 || read_error;
260 std::rethrow_exception(read_error);
262 return read_byte_count;
265 ~AsynchronousReader(){
266 if(byte_source !=
nullptr){
268 std::unique_lock<std::mutex>guard(lock);
269 termination_requested =
true;
271 read_requested_condition.notify_one();
277 std::unique_ptr<ByteSourceBase>byte_source;
281 bool termination_requested;
282 std::exception_ptr read_error;
284 int desired_byte_count;
288 std::condition_variable read_finished_condition;
289 std::condition_variable read_requested_condition;
293 class SynchronousReader{
295 void init(std::unique_ptr<ByteSourceBase>arg_byte_source){
296 byte_source = std::move(arg_byte_source);
299 bool is_valid()
const{
300 return byte_source !=
nullptr;
303 void start_read(
char*arg_buffer,
int arg_desired_byte_count){
305 desired_byte_count = arg_desired_byte_count;
309 return byte_source->read(buffer, desired_byte_count);
312 std::unique_ptr<ByteSourceBase>byte_source;
314 int desired_byte_count;
320 static const int block_len = 1<<20;
321 std::unique_ptr<char[]>buffer;
322 #ifdef CSV_IO_NO_THREAD 323 detail::SynchronousReader reader;
325 detail::AsynchronousReader reader;
330 char file_name[error::max_file_name_length+1];
333 static std::unique_ptr<ByteSourceBase> open_file(
const char*file_name){
336 FILE*file = std::fopen(file_name,
"rb");
339 error::can_not_open_file err;
341 err.set_file_name(file_name);
344 return std::unique_ptr<ByteSourceBase>(
new detail::OwningStdIOByteSourceBase(file));
347 void init(std::unique_ptr<ByteSourceBase>byte_source){
350 buffer = std::unique_ptr<char[]>(
new char[3*block_len]);
352 data_end = byte_source->read(buffer.get(), 2*block_len);
355 if(data_end >= 3 && buffer[0] ==
'\xEF' && buffer[1] ==
'\xBB' && buffer[2] ==
'\xBF')
358 if(data_end == 2*block_len){
359 reader.init(std::move(byte_source));
360 reader.start_read(buffer.get() + 2*block_len, block_len);
365 LineReader() =
delete;
366 LineReader(
const LineReader&) =
delete;
367 LineReader&operator=(
const LineReader&) =
delete;
369 explicit LineReader(
const char*file_name){
370 set_file_name(file_name);
371 init(open_file(file_name));
374 explicit LineReader(
const std::string&file_name){
375 set_file_name(file_name.c_str());
376 init(open_file(file_name.c_str()));
379 LineReader(
const char*file_name, std::unique_ptr<ByteSourceBase>byte_source){
380 set_file_name(file_name);
381 init(std::move(byte_source));
384 LineReader(
const std::string&file_name, std::unique_ptr<ByteSourceBase>byte_source){
385 set_file_name(file_name.c_str());
386 init(std::move(byte_source));
389 LineReader(
const char*file_name,
const char*data_begin,
const char*data_end){
390 set_file_name(file_name);
391 init(std::unique_ptr<ByteSourceBase>(
new detail::NonOwningStringByteSource(data_begin, data_end-data_begin)));
394 LineReader(
const std::string&file_name,
const char*data_begin,
const char*data_end){
395 set_file_name(file_name.c_str());
396 init(std::unique_ptr<ByteSourceBase>(
new detail::NonOwningStringByteSource(data_begin, data_end-data_begin)));
399 LineReader(
const char*file_name, FILE*file){
400 set_file_name(file_name);
401 init(std::unique_ptr<ByteSourceBase>(
new detail::OwningStdIOByteSourceBase(file)));
404 LineReader(
const std::string&file_name, FILE*file){
405 set_file_name(file_name.c_str());
406 init(std::unique_ptr<ByteSourceBase>(
new detail::OwningStdIOByteSourceBase(file)));
409 LineReader(
const char*file_name, std::istream&in){
410 set_file_name(file_name);
411 init(std::unique_ptr<ByteSourceBase>(
new detail::NonOwningIStreamByteSource(in)));
414 LineReader(
const std::string&file_name, std::istream&in){
415 set_file_name(file_name.c_str());
416 init(std::unique_ptr<ByteSourceBase>(
new detail::NonOwningIStreamByteSource(in)));
419 void set_file_name(
const std::string&file_name){
420 set_file_name(file_name.c_str());
423 void set_file_name(
const char*file_name){
424 if(file_name !=
nullptr){
425 strncpy(this->file_name, file_name,
sizeof(this->file_name));
426 this->file_name[
sizeof(this->file_name)-1] =
'\0';
428 this->file_name[0] =
'\0';
432 const char*get_truncated_file_name()
const{
436 void set_file_line(
unsigned file_line){
437 this->file_line = file_line;
440 unsigned get_file_line()
const{
445 if(data_begin == data_end)
450 assert(data_begin < data_end);
451 assert(data_end <= block_len*2);
453 if(data_begin >= block_len){
454 std::memcpy(buffer.get(), buffer.get()+block_len, block_len);
455 data_begin -= block_len;
456 data_end -= block_len;
457 if(reader.is_valid())
459 data_end += reader.finish_read();
460 std::memcpy(buffer.get()+block_len, buffer.get()+2*block_len, block_len);
461 reader.start_read(buffer.get() + 2*block_len, block_len);
465 int line_end = data_begin;
466 while(buffer[line_end] !=
'\n' && line_end != data_end){
470 if(line_end - data_begin + 1 > block_len){
471 error::line_length_limit_exceeded err;
472 err.set_file_name(file_name);
473 err.set_file_line(file_line);
477 if(buffer[line_end] ==
'\n' && line_end != data_end){
478 buffer[line_end] =
'\0';
483 buffer[line_end] =
'\0';
487 if(line_end != data_begin && buffer[line_end-1] ==
'\r')
488 buffer[line_end-1] =
'\0';
490 char*ret = buffer.get() + data_begin;
491 data_begin = line_end+1;
502 const int max_column_name_length = 63;
503 struct with_column_name{
505 std::memset(column_name, 0, max_column_name_length+1);
508 void set_column_name(
const char*column_name){
509 if(column_name !=
nullptr){
510 std::strncpy(this->column_name, column_name, max_column_name_length);
511 this->column_name[max_column_name_length] =
'\0';
513 this->column_name[0] =
'\0';
517 char column_name[max_column_name_length+1];
521 const int max_column_content_length = 63;
523 struct with_column_content{
524 with_column_content(){
525 std::memset(column_content, 0, max_column_content_length+1);
528 void set_column_content(
const char*column_content){
529 if(column_content !=
nullptr){
530 std::strncpy(this->column_content, column_content, max_column_content_length);
531 this->column_content[max_column_content_length] =
'\0';
533 this->column_content[0] =
'\0';
537 char column_content[max_column_content_length+1];
541 struct extra_column_in_header :
545 void format_error_message()
const override{
546 std::snprintf(error_message_buffer,
sizeof(error_message_buffer),
547 R
"(Extra column "%s" in header of file "%s".)" 548 , column_name, file_name); 552 struct missing_column_in_header :
556 void format_error_message()
const override{
557 std::snprintf(error_message_buffer,
sizeof(error_message_buffer),
558 R
"(Missing column "%s" in header of file "%s".)" 559 , column_name, file_name); 563 struct duplicated_column_in_header :
567 void format_error_message()
const override{
568 std::snprintf(error_message_buffer,
sizeof(error_message_buffer),
569 R
"(Duplicated column "%s" in header of file "%s".)" 570 , column_name, file_name); 574 struct header_missing :
577 void format_error_message()
const override{
578 std::snprintf(error_message_buffer,
sizeof(error_message_buffer),
579 "Header missing in file \"%s\"." 584 struct too_few_columns :
588 void format_error_message()
const override{
589 std::snprintf(error_message_buffer,
sizeof(error_message_buffer),
590 "Too few columns in line %d in file \"%s\"." 591 , file_line, file_name);
595 struct too_many_columns :
599 void format_error_message()
const override{
600 std::snprintf(error_message_buffer,
sizeof(error_message_buffer),
601 "Too many columns in line %d in file \"%s\"." 602 , file_line, file_name);
606 struct escaped_string_not_closed :
610 void format_error_message()
const override{
611 std::snprintf(error_message_buffer,
sizeof(error_message_buffer),
612 "Escaped string was not closed in line %d in file \"%s\"." 613 , file_line, file_name);
617 struct integer_must_be_positive :
623 void format_error_message()
const override{
624 std::snprintf(error_message_buffer,
sizeof(error_message_buffer),
625 R
"(The integer "%s" must be positive or 0 in column "%s" in file "%s" in line "%d".)" 626 , column_content, column_name, file_name, file_line); 636 void format_error_message()
const override{
637 std::snprintf(error_message_buffer,
sizeof(error_message_buffer),
638 R
"(The integer "%s" contains an invalid digit in column "%s" in file "%s" in line "%d".)" 639 , column_content, column_name, file_name, file_line); 643 struct integer_overflow :
649 void format_error_message()
const override{
650 std::snprintf(error_message_buffer,
sizeof(error_message_buffer),
651 R
"(The integer "%s" overflows in column "%s" in file "%s" in line "%d".)" 652 , column_content, column_name, file_name, file_line); 656 struct integer_underflow :
662 void format_error_message()
const override{
663 std::snprintf(error_message_buffer,
sizeof(error_message_buffer),
664 R
"(The integer "%s" underflows in column "%s" in file "%s" in line "%d".)" 665 , column_content, column_name, file_name, file_line); 669 struct invalid_single_character :
675 void format_error_message()
const override{
676 std::snprintf(error_message_buffer,
sizeof(error_message_buffer),
677 R
"(The content "%s" of column "%s" in file "%s" in line "%d" is not a single character.)" 678 , column_content, column_name, file_name, file_line); 683 using ignore_column =
unsigned int;
684 static const ignore_column ignore_no_column = 0;
685 static const ignore_column ignore_extra_column = 1;
686 static const ignore_column ignore_missing_column = 2;
688 template<
char ... trim_char_list>
691 constexpr
static bool is_trim_char(
char){
695 template<
class ...OtherTrimChars>
696 constexpr
static bool is_trim_char(
char c,
char trim_char, OtherTrimChars...other_trim_chars){
697 return c == trim_char || is_trim_char(c, other_trim_chars...);
701 static void trim(
char*&str_begin,
char*&str_end){
702 while(str_begin != str_end && is_trim_char(*str_begin, trim_char_list...))
704 while(str_begin != str_end && is_trim_char(*(str_end-1), trim_char_list...))
712 static bool is_comment(
const char*){
717 template<
char ... comment_start_char_list>
718 struct single_line_comment{
720 constexpr
static bool is_comment_start_char(
char){
724 template<
class ...OtherCommentStartChars>
725 constexpr
static bool is_comment_start_char(
char c,
char comment_start_char, OtherCommentStartChars...other_comment_start_chars){
726 return c == comment_start_char || is_comment_start_char(c, other_comment_start_chars...);
731 static bool is_comment(
const char*line){
732 return is_comment_start_char(*line, comment_start_char_list...);
736 struct empty_line_comment{
737 static bool is_comment(
const char*line){
740 while(*line ==
' ' || *line ==
'\t'){
749 template<
char ... comment_start_char_list>
750 struct single_and_empty_line_comment{
751 static bool is_comment(
const char*line){
752 return single_line_comment<comment_start_char_list...>::is_comment(line) || empty_line_comment::is_comment(line);
757 struct no_quote_escape{
758 static const char*find_next_column_end(
const char*col_begin){
759 while(*col_begin != sep && *col_begin !=
'\0')
764 static void unescape(
char*&,
char*&){
769 template<
char sep,
char quote>
770 struct double_quote_escape{
771 static const char*find_next_column_end(
const char*col_begin){
772 while(*col_begin != sep && *col_begin !=
'\0')
773 if(*col_begin != quote)
778 while(*col_begin != quote){
779 if(*col_begin ==
'\0')
780 throw error::escaped_string_not_closed();
784 }
while(*col_begin == quote);
789 static void unescape(
char*&col_begin,
char*&col_end){
790 if(col_end - col_begin >= 2){
791 if(*col_begin == quote && *(col_end-1) == quote){
794 char*out = col_begin;
795 for(
char*in = col_begin; in!=col_end; ++in){
796 if(*in == quote && (in+1) != col_end && *(in+1) == quote){
810 struct throw_on_overflow{
812 static void on_overflow(T&){
813 throw error::integer_overflow();
817 static void on_underflow(T&){
818 throw error::integer_underflow();
822 struct ignore_overflow{
824 static void on_overflow(T&){}
827 static void on_underflow(T&){}
830 struct set_to_max_on_overflow{
832 static void on_overflow(T&x){
833 x = std::numeric_limits<T>::max();
837 static void on_underflow(T&x){
838 x = std::numeric_limits<T>::min();
844 template<
class quote_policy>
845 void chop_next_column(
846 char*&line,
char*&col_begin,
char*&col_end
848 assert(line !=
nullptr);
852 col_end = col_begin + (quote_policy::find_next_column_end(col_begin) - col_begin);
854 if(*col_end ==
'\0'){
862 template<
class trim_policy,
class quote_policy>
866 const std::vector<int>&col_order
868 for (
int i : col_order) {
870 throw ::io::error::too_few_columns();
871 char*col_begin, *col_end;
872 chop_next_column<quote_policy>(line, col_begin, col_end);
875 trim_policy::trim(col_begin, col_end);
876 quote_policy::unescape(col_begin, col_end);
878 sorted_col[i] = col_begin;
882 throw ::io::error::too_many_columns();
885 template<
unsigned column_count,
class trim_policy,
class quote_policy>
886 void parse_header_line(
888 std::vector<int>&col_order,
889 const std::string*col_name,
890 ignore_column ignore_policy
894 bool found[column_count];
895 std::fill(found, found + column_count,
false);
897 char*col_begin,*col_end;
898 chop_next_column<quote_policy>(line, col_begin, col_end);
900 trim_policy::trim(col_begin, col_end);
901 quote_policy::unescape(col_begin, col_end);
903 for(
unsigned i=0; i<column_count; ++i)
904 if(col_begin == col_name[i]){
906 error::duplicated_column_in_header err;
907 err.set_column_name(col_begin);
911 col_order.push_back(i);
916 if(ignore_policy & ::io::ignore_extra_column)
917 col_order.push_back(-1);
919 error::extra_column_in_header err;
920 err.set_column_name(col_begin);
925 if(!(ignore_policy & ::io::ignore_missing_column)){
926 for(
unsigned i=0; i<column_count; ++i){
928 error::missing_column_in_header err;
929 err.set_column_name(col_name[i].c_str());
936 template<
class overflow_policy>
937 void parse(
char*col,
char &x){
939 throw error::invalid_single_character();
943 throw error::invalid_single_character();
946 template<
class overflow_policy>
947 void parse(
char*col, std::string&x){
951 template<
class overflow_policy>
952 void parse(
char*col,
const char*&x){
956 template<
class overflow_policy>
957 void parse(
char*col,
char*&x){
961 template<
class overflow_policy,
class T>
962 void parse_unsigned_integer(
const char*col, T&x){
965 if(
'0' <= *col && *col <=
'9'){
967 if(x > (std::numeric_limits<T>::max()-y)/10){
968 overflow_policy::on_overflow(x);
973 throw error::no_digit();
978 template<
class overflow_policy>
void parse(
char*col,
unsigned char &x)
979 {parse_unsigned_integer<overflow_policy>(col, x);}
980 template<
class overflow_policy>
void parse(
char*col,
unsigned short &x)
981 {parse_unsigned_integer<overflow_policy>(col, x);}
982 template<
class overflow_policy>
void parse(
char*col,
unsigned int &x)
983 {parse_unsigned_integer<overflow_policy>(col, x);}
984 template<
class overflow_policy>
void parse(
char*col,
unsigned long &x)
985 {parse_unsigned_integer<overflow_policy>(col, x);}
986 template<
class overflow_policy>
void parse(
char*col,
unsigned long long &x)
987 {parse_unsigned_integer<overflow_policy>(col, x);}
989 template<
class overflow_policy,
class T>
990 void parse_signed_integer(
const char*col, T&x){
996 if(
'0' <= *col && *col <=
'9'){
998 if(x < (std::numeric_limits<T>::min()+y)/10){
999 overflow_policy::on_underflow(x);
1004 throw error::no_digit();
1008 }
else if(*col ==
'+')
1010 parse_unsigned_integer<overflow_policy>(col, x);
1013 template<
class overflow_policy>
void parse(
char*col,
signed char &x)
1014 {parse_signed_integer<overflow_policy>(col, x);}
1015 template<
class overflow_policy>
void parse(
char*col,
signed short &x)
1016 {parse_signed_integer<overflow_policy>(col, x);}
1017 template<
class overflow_policy>
void parse(
char*col,
signed int &x)
1018 {parse_signed_integer<overflow_policy>(col, x);}
1019 template<
class overflow_policy>
void parse(
char*col,
signed long &x)
1020 {parse_signed_integer<overflow_policy>(col, x);}
1021 template<
class overflow_policy>
void parse(
char*col,
signed long long &x)
1022 {parse_signed_integer<overflow_policy>(col, x);}
1025 void parse_float(
const char*col, T&x){
1026 bool is_neg =
false;
1030 }
else if(*col ==
'+')
1034 while(
'0' <= *col && *col <=
'9'){
1041 if(*col ==
'.'|| *col ==
','){
1044 while(
'0' <= *col && *col <=
'9'){
1052 if(*col ==
'e' || *col ==
'E'){
1056 parse_signed_integer<set_to_max_on_overflow>(col, e);
1080 throw error::no_digit();
1087 template<
class overflow_policy>
void parse(
char*col,
float&x) { parse_float(col, x); }
1088 template<
class overflow_policy>
void parse(
char*col,
double&x) { parse_float(col, x); }
1089 template<
class overflow_policy>
void parse(
char*col,
long double&x) { parse_float(col, x); }
1091 template<
class overflow_policy,
class T>
1092 void parse(
char*col, T&x){
1099 static_assert(
sizeof(T)!=
sizeof(T),
1100 "Can not parse this type. Only buildin integrals, floats, char, char*, const char* and std::string are supported");
1105 template<
unsigned column_count,
1106 class trim_policy = trim_chars<' ', '\t'>,
1107 class quote_policy = no_quote_escape<','>,
1108 class overflow_policy = throw_on_overflow,
1109 class comment_policy = no_comment
1115 char*row[column_count];
1116 std::string column_names[column_count];
1118 std::vector<int>col_order;
1120 template<
class ...ColNames>
1121 void set_column_names(std::string s, ColNames...cols){
1122 column_names[column_count-
sizeof...(ColNames)-1] = std::move(s);
1123 set_column_names(std::forward<ColNames>(cols)...);
1126 void set_column_names(){}
1130 CSVReader() =
delete;
1131 CSVReader(
const CSVReader&) =
delete;
1132 CSVReader&operator=(
const CSVReader&);
1134 template<
class ...Args>
1135 explicit CSVReader(Args&&...args):in(
std::forward<Args>(args)...){
1136 std::fill(row, row+column_count,
nullptr);
1137 col_order.resize(column_count);
1138 for(
unsigned i=0; i<column_count; ++i)
1140 for(
unsigned i=1; i<=column_count; ++i)
1141 column_names[i-1] =
"col"+std::to_string(i);
1145 return in.next_line();
1148 template<
class ...ColNames>
1149 void read_header(ignore_column ignore_policy, ColNames...cols){
1150 static_assert(
sizeof...(ColNames)>=column_count,
"not enough column names specified");
1151 static_assert(
sizeof...(ColNames)<=column_count,
"too many column names specified");
1153 set_column_names(std::forward<ColNames>(cols)...);
1157 line = in.next_line();
1159 throw error::header_missing();
1160 }
while(comment_policy::is_comment(line));
1162 detail::parse_header_line
1163 <column_count, trim_policy, quote_policy>
1164 (line, col_order, column_names, ignore_policy);
1165 }
catch(error::with_file_name&err){
1166 err.set_file_name(in.get_truncated_file_name());
1171 template<
class ...ColNames>
1172 void set_header(ColNames...cols){
1173 static_assert(
sizeof...(ColNames)>=column_count,
1174 "not enough column names specified");
1175 static_assert(
sizeof...(ColNames)<=column_count,
1176 "too many column names specified");
1177 set_column_names(std::forward<ColNames>(cols)...);
1178 std::fill(row, row+column_count,
nullptr);
1179 col_order.resize(column_count);
1180 for(
unsigned i=0; i<column_count; ++i)
1184 bool has_column(
const std::string&name)
const {
1185 return col_order.end() != std::find(
1186 col_order.begin(), col_order.end(),
1187 std::find(std::begin(column_names), std::end(column_names), name)
1188 - std::begin(column_names));
1191 void set_file_name(
const std::string&file_name){
1192 in.set_file_name(file_name);
1195 void set_file_name(
const char*file_name){
1196 in.set_file_name(file_name);
1199 const char*get_truncated_file_name()
const{
1200 return in.get_truncated_file_name();
1203 void set_file_line(
unsigned file_line){
1204 in.set_file_line(file_line);
1207 unsigned get_file_line()
const{
1208 return in.get_file_line();
1212 void parse_helper(std::size_t){}
1214 template<
class T,
class ...ColType>
1215 void parse_helper(std::size_t r, T&t, ColType&...cols){
1219 ::io::detail::parse<overflow_policy>(row[r], t);
1220 }
catch(error::with_column_content&err){
1221 err.set_column_content(row[r]);
1224 }
catch(error::with_column_name&err){
1225 err.set_column_name(column_names[r].c_str());
1229 parse_helper(r+1, cols...);
1234 template<
class ...ColType>
1235 bool read_row(ColType& ...cols){
1236 static_assert(
sizeof...(ColType)>=column_count,
1237 "not enough columns specified");
1238 static_assert(
sizeof...(ColType)<=column_count,
1239 "too many columns specified");
1245 line = in.next_line();
1248 }
while(comment_policy::is_comment(line));
1250 detail::parse_line<trim_policy, quote_policy>
1251 (line, row, col_order);
1253 parse_helper(0, cols...);
1254 }
catch(error::with_file_name&err){
1255 err.set_file_name(in.get_truncated_file_name());
1258 }
catch(error::with_file_line&err){
1259 err.set_file_line(in.get_file_line());