summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Schmucker <ts@its1.de>2020-06-17 15:59:37 +0200
committerThomas Schmucker <ts@its1.de>2020-06-17 15:59:37 +0200
commitee9dab6ba9b48c0bd3b700347d95063285565201 (patch)
treefad50e61326c334fc4fcdc6a4dcc01ed5e2453e9
parent062053677f578b273110372d5c8f6778077e4feb (diff)
downloadlibcsv-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!
-rw-r--r--csv-test.c118
1 files changed, 65 insertions, 53 deletions
diff --git a/csv-test.c b/csv-test.c
index e16091c..220337e 100644
--- a/csv-test.c
+++ b/csv-test.c
@@ -15,21 +15,14 @@ typedef struct {
15 int cap, pos; 15 int cap, pos;
16} csv_string_t; 16} csv_string_t;
17 17
18INLINE bool 18INLINE void
19csv_string_init(csv_string_t *csv_string) 19csv_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
35INLINE void 28INLINE 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
86INLINE bool 93INLINE void
87csv_field_init(csv_field_t *csv_field) 94csv_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
103INLINE void 103INLINE 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
157int csv_init(csv_t *csv); 170void csv_init(csv_t *csv);
158int csv_init_opt(csv_t *csv, csv_options_t *csv_options); 171void csv_init_opt(csv_t *csv, csv_options_t *csv_options);
159void csv_free(csv_t *csv); 172void csv_free(csv_t *csv);
160int csv_nfields(csv_t *csv); 173int csv_nfields(csv_t *csv);
161const char * csv_field(csv_t *csv, int idx); 174const char * csv_field(csv_t *csv, int idx);
162int csv_read(csv_t *csv, FILE *in); 175int csv_read(csv_t *csv, FILE *in);
163void csv_write(csv_t *csv, int n, const char *fields[], FILE *out); 176void csv_write(csv_t *csv, int n, const char *fields[], FILE *out);
164 177
165int 178void
166csv_init(csv_t *csv) 179csv_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
173int 186void
174csv_init_opt(csv_t *csv, csv_options_t *csv_options) 187csv_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
191void 197void
@@ -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;