1 #pragma warning(disable: 4083 244 267 458)
43 # ifndef CSV_IO_NO_THREAD
44 # include <condition_variable>
62 struct base : std::exception
66 const char*
what() const noexcept
override
89 (strncpy(this->file_name,
file_name,
sizeof(this->file_name)));
90 this->file_name[
sizeof(this->
file_name) - 1] =
'\0';
92 this->file_name[0] =
'\0';
153 "Line number %d in file \"%s\" exceeds the maximum length of 2^24-1.",
file_line,
file_name);
161 virtual int read(
char* buffer,
int size) = 0;
174 std::setvbuf(file, 0, _IONBF, 0);
177 int read(
char* buffer,
int size)
179 return std::fread(buffer, 1, size, file);
197 int read(
char* buffer,
int size)
199 in.read(buffer, size);
213 str(str), remaining_byte_count(size) {}
215 int read(
char* buffer,
int desired_byte_count)
217 int to_copy_byte_count = desired_byte_count;
218 if (remaining_byte_count < to_copy_byte_count)
219 to_copy_byte_count = remaining_byte_count;
220 std::memcpy(buffer, str, to_copy_byte_count);
221 remaining_byte_count -= to_copy_byte_count;
222 str += to_copy_byte_count;
223 return to_copy_byte_count;
230 long long remaining_byte_count;
233 # ifndef CSV_IO_NO_THREAD
237 void init(std::unique_ptr<ByteSourceBase> arg_byte_source)
239 std::unique_lock<std::mutex> guard(lock);
240 byte_source = std::move(arg_byte_source);
241 desired_byte_count = -1;
242 termination_requested =
false;
243 worker = std::thread(
245 std::unique_lock<std::mutex> guard(lock);
248 read_requested_condition.wait(
251 return desired_byte_count != -1 || termination_requested;
253 if (termination_requested)
256 read_byte_count = byte_source->read(buffer, desired_byte_count);
257 desired_byte_count = -1;
258 if (read_byte_count == 0)
260 read_finished_condition.notify_one();
263 read_error = std::current_exception();
265 read_finished_condition.notify_one();
271 return byte_source !=
nullptr;
274 void start_read(
char* arg_buffer,
int arg_desired_byte_count)
276 std::unique_lock<std::mutex> guard(lock);
278 desired_byte_count = arg_desired_byte_count;
279 read_byte_count = -1;
280 read_requested_condition.notify_one();
285 std::unique_lock<std::mutex> guard(lock);
286 read_finished_condition.wait(
289 return read_byte_count != -1 || read_error;
292 std::rethrow_exception(read_error);
294 return read_byte_count;
299 if (byte_source !=
nullptr) {
301 std::unique_lock<std::mutex> guard(lock);
302 termination_requested =
true;
304 read_requested_condition.notify_one();
310 std::unique_ptr<ByteSourceBase> byte_source;
314 bool termination_requested;
315 std::exception_ptr read_error;
317 int desired_byte_count;
321 std::condition_variable read_finished_condition;
322 std::condition_variable read_requested_condition;
329 void init(std::unique_ptr<ByteSourceBase> arg_byte_source)
331 byte_source = std::move(arg_byte_source);
336 return byte_source !=
nullptr;
339 void start_read(
char* arg_buffer,
int arg_desired_byte_count)
342 desired_byte_count = arg_desired_byte_count;
347 return byte_source->read(buffer, desired_byte_count);
351 std::unique_ptr<ByteSourceBase> byte_source;
353 int desired_byte_count;
360 static const int block_len = 1 << 20;
361 std::unique_ptr<char[]> buffer;
362 # ifdef CSV_IO_NO_THREAD
373 static std::unique_ptr<ByteSourceBase> open_file(
const char* file_name)
377 FILE* file = std::fopen(file_name,
"rb");
388 void init(std::unique_ptr<ByteSourceBase> byte_source)
392 buffer = std::unique_ptr<char[]>(
new char[3 * block_len]);
394 data_end = byte_source->read(buffer.get(), 2 * block_len);
397 if (data_end >= 3 && buffer[0] ==
'\xEF' && buffer[1] ==
'\xBB' && buffer[2] ==
'\xBF')
400 if (data_end == 2 * block_len) {
401 reader.
init(std::move(byte_source));
402 reader.
start_read(buffer.get() + 2 * block_len, block_len);
414 init(open_file(file_name));
420 init(open_file(file_name.c_str()));
423 LineReader(
const char* file_name, std::unique_ptr<ByteSourceBase> byte_source)
426 init(std::move(byte_source));
432 init(std::move(byte_source));
435 LineReader(
const char* file_name,
const char* data_begin,
const char* data_end)
478 if (file_name !=
nullptr) {
479 strncpy(this->file_name, file_name,
sizeof(this->file_name));
480 this->file_name[
sizeof(this->file_name) - 1] =
'\0';
482 this->file_name[0] =
'\0';
493 this->file_line = file_line;
503 if (data_begin == data_end)
508 assert(data_begin < data_end);
509 assert(data_end <= block_len * 2);
511 if (data_begin >= block_len) {
512 std::memcpy(buffer.get(), buffer.get() + block_len, block_len);
513 data_begin -= block_len;
514 data_end -= block_len;
517 std::memcpy(buffer.get() + block_len, buffer.get() + 2 * block_len, block_len);
518 reader.
start_read(buffer.get() + 2 * block_len, block_len);
522 int line_end = data_begin;
523 while (line_end != data_end && buffer[line_end] !=
'\n') {
527 if (line_end - data_begin + 1 > block_len) {
534 if (line_end != data_end && buffer[line_end] ==
'\n') {
535 buffer[line_end] =
'\0';
540 buffer[line_end] =
'\0';
544 if (line_end != data_begin && buffer[line_end - 1] ==
'\r')
545 buffer[line_end - 1] =
'\0';
547 char* ret = buffer.get() + data_begin;
548 data_begin = line_end + 1;
573 this->column_name[0] =
'\0';
595 this->column_content[0] =
'\0';
645 "Header missing in file \"%s\".",
file_name);
761 template <
char... trim_char_list>
765 constexpr
static bool is_trim_char(
char)
770 template <
class... OtherTrimChars>
771 constexpr
static bool is_trim_char(
char c,
char trim_char, OtherTrimChars... other_trim_chars)
773 return c == trim_char || is_trim_char(c, other_trim_chars...);
777 static void trim(
char*& str_begin,
char*& str_end)
779 while (str_begin != str_end && is_trim_char(*str_begin, trim_char_list...))
781 while (str_begin != str_end && is_trim_char(*(str_end - 1), trim_char_list...))
795 template <
char... comment_start_char_list>
799 constexpr
static bool is_comment_start_char(
char)
804 template <
class... OtherCommentStartChars>
805 constexpr
static bool is_comment_start_char(
char c,
char comment_start_char, OtherCommentStartChars... other_comment_start_chars)
807 return c == comment_start_char || is_comment_start_char(c, other_comment_start_chars...);
813 return is_comment_start_char(*line, comment_start_char_list...);
823 while (*line ==
' ' || *line ==
'\t') {
832 template <
char... comment_start_char_list>
846 while (*col_begin != sep && *col_begin !=
'\0')
856 template <
char sep,
char quote>
861 while (*col_begin != sep && *col_begin !=
'\0')
862 if (*col_begin != quote)
867 while (*col_begin != quote) {
868 if (*col_begin ==
'\0')
873 }
while (*col_begin == quote);
878 static void unescape(
char*& col_begin,
char*& col_end)
880 if (col_end - col_begin >= 2) {
881 if (*col_begin == quote && *(col_end - 1) == quote) {
884 char* out = col_begin;
885 for (
char* in = col_begin; in != col_end; ++in) {
886 if (*in == quote && (in + 1) != col_end && *(in + 1) == quote) {
944 template <
class quote_policy>
946 char*& line,
char*& col_begin,
char*& col_end)
948 assert(line !=
nullptr);
952 col_end = col_begin + (quote_policy::find_next_column_end(col_begin) - col_begin);
954 if (*col_end ==
'\0') {
962 template <
class trim_policy,
class quote_policy>
966 const std::vector<int>& col_order)
968 for (
int i : col_order) {
970 throw ::io::error::too_few_columns();
971 char *col_begin, *col_end;
972 chop_next_column<quote_policy>(line, col_begin, col_end);
975 trim_policy::trim(col_begin, col_end);
976 quote_policy::unescape(col_begin, col_end);
978 sorted_col[i] = col_begin;
982 throw ::io::error::too_many_columns();
985 template <
unsigned column_count,
class trim_policy,
class quote_policy>
988 std::vector<int>& col_order,
994 bool found[column_count];
995 std::fill(found, found + column_count,
false);
997 char *col_begin, *col_end;
998 chop_next_column<quote_policy>(line, col_begin, col_end);
1000 trim_policy::trim(col_begin, col_end);
1001 quote_policy::unescape(col_begin, col_end);
1003 for (
unsigned i = 0; i < column_count; ++i)
1004 if (col_begin == col_name[i]) {
1011 col_order.push_back(i);
1017 col_order.push_back(-1);
1026 for (
unsigned i = 0; i < column_count; ++i) {
1036 template <
class overflow_policy>
1047 template <
class overflow_policy>
1053 template <
class overflow_policy>
1059 template <
class overflow_policy>
1065 template <
class overflow_policy,
class T>
1069 while (*col !=
'\0') {
1070 if (
'0' <= *col && *col <=
'9') {
1073 overflow_policy::on_overflow(x);
1083 template <
class overflow_policy>
1086 parse_unsigned_integer<overflow_policy>(col, x);
1088 template <
class overflow_policy>
1089 void parse(
char* col,
unsigned short& x)
1091 parse_unsigned_integer<overflow_policy>(col, x);
1093 template <
class overflow_policy>
1096 parse_unsigned_integer<overflow_policy>(col, x);
1098 template <
class overflow_policy>
1101 parse_unsigned_integer<overflow_policy>(col, x);
1103 template <
class overflow_policy>
1104 void parse(
char* col,
unsigned long long& x)
1106 parse_unsigned_integer<overflow_policy>(col, x);
1109 template <
class overflow_policy,
class T>
1116 while (*col !=
'\0') {
1117 if (
'0' <= *col && *col <=
'9') {
1120 overflow_policy::on_underflow(x);
1129 }
else if (*col ==
'+')
1131 parse_unsigned_integer<overflow_policy>(col, x);
1134 template <
class overflow_policy>
1137 parse_signed_integer<overflow_policy>(col, x);
1139 template <
class overflow_policy>
1142 parse_signed_integer<overflow_policy>(col, x);
1144 template <
class overflow_policy>
1147 parse_signed_integer<overflow_policy>(col, x);
1149 template <
class overflow_policy>
1152 parse_signed_integer<overflow_policy>(col, x);
1154 template <
class overflow_policy>
1155 void parse(
char* col,
signed long long& x)
1157 parse_signed_integer<overflow_policy>(col, x);
1163 bool is_neg =
false;
1167 }
else if (*col ==
'+')
1171 while (
'0' <= *col && *col <=
'9') {
1178 if (*col ==
'.' || *col ==
',') {
1181 while (
'0' <= *col && *col <=
'9') {
1189 if (*col ==
'e' || *col ==
'E') {
1193 parse_signed_integer<set_to_max_on_overflow>(col, e);
1224 template <
class overflow_policy>
1229 template <
class overflow_policy>
1234 template <
class overflow_policy>
1240 template <
class overflow_policy,
class T>
1249 static_assert(
sizeof(T) !=
sizeof(T),
1250 "Can not parse this type. Only buildin integrals, floats, char, char*, const char* and std::string are supported");
1255 template <
unsigned column_count,
1256 class trim_policy = trim_chars<' ', '\t'>,
1257 class quote_policy = no_quote_escape<','>,
1258 class overflow_policy = throw_on_overflow,
1259 class comment_policy = no_comment>
1265 char* row[column_count];
1268 std::vector<int> col_order;
1270 template <
class... ColNames>
1271 void set_column_names(
std::string s, ColNames... cols)
1273 column_names[column_count -
sizeof...(ColNames) - 1] = std::move(s);
1274 set_column_names(std::forward<ColNames>(cols)...);
1277 void set_column_names() {}
1284 template <
class... Args>
1286 in(
std::forward<Args>(args)...)
1288 std::fill(row, row + column_count,
nullptr);
1289 col_order.resize(column_count);
1290 for (
unsigned i = 0; i < column_count; ++i)
1292 for (
unsigned i = 1; i <= column_count; ++i)
1301 template <
class... ColNames>
1304 static_assert(
sizeof...(ColNames) >= column_count,
"not enough column names specified");
1305 static_assert(
sizeof...(ColNames) <= column_count,
"too many column names specified");
1307 set_column_names(std::forward<ColNames>(cols)...);
1314 }
while (comment_policy::is_comment(line));
1316 detail::parse_header_line<column_count, trim_policy, quote_policy>(line, col_order, column_names, ignore_policy);
1323 template <
class... ColNames>
1326 static_assert(
sizeof...(ColNames) >= column_count,
1327 "not enough column names specified");
1328 static_assert(
sizeof...(ColNames) <= column_count,
1329 "too many column names specified");
1330 set_column_names(std::forward<ColNames>(cols)...);
1331 std::fill(row, row + column_count,
nullptr);
1332 col_order.resize(column_count);
1333 for (
unsigned i = 0; i < column_count; ++i)
1339 return col_order.end() != std::find(
1340 col_order.begin(), col_order.end(),
1341 std::find(std::begin(column_names), std::end(column_names), name) - std::begin(column_names));
1370 void parse_helper(std::size_t) {}
1372 template <
class T,
class... ColType>
1373 void parse_helper(std::size_t r, T& t, ColType&... cols)
1378 ::io::detail::parse<overflow_policy>(row[r], t);
1379 }
catch (error::with_column_content& err) {
1380 err.set_column_content(row[r]);
1383 }
catch (error::with_column_name& err) {
1384 err.set_column_name(column_names[r].c_str());
1388 parse_helper(r + 1, cols...);
1392 template <
class... ColType>
1395 static_assert(
sizeof...(ColType) >= column_count,
1396 "not enough columns specified");
1397 static_assert(
sizeof...(ColType) <= column_count,
1398 "too many columns specified");
1406 }
while (comment_policy::is_comment(line));
1408 detail::parse_line<trim_policy, quote_policy>(line, row, col_order);
1410 parse_helper(0, cols...);
virtual int read(char *buffer, int size)=0
virtual ~ByteSourceBase()
Definition: csv.h:162
CSVReader(const CSVReader &)=delete
unsigned get_file_line() const
Definition: csv.h:1364
void set_file_line(unsigned file_line)
Definition: csv.h:1359
CSVReader & operator=(const CSVReader &)
void set_file_name(const std::string &file_name)
Definition: csv.h:1344
bool read_row(ColType &... cols)
Definition: csv.h:1393
void set_file_name(const char *file_name)
Definition: csv.h:1349
void set_header(ColNames... cols)
Definition: csv.h:1324
char * next_line()
Definition: csv.h:1296
bool has_column(const std::string &name) const
Definition: csv.h:1337
const char * get_truncated_file_name() const
Definition: csv.h:1354
void read_header(ignore_column ignore_policy, ColNames... cols)
Definition: csv.h:1302
CSVReader(Args &&... args)
Definition: csv.h:1285
LineReader(const std::string &file_name, const char *data_begin, const char *data_end)
Definition: csv.h:441
void set_file_name(const std::string &file_name)
Definition: csv.h:471
LineReader(const char *file_name, std::unique_ptr< ByteSourceBase > byte_source)
Definition: csv.h:423
LineReader(const char *file_name, std::istream &in)
Definition: csv.h:459
LineReader(const std::string &file_name, std::istream &in)
Definition: csv.h:465
unsigned get_file_line() const
Definition: csv.h:496
void set_file_line(unsigned file_line)
Definition: csv.h:491
LineReader(const std::string &file_name, std::unique_ptr< ByteSourceBase > byte_source)
Definition: csv.h:429
LineReader(const char *file_name)
Definition: csv.h:411
void set_file_name(const char *file_name)
Definition: csv.h:476
LineReader(const LineReader &)=delete
LineReader(const std::string &file_name, FILE *file)
Definition: csv.h:453
char * next_line()
Definition: csv.h:501
LineReader & operator=(const LineReader &)=delete
LineReader(const std::string &file_name)
Definition: csv.h:417
LineReader(const char *file_name, FILE *file)
Definition: csv.h:447
const char * get_truncated_file_name() const
Definition: csv.h:486
LineReader(const char *file_name, const char *data_begin, const char *data_end)
Definition: csv.h:435
~AsynchronousReader()
Definition: csv.h:297
void init(std::unique_ptr< ByteSourceBase > arg_byte_source)
Definition: csv.h:237
int finish_read()
Definition: csv.h:283
void start_read(char *arg_buffer, int arg_desired_byte_count)
Definition: csv.h:274
bool is_valid() const
Definition: csv.h:269
~NonOwningIStreamByteSource()
Definition: csv.h:203
NonOwningIStreamByteSource(std::istream &in)
Definition: csv.h:194
int read(char *buffer, int size)
Definition: csv.h:197
NonOwningStringByteSource(const char *str, long long size)
Definition: csv.h:212
~NonOwningStringByteSource()
Definition: csv.h:226
int read(char *buffer, int desired_byte_count)
Definition: csv.h:215
OwningStdIOByteSourceBase(FILE *file)
Definition: csv.h:170
int read(char *buffer, int size)
Definition: csv.h:177
~OwningStdIOByteSourceBase()
Definition: csv.h:182
int finish_read()
Definition: csv.h:345
void start_read(char *arg_buffer, int arg_desired_byte_count)
Definition: csv.h:339
bool is_valid() const
Definition: csv.h:334
void init(std::unique_ptr< ByteSourceBase > arg_byte_source)
Definition: csv.h:329
NiColor min(const NiColor &a_lhs, const NiColor &a_rhs)
Definition: ColorUtil.h:63
NiColor max(const NiColor &a_lhs, const NiColor &a_rhs)
Definition: ColorUtil.h:71
string(const CharT(&)[N]) -> string< CharT, N - 1 >
void parse(char *col, char &x)
Definition: csv.h:1037
void parse_header_line(char *line, std::vector< int > &col_order, const std::string *col_name, ignore_column ignore_policy)
Definition: csv.h:986
void parse_float(const char *col, T &x)
Definition: csv.h:1161
void chop_next_column(char *&line, char *&col_begin, char *&col_end)
Definition: csv.h:945
void parse_unsigned_integer(const char *col, T &x)
Definition: csv.h:1066
void parse_signed_integer(const char *col, T &x)
Definition: csv.h:1110
void parse_line(char *line, char **sorted_col, const std::vector< int > &col_order)
Definition: csv.h:963
const int max_column_content_length
Definition: csv.h:580
const int max_file_name_length
Definition: csv.h:75
const int max_column_name_length
Definition: csv.h:559
static const ignore_column ignore_no_column
Definition: csv.h:757
static const ignore_column ignore_extra_column
Definition: csv.h:758
unsigned int ignore_column
Definition: csv.h:756
static const ignore_column ignore_missing_column
Definition: csv.h:759
Definition: EffectArchetypes.h:65
std::string to_string(RE::EffectArchetype a_archetype)
Definition: EffectArchetypes.h:66
static void unescape(char *&col_begin, char *&col_end)
Definition: csv.h:878
static const char * find_next_column_end(const char *col_begin)
Definition: csv.h:859
const char * what() const noexcept override
Definition: csv.h:66
char error_message_buffer[512]
Definition: csv.h:72
virtual void format_error_message() const =0
void format_error_message() const override
Definition: csv.h:134
void format_error_message() const override
Definition: csv.h:631
void format_error_message() const override
Definition: csv.h:678
void format_error_message() const override
Definition: csv.h:607
void format_error_message() const override
Definition: csv.h:692
void format_error_message() const override
Definition: csv.h:720
void format_error_message() const override
Definition: csv.h:734
void format_error_message() const override
Definition: csv.h:748
void format_error_message() const override
Definition: csv.h:150
void format_error_message() const override
Definition: csv.h:619
void format_error_message() const override
Definition: csv.h:706
void format_error_message() const override
Definition: csv.h:654
void format_error_message() const override
Definition: csv.h:666
char column_content[max_column_content_length+1]
Definition: csv.h:599
with_column_content()
Definition: csv.h:584
void set_column_content(const char *column_content)
Definition: csv.h:589
with_column_name()
Definition: csv.h:562
void set_column_name(const char *column_name)
Definition: csv.h:567
char column_name[max_column_name_length+1]
Definition: csv.h:577
with_errno()
Definition: csv.h:116
void set_errno(int errno_value)
Definition: csv.h:121
int errno_value
Definition: csv.h:126
int file_line
Definition: csv.h:111
with_file_line()
Definition: csv.h:101
void set_file_line(int file_line)
Definition: csv.h:106
char file_name[max_file_name_length+1]
Definition: csv.h:96
void set_file_name(const char *file_name)
Definition: csv.h:84
with_file_name()
Definition: csv.h:79
static void on_underflow(T &)
Definition: csv.h:921
static void on_overflow(T &)
Definition: csv.h:917
static const char * find_next_column_end(const char *col_begin)
Definition: csv.h:844
static void unescape(char *&, char *&)
Definition: csv.h:851
static void on_overflow(T &x)
Definition: csv.h:928
static void on_underflow(T &x)
Definition: csv.h:936
static void on_overflow(T &)
Definition: csv.h:902
static void on_underflow(T &)
Definition: csv.h:908
static void trim(char *&str_begin, char *&str_end)
Definition: csv.h:777