source: libcfa/src/iostream.cfa@ fa29dfc

Last change on this file since fa29dfc 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: 48.8 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//
[b117e0c]7// iostream.cfa --
[86bd7c1f]8//
[90c3b1c]9// Author : Peter A. Buhr
[86bd7c1f]10// Created On : Wed May 27 17:56:53 2015
[e24f13a]11// Last Modified By : Peter A. Buhr
[768d091]12// Last Modified On : Mon Apr 14 20:43:14 2025
13// Update Count : 2081
[86bd7c1f]14//
[51b73452]15
[58b6d1b]16#include "iostream.hfa"
[d3b7937]17
[51b73452]18#include <stdio.h>
[53a6c2a]19#include <stdbool.h> // true/false
[e59e663]20#include <stdint.h> // UINT64_MAX
[6026628]21#include <float.h> // DBL_DIG, LDBL_DIG
22#include <complex.h> // creal, cimag
[0860d9c]23#include <ctype.h> // isspace
[aa25216]24//#include <stdio.h>
25
[6026628]26extern "C" {
[44574f2]27extern size_t strlen (const char *__s) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__pure__)) __attribute__ ((__nonnull__ (1)));
[3c573e9]28extern int strcmp (const char *__s1, const char *__s2) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__pure__)) __attribute__ ((__nonnull__ (1, 2)));
29extern char *strcpy (char *__restrict __dest, const char *__restrict __src) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1, 2)));
30extern void *memcpy (void *__restrict __dest, const void *__restrict __src, size_t __n) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1, 2)));
[0860d9c]31extern char *strchr(const char *str, int ch);
[3c573e9]32} // extern "C"
[51b73452]33
[7cfef0d]34#include "math.hfa" // isfinite, floor, ceiling_div
35#include "bitmanip.hfa" // high1
[7fd71c7]36
[cce4648]37#pragma GCC visibility push(default)
[61c7239]38
[94d2544]39
[8d321f9]40// *********************************** ostream ***********************************
[61c7239]41
42
[85d8153]43forall( ostype & | basic_ostream( ostype ) ) {
[ae0c1c3]44 ostype & ?|?( ostype & os, bool b ) with ( basic_ostream_table ) {
[6c5d92f]45 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[3ce0d440]46 fmt( os, "%s", b ? "true" : "false" );
47 return os;
48 } // ?|?
[b12e4ad]49 OSTYPE_VOID_IMPL( os, bool )
[51b73452]50
[ae0c1c3]51 ostype & ?|?( ostype & os, char c ) with ( basic_ostream_table ) {
[200fcb3]52 fmt( os, "%c", c );
[6c5d92f]53 if ( c == '\n' ) setNL$( os, true );
[f5d9c37]54 return nosep( os );
[200fcb3]55 } // ?|?
[b12e4ad]56 OSTYPE_VOID_IMPL( os, char )
[3ce0d440]57
[ae0c1c3]58 ostype & ?|?( ostype & os, signed char sc ) with ( basic_ostream_table ) {
[6c5d92f]59 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[0c51f9ad]60 fmt( os, "%'hhd", sc );
[3ce0d440]61 return os;
62 } // ?|?
[b12e4ad]63 OSTYPE_VOID_IMPL( os, signed char )
[3ce0d440]64
[ae0c1c3]65 ostype & ?|?( ostype & os, unsigned char usc ) with ( basic_ostream_table ) {
[6c5d92f]66 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[0c51f9ad]67 fmt( os, "%'hhu", usc );
[3ce0d440]68 return os;
69 } // ?|?
[b12e4ad]70 OSTYPE_VOID_IMPL( os, unsigned char )
[3ce0d440]71
[ae0c1c3]72 ostype & ?|?( ostype & os, short int si ) with ( basic_ostream_table ) {
[6c5d92f]73 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[0c51f9ad]74 fmt( os, "%'hd", si );
[3ce0d440]75 return os;
76 } // ?|?
[b12e4ad]77 OSTYPE_VOID_IMPL( os, short int )
[3ce0d440]78
[ae0c1c3]79 ostype & ?|?( ostype & os, unsigned short int usi ) with ( basic_ostream_table ) {
[6c5d92f]80 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[0c51f9ad]81 fmt( os, "%'hu", usi );
[3ce0d440]82 return os;
83 } // ?|?
[b12e4ad]84 OSTYPE_VOID_IMPL( os, unsigned short int )
[3ce0d440]85
[ae0c1c3]86 ostype & ?|?( ostype & os, int i ) with ( basic_ostream_table ) {
[6c5d92f]87 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[0c51f9ad]88 fmt( os, "%'d", i );
[3ce0d440]89 return os;
90 } // ?|?
[b12e4ad]91 OSTYPE_VOID_IMPL( os, int )
[3ce0d440]92
[ae0c1c3]93 ostype & ?|?( ostype & os, unsigned int ui ) with ( basic_ostream_table ) {
[6c5d92f]94 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[0c51f9ad]95 fmt( os, "%'u", ui );
[3ce0d440]96 return os;
97 } // ?|?
[b12e4ad]98 OSTYPE_VOID_IMPL( os, unsigned int )
[3ce0d440]99
[ae0c1c3]100 ostype & ?|?( ostype & os, long int li ) with ( basic_ostream_table ) {
[6c5d92f]101 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[0c51f9ad]102 fmt( os, "%'ld", li );
[3ce0d440]103 return os;
104 } // ?|?
[b12e4ad]105 OSTYPE_VOID_IMPL( os, long int )
[3ce0d440]106
[ae0c1c3]107 ostype & ?|?( ostype & os, unsigned long int uli ) with ( basic_ostream_table ) {
[6c5d92f]108 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[0c51f9ad]109 fmt( os, "%'lu", uli );
[3ce0d440]110 return os;
111 } // ?|?
[b12e4ad]112 OSTYPE_VOID_IMPL( os, unsigned long int )
[3ce0d440]113
[ae0c1c3]114 ostype & ?|?( ostype & os, long long int lli ) with ( basic_ostream_table ) {
[6c5d92f]115 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[0c51f9ad]116 fmt( os, "%'lld", lli );
[3ce0d440]117 return os;
118 } // ?|?
[b12e4ad]119 OSTYPE_VOID_IMPL( os, long long int )
[3ce0d440]120
[ae0c1c3]121 ostype & ?|?( ostype & os, unsigned long long int ulli ) with ( basic_ostream_table ) {
[6c5d92f]122 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[0c51f9ad]123 fmt( os, "%'llu", ulli );
[3ce0d440]124 return os;
125 } // ?|?
[b12e4ad]126 OSTYPE_VOID_IMPL( os, unsigned long long int )
[3ce0d440]127
[ef3ac46]128 #if defined( __SIZEOF_INT128__ )
[bd5b443]129 // UINT64_MAX 18_446_744_073_709_551_615_ULL
130 #define P10_UINT64 10_000_000_000_000_000_000_ULL // 19 zeroes
131
[ae0c1c3]132 static inline void base10_128( ostype & os, unsigned int128 val ) with ( basic_ostream_table ) {
[ef3ac46]133 #if defined(__GNUC__) && __GNUC_PREREQ(7,0) // gcc version >= 7
[2c60c644]134 if ( val > P10_UINT64 ) {
[ef3ac46]135 #else
[ffa48a8]136 if ( (uint64_t)(val >> 64) != 0 || (uint64_t)val > P10_UINT64 ) { // patch gcc 5 & 6 -O3 bug
[ef3ac46]137 #endif // __GNUC_PREREQ(7,0)
[bd5b443]138 base10_128( os, val / P10_UINT64 ); // recursive
139 fmt( os, "%.19lu", (uint64_t)(val % P10_UINT64) );
140 } else {
141 fmt( os, "%lu", (uint64_t)val );
142 } // if
143 } // base10_128
144
[ae0c1c3]145 static inline void base10_128( ostype & os, int128 val ) with ( basic_ostream_table ) {
[bd5b443]146 if ( val < 0 ) {
147 fmt( os, "-" ); // leading negative sign
148 val = -val;
149 } // if
150 base10_128( os, (unsigned int128)val ); // print zero/positive value
151 } // base10_128
152
[ae0c1c3]153 ostype & ?|?( ostype & os, int128 llli ) with ( basic_ostream_table ) {
[6c5d92f]154 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[bd5b443]155 base10_128( os, llli );
156 return os;
157 } // ?|?
[b12e4ad]158 OSTYPE_VOID_IMPL( os, int128 )
[bd5b443]159
[ae0c1c3]160 ostype & ?|?( ostype & os, unsigned int128 ullli ) with ( basic_ostream_table ) {
[6c5d92f]161 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[bd5b443]162 base10_128( os, ullli );
163 return os;
164 } // ?|?
[b12e4ad]165 OSTYPE_VOID_IMPL( os, unsigned int128 )
[ef3ac46]166 #endif // __SIZEOF_INT128__
[bd5b443]167
[94d2544]168 #define PRINT_WITH_DP( os, format, val, ... ) \
[e63326b]169 { \
170 enum { size = 48 }; \
171 char buf[size]; \
172 int len = snprintf( buf, size, format, ##__VA_ARGS__, val ); \
173 fmt( os, "%s", buf ); \
[fd4c009]174 if ( isfinite( val ) ) { /* if number, print decimal point when no fraction or exponent */ \
[f6a4917]175 for ( i; 0 ~ @ ) { \
[e63326b]176 if ( i == len ) { fmt( os, "." ); break; } \
[09a767e]177 if ( buf[i] == '.' || buf[i] == 'e' || buf[i] == 'E' || \
178 buf[i] == 'p' || buf[i] == 'P' ) break; /* decimal point or scientific ? */ \
[e63326b]179 } /* for */ \
180 } /* if */ \
181 }
[b2ac656]182
[ae0c1c3]183 ostype & ?|?( ostype & os, float f ) with ( basic_ostream_table ) {
[6c5d92f]184 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[94d2544]185 PRINT_WITH_DP( os, "%'g", f );
[3ce0d440]186 return os;
187 } // ?|?
[b12e4ad]188 OSTYPE_VOID_IMPL( os, float )
[3ce0d440]189
[ae0c1c3]190 ostype & ?|?( ostype & os, double d ) with ( basic_ostream_table ) {
[6c5d92f]191 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[94d2544]192 PRINT_WITH_DP( os, "%'.*lg", d, DBL_DIG );
[3ce0d440]193 return os;
194 } // ?|?
[b12e4ad]195 OSTYPE_VOID_IMPL( os, double )
[3ce0d440]196
[ae0c1c3]197 ostype & ?|?( ostype & os, long double ld ) with ( basic_ostream_table ) {
[6c5d92f]198 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[94d2544]199 PRINT_WITH_DP( os, "%'.*Lg", ld, LDBL_DIG );
[3ce0d440]200 return os;
201 } // ?|?
[b12e4ad]202 OSTYPE_VOID_IMPL( os, long double )
[3ce0d440]203
[ae0c1c3]204 ostype & ?|?( ostype & os, float _Complex fc ) with ( basic_ostream_table ) {
[6c5d92f]205 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[b2ac656]206// os | crealf( fc ) | nonl;
[94d2544]207 PRINT_WITH_DP( os, "%'g", crealf( fc ) );
208 PRINT_WITH_DP( os, "%'+g", cimagf( fc ) );
[3c5dee4]209 fmt( os, "i" );
[3ce0d440]210 return os;
211 } // ?|?
[b12e4ad]212 OSTYPE_VOID_IMPL( os, float _Complex )
[3ce0d440]213
[ae0c1c3]214 ostype & ?|?( ostype & os, double _Complex dc ) with ( basic_ostream_table ) {
[6c5d92f]215 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[b2ac656]216// os | creal( dc ) | nonl;
[94d2544]217 PRINT_WITH_DP( os, "%'.*lg", creal( dc ), DBL_DIG );
218 PRINT_WITH_DP( os, "%'+.*lg", cimag( dc ), DBL_DIG );
[3c5dee4]219 fmt( os, "i" );
[3ce0d440]220 return os;
221 } // ?|?
[b12e4ad]222 OSTYPE_VOID_IMPL( os, double _Complex )
[3ce0d440]223
[ae0c1c3]224 ostype & ?|?( ostype & os, long double _Complex ldc ) with ( basic_ostream_table ) {
[6c5d92f]225 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[b2ac656]226// os | creall( ldc ) || nonl;
[94d2544]227 PRINT_WITH_DP( os, "%'.*Lg", creall( ldc ), LDBL_DIG );
228 PRINT_WITH_DP( os, "%'+.*Lg", cimagl( ldc ), LDBL_DIG );
[3c5dee4]229 fmt( os, "i" );
[3ce0d440]230 return os;
231 } // ?|?
[b12e4ad]232 OSTYPE_VOID_IMPL( os, long double _Complex )
[3ce0d440]233
[ae0c1c3]234 ostype & ?|?( ostype & os, const char s[] ) with ( basic_ostream_table ) {
[3ce0d440]235 enum { Open = 1, Close, OpenClose };
[28c2933d]236 static const unsigned char mask[256] @= { // 256 covers all Latin-1 characters
[3ce0d440]237 // opening delimiters, no space after
[1a7203d]238 ['('] = Open, ['['] = Open, ['{'] = Open,
239 ['='] = Open, ['$'] = Open, [(unsigned char)'£'] = Open, [(unsigned char)'¥'] = Open,
240 [(unsigned char)'¡'] = Open, [(unsigned char)'¿'] = Open, [(unsigned char)'«'] = Open,
[3ce0d440]241 // closing delimiters, no space before
[1a7203d]242 [','] = Close, ['.'] = Close, [';'] = Close, ['!'] = Close, ['?'] = Close,
243 ['%'] = Close, [(unsigned char)'¢'] = Close, [(unsigned char)'»'] = Close,
244 [')'] = Close, [']'] = Close, ['}'] = Close,
[3ce0d440]245 // opening-closing delimiters, no space before or after
[1a7203d]246 ['\''] = OpenClose, ['`'] = OpenClose, ['"'] = OpenClose, [':'] = OpenClose,
247 [' '] = OpenClose, ['\f'] = OpenClose, ['\n'] = OpenClose, ['\r'] = OpenClose, ['\t'] = OpenClose, ['\v'] = OpenClose, // isspace
[3ce0d440]248 }; // mask
249
[6a33e40]250 if ( s == 0p ) { fmt( os, "%s", "0p" ); return os; } // null pointer
[f5d9c37]251 if ( s[0] == '\0' ) { nosep( os ); return os; } // null string => no leading/trailing separator
[3ce0d440]252
253 // first character IS NOT spacing or closing punctuation => add left separator
[e474cf09]254 unsigned char ch = s[0]; // must make unsigned
[6c5d92f]255 if ( sepPrt$( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) {
256 fmt( os, "%s", sepGetCur$( os ) );
[3ce0d440]257 } // if
258
259 // if string starts line, must reset to determine open state because separator is off
[6c5d92f]260 sepReset$( os ); // reset separator
[3ce0d440]261
262 // last character IS spacing or opening punctuation => turn off separator for next item
[85d8153]263 int len = strlen( s );
[e474cf09]264 ch = s[len - 1]; // must make unsigned
[85d8153]265 fmt( os, "%s", s ); // fmt resets seperator, but reset it again
[6c5d92f]266 if ( sepPrt$( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) {
[f5d9c37]267 sep( os );
[3ce0d440]268 } else {
[f5d9c37]269 nosep( os );
[3ce0d440]270 } // if
[6c5d92f]271 if ( ch == '\n' ) setNL$( os, true ); // check *AFTER* sepPrt$ call above as it resets NL flag
[85d8153]272 return os;
273// return write( os, s, len );
[3ce0d440]274 } // ?|?
[b12e4ad]275 OSTYPE_VOID_IMPL( os, const char * )
[3ce0d440]276
[e7a8f65]277// ostype & ?|?( ostype & os, const char16_t s[] ) {
[6c5d92f]278// if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[e474cf09]279// fmt( os, "%ls", s );
[3ce0d440]280// return os;
281// } // ?|?
[d3b7937]282
[3ce0d440]283// #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous
[e7a8f65]284// ostype & ?|?( ostype & os, const char32_t s[] ) {
[6c5d92f]285// if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[e474cf09]286// fmt( os, "%ls", s );
[3ce0d440]287// return os;
288// } // ?|?
289// #endif // ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 )
[d3b7937]290
[e7a8f65]291// ostype & ?|?( ostype & os, const wchar_t s[] ) {
[6c5d92f]292// if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[e474cf09]293// fmt( os, "%ls", s );
[3ce0d440]294// return os;
295// } // ?|?
296
[ae0c1c3]297 ostype & ?|?( ostype & os, const void * p ) with ( basic_ostream_table ) {
[6c5d92f]298 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[3ce0d440]299 fmt( os, "%p", p );
300 return os;
301 } // ?|?
[b12e4ad]302 OSTYPE_VOID_IMPL( os, const void * )
[3ce0d440]303
304 // manipulators
305 ostype & ?|?( ostype & os, ostype & (* manip)( ostype & ) ) {
[e474cf09]306 return manip( os );
[200fcb3]307 } // ?|?
[ae0c1c3]308 void ?|?( ostype & os, ostype & (* manip)( ostype & ) ) with ( basic_ostream_table ) {
[e474cf09]309 manip( os );
[6c5d92f]310 if ( getPrt$( os ) ) ends( os ); // something printed ?
311 setPrt$( os, false ); // turn off
[3ce0d440]312 } // ?|?
313
[ae0c1c3]314 ostype & nl( ostype & os ) with ( basic_ostream_table ) {
[9d362a0]315 (ostype &)(os | '\n');
[6c5d92f]316 setPrt$( os, false ); // turn off
317 setNL$( os, true );
[f5d9c37]318 return nosep( os ); // prepare for next line
[200fcb3]319 } // nl
320
[ae0c1c3]321 ostype & nonl( ostype & os ) with ( basic_ostream_table ) {
[6c5d92f]322 setPrt$( os, false ); // turn off
[3ce0d440]323 return os;
[200fcb3]324 } // nonl
[3ce0d440]325
[ae0c1c3]326 ostype & nlOn( ostype & os ) with ( basic_ostream_table ) {
[f5d9c37]327 nlOn( os ); // call void returning
[3ce0d440]328 return os;
[f5d9c37]329 } // nlOn
[3ce0d440]330
[ae0c1c3]331 ostype & nlOff( ostype & os ) with ( basic_ostream_table ) {
[f5d9c37]332 nlOff( os ); // call void returning
[3ce0d440]333 return os;
[f5d9c37]334 } // nlOff
[6de9f4a]335
[ae0c1c3]336 ostype & sepVal( ostype & os ) with ( basic_ostream_table ) {
[f5d9c37]337 return (ostype &)(os | sepGet( os ));
338 } // sepVal
339
[ae0c1c3]340 ostype & sepTupleVal( ostype & os ) with ( basic_ostream_table ) {
[f5d9c37]341 return os | sepGetTuple( os );
342 } // sepTupleVal
343
[ae0c1c3]344 ostype & sep( ostype & os ) with ( basic_ostream_table ) {
[f5d9c37]345 sep( os ); // call void returning
[3ce0d440]346 return os;
[f5d9c37]347 } // sep
[b6dc097]348
[ae0c1c3]349 ostype & nosep( ostype & os ) with ( basic_ostream_table ) {
[f5d9c37]350 nosep( os ); // call void returning
[3ce0d440]351 return os;
[f5d9c37]352 } // nosep
[cf16f94]353
[ae0c1c3]354 ostype & sepOn( ostype & os ) with ( basic_ostream_table ) {
[f5d9c37]355 sepOn( os ); // call void returning
[200fcb3]356 return os;
[f5d9c37]357 } // sepOn
[200fcb3]358
[ae0c1c3]359 ostype & sepOff( ostype & os ) with ( basic_ostream_table ) {
[f5d9c37]360 sepOff( os ); // call void returning
[200fcb3]361 return os;
[f5d9c37]362 } // sepOff
[85d8153]363} // distribution
[e474cf09]364
[c443d1d]365// tuples
[fd54fef]366forall( ostype &, T, Params... | writeable( T, ostype ) | { ostype & ?|?( ostype &, Params ); } ) {
[ae0c1c3]367 ostype & ?|?( ostype & os, T arg, Params rest ) with ( basic_ostream_table ) {
[9d362a0]368 (ostype &)(os | arg); // print first argument
[6c5d92f]369 sepSetCur$( os, sepGetTuple( os ) ); // switch to tuple separator
[9d362a0]370 (ostype &)(os | rest); // print remaining arguments
[6c5d92f]371 sepSetCur$( os, sepGet( os ) ); // switch to regular separator
[200fcb3]372 return os;
373 } // ?|?
[ae0c1c3]374 void ?|?( ostype & os, T arg, Params rest ) with ( basic_ostream_table ) {
[65240bb]375 // (ostype &)(?|?( os, arg, rest )); ends( os );
[9d362a0]376 (ostype &)(os | arg); // print first argument
[6c5d92f]377 sepSetCur$( os, sepGetTuple( os ) ); // switch to tuple separator
[9d362a0]378 (ostype &)(os | rest); // print remaining arguments
[6c5d92f]379 sepSetCur$( os, sepGet( os ) ); // switch to regular separator
[65240bb]380 ends( os );
[200fcb3]381 } // ?|?
382} // distribution
[c443d1d]383
[61c7239]384// writes the range [begin, end) to the given stream
[fd54fef]385forall( ostype &, elt_type | writeable( elt_type, ostype ), iterator_type | iterator( iterator_type, elt_type ) ) {
[61c7239]386 void write( iterator_type begin, iterator_type end, ostype & os ) {
387 void print( elt_type i ) { os | i; }
388 for_each( begin, end, print );
389 } // ?|?
390
391 void write_reverse( iterator_type begin, iterator_type end, ostype & os ) {
392 void print( elt_type i ) { os | i; }
393 for_each_reverse( begin, end, print );
394 } // ?|?
395} // distribution
396
[8d321f9]397// *********************************** manipulators ***********************************
[3c573e9]398
[8d321f9]399// *********************************** integral ***********************************
[3c573e9]400
401static const char * shortbin[] = { "0", "1", "10", "11", "100", "101", "110", "111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" };
402static const char * longbin[] = { "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" };
403
404// Default prefix for non-decimal prints is 0b, 0, 0x.
[94d2544]405#define INTEGRAL_FMT_IMPL( T, IFMTNP, IFMTP ) \
[85d8153]406forall( ostype & | basic_ostream( ostype ) ) { \
[ae0c1c3]407 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) with ( basic_ostream_table ) { \
[6c5d92f]408 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); \
[3c573e9]409\
410 if ( f.base == 'b' || f.base == 'B' ) { /* bespoke binary format */ \
[7fd71c7]411 int bits = high1( f.val ); /* position of most significant bit */ \
412 if ( bits == 0 ) bits = 1; /* 0 value => force one bit to print */ \
[c7978c0]413 int spaces; \
[3c573e9]414 if ( ! f.flags.left ) { /* right justified ? */ \
415 /* Note, base prefix then zero padding or spacing then prefix. */ \
[c7978c0]416 if ( f.flags.pc ) { \
417 spaces = f.wd - f.pc; \
418 if ( ! f.flags.nobsdp ) { spaces -= 2; } /* base prefix takes space */ \
419 if ( spaces > 0 ) fmt( os, "%*s", spaces, " " ); /* space pad */ \
[3c573e9]420 if ( ! f.flags.nobsdp ) { fmt( os, "0%c", f.base ); } \
[c7978c0]421 spaces = f.pc - bits; \
[3c573e9]422 if ( spaces > 0 ) fmt( os, "%0*d", spaces, 0 ); /* zero pad */ \
423 } else { \
[c7978c0]424 spaces = f.wd - bits; \
425 if ( ! f.flags.nobsdp ) { spaces -= 2; } /* base prefix takes space */ \
426 if ( f.flags.pad0 ) { \
427 if ( ! f.flags.nobsdp ) { fmt( os, "0%c", f.base ); } \
428 if ( spaces > 0 ) fmt( os, "%0*d", spaces, 0 ); /* zero pad */ \
429 } else { \
430 if ( spaces > 0 ) fmt( os, "%*s", spaces, " " ); /* space pad */ \
431 if ( ! f.flags.nobsdp ) { fmt( os, "0%c", f.base ); } \
432 } /* if */ \
433 } /* if */ \
434 } else { \
435 if ( ! f.flags.nobsdp ) fmt( os, "0%c", f.base ); \
436 if ( f.flags.pc ) { \
437 spaces = f.pc - bits; \
438 if ( spaces > 0 ) fmt( os, "%0*d", spaces, 0 ); /* zero pad */ \
439 spaces = f.wd - f.pc; \
440 } else { /* pad0 flag ignored with left flag */ \
441 spaces = f.wd - bits; \
[3c573e9]442 } /* if */ \
[c7978c0]443 if ( ! f.flags.nobsdp ) { spaces -= 2; } /* base prefix takes space */ \
[3c573e9]444 } /* if */ \
[fd4d3017]445 int shift = floor( bits - 1, 4 ); \
[3c573e9]446 typeof( f.val ) temp = f.val; \
447 fmt( os, "%s", shortbin[(temp >> shift) & 0xf] ); \
448 for () { \
449 shift -= 4; \
450 if ( shift < 0 ) break; \
451 temp = f.val; \
452 fmt( os, "%s", longbin[(temp >> shift) & 0xf] ); \
453 } /* for */ \
454 if ( f.flags.left && spaces > 0 ) fmt( os, "%*s", spaces, " " ); \
455 return os; \
[2c60c644]456 } /* if */ \
[3c573e9]457\
458 char fmtstr[sizeof(IFMTP)]; /* sizeof includes '\0' */ \
459 if ( ! f.flags.pc ) memcpy( &fmtstr, IFMTNP, sizeof(IFMTNP) ); \
460 else memcpy( &fmtstr, IFMTP, sizeof(IFMTP) ); \
[0c51f9ad]461 int star = 5; /* position before first '*' */ \
[3c573e9]462\
463 /* Insert flags into spaces before '*', from right to left. */ \
464 if ( ! f.flags.nobsdp ) { fmtstr[star] = '#'; star -= 1; } \
465 if ( f.flags.left ) { fmtstr[star] = '-'; star -= 1; } \
[2c60c644]466 if ( f.flags.sign ) { fmtstr[star] = '+'; star -= 1; } \
[3c573e9]467 if ( f.flags.pad0 && ! f.flags.pc ) { fmtstr[star] = '0'; star -= 1; } \
[0c51f9ad]468 fmtstr[star] = '\''; star -= 1; /* locale */ \
[3c573e9]469 fmtstr[star] = '%'; \
[09a767e]470\
471 /* Special case printing 0 in hexadecimal as printf does not put the base. */ \
472 if ( (f.base == 'x' | f.base == 'X') && ! f.flags.nobsdp && f.val == 0 ) { \
473 fmt( os, f.base == 'x' ? "0x" : "0X" ); \
474 f.wd -= 2; \
475 if ( f.wd < 0 ) f.wd = 1; \
476 } /* if */ \
[3c573e9]477\
478 if ( ! f.flags.pc ) { /* no precision */ \
479 fmtstr[sizeof(IFMTNP)-2] = f.base; /* sizeof includes '\0' */ \
[2c60c644]480 /* printf( "%s %c\n", &fmtstr[star], f.base ); */ \
[3c573e9]481 fmt( os, &fmtstr[star], f.wd, f.val ); \
482 } else { /* precision */ \
483 fmtstr[sizeof(IFMTP)-2] = f.base; /* sizeof includes '\0' */ \
[2c60c644]484 /* printf( "%s %c\n", &fmtstr[star], f.base ); */ \
[3c573e9]485 fmt( os, &fmtstr[star], f.wd, f.pc, f.val ); \
486 } /* if */ \
487 return os; \
488 } /* ?|? */ \
[b12e4ad]489 OSTYPE_VOID_IMPL( os, _Ostream_Manip(T) ) \
[3c573e9]490} // distribution
491
[94d2544]492INTEGRAL_FMT_IMPL( signed char, " *hh ", " *.*hh " )
493INTEGRAL_FMT_IMPL( unsigned char, " *hh ", " *.*hh " )
494INTEGRAL_FMT_IMPL( signed short int, " *h ", " *.*h " )
495INTEGRAL_FMT_IMPL( unsigned short int, " *h ", " *.*h " )
496INTEGRAL_FMT_IMPL( signed int, " * ", " *.* " )
497INTEGRAL_FMT_IMPL( unsigned int, " * ", " *.* " )
498INTEGRAL_FMT_IMPL( signed long int, " *l ", " *.*l " )
499INTEGRAL_FMT_IMPL( unsigned long int, " *l ", " *.*l " )
500INTEGRAL_FMT_IMPL( signed long long int, " *ll ", " *.*ll " )
501INTEGRAL_FMT_IMPL( unsigned long long int, " *ll ", " *.*ll " )
[bd5b443]502
[2c60c644]503
504#if defined( __SIZEOF_INT128__ )
505// Default prefix for non-decimal prints is 0b, 0, 0x.
[85d8153]506forall( ostype & | basic_ostream( ostype ) )
[2c60c644]507static inline void base_128( ostype & os, unsigned int128 val, unsigned int128 power, _Ostream_Manip(uint64_t) & f, unsigned int maxdig, unsigned int bits, unsigned int cnt = 0 ) {
508 int wd = 1; // f.wd is never 0 because 0 implies left-pad
509 if ( val > power ) { // subdivide value into printable 64-bit values
510 base_128( os, val / power, power, f, maxdig, bits, cnt + 1 ); // recursive
511 f.val = val % power;
[ac9ba12]512 if ( cnt == 1 && f.flags.left ) { wd = f.wd; f.wd = maxdig; } // copy f.wd and reset for printing middle chunk
[7d9bbef]513 // printf( "R val:%#lx(%lu) wd:%u pc:%u base:%c neg:%d pc:%d left:%d nobsdp:%d sign:%d pad0:%d\n",
[737bf73]514 // f.val, f.val, f.wd, f.pc, f.base, f.flags.neg, f.flags.pc, f.flags.left, f.flags.nobsdp, f.flags.sign, f.flags.pad0 );
[2c60c644]515 (ostype &)(os | f);
516 if ( cnt == 1 ) {
[ac9ba12]517 if ( f.flags.left ) { wd -= maxdig; f.wd = wd < 0 ? 1 : wd; } // update and restore f.wd for printing end chunk
[f5d9c37]518 nosep( os ); // no seperator between chunks
[2c60c644]519 } // if
[ac9ba12]520 } else { // print start chunk
[2c60c644]521 f.val = val;
522 // f.pc is unsigned => use wd
523 if ( f.flags.pc && f.pc > maxdig * cnt ) { wd = f.pc - maxdig * cnt; f.pc = wd < 0 ? 0 : wd; }
524 else { f.flags.pc = false; f.pc = 0; }
525
526 if ( ! f.flags.left ) { // right justify
527 wd = f.wd - maxdig * cnt;
528 f.wd = wd < 0 ? 1 : wd;
529 wd = maxdig;
530 } else { // left justify
531 if ( cnt != 0 ) { // value >= 2^64 ?
532 unsigned int dig, bs = 0;
[ac9ba12]533 // compute size of prefix digits and base
[2c60c644]534 if ( f.base == 'd' || f.base == 'u' ) { // no base prefix
535 dig = ceil( log10( f.val ) ); // use floating-point
536 if ( f.base == 'd' && (f.flags.neg || f.flags.sign) ) bs = 1; // sign ?
537 } else {
[53fd995]538 dig = ceiling_div( high1( f.val ), bits );
[2c60c644]539 if ( ! f.flags.nobsdp ) { // base prefix ?
540 if ( f.base == 'o' ) {
541 // 0 prefix for octal is not added for precision with leading zero
542 if ( f.pc <= dig ) bs = 1; // 1 character prefix
543 } else bs = 2; // 2 character prefix
544 } // if
545 } // if
546 wd = f.wd - (f.pc > dig ? f.pc : dig) - bs; // precision > leading digits ?
547 if ( wd < 0 ) wd = 1;
548 f.wd = 1;
549 } // if
550 // all manipulators handled implicitly for value < 2^64
551 } // if
552 // prior checks ensure wd not negative
553
554 if ( f.flags.neg ) f.val = -f.val;
[7d9bbef]555 // printf( "L val:%#lx(%lu) wd:%u pc:%u base:%c neg:%d pc:%d left:%d nobsdp:%d sign:%d pad0:%d\n",
[737bf73]556 // f.val, f.val, f.wd, f.pc, f.base, f.flags.neg, f.flags.pc, f.flags.left, f.flags.nobsdp, f.flags.sign, f.flags.pad0 );
[2c60c644]557 (ostype &)(os | f);
558
[ac9ba12]559 // remaining middle and end chunks are padded with 0s on the left
[2c60c644]560 if ( ! f.flags.left ) { f.flags.pad0 = true; f.flags.pc = false; } // left pad with 0s
561 else { f.pc = maxdig; f.flags.pc = true; } // left pad with precision
[ac9ba12]562
[f5d9c37]563 if ( cnt != 0 ) nosep( os ); // no seperator between chunks
[ac9ba12]564 f.wd = wd; // reset f.wd for next chunk
565 f.flags.sign = false; // no leading +/- sign
566 f.flags.nobsdp = true; // no leading base prefix
[2c60c644]567 } // if
568} // base_128
569
[94d2544]570#define INTEGRAL_FMT_IMPL128( T ) \
[85d8153]571forall( ostype & | basic_ostream( ostype ) ) { \
[2c60c644]572 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
573 _Ostream_Manip(uint64_t) fmt; \
574 fmt.[wd, pc, base, all] = f.[wd, pc, base, all]; \
575 if ( f.base == 'b' | f.base == 'B' ) { \
576 base_128( os, f.val, (unsigned int128)1 << 64, fmt, 64, 1 ); \
577 } else if ( f.base == 'o' ) { \
578 base_128( os, f.val, (unsigned int128)1 << 63, fmt, 21, 3 ); \
579 } else if ( f.base == 'd' || f.base == 'u' ) { \
580 if ( f.base == 'd' && f.val < 0 ) { f.val = -f.val; fmt.flags.neg = true; } \
581 base_128( os, f.val, (unsigned int128)10_000_000_000_000_000_000UL, fmt, 19, 0 ); \
582 } else { \
583 base_128( os, f.val, (unsigned int128)1 << 64, fmt, 16, 4 ); \
584 } /* if */ \
585 return os; \
586 } /* ?|? */ \
[b12e4ad]587 OSTYPE_VOID_IMPL( os, _Ostream_Manip(T) ) \
[2c60c644]588} // distribution
589
[94d2544]590INTEGRAL_FMT_IMPL128( int128 )
591INTEGRAL_FMT_IMPL128( unsigned int128 )
[2c60c644]592#endif // __SIZEOF_INT128__
[bd5b443]593
[8d321f9]594// *********************************** floating point ***********************************
[3c573e9]595
[fd4c009]596static const char *suffixes[] = {
597 "y", "z", "a", "f", "p", "n", "u", "m", "",
598 "K", "M", "G", "T", "P", "E", "Z", "Y"
[737bf73]599};
[fd4c009]600#define SUFFIXES_START (-24) /* Smallest power for which there is a suffix defined. */
601#define SUFFIXES_END (SUFFIXES_START + (int)((sizeof(suffixes) / sizeof(char *) - 1) * 3))
602
[94d2544]603#define PRINT_WITH_DP2( os, format, ... ) \
[3c573e9]604 { \
[fd4c009]605 if ( ! f.flags.eng ) { \
606 len = snprintf( buf, size, format, ##__VA_ARGS__ ); \
[bcbc7e4]607 if ( isfinite( f.val ) && ! f.flags.nobsdp ) { /* if number, print decimal point when no fraction or exponent */ \
[09a767e]608 for ( i = 0; i < len && buf[i] != '.' && buf[i] != 'e' && buf[i] != 'E' && \
[bcbc7e4]609 buf[i] != 'p' && buf[i] != 'P'; i += 1 ); /* decimal point or scientific ? */ \
[fd4c009]610 if ( i == len ) { \
611 if ( ! f.flags.left ) { \
612 buf[i] = '.'; buf[i + 1] = '\0'; \
613 if ( buf[0] == ' ' ) bufbeg = 1; /* decimal point within width */ \
614 } else { \
615 for ( i = 0; i < len && buf[i] != ' '; i += 1 ); /* trailing blank ? */ \
616 buf[i] = '.'; \
617 if ( i == len ) buf[i + 1] = '\0'; \
618 } /* if */ \
[3c573e9]619 } /* if */ \
620 } /* if */ \
[fd4c009]621 } else { \
622 int exp10, len2; \
623 eng( f.val, f.pc, exp10 ); /* changes arguments */ \
[b1e614f4]624 /* printf( "%g %d %d %d %s\n", f.val, f.wd, f.pc, exp10, format ); */ \
[fd4c009]625 if ( ! f.flags.left && f.wd > 1 ) { \
[b1e614f4]626 /* Exponent size: 'e', optional minus sign, number of digits: log10(0) => undefined */ \
627 f.wd -= 1 + (exp10 < 0 ? 1 : 0) + lrint( floor( exp10 == 0 ? 0 : log10( abs( exp10 ) ) ) ) + 1; \
[fd4c009]628 if ( f.wd < 1 ) f.wd = 1; \
629 } /* if */ \
630 len = snprintf( buf, size, format, ##__VA_ARGS__ ); \
631 if ( f.flags.left ) { \
632 for ( len -= 1; len > 0 && buf[len] == ' '; len -= 1 ); \
633 len += 1; \
634 } /* if */ \
635 if ( ! f.flags.nobsdp || (exp10 < SUFFIXES_START) || (exp10 > SUFFIXES_END) ) { \
[fb907d3]636 len2 = snprintf( &buf[len], size - len, "e%d", (int)exp10 /* ambiguity with function exp10 */ ); \
[fd4c009]637 } else { \
638 len2 = snprintf( &buf[len], size - len, "%s", suffixes[(exp10 - SUFFIXES_START) / 3] ); \
639 } /* if */ \
640 if ( f.flags.left && len + len2 < f.wd ) buf[len + len2] = ' '; \
[3c573e9]641 } /* if */ \
642 fmt( os, "%s", &buf[bufbeg] ); \
643 }
644
[94d2544]645#define FLOATING_POINT_FMT_IMPL( T, DFMTNP, DFMTP ) \
[85d8153]646forall( ostype & | basic_ostream( ostype ) ) { \
[fd4c009]647 static void eng( T &value, int & pc, int & exp10 ) { \
648 exp10 = lrint( floor( log10( abs( value ) ) ) ); /* round to desired precision */ \
649 if ( exp10 < 0 ) exp10 -= 2; \
650 exp10 = floor( exp10, 3 ); \
651 value *= pow( 10.0, -exp10 ); \
[0d49efb]652 if ( pc < 0 ) pc = 3; \
[fd4c009]653 } /* eng */ \
654\
[ae0c1c3]655 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) with ( basic_ostream_table ) { \
[fd4c009]656 enum { size = 48 }; \
657 char buf[size]; \
658 int bufbeg = 0, i, len; \
659\
[6c5d92f]660 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); \
[fd4c009]661 char fmtstr[sizeof(DFMTP) + 8]; /* sizeof includes '\0' */ \
[3c573e9]662 if ( ! f.flags.pc ) memcpy( &fmtstr, DFMTNP, sizeof(DFMTNP) ); \
663 else memcpy( &fmtstr, DFMTP, sizeof(DFMTP) ); \
[b5f17e14]664 int star = 5; /* position before first '*' */ \
[3c573e9]665\
666 /* Insert flags into spaces before '*', from right to left. */ \
667 if ( f.flags.left ) { fmtstr[star] = '-'; star -= 1; } \
668 if ( f.flags.sign ) { fmtstr[star] = '+'; star -= 1; } \
669 if ( f.flags.pad0 ) { fmtstr[star] = '0'; star -= 1; } \
[b5f17e14]670 fmtstr[star] = '\''; star -= 1; /* locale */ \
[3c573e9]671 fmtstr[star] = '%'; \
672\
673 if ( ! f.flags.pc ) { /* no precision */ \
674 fmtstr[sizeof(DFMTNP)-2] = f.base; /* sizeof includes '\0' */ \
[b1e614f4]675 /* printf( "%g %d %s\n", f.val, f.wd, &fmtstr[star] ); */ \
[94d2544]676 PRINT_WITH_DP2( os, &fmtstr[star], f.wd, f.val ) \
[3c573e9]677 } else { /* precision */ \
678 fmtstr[sizeof(DFMTP)-2] = f.base; /* sizeof includes '\0' */ \
679 /* printf( "%g %d %d %s\n", f.val, f.wd, f.pc, &fmtstr[star] ); */ \
[94d2544]680 PRINT_WITH_DP2( os, &fmtstr[star], f.wd, f.pc, f.val ) \
[3c573e9]681 } /* if */ \
682 return os; \
683 } /* ?|? */ \
[e3fea42]684\
[b12e4ad]685 OSTYPE_VOID_IMPL( os, _Ostream_Manip(T) ) \
[3c573e9]686} // distribution
687
[94d2544]688FLOATING_POINT_FMT_IMPL( double, " * ", " *.* " )
689FLOATING_POINT_FMT_IMPL( long double, " *L ", " *.*L " )
[3c573e9]690
[8d321f9]691// *********************************** character ***********************************
[3c573e9]692
[85d8153]693forall( ostype & | basic_ostream( ostype ) ) {
[ae0c1c3]694 ostype & ?|?( ostype & os, _Ostream_Manip(char) f ) with ( basic_ostream_table ) {
[4f37255]695 if ( f.base != 'c' ) { // bespoke binary/octal/hex format
[3c573e9]696 _Ostream_Manip(unsigned char) fmtuc @= { f.val, f.wd, f.pc, f.base, {'\0'} };
697 fmtuc.flags.pc = f.flags.pc;
698 fmtuc.flags.nobsdp = f.flags.nobsdp;
699// os | fmtuc | nonl;
700 (ostype &)(os | fmtuc);
701 return os;
702 } // if
703
[6c5d92f]704 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[3c573e9]705
706 #define CFMTNP "% * "
[4f37255]707 char fmtstr[sizeof(CFMTNP)]; // sizeof includes '\0'
[3c573e9]708 memcpy( &fmtstr, CFMTNP, sizeof(CFMTNP) );
[4f37255]709 int star = 1; // position before first '*'
[3c573e9]710
711 // Insert flags into spaces before '*', from right to left.
712 if ( f.flags.left ) { fmtstr[star] = '-'; star -= 1; }
713 fmtstr[star] = '%';
714
[4f37255]715 fmtstr[sizeof(CFMTNP)-2] = f.base; // sizeof includes '\0'
[3c573e9]716 // printf( "%d %s\n", f.wd, &fmtstr[star] );
717 fmt( os, &fmtstr[star], f.wd, f.val );
718 return os;
719 } // ?|?
[b12e4ad]720 OSTYPE_VOID_IMPL( os, _Ostream_Manip(char) )
[3c573e9]721} // distribution
722
[8d321f9]723// *********************************** C string ***********************************
[3c573e9]724
[85d8153]725forall( ostype & | basic_ostream( ostype ) ) {
[ae0c1c3]726 ostype & ?|?( ostype & os, _Ostream_Manip(const char *) f ) with ( basic_ostream_table ) {
[3c573e9]727 if ( ! f.val ) return os; // null pointer ?
728
729 if ( f.base != 's' ) { // bespoke binary/octal/hex format
730 _Ostream_Manip(unsigned char) fmtuc @= { 0, f.wd, f.pc, f.base, {'\0'} };
731 fmtuc.flags.pc = f.flags.pc;
732 fmtuc.flags.nobsdp = f.flags.nobsdp;
[ebf8ca5]733 for ( i; 0 ~ @ : @; f.val[i] != '\0' ) {
[3c573e9]734 fmtuc.val = f.val[i];
735// os | fmtuc | nonl;
736 (ostype &)(os | fmtuc);
737 } // for
738 return os;
739 } // if
740
[f5d9c37]741 if ( f.val[0] != '\0' && // null string => no leading separator
742 sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
[3c573e9]743
744 #define SFMTNP "% * "
745 #define SFMTP "% *.* "
746 char fmtstr[sizeof(SFMTP)]; // sizeof includes '\0'
747 if ( ! f.flags.pc ) memcpy( &fmtstr, SFMTNP, sizeof(SFMTNP) );
748 else memcpy( &fmtstr, SFMTP, sizeof(SFMTP) );
749 int star = 1; // position before first '*'
750
751 // Insert flags into spaces before '*', from right to left.
752 if ( f.flags.left ) { fmtstr[star] = '-'; star -= 1; }
753 fmtstr[star] = '%';
754
755 if ( ! f.flags.pc ) { // no precision
756 // printf( "%d %s\n", f.wd, &fmtstr[star] );
757 fmtstr[sizeof(SFMTNP)-2] = f.base; // sizeof includes '\0'
758 fmt( os, &fmtstr[star], f.wd, f.val );
759 } else { // precision
760 fmtstr[sizeof(SFMTP)-2] = f.base; // sizeof includes '\0'
761 // printf( "%d %d %s\n", f.wd, f.pc, &fmtstr[star] );
762 fmt( os, &fmtstr[star], f.wd, f.pc, f.val );
763 } // if
[f5d9c37]764 if ( f.val[0] == '\0' ) { nosep( os ); } // null string => no trailing separator
[3c573e9]765 return os;
766 } // ?|?
[b12e4ad]767 OSTYPE_VOID_IMPL( os, _Ostream_Manip(const char *) )
[3c573e9]768} // distribution
769
770
[8d321f9]771// *********************************** istream ***********************************
[3c573e9]772
[e56cfdb0]773
[c015e2d]774#define FALSE "false"
775#define TRUE "true"
776
[ef3ac46]777forall( istype & | basic_istream( istype ) ) {
[ae0c1c3]778 istype & ?|?( istype & is, bool & b ) with ( basic_istream_table ) {
[c015e2d]779 int len = -1; // len not set if no match
[04138cc]780 fmt( is, " " ); // remove leading whitespace
781 fmt( is, FALSE "%n", &len ); // try false, returns 0
[d796be70]782 if ( len != sizeof( FALSE ) - 1 ) { // -1 removes null terminate
[04138cc]783 if ( eof( is ) ) throwResume ExceptionInst( end_of_file );
784 fmt( is, " " ); // remove leading whitespace
785 fmt( is, TRUE "%n", &len ); // try true, returns 0
[c015e2d]786 if ( len != sizeof( TRUE ) - 1 ) throwResume ExceptionInst( missing_data );
[2f4c910]787 b = true;
788 } else {
789 b = false;
[3ce0d440]790 } // if
791 return is;
792 } // ?|?
793
[ae0c1c3]794 istype & ?|?( istype & is, char & c ) with ( basic_istream_table ) {
[0efb269]795 char temp;
796 for () {
[fd5d251]797 int args = fmt( is, "%c", &temp ); // can be called with EOF on
[3ac5fd8]798 if ( eof( is ) ) throwResume ExceptionInst( end_of_file );
799 assert( args == 1 ); // if not EOF => a single character must be read
[0efb269]800 // do not overwrite parameter with newline unless appropriate
[c8371b5]801 if ( temp != '\n' || getANL$( is ) ) { c = temp; break; }
[0efb269]802 } // for
[3ce0d440]803 return is;
804 } // ?|?
805
[ae0c1c3]806 istype & ?|?( istype & is, signed char & sc ) with ( basic_istream_table ) {
[3ac5fd8]807 int args = fmt( is, "%hhi", &sc ); // can be multiple characters (100)
808 if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
[fd5d251]809 if ( eof( is ) && args != 1 ) throwResume ExceptionInst( end_of_file );
[3ce0d440]810 return is;
811 } // ?|?
812
[ae0c1c3]813 istype & ?|?( istype & is, unsigned char & usc ) with ( basic_istream_table ) {
[3ac5fd8]814 int args = fmt( is, "%hhi", &usc ); // can be multiple characters (-100)
[714e206]815 if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
[fd5d251]816 if ( eof( is ) && args != 1 ) throwResume ExceptionInst( end_of_file );
[3ce0d440]817 return is;
818 } // ?|?
819
[ae0c1c3]820 istype & ?|?( istype & is, short int & si ) with ( basic_istream_table ) {
[fd5d251]821 int args = fmt( is, "%hi", &si ); // can be called with EOF on
[714e206]822 if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
[fd5d251]823 if ( eof( is ) && args != 1 ) throwResume ExceptionInst( end_of_file );
[3ce0d440]824 return is;
825 } // ?|?
826
[ae0c1c3]827 istype & ?|?( istype & is, unsigned short int & usi ) with ( basic_istream_table ) {
[fd5d251]828 int args = fmt( is, "%hi", &usi ); // can be called with EOF on
[714e206]829 if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
[fd5d251]830 if ( eof( is ) && args != 1 ) throwResume ExceptionInst( end_of_file );
[3ce0d440]831 return is;
832 } // ?|?
833
[ae0c1c3]834 istype & ?|?( istype & is, int & i ) with ( basic_istream_table ) {
[fd5d251]835 int args = fmt( is, "%i", &i ); // can be called with EOF on
[714e206]836 if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
[fd5d251]837 if ( eof( is ) && args != 1 ) throwResume ExceptionInst( end_of_file );
[3ce0d440]838 return is;
839 } // ?|?
840
[ae0c1c3]841 istype & ?|?( istype & is, unsigned int & ui ) with ( basic_istream_table ) {
[fd5d251]842 int args = fmt( is, "%i", &ui ); // can be called with EOF on
[714e206]843 if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
[fd5d251]844 if ( eof( is ) && args != 1 ) throwResume ExceptionInst( end_of_file );
[3ce0d440]845 return is;
846 } // ?|?
847
[ae0c1c3]848 istype & ?|?( istype & is, long int & li ) with ( basic_istream_table ) {
[fd5d251]849 int args = fmt( is, "%li", &li ); // can be called with EOF on
[714e206]850 if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
[fd5d251]851 if ( eof( is ) && args != 1 ) throwResume ExceptionInst( end_of_file );
[3ce0d440]852 return is;
853 } // ?|?
854
[ae0c1c3]855 istype & ?|?( istype & is, unsigned long int & ulli ) with ( basic_istream_table ) {
[fd5d251]856 int args = fmt( is, "%li", &ulli ); // can be called with EOF on
[714e206]857 if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
[fd5d251]858 if ( eof( is ) && args != 1 ) throwResume ExceptionInst( end_of_file );
[3ce0d440]859 return is;
860 } // ?|?
861
[ae0c1c3]862 istype & ?|?( istype & is, long long int & lli ) with ( basic_istream_table ) {
[fd5d251]863 int args = fmt( is, "%lli", &lli ); // can be called with EOF on
[714e206]864 if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
[fd5d251]865 if ( eof( is ) && args != 1 ) throwResume ExceptionInst( end_of_file );
[3ce0d440]866 return is;
867 } // ?|?
868
[ae0c1c3]869 istype & ?|?( istype & is, unsigned long long int & ulli ) with ( basic_istream_table ) {
[fd5d251]870 int args = fmt( is, "%lli", &ulli ); // can be called with EOF on
[714e206]871 if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
[fd5d251]872 if ( eof( is ) && args != 1 ) throwResume ExceptionInst( end_of_file );
[3ce0d440]873 return is;
874 } // ?|?
875
[ef3ac46]876 #if defined( __SIZEOF_INT128__ )
[e474cf09]877 istype & ?|?( istype & is, int128 & llli ) {
878 return (istype &)(is | (unsigned int128 &)llli);
879 } // ?|?
[fe68bdf]880
[ae0c1c3]881 istype & ?|?( istype & is, unsigned int128 & ullli ) with ( basic_istream_table ) {
[fe68bdf]882 char s[40];
883 bool sign = false;
884
885 if ( fmt( is, " %[-]", s ) == 1 ) sign = true; // skip whitespace, negative sign ?
886 // If the input is too large, the value returned is undefined. If there is no input, no value is returned
887 if ( fmt( is, "%39[0-9]%*[0-9]", s ) == 1 ) { // take first 39 characters, ignore remaining
[e474cf09]888 ullli = 0;
[ebf8ca5]889 for ( i; 0 ~ @ : @; s[i] != '\0' ) {
[e474cf09]890 ullli = ullli * 10 + s[i] - '0';
[fe68bdf]891 } // for
[e474cf09]892 if ( sign ) ullli = -ullli;
[3ac5fd8]893 } // if
[fe68bdf]894 return is;
895 } // ?|?
[ef3ac46]896 #endif // __SIZEOF_INT128__
[3ce0d440]897
[ae0c1c3]898 istype & ?|?( istype & is, float & f ) with ( basic_istream_table ) {
[fd5d251]899 int args = fmt( is, "%f", &f ); // can be called with EOF on
[714e206]900 if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
[fd5d251]901 if ( eof( is ) && args != 1 ) throwResume ExceptionInst( end_of_file );
[3ce0d440]902 return is;
903 } // ?|?
904
[ae0c1c3]905 istype & ?|?( istype & is, double & d ) with ( basic_istream_table ) {
[fd5d251]906 int args = fmt( is, "%lf", &d ); // can be called with EOF on
[714e206]907 if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
[fd5d251]908 if ( eof( is ) && args != 1 ) throwResume ExceptionInst( end_of_file );
[3ce0d440]909 return is;
910 } // ?|?
911
[ae0c1c3]912 istype & ?|?( istype & is, long double & ld ) with ( basic_istream_table ) {
[fd5d251]913 int args = fmt( is, "%Lf", &ld ); // can be called with EOF on
[714e206]914 if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
[fd5d251]915 if ( eof( is ) && args != 1 ) throwResume ExceptionInst( end_of_file );
[3ce0d440]916 return is;
917 } // ?|?
918
[ae0c1c3]919 istype & ?|?( istype & is, float _Complex & fc ) with ( basic_istream_table ) {
[3ce0d440]920 float re, im;
[fd5d251]921 int args = fmt( is, "%f%fi", &re, &im ); // can be called with EOF on
[714e206]922 if ( ! eof( is ) && args != 2 ) throwResume ExceptionInst( missing_data );
[fd5d251]923 if ( eof( is ) && args != 2 ) throwResume ExceptionInst( end_of_file );
[3ce0d440]924 fc = re + im * _Complex_I;
925 return is;
926 } // ?|?
927
[ae0c1c3]928 istype & ?|?( istype & is, double _Complex & dc ) with ( basic_istream_table ) {
[3ce0d440]929 double re, im;
[fd5d251]930 int args = fmt( is, "%lf%lfi", &re, &im ); // can be called with EOF on
[714e206]931 if ( ! eof( is ) && args != 2 ) throwResume ExceptionInst( missing_data );
[fd5d251]932 if ( eof( is ) && args != 2 ) throwResume ExceptionInst( end_of_file );
[3ce0d440]933 dc = re + im * _Complex_I;
934 return is;
935 } // ?|?
936
[ae0c1c3]937 istype & ?|?( istype & is, long double _Complex & ldc ) with ( basic_istream_table ) {
[3ce0d440]938 long double re, im;
[fd5d251]939 int args = fmt( is, "%Lf%Lfi", &re, &im ); // can be called with EOF on
[714e206]940 if ( ! eof( is ) && args != 2 ) throwResume ExceptionInst( missing_data );
[fd5d251]941 if ( eof( is ) && args != 2 ) throwResume ExceptionInst( end_of_file );
[3ce0d440]942 ldc = re + im * _Complex_I;
943 return is;
944 } // ?|?
945
[ae0c1c3]946 istype & ?|?( istype & is, const char fmt[] ) with ( basic_istream_table ) { // match text
[8c13ca8]947 size_t len = strlen( fmt );
[714e206]948 char fmtstr[len + 16];
949 strcpy( fmtstr, fmt ); // copy format and add %n
950 strcpy( &fmtstr[len], "%n" );
[c015e2d]951 len = -1;
[04138cc]952 // scanf cursor does not move if no match, so eof cannot be detected.
[fd5d251]953 fmt( is, fmtstr, &len ); // can be called with EOF on
954 if ( ! eof( is ) && len == -1 ) throwResume ExceptionInst( missing_data );
955 if ( eof( is ) && len == -1 ) throwResume ExceptionInst( end_of_file );
[0f107e4]956 return is;
957 } // ?|?
[04396aa]958
[3ce0d440]959 // manipulators
960 istype & ?|?( istype & is, istype & (* manip)( istype & ) ) {
961 return manip( is );
962 } // ?|?
[ff7f6d07]963
[e474cf09]964 void ?|?( istype & is, istype & (* manip)( istype & ) ) {
[f842032]965 manip( is );
[e474cf09]966 } // ?|?
[3ce0d440]967
[ae0c1c3]968 istype & nl( istype & is ) with ( basic_istream_table ) {
[3c5dee4]969 fmt( is, "%*[^\n]" ); // ignore characters to newline
[63e129c]970 if ( ! eof( is ) ) fmt( is, "%*c" ); // read newline
[3ce0d440]971 return is;
[200fcb3]972 } // nl
[0efb269]973
[ae0c1c3]974 istype & nlOn( istype & is ) with ( basic_istream_table ) {
[0efb269]975 nlOn( is ); // call void returning
976 return is;
977 } // nlOn
978
[ae0c1c3]979 istype & nlOff( istype & is ) with ( basic_istream_table ) {
[0efb269]980 nlOff( is ); // call void returning
981 return is;
982 } // nlOff
[ef3ac46]983} // distribution
[44574f2]984
[8d321f9]985// *********************************** manipulators ***********************************
[3c573e9]986
[ef3ac46]987forall( istype & | basic_istream( istype ) ) {
[ae0c1c3]988 istype & ?|?( istype & is, _Istream_Cskip f ) with ( basic_istream_table ) {
[3ac5fd8]989 if ( eof( is ) ) throwResume ExceptionInst( end_of_file );
[bf1cbde]990 if ( f.scanset ) {
991 int nscanset = strlen(f.scanset);
992 char fmtstr[ sizeof("%*[]") + nscanset ];
993 int pos = 0;
[e0dc038]994 strcpy( &fmtstr[pos], "%*[" ); pos += 3;
[bf1cbde]995 strcpy( &fmtstr[pos], f.scanset ); pos += nscanset;
[e0dc038]996 strcpy( &fmtstr[pos], "]" );
[714e206]997 fmt( is, fmtstr, "" ); // skip scanset, zero or more
[e0dc038]998 } else {
999 char ch;
1000 for ( f.wd ) { // skip N characters
[fd5d251]1001 int args = fmt( is, "%c", &ch ); // can be called with EOF on
[3ac5fd8]1002 if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
[e0dc038]1003 } // for
1004 } // if
[0f107e4]1005 return is;
1006 }
[e7a8f65]1007
[ae0c1c3]1008 istype & ?|?( istype & is, _Istream_Cquote f ) with( basic_istream_table, f.cstr ) {
[3ac5fd8]1009 if ( eof( is ) ) throwResume ExceptionInst( end_of_file );
[8c13ca8]1010 int args;
[5764204]1011 fini: {
[714e206]1012 char rfmt[5] = { ' ', delimiters[0], '%', 'n', '\0' };
1013 int len = -1; // may not be set in fmt
1014 args = fmt( is, rfmt, &len ); // remove leading whitespace and quote
1015 if ( eof( is ) || len == -1 ) break fini;
[5764204]1016
1017 // Change the remainder of the read into a getline by reseting the closing delimiter.
1018 if ( delimiters[1] != '\0' ) {
1019 delimiters[0] = delimiters[1];
1020 delimiters[1] = '\0';
[8c13ca8]1021 } // if
[5764204]1022 flags.delimiter = true;
1023 return is | *(_Istream_Cstr *)&f;
1024 } // fini
[baa1d5d]1025 // read failed => no pattern match => set string to null
1026 if ( ! flags.ignore && s != 0p && args == 0 ) s[0] = '\0';
[8c13ca8]1027 if ( args == 1 && eof( is ) ) { // data but scan ended at EOF
[768d091]1028 clearerr( is ); // => reset EOF => detect again on next read
[8c13ca8]1029 } // if
1030 return is;
1031 }
1032
[ae0c1c3]1033 istype & ?|?( istype & is, _Istream_Cstr f ) with( basic_istream_table, f.cstr ) {
1034 assert(eof);
[3ac5fd8]1035 if ( eof( is ) ) throwResume ExceptionInst( end_of_file );
[e0dc038]1036 const char * scanset;
1037 size_t nscanset = 0;
[4aae2bd]1038 if ( flags.delimiter ) scanset = delimiters; // getline ?
[5764204]1039 else scanset = f.cstr.scanset;
[e0dc038]1040 if ( scanset ) nscanset = strlen( scanset );
[5ad2c6c7]1041
[e0dc038]1042 char fmtstr[nscanset + 32]; // storage for scanset and format codes
[e474cf09]1043 fmtstr[0] = '%';
[e0dc038]1044 int pos = 1;
1045 int args;
1046 bool check = true;
1047
[5764204]1048 if ( flags.ignore ) { check = false; fmtstr[1] = '*'; pos += 1; }
1049 int rwd = wd;
1050 if ( wd != -1 ) { // => just ignore versus ignore with width
[2fa0237]1051 // wd is buffer bytes available (for input chars + null terminator)
1052 // rwd is count of input chars
[e0dc038]1053 // no maximum width necessary because text ignored => width is read width
[5764204]1054 if ( flags.rwd ) check = false;
1055 else rwd = wd - 1;
1056 assert( rwd > 0 );
[e0dc038]1057 pos += sprintf( &fmtstr[pos], "%d", rwd );
[e474cf09]1058 } // if
[2f34fde]1059
[e0dc038]1060 if ( ! scanset ) { // %s, %*s, %ws, %*ws
[5764204]1061 // fprintf( stderr, "cstr %s\n", s );
[e0dc038]1062 strcpy( &fmtstr[pos], "s%n" );
1063 int len = 0; // may not be set in fmt
[5764204]1064 if ( flags.ignore ) args = fmt( is, fmtstr, &len ); // no string argument for '*'
1065 else args = fmt( is, fmtstr, s, &len );
[7b93027e]1066 // fprintf( stderr, "cstr %s %d %d %d\n", fmtstr, args, len, f.cstr.wd );
[737bf73]1067
1068 // No data read and eof is on => true eof so raise exception.
1069 if ( len == 0 && eof( is ) ) throwResume ExceptionInst( end_of_file );
1070
[e0dc038]1071 if ( check && len >= rwd && ! eof( is ) ) { // might not fit
[0860d9c]1072 char peek;
[e0dc038]1073 fmt( is, "%c", &peek ); // check for whitespace terminator
[8c13ca8]1074 // fprintf( stderr, "peek %d '%c'\n", args, peek );
[714e206]1075 if ( ! eof( is ) ) { // can only fail at eof
[a1a1f37d]1076 ungetc( peek, is );
[8c13ca8]1077 if ( ! isspace( peek ) ) throwResume ExceptionInst( cstring_length );
[e0dc038]1078 } // if
[0860d9c]1079 } // if
[3e4bf0d]1080 // FIX ME: CFA strings need to be modified to NOT change the argument for this case, then this can be removed.
[7b93027e]1081 //fprintf( stderr, "cstr %d %d %d %d '%s'\n", flags.ignore, args, len, eof( is ), s );
1082 //if ( ! flags.ignore && args == 0 ) s[0]= '\0'; // read failed => no pattern match => set string to null
[e0dc038]1083 } else {
[5764204]1084 if ( flags.delimiter ) { // getline
[e0dc038]1085 int len = 0; // may not be set in fmt
[30548de]1086 if ( delimiters[2] != '\0' ) { // (quote) read single character ?
[baa1d5d]1087 sprintf( &fmtstr[pos], "c%%n" );
1088 } else {
1089 sprintf( &fmtstr[pos], "[^%c]%%n", delimiters[0] );
1090 } // if
[5764204]1091 if ( flags.ignore ) args = fmt( is, fmtstr, &len ); // no string argument for '*'
1092 else args = fmt( is, fmtstr, s, &len );
[714e206]1093
[737bf73]1094 // No data read and eof is on => true eof so raise exception.
1095 if ( len == 0 && eof( is ) ) throwResume ExceptionInst( end_of_file );
1096
[e0dc038]1097 if ( check && len == rwd && ! eof( is ) ) { // might not fit
[5764204]1098 char peek;
1099 fmt( is, "%c", &peek ); // check for delimiter
[e0dc038]1100 if ( ! eof( is ) ) {
[5764204]1101 if ( peek != delimiters[0] ) {
[a1a1f37d]1102 ungetc( peek, is );
[8c13ca8]1103 throwResume ExceptionInst( cstring_length );
[e0dc038]1104 } // if
1105 } // if
[4aae2bd]1106 } else fmt( is, "%*c" ); // remove delimiter
[e0dc038]1107 } else {
1108 // incl %[xxx], %*[xxx], %w[xxx], %*w[xxx]
1109 // excl %[^xxx], %*[^xxx], %w[^xxx], %*w[^xxx]
[5764204]1110 sprintf( &fmtstr[pos], "[%s%s]%%n", flags.inex ? "^" : "", scanset );
1111 // fprintf( stderr, "incl/excl %s %d\n", fmtstr, wd );
[e0dc038]1112 int len = 0; // may not be set in fmt
[5764204]1113 if ( flags.ignore ) args = fmt( is, fmtstr, &len ); // no string argument for '*'
1114 else args = fmt( is, fmtstr, s, &len );
1115 // fprintf( stderr, "incl/excl %s \"%s\" %d %d %d %d %d %c\n", fmtstr, s, args, wd, len, eof( is ), check, s[wd] );
[737bf73]1116
1117 // No data read and eof is on => true eof so raise exception.
1118 if ( len == 0 && eof( is ) ) throwResume ExceptionInst( end_of_file );
1119
[e0dc038]1120 if ( check && len == rwd && ! eof( is ) ) { // might not fit
[8c13ca8]1121 // fprintf( stderr, "overflow\n" );
[e0dc038]1122 char peek;
1123 fmt( is, "%c", &peek ); // check for whitespace terminator
[8c13ca8]1124 // fprintf( stderr, "peek %d '%c'\n", args, peek );
[e0dc038]1125 if ( ! eof( is ) ) {
[a1a1f37d]1126 ungetc( peek, is );
[5764204]1127 if ( flags.inex ^ strchr( scanset, peek ) != 0p ) throwResume ExceptionInst( cstring_length );
[e0dc038]1128 } // if
1129 } // if
[0f107e4]1130 } // if
[5764204]1131 if ( ! flags.ignore && args == 0 ) s[0]= '\0'; // read failed => no pattern match => set string to null
[e0dc038]1132 } // if
1133 if ( args == 1 && eof( is ) ) { // data but scan ended at EOF
[768d091]1134 clearerr( is ); // => reset EOF => detect again on next read
[e0dc038]1135 } // if
[61c7239]1136 return is;
[e474cf09]1137 } // ?|?
1138} // distribution
[86a8be5]1139
[94d2544]1140#define INPUT_FMT_IMPL( T, CODE ) \
[ef3ac46]1141forall( istype & | basic_istream( istype ) ) { \
[ae0c1c3]1142 istype & ?|?( istype & is, _Istream_Manip(T) f ) with ( basic_istream_table ) { \
[e474cf09]1143 enum { size = 16 }; \
1144 char fmtstr[size]; \
1145 if ( f.wd == -1 ) { \
1146 snprintf( fmtstr, size, "%%%s%s", f.ignore ? "*" : "", CODE ); \
1147 } else { \
1148 snprintf( fmtstr, size, "%%%s%d%s", f.ignore ? "*" : "", f.wd, CODE ); \
1149 } /* if */ \
1150 /* printf( "%d %s %p\n", f.wd, fmtstr, &f.val ); */ \
1151 fmt( is, fmtstr, &f.val ); \
1152 return is; \
1153 } /* ?|? */ \
1154} // distribution
[3c573e9]1155
[baa1d5d]1156INPUT_FMT_IMPL( char, "c" )
[94d2544]1157INPUT_FMT_IMPL( signed char, "hhi" )
1158INPUT_FMT_IMPL( unsigned char, "hhi" )
1159INPUT_FMT_IMPL( signed short int, "hi" )
1160INPUT_FMT_IMPL( unsigned short int, "hi" )
1161INPUT_FMT_IMPL( signed int, "i" )
1162INPUT_FMT_IMPL( unsigned int, "i" )
1163INPUT_FMT_IMPL( signed long int, "li" )
1164INPUT_FMT_IMPL( unsigned long int, "li" )
1165INPUT_FMT_IMPL( signed long long int, "lli" )
1166INPUT_FMT_IMPL( unsigned long long int, "lli" )
1167
1168INPUT_FMT_IMPL( float, "f" )
1169INPUT_FMT_IMPL( double, "lf" )
1170INPUT_FMT_IMPL( long double, "Lf" )
[3c573e9]1171
[ef3ac46]1172forall( istype & | basic_istream( istype ) ) {
[e474cf09]1173 istype & ?|?( istype & is, _Istream_Manip(float _Complex) fc ) {
1174 float re, im;
1175 _Istream_Manip(float) fmtuc @= { re, fc.wd, fc.ignore };
1176 is | fmtuc;
1177 &fmtuc.val = &im;
1178 is | fmtuc;
1179 if ( ! fc.ignore ) fc.val = re + im * _Complex_I; // re/im are uninitialized for ignore
1180 return is;
1181 } // ?|?
1182
1183 istype & ?|?( istype & is, _Istream_Manip(double _Complex) dc ) {
1184 double re, im;
1185 _Istream_Manip(double) fmtuc @= { re, dc.wd, dc.ignore };
1186 is | fmtuc;
1187 &fmtuc.val = &im;
1188 is | fmtuc;
1189 if ( ! dc.ignore ) dc.val = re + im * _Complex_I; // re/im are uninitialized for ignore
1190 return is;
1191 } // ?|?
1192
1193 istype & ?|?( istype & is, _Istream_Manip(long double _Complex) ldc ) {
1194 long double re, im;
1195 _Istream_Manip(long double) fmtuc @= { re, ldc.wd, ldc.ignore };
1196 is | fmtuc;
1197 &fmtuc.val = &im;
1198 is | fmtuc;
1199 if ( ! ldc.ignore ) ldc.val = re + im * _Complex_I; // re/im are uninitialized for ignore
1200 return is;
1201 } // ?|?
1202} // distribution
[3c573e9]1203
[2f34fde]1204
[eae8b37]1205forall( istype & | istream( istype ), E | CfaEnum( E ) | Serial( E ) )
[ae0c1c3]1206istype & ?|?( istype & is, E & e ) with ( basic_istream_table ) {
[04138cc]1207// if ( eof( is ) ) throwResume ExceptionInst( end_of_file );
[eae8b37]1208
1209 // Match longest input enumerator string to enumerator labels, where enumerator names are unique.
1210
1211 int N = countof( E ), lnths[N], fred = 0;
1212 int r = 0;
1213 for ( s; E ) { // scan string rows gathering lengths
1214 lnths[r] = strlen( label( s ) );
1215 if ( lnths[r] > fred ) fred = lnths[r];
1216 r += 1;
1217 } // for
1218
1219 int mcol = -1; // last match column
1220 char ch, curr = '\0', prev = '\0';
1221
[04138cc]1222 fmt( is, " " ); // remove leading whitespace
[eae8b37]1223 if ( eof( is ) ) throwResume ExceptionInst( end_of_file );
1224
1225 for ( c; fred ) { // scan columns of the label matix (some columns missing)
1226 int args = fmt( is, "%c", &ch ); // read character
1227 if ( eof( is ) ) {
1228 if ( c == 0 ) return is; // no characters read ?
[768d091]1229 clearerr( is ); // => read something => reset EOF => detect again on next read
[eae8b37]1230 break;
1231 } // if
1232 if ( args != 1 ) throwResume ExceptionInst( missing_data ); // may be unnecessary since reading single character
1233
1234 for ( r; N ) { // scan enumeration strings for matching character in current column
1235 if ( c < lnths[r] ) { // string long enough for this column check ?
1236 char match = label( fromInt( r ) )[c]; // optimization
1237 // Stop on first match, could be other matches.
1238 if ( (match == ch) && (c == 0 || curr == label( fromInt( r ) )[c - 1]) ) {
1239 mcol = c; // matching column
1240 prev = curr; // last matching character
1241 curr = ch; // current matching character
1242 break;
1243 } // if
1244 } // if
1245 } else {
1246 ungetc( ch, is ); // push back last unmatching character
1247 if ( mcol == -1 ) throwResume ExceptionInst( missing_data ); // no matching character in first column
1248 break;
1249 } // for
1250 } // for
1251
1252 for ( c; N ) { // scan enumeration strings of length "mcol" for match
1253 if ( mcol == lnths[c] - 1 ) {
1254 char match = label( fromInt( c ) )[mcol]; // optimization
1255 if ( (match == curr) && (mcol == 0 || prev == label( fromInt( c ) )[mcol - 1]) ) {
1256 e = fromInt( c );
1257 break;
1258 } // if
1259 } // if
1260 } else {
1261 throwResume ExceptionInst( missing_data ); // no match in this column
1262 } // for
1263 return is;
1264}
1265
1266forall( ostype & | ostream( ostype ), E | CfaEnum( E ) ) {
1267 ostype & ?|?( ostype & os, E e ) {
1268 return os | label( e );
1269 }
1270 OSTYPE_VOID_IMPL( os, E )
1271}
1272
[86bd7c1f]1273// Local Variables: //
1274// tab-width: 4 //
[084520f]1275// compile-command: "cfa iostream.cfa" //
[86bd7c1f]1276// End: //
Note: See TracBrowser for help on using the repository browser.