diff options
| author | Thomas Schmucker <ts@its1.de> | 2020-06-17 15:59:37 +0200 |
|---|---|---|
| committer | Thomas Schmucker <ts@its1.de> | 2020-06-17 15:59:37 +0200 |
| commit | ee9dab6ba9b48c0bd3b700347d95063285565201 (patch) | |
| tree | fad50e61326c334fc4fcdc6a4dcc01ed5e2453e9 /csv-test.c | |
| parent | 062053677f578b273110372d5c8f6778077e4feb (diff) | |
| download | libcsv-ee9dab6ba9b48c0bd3b700347d95063285565201.tar.gz libcsv-ee9dab6ba9b48c0bd3b700347d95063285565201.tar.bz2 libcsv-ee9dab6ba9b48c0bd3b700347d95063285565201.zip | |
Vereinfache den Code an mehreren Stellen. Speicherverwaltung ist nun
zentralisiert und wo nicht notwendig, wird auf einen Returncode
verzichtet!
Diffstat (limited to 'csv-test.c')
| -rw-r--r-- | csv-test.c | 118 |
1 files changed, 65 insertions, 53 deletions
| @@ -15,21 +15,14 @@ typedef struct { | |||
| 15 | int cap, pos; | 15 | int cap, pos; |
| 16 | } csv_string_t; | 16 | } csv_string_t; |
| 17 | 17 | ||
| 18 | INLINE bool | 18 | INLINE void |
| 19 | csv_string_init(csv_string_t *csv_string) | 19 | csv_string_init(csv_string_t *csv_string) |
| 20 | { | 20 | { |
| 21 | assert(csv_string != NULL); | 21 | assert(csv_string != NULL); |
| 22 | 22 | ||
| 23 | static const int INITIAL_CAP = 16; | 23 | csv_string->str = NULL; |
| 24 | 24 | csv_string->cap = 0; | |
| 25 | if ( (csv_string->str = malloc(INITIAL_CAP)) == NULL ) { | ||
| 26 | return false; | ||
| 27 | } | ||
| 28 | |||
| 29 | csv_string->cap = INITIAL_CAP; | ||
| 30 | csv_string->pos = 0; | 25 | csv_string->pos = 0; |
| 31 | |||
| 32 | return true; | ||
| 33 | } | 26 | } |
| 34 | 27 | ||
| 35 | INLINE void | 28 | INLINE void |
| @@ -53,14 +46,25 @@ csv_string_append(csv_string_t *csv_string, char ch) | |||
| 53 | { | 46 | { |
| 54 | assert(csv_string != NULL); | 47 | assert(csv_string != NULL); |
| 55 | 48 | ||
| 49 | static const int INITIAL_CAP = 16; | ||
| 50 | |||
| 56 | if ( csv_string->pos == csv_string->cap ) { /* grow if needed */ | 51 | if ( csv_string->pos == csv_string->cap ) { /* grow if needed */ |
| 57 | int cap = (csv_string->cap * 3) / 2; /* *= 1.5 */ | 52 | if ( csv_string->str == NULL ) { /* first call? */ |
| 58 | char *str = realloc(csv_string->str, cap); | 53 | if ( (csv_string->str = malloc(INITIAL_CAP)) == NULL ) { |
| 59 | if ( str == NULL ) { | 54 | return false; |
| 60 | return false; | 55 | } |
| 56 | |||
| 57 | csv_string->cap = INITIAL_CAP; | ||
| 58 | } | ||
| 59 | else { /* subsequent call */ | ||
| 60 | int cap = (csv_string->cap * 3) / 2; /* *= 1.5 */ | ||
| 61 | char *str = realloc(csv_string->str, cap); | ||
| 62 | if ( str == NULL ) { | ||
| 63 | return false; | ||
| 64 | } | ||
| 65 | csv_string->str = str; | ||
| 66 | csv_string->cap = cap; | ||
| 61 | } | 67 | } |
| 62 | csv_string->str = str; | ||
| 63 | csv_string->cap = cap; | ||
| 64 | } | 68 | } |
| 65 | 69 | ||
| 66 | csv_string->str[csv_string->pos++] = ch; /* append char */ | 70 | csv_string->str[csv_string->pos++] = ch; /* append char */ |
| @@ -74,6 +78,9 @@ csv_string_free(csv_string_t *csv_string) | |||
| 74 | assert(csv_string != NULL); | 78 | assert(csv_string != NULL); |
| 75 | 79 | ||
| 76 | free(csv_string->str); | 80 | free(csv_string->str); |
| 81 | |||
| 82 | /* call *_init() for sane default values; prevent possible double-free */ | ||
| 83 | csv_string_init(csv_string); | ||
| 77 | } | 84 | } |
| 78 | 85 | ||
| 79 | /* === CSV-FIELD Interface === */ | 86 | /* === CSV-FIELD Interface === */ |
| @@ -83,21 +90,14 @@ typedef struct { | |||
| 83 | int cap, pos; | 90 | int cap, pos; |
| 84 | } csv_field_t; | 91 | } csv_field_t; |
| 85 | 92 | ||
| 86 | INLINE bool | 93 | INLINE void |
| 87 | csv_field_init(csv_field_t *csv_field) | 94 | csv_field_init(csv_field_t *csv_field) |
| 88 | { | 95 | { |
| 89 | assert(csv_field != NULL); | 96 | assert(csv_field != NULL); |
| 90 | 97 | ||
| 91 | static const size_t INITIAL_CAP = 16; | 98 | csv_field->fields = NULL; |
| 92 | 99 | csv_field->cap = 0; | |
| 93 | if ( (csv_field->fields = calloc(INITIAL_CAP, sizeof(csv_field->fields[0]))) == NULL ) { | ||
| 94 | return false; | ||
| 95 | } | ||
| 96 | |||
| 97 | csv_field->cap = INITIAL_CAP; | ||
| 98 | csv_field->pos = 0; | 100 | csv_field->pos = 0; |
| 99 | |||
| 100 | return true; | ||
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | INLINE void | 103 | INLINE void |
| @@ -113,14 +113,25 @@ csv_field_append(csv_field_t *csv_field, int idx) | |||
| 113 | { | 113 | { |
| 114 | assert(csv_field != NULL); | 114 | assert(csv_field != NULL); |
| 115 | 115 | ||
| 116 | static const size_t INITIAL_CAP = 16; | ||
| 117 | |||
| 116 | if ( csv_field->pos == csv_field->cap ) { /* grow if needed */ | 118 | if ( csv_field->pos == csv_field->cap ) { /* grow if needed */ |
| 117 | int cap = (csv_field->cap * 3) / 2; /* *= 1.5 */ | 119 | if ( csv_field->fields == NULL ) { |
| 118 | int *fields = reallocarray(csv_field->fields, cap, sizeof(csv_field->fields[0])); | 120 | if ( (csv_field->fields = calloc(INITIAL_CAP, sizeof(csv_field->fields[0]))) == NULL ) { |
| 119 | if ( fields == NULL ) { | 121 | return false; |
| 120 | return false; | 122 | } |
| 123 | |||
| 124 | csv_field->cap = INITIAL_CAP; | ||
| 125 | } | ||
| 126 | else { | ||
| 127 | int cap = (csv_field->cap * 3) / 2; /* *= 1.5 */ | ||
| 128 | int *fields = reallocarray(csv_field->fields, cap, sizeof(csv_field->fields[0])); | ||
| 129 | if ( fields == NULL ) { | ||
| 130 | return false; | ||
| 131 | } | ||
| 132 | csv_field->fields = fields; | ||
| 133 | csv_field->cap = cap; | ||
| 121 | } | 134 | } |
| 122 | csv_field->fields = fields; | ||
| 123 | csv_field->cap = cap; | ||
| 124 | } | 135 | } |
| 125 | 136 | ||
| 126 | csv_field->fields[csv_field->pos++] = idx; /* append idx */ | 137 | csv_field->fields[csv_field->pos++] = idx; /* append idx */ |
| @@ -134,6 +145,8 @@ csv_field_free(csv_field_t *csv_field) | |||
| 134 | assert(csv_field != NULL); | 145 | assert(csv_field != NULL); |
| 135 | 146 | ||
| 136 | free(csv_field->fields); | 147 | free(csv_field->fields); |
| 148 | |||
| 149 | csv_field_init(csv_field); | ||
| 137 | } | 150 | } |
| 138 | 151 | ||
| 139 | /* === CSV Interface === */ | 152 | /* === CSV Interface === */ |
| @@ -154,38 +167,31 @@ typedef struct { | |||
| 154 | csv_field_t csv_field; | 167 | csv_field_t csv_field; |
| 155 | } csv_t; | 168 | } csv_t; |
| 156 | 169 | ||
| 157 | int csv_init(csv_t *csv); | 170 | void csv_init(csv_t *csv); |
| 158 | int csv_init_opt(csv_t *csv, csv_options_t *csv_options); | 171 | void csv_init_opt(csv_t *csv, csv_options_t *csv_options); |
| 159 | void csv_free(csv_t *csv); | 172 | void csv_free(csv_t *csv); |
| 160 | int csv_nfields(csv_t *csv); | 173 | int csv_nfields(csv_t *csv); |
| 161 | const char * csv_field(csv_t *csv, int idx); | 174 | const char * csv_field(csv_t *csv, int idx); |
| 162 | int csv_read(csv_t *csv, FILE *in); | 175 | int csv_read(csv_t *csv, FILE *in); |
| 163 | void csv_write(csv_t *csv, int n, const char *fields[], FILE *out); | 176 | void csv_write(csv_t *csv, int n, const char *fields[], FILE *out); |
| 164 | 177 | ||
| 165 | int | 178 | void |
| 166 | csv_init(csv_t *csv) | 179 | csv_init(csv_t *csv) |
| 167 | { | 180 | { |
| 168 | assert(csv != NULL); | 181 | assert(csv != NULL); |
| 169 | 182 | ||
| 170 | return csv_init_opt(csv, &default_csv_options); | 183 | csv_init_opt(csv, &default_csv_options); |
| 171 | } | 184 | } |
| 172 | 185 | ||
| 173 | int | 186 | void |
| 174 | csv_init_opt(csv_t *csv, csv_options_t *csv_options) | 187 | csv_init_opt(csv_t *csv, csv_options_t *csv_options) |
| 175 | { | 188 | { |
| 176 | assert(csv != NULL); | 189 | assert(csv != NULL); |
| 177 | 190 | ||
| 178 | csv->csv_options = ( csv_options != NULL ) ? csv_options : &default_csv_options; | 191 | csv->csv_options = ( csv_options != NULL ) ? csv_options : &default_csv_options; |
| 179 | 192 | ||
| 180 | if ( !csv_string_init(&csv->csv_string) ) { | 193 | csv_string_init(&csv->csv_string); |
| 181 | return -1; | 194 | csv_field_init(&csv->csv_field); |
| 182 | } | ||
| 183 | if ( !csv_field_init(&csv->csv_field) ) { | ||
| 184 | csv_string_free(&csv->csv_string); | ||
| 185 | return -1; | ||
| 186 | } | ||
| 187 | |||
| 188 | return 0; | ||
| 189 | } | 195 | } |
| 190 | 196 | ||
| 191 | void | 197 | void |
| @@ -418,19 +424,25 @@ main(void) | |||
| 418 | csv_t csv[1]; | 424 | csv_t csv[1]; |
| 419 | int n, line = 0; | 425 | int n, line = 0; |
| 420 | 426 | ||
| 427 | FILE *in = fopen("500000 Records.csv", "r"); | ||
| 428 | if ( in == NULL ) { | ||
| 429 | fprintf(stderr, "failed to open testfile...\n"); | ||
| 430 | return EXIT_FAILURE; | ||
| 431 | } | ||
| 432 | |||
| 421 | clock_t start = clock(); | 433 | clock_t start = clock(); |
| 422 | 434 | ||
| 423 | int err = csv_init(csv); | 435 | csv_init(csv); |
| 424 | if ( !err ) { | 436 | while ( (n = csv_read(csv, in)) != -1 ) { |
| 425 | while ( (n = csv_read(csv, stdin)) != -1 ) { | 437 | //csv_field(csv, -1); |
| 426 | //csv_field(csv, -1); | 438 | ++line; |
| 427 | ++line; | ||
| 428 | } | ||
| 429 | csv_free(csv); | ||
| 430 | } | 439 | } |
| 440 | csv_free(csv); | ||
| 431 | 441 | ||
| 432 | clock_t end = clock(); | 442 | clock_t end = clock(); |
| 433 | 443 | ||
| 444 | fclose(in); | ||
| 445 | |||
| 434 | printf("%d lines processed, duration: %.3lf sec\n", line, ((double)(end - start)) / CLOCKS_PER_SEC); | 446 | printf("%d lines processed, duration: %.3lf sec\n", line, ((double)(end - start)) / CLOCKS_PER_SEC); |
| 435 | 447 | ||
| 436 | return EXIT_SUCCESS; | 448 | return EXIT_SUCCESS; |
