source: libcfa/src/iostream.hfa@ ecfa58be

Last change on this file since ecfa58be 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: 24.1 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// iostream.hfa --
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:42:53 2025
13// Update Count : 767
14//
15
16#pragma once
17
18#include "iterator.hfa"
19#include "Exception.hfa"
20
21// *********************************** ostream ***********************************
22
23forall( ostype & )
24struct basic_ostream_data {
25 // private
26 bool (*sepPrt$)( ostype & ); // get separator state (on/off)
27 void (*sepReset$)( ostype & ); // set separator state to default state
28 void (*sepReset$)( ostype &, bool ); // set separator and default state
29 const char * (*sepGetCur$)( ostype & ); // get current separator string
30 void (*sepSetCur$)( ostype &, const char [] ); // set current separator string
31 bool (*getNL$)( ostype & ); // get newline
32 bool (*setNL$)( ostype &, bool ); // set newline
33 bool (*getANL$)( ostype & ); // get auto newline (on/off)
34 bool (*setANL$)( ostype &, bool ); // set auto newline (on/off), and return previous state
35 bool (*getPrt$)( ostype & ); // get fmt called in output cascade
36 bool (*setPrt$)( ostype &, bool ); // set fmt called in output cascade
37 // public
38 void (*nlOn)( ostype & ); // turn auto-newline state on
39 void (*nlOff)( ostype & ); // turn auto-newline state off
40
41 void (*sep)( ostype & ); // turn separator state on
42 void (*nosep)( ostype & ); // turn separator state off
43 bool (*sepOn)( ostype & ); // set default state to on, and return previous state
44 bool (*sepOff)( ostype & ); // set default state to off, and return previous state
45 const char * (*sepGet)( ostype & ); // get separator string
46 void (*sepSet)( ostype &, const char [] ); // set separator to string (15 character maximum)
47 const char * (*sepGetTuple)( ostype & ); // get tuple separator string
48 void (*sepSetTuple)( ostype &, const char [] ); // set tuple separator to string (15 character maximum)
49
50 void (*ends)( ostype & ); // end of output statement
51 int (*fmt)( ostype &, const char format[], ... ) __attribute__(( format(printf, 2, 3) ));
52}; // basic_ostream
53
54forall( ostype & )
55struct ostream_data {
56 inline basic_ostream_data( ostype );
57 bool (*fail)( ostype & ); // operation failed?
58 void (*clearerr)( ostype & );
59 int (*flush)( ostype & );
60 void (*open)( ostype &, const char name[], const char mode[] );
61 void (*close)( ostype & );
62 ostype & (*write)( ostype &, const char [], size_t );
63}; // ostream
64
65forall( ostype & )
66trait basic_ostream {
67 basic_ostream_data(ostype) const & basic_ostream_table;
68};
69
70forall( ostype & | basic_ostream( ostype ) )
71trait ostream {
72 ostream_data(ostype) const & ostream_table;
73};
74
75// forall( T )
76// trait writeable {
77// forall( ostype & | ostream( ostype ) ) ostype & ?|?( ostype &, T );
78// }; // writeable
79
80forall( T, ostype & | ostream( ostype ) )
81trait writeable {
82 ostype & ?|?( ostype &, T );
83}; // writeable
84
85// implement writable for intrinsic types
86
87#define OSTYPE_VOID( T ) void ?|?( ostype &, T )
88#define OSTYPE_VOID_IMPL( os, T ) \
89 void ?|?( ostype & os, T t ) { \
90 (ostype &)(os | t); \
91 basic_ostream_table.ends( os ); \
92 } // ?|?
93
94forall( ostype & | basic_ostream( ostype ) ) {
95 ostype & ?|?( ostype &, bool );
96 OSTYPE_VOID( bool );
97
98 ostype & ?|?( ostype &, char );
99 OSTYPE_VOID( char );
100 ostype & ?|?( ostype &, signed char );
101 OSTYPE_VOID( signed char );
102 ostype & ?|?( ostype &, unsigned char );
103 OSTYPE_VOID( unsigned char );
104
105 ostype & ?|?( ostype &, short int );
106 OSTYPE_VOID( short int );
107 ostype & ?|?( ostype &, unsigned short int );
108 OSTYPE_VOID( unsigned short int );
109 ostype & ?|?( ostype &, int );
110 OSTYPE_VOID( int );
111 ostype & ?|?( ostype &, unsigned int );
112 OSTYPE_VOID( unsigned int );
113 ostype & ?|?( ostype &, long int );
114 OSTYPE_VOID( long int );
115 ostype & ?|?( ostype &, long long int );
116 OSTYPE_VOID( long long int );
117 ostype & ?|?( ostype &, unsigned long int );
118 OSTYPE_VOID( unsigned long int );
119 ostype & ?|?( ostype &, unsigned long long int );
120 OSTYPE_VOID( unsigned long long int );
121 #if defined( __SIZEOF_INT128__ )
122 ostype & ?|?( ostype &, int128 );
123 OSTYPE_VOID( int128 );
124 ostype & ?|?( ostype &, unsigned int128 );
125 OSTYPE_VOID( unsigned int128 );
126 #endif // __SIZEOF_INT128__
127
128 ostype & ?|?( ostype &, float );
129 OSTYPE_VOID( float );
130 ostype & ?|?( ostype &, double );
131 OSTYPE_VOID( double );
132 ostype & ?|?( ostype &, long double );
133 OSTYPE_VOID( long double );
134
135 ostype & ?|?( ostype &, float _Complex );
136 OSTYPE_VOID( float _Complex );
137 ostype & ?|?( ostype &, double _Complex );
138 OSTYPE_VOID( double _Complex );
139 ostype & ?|?( ostype &, long double _Complex );
140 OSTYPE_VOID( long double _Complex );
141
142 ostype & ?|?( ostype &, const char [] );
143 OSTYPE_VOID( const char [] );
144 // ostype & ?|?( ostype &, const char16_t [] );
145 #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous
146 // ostype & ?|?( ostype &, const char32_t [] );
147 #endif // ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 )
148 // ostype & ?|?( ostype &, const wchar_t [] );
149 ostype & ?|?( ostype &, const void * );
150 OSTYPE_VOID( const void * );
151
152 // FIX-ME: does not work so using macros
153 // forall( T | { ostype & ?|?( ostype &, T ); } )
154 // void ?|?( ostype & os, T );
155
156 // manipulators
157 ostype & ?|?( ostype &, ostype & (*)( ostype & ) );
158 OSTYPE_VOID( ostype & (*)( ostype & ) );
159
160 ostype & nl( ostype & );
161 ostype & nonl( ostype & );
162 ostype & nlOn( ostype & );
163 ostype & nlOff( ostype & );
164
165 ostype & sepVal( ostype & );
166 ostype & sepTupleVal( ostype & );
167 ostype & sep( ostype & );
168 ostype & nosep( ostype & );
169 ostype & sepOn( ostype & );
170 ostype & sepOff( ostype & );
171} // distribution
172
173// tuples
174forall( ostype &, T, List ... | writeable( T, ostype ) | { ostype & ?|?( ostype &, List ); } ) {
175 ostype & ?|?( ostype & os, T arg, List rest );
176 void ?|?( ostype & os, T arg, List rest );
177} // distribution
178
179// writes the range [begin, end) to the given stream
180forall( ostype &, elt_type | writeable( elt_type, ostype ), iterator_type | iterator( iterator_type, elt_type ) ) {
181 void write( iterator_type begin, iterator_type end, ostype & os );
182 void write_reverse( iterator_type begin, iterator_type end, ostype & os );
183} // distribution
184
185// *********************************** manipulators ***********************************
186
187struct _Ostream_Flags {
188 unsigned char eng:1; // engineering notation
189 unsigned char neg:1; // val is negative
190 unsigned char pc:1; // precision specified
191 unsigned char left:1; // left justify
192 unsigned char nobsdp:1; // base prefix / decimal point
193 unsigned char sign:1; // plus / minus sign
194 unsigned char pad0:1; // zero pad
195};
196
197// FIXME: Should be an anonymous inner union of _Ostream_Manip.
198// Hoisting manually to work around warning of #294.
199union _Ostream_Manip_Mode {
200 unsigned char all;
201 _Ostream_Flags flags;
202};
203
204forall( T )
205struct _Ostream_Manip {
206 T val; // polymorphic base-type
207 int wd, pc; // width, precision: signed for computations
208 char base; // numeric base / floating-point style
209 inline _Ostream_Manip_Mode;
210}; // _Ostream_Manip
211
212// *********************************** integral ***********************************
213
214#define INTEGRAL_FMT_DECL( T, CODE ) \
215static inline { \
216 _Ostream_Manip(T) bin( T val ) { return (_Ostream_Manip(T))@{ .val = val, .wd = 1, .pc = 0, .base = 'b', { .all = 0 } }; } \
217 _Ostream_Manip(T) oct( T val ) { return (_Ostream_Manip(T))@{ .val = val, .wd = 1, .pc = 0, .base = 'o', { .all = 0 } }; } \
218 _Ostream_Manip(T) hex( T val ) { return (_Ostream_Manip(T))@{ .val = val, .wd = 1, .pc = 0, .base = 'x', { .all = 0 } }; } \
219 _Ostream_Manip(T) wd( unsigned int wd, T val ) { return (_Ostream_Manip(T))@{ .val = val, .wd = wd, .pc = 0, .base = CODE, { .all = 0 } }; } \
220 _Ostream_Manip(T) wd( unsigned int wd, unsigned int pc, T val ) { return (_Ostream_Manip(T))@{ .val = val, .wd = wd, .pc = pc, .base = CODE, { .flags.pc = true } }; } \
221 _Ostream_Manip(T) & wd( unsigned int wd, _Ostream_Manip(T) & fmt ) { fmt.wd = wd; return fmt; } \
222 _Ostream_Manip(T) & wd( unsigned int wd, unsigned int pc, _Ostream_Manip(T) & fmt ) { fmt.wd = wd; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
223 _Ostream_Manip(T) & left( _Ostream_Manip(T) & fmt ) { fmt.flags.left = true; return fmt; } \
224 _Ostream_Manip(T) & upcase( _Ostream_Manip(T) & fmt ) { if ( fmt.base == 'x' || fmt.base == 'b' ) fmt.base -= 32; /* upper case */ return fmt; } \
225 _Ostream_Manip(T) & nobase( _Ostream_Manip(T) & fmt ) { fmt.flags.nobsdp = true; return fmt; } \
226 _Ostream_Manip(T) & pad0( _Ostream_Manip(T) & fmt ) { fmt.flags.pad0 = true; return fmt; } \
227 _Ostream_Manip(T) sign( T val ) { return (_Ostream_Manip(T))@{ .val = val, .wd = 1, .pc = 0, .base = CODE, { .flags.sign = true } }; } \
228 _Ostream_Manip(T) & sign( _Ostream_Manip(T) & fmt ) { fmt.flags.sign = true; return fmt; } \
229} /* distribution */ \
230forall( ostype & | basic_ostream( ostype ) ) { \
231 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ); \
232 OSTYPE_VOID( _Ostream_Manip(T) ); \
233} // ?|?
234
235INTEGRAL_FMT_DECL( signed char, 'd' )
236INTEGRAL_FMT_DECL( unsigned char, 'u' )
237INTEGRAL_FMT_DECL( signed short int, 'd' )
238INTEGRAL_FMT_DECL( unsigned short int, 'u' )
239INTEGRAL_FMT_DECL( signed int, 'd' )
240INTEGRAL_FMT_DECL( unsigned int, 'u' )
241INTEGRAL_FMT_DECL( signed long int, 'd' )
242INTEGRAL_FMT_DECL( unsigned long int, 'u' )
243INTEGRAL_FMT_DECL( signed long long int, 'd' )
244INTEGRAL_FMT_DECL( unsigned long long int, 'u' )
245#if defined( __SIZEOF_INT128__ )
246INTEGRAL_FMT_DECL( int128, 'd' )
247INTEGRAL_FMT_DECL( unsigned int128, 'u' )
248#endif // __SIZEOF_INT128__
249
250// *********************************** floating point ***********************************
251
252// Default suffix for values with no fraction is "."
253#define FLOATING_POINT_FMT_DECL( T ) \
254static inline { \
255 _Ostream_Manip(T) hex( T val ) { return (_Ostream_Manip(T))@{ .val = val, .wd = 1, .pc = 0, .base = 'a', { .all = 0 } }; } \
256 _Ostream_Manip(T) sci( T val ) { return (_Ostream_Manip(T))@{ .val = val, .wd = 1, .pc = 0, .base = 'e', { .all = 0 } }; } \
257 _Ostream_Manip(T) eng( T val ) { return (_Ostream_Manip(T))@{ .val = val, 1, -1, .base = 'g', { .flags.eng = true } }; } \
258 _Ostream_Manip(T) wd( unsigned int wd, T val ) { return (_Ostream_Manip(T))@{ .val = val, .wd = wd, .pc = 0, .base = 'g', { .all = 0 } }; } \
259 _Ostream_Manip(T) wd( unsigned int wd, unsigned int pc, T val ) { return (_Ostream_Manip(T))@{ .val = val, .wd = wd, .pc = pc, .base = 'f', { .flags.pc = true } }; } \
260 _Ostream_Manip(T) ws( unsigned int wd, unsigned int pc, T val ) { return (_Ostream_Manip(T))@{ .val = val, .wd = wd, .pc = pc, .base = 'g', { .flags.pc = true } }; } \
261 _Ostream_Manip(T) & wd( unsigned int wd, _Ostream_Manip(T) & fmt ) { if ( fmt.flags.eng ) fmt.base = 'f'; fmt.wd = wd; return fmt; } \
262 _Ostream_Manip(T) & wd( unsigned int wd, unsigned int pc, _Ostream_Manip(T) & fmt ) { \
263 if ( fmt.flags.eng ) fmt.base = 'f'; fmt.wd = wd; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
264 _Ostream_Manip(T) & ws( unsigned int wd, unsigned int pc, _Ostream_Manip(T) & fmt ) { fmt.wd = wd; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
265 _Ostream_Manip(T) & left( _Ostream_Manip(T) & fmt ) { fmt.flags.left = true; return fmt; } \
266 _Ostream_Manip(T) upcase( T val ) { return (_Ostream_Manip(T))@{ .val = val, .wd = 1, .pc = 0, .base = 'G', { .all = 0 } }; } \
267 _Ostream_Manip(T) & upcase( _Ostream_Manip(T) & fmt ) { fmt.base -= 32; /* upper case */ return fmt; } \
268 _Ostream_Manip(T) & pad0( _Ostream_Manip(T) & fmt ) { fmt.flags.pad0 = true; return fmt; } \
269 _Ostream_Manip(T) sign( T val ) { return (_Ostream_Manip(T))@{ .val = val, .wd = 1, .pc = 0, .base = 'g', { .flags.sign = true } }; } \
270 _Ostream_Manip(T) & sign( _Ostream_Manip(T) & fmt ) { fmt.flags.sign = true; return fmt; } \
271 _Ostream_Manip(T) nodp( T val ) { return (_Ostream_Manip(T))@{ .val = val, .wd = 1, .pc = 0, .base = 'g', { .flags.nobsdp = true } }; } \
272 _Ostream_Manip(T) & nodp( _Ostream_Manip(T) & fmt ) { fmt.flags.nobsdp = true; return fmt; } \
273 _Ostream_Manip(T) unit( T val ) { return (_Ostream_Manip(T))@{ .val = val, .wd = 1, .pc = 0, .base = 'g', { .flags.nobsdp = true } }; } \
274 _Ostream_Manip(T) & unit( _Ostream_Manip(T) & fmt ) { fmt.flags.nobsdp = true; return fmt; } \
275} /* distribution */ \
276forall( ostype & | basic_ostream( ostype ) ) { \
277 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ); \
278 OSTYPE_VOID( _Ostream_Manip(T) ); \
279} // ?|?
280
281FLOATING_POINT_FMT_DECL( double )
282FLOATING_POINT_FMT_DECL( long double )
283
284// *********************************** character ***********************************
285
286static inline {
287 _Ostream_Manip(char) bin( char c ) { return (_Ostream_Manip(char))@{ .val = c, .wd = 1, .pc = 0, .base = 'b', { .all = 0 } }; }
288 _Ostream_Manip(char) oct( char c ) { return (_Ostream_Manip(char))@{ .val = c, .wd = 1, .pc = 0, .base = 'o', { .all = 0 } }; }
289 _Ostream_Manip(char) hex( char c ) { return (_Ostream_Manip(char))@{ .val = c, .wd = 1, .pc = 0, .base = 'x', { .all = 0 } }; }
290 _Ostream_Manip(char) wd( unsigned int wd, char c ) { return (_Ostream_Manip(char))@{ c, wd, 0, .base = 'c', { .all = 0 } }; }
291 _Ostream_Manip(char) & wd( unsigned int wd, _Ostream_Manip(char) & fmt ) { fmt.wd = wd; return fmt; }
292 _Ostream_Manip(char) & left( _Ostream_Manip(char) & fmt ) { fmt.flags.left = true; return fmt; }
293 _Ostream_Manip(char) & upcase( _Ostream_Manip(char) & fmt ) { if ( fmt.base == 'x' || fmt.base == 'b' ) fmt.base -= 32; /* upper case */ return fmt; }
294 _Ostream_Manip(char) & nobase( _Ostream_Manip(char) & fmt ) { fmt.flags.nobsdp = true; return fmt; }
295} // distribution
296forall( ostype & | basic_ostream( ostype ) ) {
297 ostype & ?|?( ostype & os, _Ostream_Manip(char) f );
298 OSTYPE_VOID( _Ostream_Manip(char) ); \
299} // ?|?
300
301// *********************************** C string ***********************************
302
303static inline {
304 _Ostream_Manip(const char *) bin( const char s[] ) { return (_Ostream_Manip(const char *))@{ .val = s, .wd = 1, .pc = 0, .base = 'b', { .all = 0 } }; }
305 _Ostream_Manip(const char *) oct( const char s[] ) { return (_Ostream_Manip(const char *))@{ .val = s, .wd = 1, .pc = 0, .base = 'o', { .all = 0 } }; }
306 _Ostream_Manip(const char *) hex( const char s[] ) { return (_Ostream_Manip(const char *))@{ .val = s, .wd = 1, .pc = 0, .base = 'x', { .all = 0 } }; }
307 _Ostream_Manip(const char *) wd( unsigned int wd, const char s[] ) { return (_Ostream_Manip(const char *))@{ s, wd, 0, .base = 's', { .all = 0 } }; }
308 _Ostream_Manip(const char *) wd( unsigned int wd, unsigned int pc, const char s[] ) { return (_Ostream_Manip(const char *))@{ s, .wd = wd, .pc = pc, .base = 's', { .flags.pc = true } }; }
309 _Ostream_Manip(const char *) & wd( unsigned int wd, _Ostream_Manip(const char *) & fmt ) { fmt.wd = wd; return fmt; }
310 _Ostream_Manip(const char *) & wd( unsigned int wd, unsigned int pc, _Ostream_Manip(const char *) & fmt ) { fmt.wd = wd; fmt.pc = pc; fmt.flags.pc = true; return fmt; }
311 _Ostream_Manip(const char *) & left( _Ostream_Manip(const char *) & fmt ) { fmt.flags.left = true; return fmt; }
312 _Ostream_Manip(const char *) & nobase( _Ostream_Manip(const char *) & fmt ) { fmt.flags.nobsdp = true; return fmt; }
313} // distribution
314forall( ostype & | basic_ostream( ostype ) ) {
315 ostype & ?|?( ostype & os, _Ostream_Manip(const char *) f );
316 OSTYPE_VOID( _Ostream_Manip(const char *) ); \
317} // ?|?
318
319// *********************************** istream ***********************************
320
321forall( istype & )
322struct basic_istream_data {
323 // private
324 bool (*getANL$)( istype & ); // get scan newline (on/off)
325 bool (*setANL$)( istype &, bool ); // set scan newline (on/off)
326 // public
327 void (*nlOn)( istype & ); // read newline
328 void (*nlOff)( istype & ); // scan newline
329 int (*fmt)( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
330 istype & (*ungetc)( char, istype & );
331 bool (*eof)( istype & );
332 void (*clearerr)( istype & );
333}; // basic_istream
334
335forall( istype & )
336struct istream_data {
337 inline basic_istream_data( istype );
338 bool (*fail)( istype & );
339 void (*open)( istype & is, const char name[], const char mode[] );
340 void (*open)( istype & is, const char name[] );
341 void (*close)( istype & is );
342 istype & (*read)( istype &, char [], size_t );
343}; // istream
344
345forall( istype & )
346trait basic_istream {
347 basic_istream_data(istype) const & basic_istream_table;
348};
349
350forall( istype & | basic_istream( istype ) )
351trait istream {
352 istream_data(istype) const & istream_table;
353};
354
355forall( T )
356trait readable {
357 forall( istype & | istream( istype ) ) istype & ?|?( istype &, T );
358}; // readable
359
360forall( istype & | basic_istream( istype ) ) {
361 istype & ?|?( istype &, bool & );
362
363 istype & ?|?( istype &, char & );
364 istype & ?|?( istype &, signed char & );
365 istype & ?|?( istype &, unsigned char & );
366
367 istype & ?|?( istype &, short int & );
368 istype & ?|?( istype &, unsigned short int & );
369 istype & ?|?( istype &, int & );
370 istype & ?|?( istype &, unsigned int & );
371 istype & ?|?( istype &, long int & );
372 istype & ?|?( istype &, unsigned long int & );
373 istype & ?|?( istype &, long long int & );
374 istype & ?|?( istype &, unsigned long long int & );
375 #if defined( __SIZEOF_INT128__ )
376 istype & ?|?( istype &, int128 & );
377 istype & ?|?( istype &, unsigned int128 & );
378 #endif // __SIZEOF_INT128__
379
380 istype & ?|?( istype &, float & );
381 istype & ?|?( istype &, double & );
382 istype & ?|?( istype &, long double & );
383
384 istype & ?|?( istype &, float _Complex & );
385 istype & ?|?( istype &, double _Complex & );
386 istype & ?|?( istype &, long double _Complex & );
387
388 // This is too restrictive as it prevents building a format in a string and using that format.
389 // inline istype & ?|?( istype &, char [] ) { // possible error, too restrictive to change
390 // _Static_assert( false, "reading a character array without a maximum length is unsafe. Use input manipulator \"wdi( N, s )\", where \"char s[N]\" or fmt( s )." );
391 // }
392 istype & ?|?( istype &, const char [] ); // match text
393
394 // manipulators
395 istype & ?|?( istype &, istype & (*)( istype & ) );
396 istype & nl( istype & is );
397 istype & nlOn( istype & );
398 istype & nlOff( istype & );
399} // distribution
400
401// *********************************** exceptions ***********************************
402
403ExceptionDecl( end_of_file ); // read encounters end of file
404ExceptionDecl( missing_data ); // read finds no appropriate data
405ExceptionDecl( cstring_length ); // character string size exceeded
406ExceptionDecl( data_range ); // value too large for numerical type
407
408// *********************************** manipulators ***********************************
409
410// skip does not compose with other C string manipulators.
411struct _Istream_Cskip {
412 const char * scanset;
413 unsigned wd; // scan width
414}; // _Istream_Cskip
415
416static inline {
417 _Istream_Cskip skip( const char scanset[] ) { return (_Istream_Cskip)@{ .scanset = scanset, .wd = 0 }; }
418 _Istream_Cskip skip( unsigned int wd ) { return (_Istream_Cskip)@{ .scanset = 0p, .wd = wd }; }
419} // distribution
420
421struct _Istream_str_base {
422 union {
423 const char * scanset;
424 char delimiters[3]; // [0] => left, [1] => right
425 };
426 int wd; // width
427 union {
428 unsigned char all;
429 struct {
430 unsigned char ignore:1; // do not change input argument
431 unsigned char inex:1; // include/exclude characters in scanset
432 unsigned char delimiter:1; // delimit character(s)
433 unsigned char rwd:1; // read width
434 } flags;
435 };
436}; // _Istream_str_base
437
438struct _Istream_Cwidth {
439 char * s;
440 inline _Istream_str_base;
441}; // _Istream_Cwidth
442
443// Restrict nesting of input manipulators to those combinations that make sense.
444
445struct _Istream_Cquote {
446 _Istream_Cwidth cstr;
447}; // _Istream_Cquote
448
449struct _Istream_Cstr {
450 _Istream_Cwidth cstr;
451}; // _Istream_Cstr
452
453static inline {
454 // width must include room for null terminator, (gcc) scanf does not allow a 0 width => wd > 1 (1 char and null) and rd > 0 (1 char);
455 _Istream_Cwidth wdi( unsigned int wd, char s[] ) {
456 if ( wd <= 1 ) throwResume ExceptionInst( cstring_length ); // minimum 1 character and null terminator
457 return (_Istream_Cwidth)@{ .s = s, { {.scanset = 0p}, .wd = wd, {.all = 0} } };
458 }
459 _Istream_Cwidth wdi( unsigned int wd, unsigned int rwd, char s[] ) {
460 if ( wd <= 1 || wd <= rwd ) throwResume ExceptionInst( cstring_length ); // minimum 1 character, null terminator, plus subset
461 return (_Istream_Cwidth)@{ .s = s, { {.scanset = 0p}, .wd = rwd, {.flags.rwd = true} } };
462 }
463 _Istream_Cstr & getline( _Istream_Cwidth & f, const char delimiter = '\n' ) {
464 f.delimiters[0] = delimiter; f.delimiters[1] = '\0'; f.flags.delimiter = true; return (_Istream_Cstr &)f;
465 }
466 _Istream_Cquote quote( char & ch, const char Ldelimiter = '\'', const char Rdelimiter = '\0' ) {
467 return (_Istream_Cquote)@{ { .s = &ch, { {.delimiters = { Ldelimiter, Rdelimiter, '\1' }}, .wd = 1, {.flags.rwd = true} } } };
468 }
469 _Istream_Cquote & quote( _Istream_Cwidth & f, const char Ldelimiter = '"', const char Rdelimiter = '\0' ) {
470 f.delimiters[0] = Ldelimiter; f.delimiters[1] = Rdelimiter; f.delimiters[2] = '\0';
471 return (_Istream_Cquote &)f;
472 }
473 _Istream_Cstr & incl( const char scanset[], _Istream_Cwidth & f ) { f.scanset = scanset; f.flags.inex = false; return (_Istream_Cstr &)f; }
474 _Istream_Cstr & excl( const char scanset[], _Istream_Cwidth & f ) { f.scanset = scanset; f.flags.inex = true; return (_Istream_Cstr &)f; }
475 _Istream_Cstr ignore( const char s[] ) { return (_Istream_Cstr)@{ { .s = (char *)s, { {.scanset = 0p}, .wd = -1, {.flags.ignore = true} } } }; }
476 _Istream_Cstr & ignore( _Istream_Cwidth & f ) { f.flags.ignore = true; return (_Istream_Cstr &)f; }
477 _Istream_Cquote & ignore( _Istream_Cquote & f ) { f.cstr.flags.ignore = true; return (_Istream_Cquote &)f; }
478 _Istream_Cstr & ignore( _Istream_Cstr & f ) { f.cstr.flags.ignore = true; return (_Istream_Cstr &)f; }
479} // distribution
480
481forall( istype & | basic_istream( istype ) ) {
482 istype & ?|?( istype & is, _Istream_Cskip f );
483 istype & ?|?( istype & is, _Istream_Cquote f );
484 istype & ?|?( istype & is, _Istream_Cstr f );
485 static inline istype & ?|?( istype & is, _Istream_Cwidth f ) { return is | *(_Istream_Cstr *)&f; }
486} // distribution
487
488// FIXME: `| sized(T)` seems to be working around a bug, but it is logically unnecessary.
489// Including sized(T) causes a warning that is telling us to get rid of it.
490#pragma GCC diagnostic push
491#pragma GCC diagnostic ignored "-Wunused-parameter"
492forall( T & | sized(T) )
493struct _Istream_Manip {
494 T & val; // polymorphic base-type
495 int wd; // width
496 bool ignore; // do not change input argument
497}; // _Istream_Manip
498#pragma GCC diagnostic pop
499
500#define INPUT_FMT_DECL( T ) \
501static inline { \
502 _Istream_Manip(T) wdi( unsigned int wd, T & val ) { return (_Istream_Manip(T))@{ .val = val, .wd = wd, .ignore = false }; } \
503 _Istream_Manip(T) ignore( const T & val ) { return (_Istream_Manip(T))@{ .val = (T &)val, .wd = -1, .ignore = true }; } \
504 _Istream_Manip(T) & ignore( _Istream_Manip(T) & fmt ) { fmt.ignore = true; return fmt; } \
505} /* distribution */ \
506forall( istype & | basic_istream( istype ) ) { \
507 istype & ?|?( istype & is, _Istream_Manip(T) f ); \
508} // ?|?
509
510INPUT_FMT_DECL( char )
511INPUT_FMT_DECL( signed char )
512INPUT_FMT_DECL( unsigned char )
513INPUT_FMT_DECL( signed short int )
514INPUT_FMT_DECL( unsigned short int )
515INPUT_FMT_DECL( signed int )
516INPUT_FMT_DECL( unsigned int )
517INPUT_FMT_DECL( signed long int )
518INPUT_FMT_DECL( unsigned long int )
519INPUT_FMT_DECL( signed long long int )
520INPUT_FMT_DECL( unsigned long long int )
521
522INPUT_FMT_DECL( float )
523INPUT_FMT_DECL( double )
524INPUT_FMT_DECL( long double )
525
526INPUT_FMT_DECL( float _Complex )
527INPUT_FMT_DECL( double _Complex )
528INPUT_FMT_DECL( long double _Complex )
529
530// *********************************** time ***********************************
531
532#include <time_t.hfa> // Duration (constructors) / Time (constructors)
533
534forall( ostype & | ostream( ostype ) ) {
535 ostype & ?|?( ostype & os, Duration dur );
536 OSTYPE_VOID( Duration );
537 ostype & ?|?( ostype & os, Time time );
538 OSTYPE_VOID( Time );
539} // distribution
540
541forall( istype & | istream( istype ), E | CfaEnum( E ) | Serial(E) )
542istype & ?|?( istype &, E & );
543
544forall( ostype & | ostream( ostype ), E | CfaEnum( E ) ) {
545 ostype & ?|?( ostype &, E );
546 OSTYPE_VOID( E );
547}
548
549// Local Variables: //
550// tab-width: 4 //
551// End: //
Note: See TracBrowser for help on using the repository browser.