source: libcfa/src/fstream.cfa@ b28ce93

Last change on this file since b28ce93 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
RevLine 
[86bd7c1f]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//
[356189a]7// fstream.c --
[86bd7c1f]8//
[90c3b1c]9// Author : Peter A. Buhr
[86bd7c1f]10// Created On : Wed May 27 17:56:53 2015
[5d125e4]11// Last Modified By : Peter A. Buhr
[768d091]12// Last Modified On : Mon Apr 14 20:41:51 2025
13// Update Count : 583
[86bd7c1f]14//
15
[f451177]16#include "fstream.hfa" // also includes iostream.hfa
[51b73452]17
[90c3b1c]18#include <stdio.h> // vfprintf, vfscanf
19#include <stdlib.h> // exit
20#include <stdarg.h> // varargs
[b431515]21#include <string.h> // strncpy, strerror
[91c389a]22#include <assert.h>
[8a25be9]23#include <errno.h> // errno
[51b73452]24
[cce4648]25#pragma GCC visibility push(default)
26
[7baff35]27
[8d321f9]28// *********************************** ofstream ***********************************
[65240bb]29
30
[53ba273]31#define IO_MSG "I/O error: "
[6ba0659]32
[7ce2483]33// private
34void ?{}( ofstream & os, void * file ) with( os ) {
[3bf3b6b]35 file$ = file;
36 sepDefault$ = true;
37 sepOnOff$ = false;
38 nlOnOff$ = true;
39 prt$ = false;
40 sawNL$ = false;
[6c5d92f]41 sepSetCur$( os, sepGet( os ) );
[5cb2b8c]42 sepSet( os, " " );
43 sepSetTuple( os, ", " );
[65240bb]44} // ?{}
[0583064b]45
[f5d9c37]46inline bool getNL$( ofstream & os ) { return os.sawNL$; }
[d0cfcbe1]47inline bool setNL$( ofstream & os, bool state ) { bool temp = os.sawNL$; os.sawNL$ = state; return temp; }
[f5d9c37]48inline bool getANL$( ofstream & os ) { return os.nlOnOff$; }
[d0cfcbe1]49inline bool setANL$( ofstream & os, bool state ) { bool temp = os.nlOnOff$; os.nlOnOff$ = state; return temp; }
[f5d9c37]50
[7ce2483]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; }
[f5d9c37]56
[7ce2483]57inline bool getPrt$( ofstream & os ) { return os.prt$; }
[d0cfcbe1]58inline bool setPrt$( ofstream & os, bool state ) { bool temp = os.prt$; os.prt$ = state; return temp; }
[7ce2483]59
[c52f033]60inline void lock( ofstream & os ) with( os ) { lock( os.lock$ ); }
[7ce2483]61inline void unlock( ofstream & os ) { unlock( os.lock$ ); }
[829c907]62
[9ebd778]63// public
[6c5d92f]64void ?{}( ofstream & os ) { os.file$ = 0p; }
[7ce2483]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 ); }
[4cae032]68
[f5d9c37]69void nlOn( ofstream & os ) { os.nlOnOff$ = true; }
70void nlOff( ofstream & os ) { os.nlOnOff$ = false; }
[09687aa]71
[f5d9c37]72void sep( ofstream & os ) { os.sepOnOff$ = ! getNL$( os ); }
73void nosep( ofstream & os ) { os.sepOnOff$ = false; }
[6152c81]74
[f5d9c37]75bool sepOn( ofstream & os ) {
[6c5d92f]76 bool temp = os.sepDefault$;
77 os.sepDefault$ = true;
78 if ( os.sepOnOff$ ) sepReset$( os ); // start of line ?
[53ba273]79 return temp;
[f5d9c37]80} // sepOn
[90c3b1c]81
[f5d9c37]82bool sepOff( ofstream & os ) {
83 bool temp = os.sepDefault$;
84 os.sepDefault$ = false;
85 sepReset$( os );
86 return temp;
87} // sepOff
[200fcb3]88
[6c5d92f]89const char * sepGet( ofstream & os ) { return os.separator$; }
[e3fea42]90void sepSet( ofstream & os, const char s[] ) {
[9ebd778]91 assert( s );
[b431515]92 strncpy( os.separator$, s, ofstream_sepSize - 1 );
93 os.separator$[ofstream_sepSize - 1] = '\0';
[9ebd778]94} // sepSet
95
[6c5d92f]96const char * sepGetTuple( ofstream & os ) { return os.tupleSeparator$; }
[e3fea42]97void sepSetTuple( ofstream & os, const char s[] ) {
[9ebd778]98 assert( s );
[b431515]99 strncpy( os.tupleSeparator$, s, ofstream_sepSize - 1 );
100 os.tupleSeparator$[ofstream_sepSize - 1] = '\0';
[9ebd778]101} // sepSet
102
[65240bb]103void ends( ofstream & os ) {
[6c5d92f]104 if ( getANL$( os ) ) nl( os );
105 else setPrt$( os, false ); // turn off
[65240bb]106 if ( &os == &exit ) exit( EXIT_FAILURE );
107 if ( &os == &abort ) abort();
108} // ends
109
[7ce2483]110bool fail( ofstream & os ) { return os.file$ == 0 || ferror( (FILE *)(os.file$) ); }
[768d091]111void clearerr( ofstream & os ) { clearerr( (FILE *)(os.file$) ); }
[7ce2483]112int flush( ofstream & os ) { return fflush( (FILE *)(os.file$) ); }
[6ba0659]113
[e3fea42]114void open( ofstream & os, const char name[], const char mode[] ) {
[8dcb832]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
[d1a9ff5]122 if ( file == 0p ) {
[211def2]123 throwResume (open_failure){ os };
[8d321f9]124 // abort | IO_MSG "open output file \"" | name | "\"" | nl | strerror( errno );
[93c2e0a]125 } // if
[cce4648]126 (os){ file }; // initialize
[6ba0659]127} // open
128
[7ce2483]129void open( ofstream & os, const char name[] ) { open( os, name, "w" ); }
[8da74119]130
[7ce2483]131void close( ofstream & os ) with( os ) {
[3bf3b6b]132 if ( (FILE *)(file$) == 0p ) return;
133 if ( (FILE *)(file$) == (FILE *)stdout || (FILE *)(file$) == (FILE *)stderr ) return;
[6ba0659]134
[8dcb832]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 ) {
[874b16e]143 throw (close_failure){ os };
[ba0d2ea]144 // abort | IO_MSG "close output" | nl | strerror( errno );
[356189a]145 } // if
[7ce2483]146 file$ = 0p; // safety after close
[6ba0659]147} // close
148
[e3fea42]149ofstream & write( ofstream & os, const char data[], size_t size ) {
[6ba0659]150 if ( fail( os ) ) {
[874b16e]151 throw (write_failure){ os };
[ba0d2ea]152 // abort | IO_MSG "attempt write I/O on failed stream";
[6ba0659]153 } // if
154
[6c5d92f]155 if ( fwrite( data, 1, size, (FILE *)(os.file$) ) != size ) {
[874b16e]156 throw (write_failure){ os };
[ba0d2ea]157 // abort | IO_MSG "write" | nl | strerror( errno );
[839ccbb]158 } // if
[86bd7c1f]159 return os;
[839ccbb]160} // write
[51b73452]161
[09687aa]162int fmt( ofstream & os, const char format[], ... ) {
[5d125e4]163 va_list args;
[829c907]164 va_start( args, format );
[cce4648]165
[8dcb832]166 int len;
167 for ( cnt; 10 ) {
168 errno = 0;
[7a1b7e6]169 disable_interrupts();
[8dcb832]170 len = vfprintf( (FILE *)(os.file$), format, args );
[7a1b7e6]171 enable_interrupts();
[8dcb832]172 if ( len != EOF || errno != EINTR ) break; // timer interrupt ?
173 if ( cnt == 9 ) abort( "ofstream fmt EINTR spinning exceeded" );
174 } // for
[bbdf954]175 if ( len == EOF ) { // error writing ?
176 abort | IO_MSG "invalid write";
[90c3b1c]177 } // if
[5d125e4]178 va_end( args );
[b72bad4f]179
[6c5d92f]180 setPrt$( os, true ); // called in output cascade
181 sepReset$( os ); // reset separator
[90c3b1c]182 return len;
[829c907]183} // fmt
184
[fd8f88f]185static ofstream soutFile = { (FILE *)stdout };
[a87d40b]186ofstream & sout = soutFile, & stdout = soutFile;
[fd8f88f]187static ofstream serrFile = { (FILE *)stderr };
[a87d40b]188ofstream & serr = serrFile, & stderr = serrFile;
[51b73452]189
[e474cf09]190static ofstream lsoutFile = { (FILE *)stdout };
191ofstream & lsout = lsoutFile;
192
[7968301]193static ofstream exitFile = { (FILE *)stderr };
[65240bb]194ofstream & exit = exitFile;
[fd8f88f]195static ofstream abortFile = { (FILE *)stderr };
[65240bb]196ofstream & abort = abortFile;
[5cb2b8c]197
[f451177]198ofstream & nl( ofstream & os ) {
199 nl$( os ); // call basic_ostream nl
200 flush( os );
201 return os;
202} // nl
[90c3b1c]203
[ae0c1c3]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;
[00e9be9]271
[8d321f9]272// *********************************** ifstream ***********************************
[65240bb]273
[51b73452]274
[09687aa]275// private
[7ce2483]276void ?{}( ifstream & is, void * file ) with( is ) {
[3bf3b6b]277 file$ = file;
[63e129c]278 nlOnOff$ = false; // => skip newlines when reading single characters
[65240bb]279} // ?{}
[09687aa]280
[ae0c1c3]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
[c8371b5]318bool getANL$( ifstream & os ) { return os.nlOnOff$; }
[d0cfcbe1]319bool setANL$( ifstream & os, bool state ) { bool temp = os.nlOnOff$; os.nlOnOff$ = state; return temp; }
[c8371b5]320
[7ce2483]321inline void lock( ifstream & os ) with( os ) { lock( os.lock$ ); }
322inline void unlock( ifstream & os ) { unlock( os.lock$ ); }
323
[09687aa]324// public
[6c5d92f]325void ?{}( ifstream & is ) { is.file$ = 0p; }
[7ce2483]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 ); }
[4cae032]329
[7ce2483]330bool fail( ifstream & is ) { return is.file$ == 0p || ferror( (FILE *)(is.file$) ); }
[768d091]331void clearerr( ifstream & is ) { clearerr( (FILE *)(is.file$) ); }
[00e9be9]332
[c8371b5]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; }
[6ba0659]337
[e3fea42]338void open( ifstream & is, const char name[], const char mode[] ) {
[8dcb832]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
[d1a9ff5]346 if ( file == 0p ) {
[211def2]347 throwResume (open_failure){ is };
[8d321f9]348 // abort | IO_MSG "open input file \"" | name | "\"" | nl | strerror( errno );
[93c2e0a]349 } // if
[cce4648]350 (is){ file }; // initialize
[90c3b1c]351} // open
[6ba0659]352
[7ce2483]353void open( ifstream & is, const char name[] ) { open( is, name, "r" ); }
[8da74119]354
[7ce2483]355void close( ifstream & is ) with( is ) {
[3bf3b6b]356 if ( (FILE *)(file$) == 0p ) return;
357 if ( (FILE *)(file$) == (FILE *)stdin ) return;
[90c3b1c]358
[8dcb832]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 ) {
[874b16e]367 throw (close_failure){ is };
[ba0d2ea]368 // abort | IO_MSG "close input" | nl | strerror( errno );
[356189a]369 } // if
[8dcb832]370 file$ = 0p; // safety after close
[90c3b1c]371} // close
372
[00e9be9]373ifstream & read( ifstream & is, char data[], size_t size ) {
[6ba0659]374 if ( fail( is ) ) {
[874b16e]375 throw (read_failure){ is };
[ba0d2ea]376 // abort | IO_MSG "attempt read I/O on failed stream";
[6ba0659]377 } // if
378
[6c5d92f]379 if ( fread( data, size, 1, (FILE *)(is.file$) ) == 0 ) {
[874b16e]380 throw (read_failure){ is };
[ba0d2ea]381 // abort | IO_MSG "read" | nl | strerror( errno );
[6ba0659]382 } // if
[86bd7c1f]383 return is;
[6ba0659]384} // read
[356189a]385
[a1a1f37d]386ifstream &ungetc( char c, ifstream & is ) {
[6ba0659]387 if ( fail( is ) ) {
[ff2a33e]388 abort | IO_MSG "attempt ungetc I/O on failed stream";
[6ba0659]389 } // if
[51b73452]390
[6c5d92f]391 if ( ungetc( c, (FILE *)(is.file$) ) == EOF ) {
[ff2a33e]392 abort | IO_MSG "ungetc" | nl | strerror( errno );
[6ba0659]393 } // if
394 return is;
395} // ungetc
[51b73452]396
[09687aa]397int fmt( ifstream & is, const char format[], ... ) {
[5d125e4]398 va_list args;
[829c907]399 va_start( args, format );
[8dcb832]400
[211def2]401 int nargs, tmperrno;
[8dcb832]402 for () { // no check for EINTR limit waiting for keyboard input
[7a1b7e6]403 disable_interrupts();
[211def2]404 errno = 0;
[decd4a6]405 nargs = vfscanf( (FILE *)(is.file$), format, args );
[211def2]406 tmperrno = errno;
[7a1b7e6]407 enable_interrupts();
[decd4a6]408 if ( nargs != EOF || errno != EINTR ) break; // timer interrupt ?
[8dcb832]409 } // for
[decd4a6]410 if ( nargs == EOF ) { // EOF or matching failure ?
[bbdf954]411 if ( ! feof( (FILE *)(is.file$) ) && ferror( (FILE *)(is.file$) ) ) {
[ff2a33e]412 abort | IO_MSG "invalid read";
[90c3b1c]413 } // if
414 } // if
[211def2]415 if ( tmperrno == ERANGE ) throwResume ExceptionInst( data_range );
[5d125e4]416 va_end( args );
[decd4a6]417 return nargs;
[829c907]418} // fmt
[51b73452]419
[fd8f88f]420static ifstream sinFile = { (FILE *)stdin };
[a87d40b]421ifstream & sin = sinFile, & stdin = sinFile;
[86bd7c1f]422
[91e52be]423
[8d321f9]424// *********************************** exceptions ***********************************
[91e52be]425
426
[a5a6a1a8]427// exception I/O constructors
[decd4a6]428void ?{}( open_failure & ex, ofstream & ostream ) with( ex ) {
[874b16e]429 virtual_table = &open_failure_vt;
[3bf3b6b]430 ostream = &ostream;
431 tag = 1;
[a5a6a1a8]432} // ?{}
433
[decd4a6]434void ?{}( open_failure & ex, ifstream & istream ) with( ex ) {
[874b16e]435 virtual_table = &open_failure_vt;
[3bf3b6b]436 istream = &istream;
437 tag = 0;
[a5a6a1a8]438} // ?{}
439
440
[ba0d2ea]441// exception I/O constructors
[decd4a6]442void ?{}( close_failure & ex, ofstream & ostream ) with( ex ) {
[874b16e]443 virtual_table = &close_failure_vt;
[3bf3b6b]444 ostream = &ostream;
445 tag = 1;
[ba0d2ea]446} // ?{}
447
[decd4a6]448void ?{}( close_failure & ex, ifstream & istream ) with( ex ) {
[874b16e]449 virtual_table = &close_failure_vt;
[3bf3b6b]450 istream = &istream;
451 tag = 0;
[ba0d2ea]452} // ?{}
453
454
455// exception I/O constructors
[decd4a6]456void ?{}( write_failure & ex, ofstream & ostream ) with( ex ) {
[874b16e]457 virtual_table = &write_failure_vt;
[3bf3b6b]458 ostream = &ostream;
459 tag = 1;
[ba0d2ea]460} // ?{}
461
[decd4a6]462void ?{}( write_failure & ex, ifstream & istream ) with( ex ) {
[874b16e]463 virtual_table = &write_failure_vt;
[3bf3b6b]464 istream = &istream;
465 tag = 0;
[ba0d2ea]466} // ?{}
467
468
469// exception I/O constructors
[decd4a6]470void ?{}( read_failure & ex, ofstream & ostream ) with( ex ) {
[874b16e]471 virtual_table = &read_failure_vt;
[3bf3b6b]472 ostream = &ostream;
473 tag = 1;
[ba0d2ea]474} // ?{}
475
[decd4a6]476void ?{}( read_failure & ex, ifstream & istream ) with( ex ) {
[874b16e]477 virtual_table = &read_failure_vt;
[3bf3b6b]478 istream = &istream;
479 tag = 0;
[ba0d2ea]480} // ?{}
481
[874b16e]482// void throwopen_failure( ofstream & ostream ) {
483// open_failure exc = { ostream };
[ba0d2ea]484// }
485
[874b16e]486// void throwopen_failure( ifstream & istream ) {
487// open_failure exc = { istream };
[ba0d2ea]488// }
[91e52be]489
[86bd7c1f]490// Local Variables: //
491// tab-width: 4 //
492// End: //
Note: See TracBrowser for help on using the repository browser.