source: libcfa/src/fstream.cfa@ a17f496

Last change on this file since a17f496 was ae0c1c3, checked in by Andrew Beach <ajbeach@…>, 5 months ago

Rewrote the iostream traits to have a single assertion each, a table containing function pointers. This is just an experiment right now. It seems that it does cause significant speed up of assertion resolution, but for some reason also seems to add a flat overhead that mostly eats up that saving.

  • Property mode set to 100644
File size: 14.0 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// fstream.c --
8//
9// Author : Peter A. Buhr
10// Created On : Wed May 27 17:56:53 2015
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Mon Apr 14 20:41:51 2025
13// Update Count : 583
14//
15
16#include "fstream.hfa" // also includes iostream.hfa
17
18#include <stdio.h> // vfprintf, vfscanf
19#include <stdlib.h> // exit
20#include <stdarg.h> // varargs
21#include <string.h> // strncpy, strerror
22#include <assert.h>
23#include <errno.h> // errno
24
25#pragma GCC visibility push(default)
26
27
28// *********************************** ofstream ***********************************
29
30
31#define IO_MSG "I/O error: "
32
33// private
34void ?{}( ofstream & os, void * file ) with( os ) {
35 file$ = file;
36 sepDefault$ = true;
37 sepOnOff$ = false;
38 nlOnOff$ = true;
39 prt$ = false;
40 sawNL$ = false;
41 sepSetCur$( os, sepGet( os ) );
42 sepSet( os, " " );
43 sepSetTuple( os, ", " );
44} // ?{}
45
46inline bool getNL$( ofstream & os ) { return os.sawNL$; }
47inline bool setNL$( ofstream & os, bool state ) { bool temp = os.sawNL$; os.sawNL$ = state; return temp; }
48inline bool getANL$( ofstream & os ) { return os.nlOnOff$; }
49inline bool setANL$( ofstream & os, bool state ) { bool temp = os.nlOnOff$; os.nlOnOff$ = state; return temp; }
50
51inline bool sepPrt$( ofstream & os ) { setNL$( os, false ); return os.sepOnOff$; }
52inline void sepReset$( ofstream & os ) { os.sepOnOff$ = os.sepDefault$; }
53inline void sepReset$( ofstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; }
54inline const char * sepGetCur$( ofstream & os ) { return os.sepCur$; }
55inline void sepSetCur$( ofstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; }
56
57inline bool getPrt$( ofstream & os ) { return os.prt$; }
58inline bool setPrt$( ofstream & os, bool state ) { bool temp = os.prt$; os.prt$ = state; return temp; }
59
60inline void lock( ofstream & os ) with( os ) { lock( os.lock$ ); }
61inline void unlock( ofstream & os ) { unlock( os.lock$ ); }
62
63// public
64void ?{}( ofstream & os ) { os.file$ = 0p; }
65void ?{}( ofstream & os, const char name[], const char mode[] ) { open( os, name, mode ); }
66void ?{}( ofstream & os, const char name[] ) { open( os, name, "w" ); }
67void ^?{}( ofstream & os ) { close( os ); }
68
69void nlOn( ofstream & os ) { os.nlOnOff$ = true; }
70void nlOff( ofstream & os ) { os.nlOnOff$ = false; }
71
72void sep( ofstream & os ) { os.sepOnOff$ = ! getNL$( os ); }
73void nosep( ofstream & os ) { os.sepOnOff$ = false; }
74
75bool sepOn( ofstream & os ) {
76 bool temp = os.sepDefault$;
77 os.sepDefault$ = true;
78 if ( os.sepOnOff$ ) sepReset$( os ); // start of line ?
79 return temp;
80} // sepOn
81
82bool sepOff( ofstream & os ) {
83 bool temp = os.sepDefault$;
84 os.sepDefault$ = false;
85 sepReset$( os );
86 return temp;
87} // sepOff
88
89const char * sepGet( ofstream & os ) { return os.separator$; }
90void sepSet( ofstream & os, const char s[] ) {
91 assert( s );
92 strncpy( os.separator$, s, ofstream_sepSize - 1 );
93 os.separator$[ofstream_sepSize - 1] = '\0';
94} // sepSet
95
96const char * sepGetTuple( ofstream & os ) { return os.tupleSeparator$; }
97void sepSetTuple( ofstream & os, const char s[] ) {
98 assert( s );
99 strncpy( os.tupleSeparator$, s, ofstream_sepSize - 1 );
100 os.tupleSeparator$[ofstream_sepSize - 1] = '\0';
101} // sepSet
102
103void ends( ofstream & os ) {
104 if ( getANL$( os ) ) nl( os );
105 else setPrt$( os, false ); // turn off
106 if ( &os == &exit ) exit( EXIT_FAILURE );
107 if ( &os == &abort ) abort();
108} // ends
109
110bool fail( ofstream & os ) { return os.file$ == 0 || ferror( (FILE *)(os.file$) ); }
111void clearerr( ofstream & os ) { clearerr( (FILE *)(os.file$) ); }
112int flush( ofstream & os ) { return fflush( (FILE *)(os.file$) ); }
113
114void open( ofstream & os, const char name[], const char mode[] ) {
115 FILE * file;
116 for ( cnt; 10 ) {
117 errno = 0;
118 file = fopen( name, mode );
119 if ( file != 0p || errno != EINTR ) break; // timer interrupt ?
120 if ( cnt == 9 ) abort( "ofstream open EINTR spinning exceeded" );
121 } // for
122 if ( file == 0p ) {
123 throwResume (open_failure){ os };
124 // abort | IO_MSG "open output file \"" | name | "\"" | nl | strerror( errno );
125 } // if
126 (os){ file }; // initialize
127} // open
128
129void open( ofstream & os, const char name[] ) { open( os, name, "w" ); }
130
131void close( ofstream & os ) with( os ) {
132 if ( (FILE *)(file$) == 0p ) return;
133 if ( (FILE *)(file$) == (FILE *)stdout || (FILE *)(file$) == (FILE *)stderr ) return;
134
135 int ret;
136 for ( cnt; 10 ) {
137 errno = 0;
138 ret = fclose( (FILE *)(file$) );
139 if ( ret != EOF || errno != EINTR ) break; // timer interrupt ?
140 if ( cnt == 9 ) abort( "ofstream open EINTR spinning exceeded" );
141 } // for
142 if ( ret == EOF ) {
143 throw (close_failure){ os };
144 // abort | IO_MSG "close output" | nl | strerror( errno );
145 } // if
146 file$ = 0p; // safety after close
147} // close
148
149ofstream & write( ofstream & os, const char data[], size_t size ) {
150 if ( fail( os ) ) {
151 throw (write_failure){ os };
152 // abort | IO_MSG "attempt write I/O on failed stream";
153 } // if
154
155 if ( fwrite( data, 1, size, (FILE *)(os.file$) ) != size ) {
156 throw (write_failure){ os };
157 // abort | IO_MSG "write" | nl | strerror( errno );
158 } // if
159 return os;
160} // write
161
162int fmt( ofstream & os, const char format[], ... ) {
163 va_list args;
164 va_start( args, format );
165
166 int len;
167 for ( cnt; 10 ) {
168 errno = 0;
169 disable_interrupts();
170 len = vfprintf( (FILE *)(os.file$), format, args );
171 enable_interrupts();
172 if ( len != EOF || errno != EINTR ) break; // timer interrupt ?
173 if ( cnt == 9 ) abort( "ofstream fmt EINTR spinning exceeded" );
174 } // for
175 if ( len == EOF ) { // error writing ?
176 abort | IO_MSG "invalid write";
177 } // if
178 va_end( args );
179
180 setPrt$( os, true ); // called in output cascade
181 sepReset$( os ); // reset separator
182 return len;
183} // fmt
184
185static ofstream soutFile = { (FILE *)stdout };
186ofstream & sout = soutFile, & stdout = soutFile;
187static ofstream serrFile = { (FILE *)stderr };
188ofstream & serr = serrFile, & stderr = serrFile;
189
190static ofstream lsoutFile = { (FILE *)stdout };
191ofstream & lsout = lsoutFile;
192
193static ofstream exitFile = { (FILE *)stderr };
194ofstream & exit = exitFile;
195static ofstream abortFile = { (FILE *)stderr };
196ofstream & abort = abortFile;
197
198ofstream & nl( ofstream & os ) {
199 nl$( os ); // call basic_ostream nl
200 flush( os );
201 return os;
202} // nl
203
204static basic_ostream_data(ofstream) ofstream_basic_data = {
205 sepPrt$,
206 sepReset$,
207 sepReset$,
208 sepGetCur$,
209 sepSetCur$,
210 getNL$,
211 setNL$,
212 getANL$,
213 setANL$,
214 getPrt$,
215 setPrt$,
216 nlOn,
217 nlOff,
218 sep,
219 nosep,
220 sepOn,
221 sepOff,
222 sepGet,
223 sepSet,
224 sepGetTuple,
225 sepSetTuple,
226 ends,
227 fmt,
228};
229
230basic_ostream_data(ofstream) const & basic_ostream_table = ofstream_basic_data;
231
232static ostream_data(ofstream) ofstream_data;
233
234// This should be an initializer like for the basic table.
235// But, initialization of a structure with an inline structure doesn't work.
236__attribute__((constructor(200)))
237static void __ofstream_data_init__() {
238 basic_ostream_data(ofstream) & basic = ofstream_data;
239 basic.sepPrt$ = sepPrt$;
240 basic.sepReset$ = (void(*)(ofstream&))sepReset$;
241 basic.sepReset$ = (void(*)(ofstream&, bool))sepReset$;
242 basic.sepGetCur$ = sepGetCur$;
243 basic.sepSetCur$ = sepSetCur$;
244 basic.getNL$ = getNL$;
245 basic.setNL$ = setNL$;
246 basic.getANL$ = getANL$;
247 basic.setANL$ = setANL$;
248 basic.getPrt$ = getPrt$;
249 basic.setPrt$ = setPrt$;
250 basic.nlOn = nlOn;
251 basic.nlOff = nlOff;
252 basic.sep = sep;
253 basic.nosep = nosep;
254 basic.sepOn = sepOn;
255 basic.sepOff = sepOff;
256 basic.sepGet = sepGet;
257 basic.sepSet = sepSet;
258 basic.sepGetTuple = sepGetTuple;
259 basic.sepSetTuple = sepSetTuple;
260 basic.ends = ends;
261 basic.fmt = fmt;
262 ofstream_data.fail = fail;
263 ofstream_data.clearerr = clearerr;
264 ofstream_data.flush = flush;
265 ofstream_data.open = open;
266 ofstream_data.close = close;
267 ofstream_data.write = write;
268}
269
270ostream_data(ofstream) const & ostream_table = ofstream_data;
271
272// *********************************** ifstream ***********************************
273
274
275// private
276void ?{}( ifstream & is, void * file ) with( is ) {
277 file$ = file;
278 nlOnOff$ = false; // => skip newlines when reading single characters
279} // ?{}
280
281static basic_istream_data(ifstream) ifstream_basic_data = {
282 getANL$,
283 setANL$,
284 nlOn,
285 nlOff,
286 fmt,
287 ungetc,
288 eof,
289 clearerr,
290};
291
292basic_istream_data(ifstream) const & basic_istream_table = ifstream_basic_data;
293
294static istream_data(ifstream) ifstream_data;
295
296// This should be an initializer like for the basic table.
297// But, initialization of a structure with an inline structure doesn't work.
298__attribute__((constructor(200)))
299static void __ifstream_data_init__() {
300 basic_istream_data(ifstream) & basic = ifstream_data;
301 basic.getANL$ = getANL$;
302 basic.setANL$ = setANL$;
303 basic.nlOn = nlOn;
304 basic.nlOff = nlOff;
305 basic.fmt = fmt;
306 basic.ungetc = ungetc;
307 basic.eof = eof;
308 basic.clearerr = clearerr;
309 ifstream_data.fail = fail;
310 ifstream_data.open = (void(*)(ifstream &, const char *, const char *))open;
311 ifstream_data.open = (void(*)(ifstream &, const char *))open;
312 ifstream_data.close = close;
313 ifstream_data.read = read;
314}
315
316istream_data(ifstream) const & istream_table = ifstream_data;
317
318bool getANL$( ifstream & os ) { return os.nlOnOff$; }
319bool setANL$( ifstream & os, bool state ) { bool temp = os.nlOnOff$; os.nlOnOff$ = state; return temp; }
320
321inline void lock( ifstream & os ) with( os ) { lock( os.lock$ ); }
322inline void unlock( ifstream & os ) { unlock( os.lock$ ); }
323
324// public
325void ?{}( ifstream & is ) { is.file$ = 0p; }
326void ?{}( ifstream & is, const char name[], const char mode[] ) { open( is, name, mode ); }
327void ?{}( ifstream & is, const char name[] ) { open( is, name, "r" ); }
328void ^?{}( ifstream & is ) { close( is ); }
329
330bool fail( ifstream & is ) { return is.file$ == 0p || ferror( (FILE *)(is.file$) ); }
331void clearerr( ifstream & is ) { clearerr( (FILE *)(is.file$) ); }
332
333void nlOn( ifstream & os ) { os.nlOnOff$ = true; }
334void nlOff( ifstream & os ) { os.nlOnOff$ = false; }
335
336bool eof( ifstream & is ) { return feof( (FILE *)(is.file$) ) != 0; }
337
338void open( ifstream & is, const char name[], const char mode[] ) {
339 FILE * file;
340 for ( cnt; 10 ) {
341 errno = 0;
342 file = fopen( name, mode );
343 if ( file != 0p || errno != EINTR ) break; // timer interrupt ?
344 if ( cnt == 9 ) abort( "ifstream open EINTR spinning exceeded" );
345 } // for
346 if ( file == 0p ) {
347 throwResume (open_failure){ is };
348 // abort | IO_MSG "open input file \"" | name | "\"" | nl | strerror( errno );
349 } // if
350 (is){ file }; // initialize
351} // open
352
353void open( ifstream & is, const char name[] ) { open( is, name, "r" ); }
354
355void close( ifstream & is ) with( is ) {
356 if ( (FILE *)(file$) == 0p ) return;
357 if ( (FILE *)(file$) == (FILE *)stdin ) return;
358
359 int ret;
360 for ( cnt; 10 ) {
361 errno = 0;
362 ret = fclose( (FILE *)(file$) );
363 if ( ret != EOF || errno != EINTR ) break; // timer interrupt ?
364 if ( cnt == 9 ) abort( "ifstream close EINTR spinning exceeded" );
365 } // for
366 if ( ret == EOF ) {
367 throw (close_failure){ is };
368 // abort | IO_MSG "close input" | nl | strerror( errno );
369 } // if
370 file$ = 0p; // safety after close
371} // close
372
373ifstream & read( ifstream & is, char data[], size_t size ) {
374 if ( fail( is ) ) {
375 throw (read_failure){ is };
376 // abort | IO_MSG "attempt read I/O on failed stream";
377 } // if
378
379 if ( fread( data, size, 1, (FILE *)(is.file$) ) == 0 ) {
380 throw (read_failure){ is };
381 // abort | IO_MSG "read" | nl | strerror( errno );
382 } // if
383 return is;
384} // read
385
386ifstream &ungetc( char c, ifstream & is ) {
387 if ( fail( is ) ) {
388 abort | IO_MSG "attempt ungetc I/O on failed stream";
389 } // if
390
391 if ( ungetc( c, (FILE *)(is.file$) ) == EOF ) {
392 abort | IO_MSG "ungetc" | nl | strerror( errno );
393 } // if
394 return is;
395} // ungetc
396
397int fmt( ifstream & is, const char format[], ... ) {
398 va_list args;
399 va_start( args, format );
400
401 int nargs, tmperrno;
402 for () { // no check for EINTR limit waiting for keyboard input
403 disable_interrupts();
404 errno = 0;
405 nargs = vfscanf( (FILE *)(is.file$), format, args );
406 tmperrno = errno;
407 enable_interrupts();
408 if ( nargs != EOF || errno != EINTR ) break; // timer interrupt ?
409 } // for
410 if ( nargs == EOF ) { // EOF or matching failure ?
411 if ( ! feof( (FILE *)(is.file$) ) && ferror( (FILE *)(is.file$) ) ) {
412 abort | IO_MSG "invalid read";
413 } // if
414 } // if
415 if ( tmperrno == ERANGE ) throwResume ExceptionInst( data_range );
416 va_end( args );
417 return nargs;
418} // fmt
419
420static ifstream sinFile = { (FILE *)stdin };
421ifstream & sin = sinFile, & stdin = sinFile;
422
423
424// *********************************** exceptions ***********************************
425
426
427// exception I/O constructors
428void ?{}( open_failure & ex, ofstream & ostream ) with( ex ) {
429 virtual_table = &open_failure_vt;
430 ostream = &ostream;
431 tag = 1;
432} // ?{}
433
434void ?{}( open_failure & ex, ifstream & istream ) with( ex ) {
435 virtual_table = &open_failure_vt;
436 istream = &istream;
437 tag = 0;
438} // ?{}
439
440
441// exception I/O constructors
442void ?{}( close_failure & ex, ofstream & ostream ) with( ex ) {
443 virtual_table = &close_failure_vt;
444 ostream = &ostream;
445 tag = 1;
446} // ?{}
447
448void ?{}( close_failure & ex, ifstream & istream ) with( ex ) {
449 virtual_table = &close_failure_vt;
450 istream = &istream;
451 tag = 0;
452} // ?{}
453
454
455// exception I/O constructors
456void ?{}( write_failure & ex, ofstream & ostream ) with( ex ) {
457 virtual_table = &write_failure_vt;
458 ostream = &ostream;
459 tag = 1;
460} // ?{}
461
462void ?{}( write_failure & ex, ifstream & istream ) with( ex ) {
463 virtual_table = &write_failure_vt;
464 istream = &istream;
465 tag = 0;
466} // ?{}
467
468
469// exception I/O constructors
470void ?{}( read_failure & ex, ofstream & ostream ) with( ex ) {
471 virtual_table = &read_failure_vt;
472 ostream = &ostream;
473 tag = 1;
474} // ?{}
475
476void ?{}( read_failure & ex, ifstream & istream ) with( ex ) {
477 virtual_table = &read_failure_vt;
478 istream = &istream;
479 tag = 0;
480} // ?{}
481
482// void throwopen_failure( ofstream & ostream ) {
483// open_failure exc = { ostream };
484// }
485
486// void throwopen_failure( ifstream & istream ) {
487// open_failure exc = { istream };
488// }
489
490// Local Variables: //
491// tab-width: 4 //
492// End: //
Note: See TracBrowser for help on using the repository browser.