diff options
| author | Tadas Vilkeliskis <vilkeliskis.t@gmail.com> | 2026-06-11 10:28:13 -0400 |
|---|---|---|
| committer | Tadas Vilkeliskis <vilkeliskis.t@gmail.com> | 2026-06-11 10:28:13 -0400 |
| commit | 761d4f8d38cc0e1f5e438cad4a2d33e2ece37a68 (patch) | |
| tree | f4229fcd35ded58902c1b1c5293089ae4f7a8bc2 /src/csv_parser.c | |
| parent | 49553727accabf4318aba941fa6cb45d37d95d5f (diff) | |
src: optimize parser with fast-forward loops and callback caching
Diffstat (limited to 'src/csv_parser.c')
| -rw-r--r-- | src/csv_parser.c | 139 |
1 files changed, 81 insertions, 58 deletions
diff --git a/src/csv_parser.c b/src/csv_parser.c index 32cf8d4..f11e99b 100644 --- a/src/csv_parser.c +++ b/src/csv_parser.c @@ -48,6 +48,7 @@ size_t csv_parser_execute(csv_parser_t *parser, const char *cursor = data; const char *field_value = NULL; const char *data_end = data + data_len; + int (*field_cb)(csv_parser_t *, const char *, size_t, int, int) = settings->field_cb; int r; parser->nread = 0; @@ -81,45 +82,84 @@ size_t csv_parser_execute(csv_parser_t *parser, } break; case csvps_field_value: - if (ch == settings->delimiter) { - parser->state = csvps_field_end; - } else if (ch == '\r' || ch == '\n') { - parser->state = csvps_line_end_begin; - } else { - if (field_value == NULL) { - field_value = cursor; + if (field_value == NULL) { + field_value = cursor; + } + + { + const char *start = cursor; + char delim = settings->delimiter; + while (cursor < data_end) { + ch = *cursor; + if (ch == delim || ch == '\r' || ch == '\n') { + break; + } + cursor++; } + parser->nread += (cursor - start); + } - cursor++; - if (cursor == data_end) { - if (settings->field_cb && field_value) { - r = settings->field_cb(parser, - field_value, - cursor - field_value, - parser->row, - parser->col); - if (r) { - parser->state = csvps_error; - parser->nread++; - return parser->nread; - } + if (cursor == data_end) { + if (field_cb && field_value) { + r = field_cb(parser, + field_value, + cursor - field_value, + parser->row, + parser->col); + if (r) { + parser->state = csvps_error; + return parser->nread; } } - parser->nread++; + break; + } + + if (ch == settings->delimiter) { + parser->state = csvps_field_end; + } else if (ch == '\r' || ch == '\n') { + parser->state = csvps_line_end_begin; } break; case csvps_field_quoted_value: if (field_value == NULL) { field_value = cursor; } + + { + const char *start = cursor; + while (cursor < data_end) { + if (*cursor == '"') { + break; + } + cursor++; + } + parser->nread += (cursor - start); + } + + if (cursor == data_end) { + if (field_cb && field_value) { + r = field_cb(parser, + field_value, + cursor - field_value, + parser->row, + parser->col); + if (r) { + parser->state = csvps_error; + return parser->nread; + } + } + break; + } + + ch = *cursor; if (ch == '"') { parser->state = csvps_field_quoted_quote; - if (settings->field_cb && field_value && (cursor >= field_value)) { - r = settings->field_cb(parser, - field_value, - cursor - field_value, - parser->row, - parser->col); + if (field_cb && field_value && (cursor >= field_value)) { + r = field_cb(parser, + field_value, + cursor - field_value, + parser->row, + parser->col); if (r) { parser->state = csvps_error; return parser->nread; @@ -128,29 +168,12 @@ size_t csv_parser_execute(csv_parser_t *parser, field_value = NULL; cursor++; parser->nread++; - } else { - cursor++; - if (cursor == data_end) { - if (settings->field_cb && field_value) { - r = settings->field_cb(parser, - field_value, - cursor - field_value, - parser->row, - parser->col); - if (r) { - parser->state = csvps_error; - parser->nread++; - return parser->nread; - } - } - } - parser->nread++; } break; case csvps_field_quoted_quote: if (ch == '"') { - if (settings->field_cb) { - r = settings->field_cb(parser, cursor, 1, parser->row, parser->col); + if (field_cb) { + r = field_cb(parser, cursor, 1, parser->row, parser->col); if (r) { parser->state = csvps_error; return parser->nread; @@ -171,12 +194,12 @@ size_t csv_parser_execute(csv_parser_t *parser, break; case csvps_field_end: // callback - if (settings->field_cb && field_value) { - r = settings->field_cb(parser, - field_value, - cursor - field_value, - parser->row, - parser->col); + if (field_cb && field_value) { + r = field_cb(parser, + field_value, + cursor - field_value, + parser->row, + parser->col); if (r) { parser->state = csvps_error; return parser->nread; @@ -189,12 +212,12 @@ size_t csv_parser_execute(csv_parser_t *parser, break; case csvps_line_end_begin: // callback - if (settings->field_cb && field_value) { - r = settings->field_cb(parser, - field_value, - cursor - field_value, - parser->row, - parser->col); + if (field_cb && field_value) { + r = field_cb(parser, + field_value, + cursor - field_value, + parser->row, + parser->col); if (r) { parser->state = csvps_error; return parser->nread; |
