aboutsummaryrefslogtreecommitdiff
path: root/src/csv_parser.c
diff options
context:
space:
mode:
authorTadas Vilkeliskis <vilkeliskis.t@gmail.com>2026-06-11 10:28:13 -0400
committerTadas Vilkeliskis <vilkeliskis.t@gmail.com>2026-06-11 10:28:13 -0400
commit761d4f8d38cc0e1f5e438cad4a2d33e2ece37a68 (patch)
treef4229fcd35ded58902c1b1c5293089ae4f7a8bc2 /src/csv_parser.c
parent49553727accabf4318aba941fa6cb45d37d95d5f (diff)
src: optimize parser with fast-forward loops and callback caching
Diffstat (limited to 'src/csv_parser.c')
-rw-r--r--src/csv_parser.c139
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;