Changeset f988834
- Timestamp:
- Jan 19, 2024, 2:44:41 AM (20 months ago)
- Branches:
- master
- Children:
- ac939461
- Parents:
- 59c8dff (diff), e8b3717 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Files:
-
- 6 added
- 42 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/LaTeXmacros/common.sty
r59c8dff rf988834 11 11 %% Created On : Sat Apr 9 10:06:17 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Fri Sep 29 16:48:59 202314 %% Update Count : 58713 %% Last Modified On : Sun Jan 14 12:28:26 2024 14 %% Update Count : 631 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 273 273 \setlength{\columnposn}{\gcolumnposn} 274 274 \newcommand{\setgcolumn}[1]{\global\gcolumnposn=#1\global\columnposn=\gcolumnposn} 275 \newcommand{\C}[2][\@empty]{\ifx#1\@empty\else\global\setlength{\columnposn}{#1}\global\columnposn=\columnposn\fi\hfill\makebox[\textwidth-\columnposn][l]{\lst@basicstyle{\LstCommentStyle{#2}}}} 275 \newcommand{\C}[2][\@empty]{\ifx#1\@empty\else\global\setlength{\columnposn}{#1}\global\columnposn=\columnposn\fi\hfill\makebox[\textwidth-\columnposn][l]{\LstCommentStyle{#2}}} 276 \newcommand{\CD}[2][\@empty]{\ifx#1\@empty\else\global\setlength{\columnposn}{#1}\global\columnposn=\columnposn\fi\hfill\makebox[\textwidth-\columnposn][l]{\LstBasicStyle{#2}}} 276 277 \newcommand{\CRT}{\global\columnposn=\gcolumnposn} 277 278 … … 292 293 xleftmargin=\parindentlnth, % indent code to paragraph indentation 293 294 extendedchars=true, % allow ASCII characters in the range 128-255 294 escapechar= \$, % LaTeX escape in CFA code §...§ (section symbol), emacs: C-q M-'295 escapechar=§, % LaTeX escape in CFA code §...§ (section symbol), emacs: C-q M-' 295 296 mathescape=false, % disable LaTeX math escape in CFA code $...$ 296 297 keepspaces=true, % … … 302 303 % replace/adjust listing characters that look bad in sanserif 303 304 literate= 304 {-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.75ex}{0.1ex}}}}1 305 % {-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.75ex}{0.1ex}}}}1 306 {-}{\raisebox{-1pt}{\texttt{-}}}1 305 307 {^}{\raisebox{0.6ex}{$\scriptstyle\land\,$}}1 306 308 {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1 … … 308 310 {<-}{$\leftarrow$}2 309 311 {=>}{$\Rightarrow$}2 310 {->}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.075ex}}}\kern-0.2ex\textgreater}2,312 % {->}{\raisebox{-1pt}{\texttt{-}}\kern-0.1ex\textgreater}2, 311 313 }% lstset 312 314 }% CFAStyle -
doc/LaTeXmacros/common.tex
r59c8dff rf988834 11 11 %% Created On : Sat Apr 9 10:06:17 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Fri Sep 29 16:49:02 202314 %% Update Count : 59 013 %% Last Modified On : Sun Jan 14 17:59:02 2024 14 %% Update Count : 592 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 276 276 \setlength{\columnposn}{\gcolumnposn} 277 277 \newcommand{\setgcolumn}[1]{\global\gcolumnposn=#1\global\columnposn=\gcolumnposn} 278 \newcommand{\C}[2][\@empty]{\ifx#1\@empty\else\global\setlength{\columnposn}{#1}\global\columnposn=\columnposn\fi\hfill\makebox[\textwidth-\columnposn][l]{\lst@basicstyle{\LstCommentStyle{#2}}}} 278 \newcommand{\C}[2][\@empty]{\ifx#1\@empty\else\global\setlength{\columnposn}{#1}\global\columnposn=\columnposn\fi\hfill\makebox[\textwidth-\columnposn][l]{\LstCommentStyle{#2}}} 279 \newcommand{\CD}[2][\@empty]{\ifx#1\@empty\else\global\setlength{\columnposn}{#1}\global\columnposn=\columnposn\fi\hfill\makebox[\textwidth-\columnposn][l]{\LstBasicStyle{#2}}} 279 280 \newcommand{\CRT}{\global\columnposn=\gcolumnposn} 280 281 … … 296 297 xleftmargin=\parindentlnth, % indent code to paragraph indentation 297 298 extendedchars=true, % allow ASCII characters in the range 128-255 298 escapechar= \$, % LaTeX escape in CFA code §...§ (section symbol), emacs: C-q M-'299 escapechar=§, % LaTeX escape in CFA code §...§ (section symbol), emacs: C-q M-' 299 300 mathescape=false, % disable LaTeX math escape in CFA code $...$ 300 301 keepspaces=true, % … … 306 307 % replace/adjust listing characters that look bad in sanserif 307 308 literate= 308 {-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.75ex}{0.1ex}}}}1 309 % {-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.75ex}{0.1ex}}}}1 310 {-}{\raisebox{-1pt}{\texttt{-}}}1 309 311 {^}{\raisebox{0.6ex}{$\scriptstyle\land\,$}}1 310 312 {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1 … … 312 314 {<-}{$\leftarrow$}2 313 315 {=>}{$\Rightarrow$}2 314 {->}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.075ex}}}\kern-0.2ex\textgreater}2,316 % {->}{\raisebox{-1pt}{\texttt{-}}\kern-0.1ex\textgreater}2, 315 317 }% lstset 316 318 }% CFAStyle -
doc/user/user.tex
r59c8dff rf988834 11 11 %% Created On : Wed Apr 6 14:53:29 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : S at Sep 30 22:46:19 202314 %% Update Count : 5 65813 %% Last Modified On : Sun Jan 14 17:27:41 2024 14 %% Update Count : 5764 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 55 55 \SetWatermarkLightness{0.9} 56 56 57 % Default underscore is too low and wide. Cannot use lstlisting "literate" as replacing underscore 58 % removes it as a variable-name character so keywords in variables are highlighted. MUST APPEAR 59 % AFTER HYPERREF. 60 \renewcommand{\textunderscore}{\leavevmode\makebox[1.2ex][c]{\rule{1ex}{0.075ex}}} 57 % Default underscore is too low. Cannot use lstlisting "literate" as replacing underscore removes it 58 % as a variable-name character so keywords in variables are highlighted. MUST APPEAR AFTER HYPERREF. 59 \renewcommand{\textunderscore}{\makebox[1.4ex][c]{{\raisebox{1.25pt}{\char`\_}}}} 61 60 62 61 \setlength{\topmargin}{-0.45in} % move running title into header … … 67 66 \CFAStyle % use default CFA format-style 68 67 \setgcolumn{2.25in} 69 %\lstset{language=CFA} % CFA default lnaguage68 \lstset{language=CFA} % CFA default lnaguage 70 69 \lstnewenvironment{C++}[1][] % use C++ style 71 70 {\lstset{language=C++,moredelim=**[is][\protect\color{red}]{®}{®},#1}} … … 172 171 \begin{tabular}{@{}lll@{}} 173 172 \multicolumn{1}{@{}c}{\textbf{C}} & \multicolumn{1}{c}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{\CC}} \\ 174 \begin{cfa} [tabsize=3]175 #include <stdio.h> $\indexc{stdio.h}$173 \begin{cfa} 174 #include <stdio.h>§\indexc{stdio.h}§ 176 175 177 176 int main( void ) { … … 182 181 & 183 182 \begin{cfa}[tabsize=3] 184 #include <fstream> $\indexc{fstream}$183 #include <fstream>§\indexc{fstream}§ 185 184 186 185 int main( void ) { 187 186 int x = 0, y = 1, z = 2; 188 ®sout | x | y | z;® $\indexc{sout}$187 ®sout | x | y | z;®§\indexc{sout}§ 189 188 } 190 189 \end{cfa} 191 190 & 192 191 \begin{cfa}[tabsize=3] 193 #include <iostream> $\indexc{iostream}$192 #include <iostream>§\indexc{iostream}§ 194 193 using namespace std; 195 194 int main() { … … 260 259 \begin{cfa} 261 260 ®forall( T )® T identity( T val ) { return val; } 262 int forty_two = identity( 42 ); $\C{// T is bound to int, forty\_two == 42}$261 int forty_two = identity( 42 ); §\C{// T is bound to int, forty\_two == 42}§ 263 262 \end{cfa} 264 263 % extending the C type system with parametric polymorphism and overloading, as opposed to the \Index*[C++]{\CC{}} approach of object-oriented extensions. … … 288 287 289 288 double key = 5.0, vals[10] = { /* 10 sorted floating values */ }; 290 double * val = (double *)bsearch( &key, vals, 10, sizeof(vals[0]), comp ); $\C{// search sorted array}$289 double * val = (double *)bsearch( &key, vals, 10, sizeof(vals[0]), comp ); §\C{// search sorted array}§ 291 290 \end{cfa} 292 291 which can be augmented simply with a polymorphic, type-safe, \CFA-overloaded wrappers: … … 297 296 298 297 forall( T | { int ?<?( T, T ); } ) unsigned int bsearch( T key, const T * arr, size_t size ) { 299 T * result = bsearch( key, arr, size ); $\C{// call first version}$300 return result ? result - arr : size; } $\C{// pointer subtraction includes sizeof(T)}$301 302 double * val = bsearch( 5.0, vals, 10 ); $\C{// selection based on return type}$298 T * result = bsearch( key, arr, size ); §\C{// call first version}§ 299 return result ? result - arr : size; } §\C{// pointer subtraction includes sizeof(T)}§ 300 301 double * val = bsearch( 5.0, vals, 10 ); §\C{// selection based on return type}§ 303 302 int posn = bsearch( 5.0, vals, 10 ); 304 303 \end{cfa} … … 312 311 \begin{cfa} 313 312 forall( dtype T | sized(T) ) T * malloc( void ) { return (T *)malloc( sizeof(T) ); } 314 int * ip = malloc(); $\C{// select type and size from left-hand side}$313 int * ip = malloc(); §\C{// select type and size from left-hand side}§ 315 314 double * dp = malloc(); 316 315 struct S {...} * sp = malloc(); … … 324 323 \begin{cfa} 325 324 char ®abs®( char ); 326 extern "C" { int ®abs®( int ); } $\C{// use default C routine for int}$325 extern "C" { int ®abs®( int ); } §\C{// use default C routine for int}§ 327 326 long int ®abs®( long int ); 328 327 long long int ®abs®( long long int ); … … 349 348 The command ©cfa© is used to compile a \CFA program and is based on the \Index{GNU} \Indexc{gcc} command, \eg: 350 349 \begin{cfa} 351 cfa $\indexc{cfa}\index{compilation!cfa@©cfa©}$ [ gcc/$\CFA{}$-options ] [ C/$\CFA{}$source-files ] [ assembler/loader files ]350 cfa§\indexc{cfa}\index{compilation!cfa@©cfa©}§ [ gcc/§\CFA{}§-options ] [ C/§\CFA{}§ source-files ] [ assembler/loader files ] 352 351 \end{cfa} 353 352 There is no ordering among options (flags) and files, unless an option has an argument, which must appear immediately after the option possibly with or without a space separating option and argument. … … 438 437 \begin{cfa} 439 438 #ifndef __CFORALL__ 440 #include <stdio.h> $\indexc{stdio.h}$ $\C{// C header file}$439 #include <stdio.h>§\indexc{stdio.h}§ §\C{// C header file}§ 441 440 #else 442 #include <fstream> $\indexc{fstream}$ $\C{// \CFA header file}$441 #include <fstream>§\indexc{fstream}§ §\C{// \CFA header file}§ 443 442 #endif 444 443 \end{cfa} … … 450 449 Each option must be escaped with \Indexc{-XCFA}\index{translator option!-XCFA@{©-XCFA©}} to direct it to the compiler step, similar to the ©-Xlinker© flag for the linker, \eg: 451 450 \begin{lstlisting}[language=sh] 452 cfa $test$.cfa -CFA -XCFA -p # print translated code without printing the standard prelude453 cfa $test$.cfa -XCFA -P -XCFA parse -XCFA -n # show program parse without prelude451 cfa §test§.cfa -CFA -XCFA -p # print translated code without printing the standard prelude 452 cfa §test§.cfa -XCFA -P -XCFA parse -XCFA -n # show program parse without prelude 454 453 \end{lstlisting} 455 Alternatively, multiple flag es can be specified separated with commas and \emph{without} spaces.454 Alternatively, multiple flags can be specified separated with commas and \emph{without} spaces. 456 455 \begin{lstlisting}[language=sh,{moredelim=**[is][\protect\color{red}]{®}{®}}] 457 cfa $test$.cfa -XCFA®,®-Pparse®,®-n # show program parse without prelude456 cfa §test§.cfa -XCFA®,®-Pparse®,®-n # show program parse without prelude 458 457 \end{lstlisting} 459 458 \begin{description}[topsep=5pt,itemsep=0pt,parsep=0pt] … … 537 536 Keyword clashes are accommodated by syntactic transformations using the \CFA backquote escape-mechanism: 538 537 \begin{cfa} 539 int ®``®coroutine = 3; $\C{// make keyword an identifier}$538 int ®``®coroutine = 3; §\C{// make keyword an identifier}§ 540 539 double ®``®forall = 3.5; 541 540 \end{cfa} … … 547 546 \begin{cfa} 548 547 // include file uses the CFA keyword "with". 549 #if ! defined( with ) $\C{// nesting ?}$550 #define with ®``®with $\C{// make keyword an identifier}$548 #if ! defined( with ) §\C{// nesting ?}§ 549 #define with ®``®with §\C{// make keyword an identifier}§ 551 550 #define __CFA_BFD_H__ 552 551 #endif 553 $\R{\#include\_next} <bfdlink.h>$ $\C{// must have internal check for multiple expansion}$ 554 #if defined( with ) && defined( __CFA_BFD_H__ ) $\C{// reset only if set}$552 §\R{\#include\_next} <bfdlink.h>§ §\C{// must have internal check for multiple expansion}§ 553 #if defined( with ) && defined( __CFA_BFD_H__ ) §\C{// reset only if set}§ 555 554 #undef with 556 555 #undef __CFA_BFD_H__ … … 566 565 Numeric constants are extended to allow \Index{underscore}s\index{constant!underscore} as a separator, \eg: 567 566 \begin{cfa} 568 2®_®147®_®483®_®648; $\C{// decimal constant}$569 56®_®ul; $\C{// decimal unsigned long constant}$570 0®_®377; $\C{// octal constant}$571 0x®_®ff®_®ff; $\C{// hexadecimal constant}$572 0x®_®ef3d®_®aa5c; $\C{// hexadecimal constant}$573 3.141®_®592®_®654; $\C{// floating constant}$574 10®_®e®_®+1®_®00; $\C{// floating constant}$575 0x®_®ff®_®ff®_®p®_®3; $\C{// hexadecimal floating}$576 0x®_®1.ffff®_®ffff®_®p®_®128®_®l; $\C{// hexadecimal floating long constant}$577 L®_® $"\texttt{\textbackslash{x}}$®_®$\texttt{ff}$®_®$\texttt{ee}"$; $\C{// wide character constant}$567 2®_®147®_®483®_®648; §\C{// decimal constant}§ 568 56®_®ul; §\C{// decimal unsigned long constant}§ 569 0®_®377; §\C{// octal constant}§ 570 0x®_®ff®_®ff; §\C{// hexadecimal constant}§ 571 0x®_®ef3d®_®aa5c; §\C{// hexadecimal constant}§ 572 3.141®_®592®_®654; §\C{// floating constant}§ 573 10®_®e®_®+1®_®00; §\C{// floating constant}§ 574 0x®_®ff®_®ff®_®p®_®3; §\C{// hexadecimal floating}§ 575 0x®_®1.ffff®_®ffff®_®p®_®128®_®l; §\C{// hexadecimal floating long constant}§ 576 L®_®§"\texttt{\textbackslash{x}}§®_®§\texttt{ff}§®_®§\texttt{ee}"§; §\C{// wide character constant}§ 578 577 \end{cfa} 579 578 The rules for placement of underscores are: … … 635 634 Declarations in the \Indexc{do}-©while© condition are not useful because they appear after the loop body.} 636 635 \begin{cfa} 637 if ( ®int x = f()® ) ... $\C{// x != 0}$638 if ( ®int x = f(), y = g()® ) ... $\C{// x != 0 \&\& y != 0}$639 if ( ®int x = f(), y = g(); x < y® ) ... $\C{// relational expression}$640 if ( ®struct S { int i; } x = { f() }; x.i < 4® ) $\C{// relational expression}$641 642 while ( ®int x = f()® ) ... $\C{// x != 0}$643 while ( ®int x = f(), y = g()® ) ... $\C{// x != 0 \&\& y != 0}$644 while ( ®int x = f(), y = g(); x < y® ) ... $\C{// relational expression}$645 while ( ®struct S { int i; } x = { f() }; x.i < 4® ) ... $\C{// relational expression}$636 if ( ®int x = f()® ) ... §\C{// x != 0}§ 637 if ( ®int x = f(), y = g()® ) ... §\C{// x != 0 \&\& y != 0}§ 638 if ( ®int x = f(), y = g(); x < y® ) ... §\C{// relational expression}§ 639 if ( ®struct S { int i; } x = { f() }; x.i < 4® ) §\C{// relational expression}§ 640 641 while ( ®int x = f()® ) ... §\C{// x != 0}§ 642 while ( ®int x = f(), y = g()® ) ... §\C{// x != 0 \&\& y != 0}§ 643 while ( ®int x = f(), y = g(); x < y® ) ... §\C{// relational expression}§ 644 while ( ®struct S { int i; } x = { f() }; x.i < 4® ) ... §\C{// relational expression}§ 646 645 \end{cfa} 647 646 Unless a relational expression is specified, each variable is compared not equal to 0, which is the standard semantics for the ©if©/©while© expression, and the results are combined using the logical \Indexc{&&} operator. … … 713 712 \begin{cfa} 714 713 switch ( i ) { 715 case 1 $\R{\textvisiblespace}$®...®4:714 case 1§\R{\textvisiblespace}§®...®4: 716 715 ... 717 case 10 $\R{\textvisiblespace}$®...®13:716 case 10§\R{\textvisiblespace}§®...®13: 718 717 ... 719 718 } … … 752 751 case 1: 753 752 ... 754 $\R{\LstCommentStyle{// fall-through}}$753 §\R{\LstCommentStyle{// fall-through}}§ 755 754 case 2: 756 755 ... … … 853 852 \begin{cfa} 854 853 switch ( x ) { 855 ®int y = 1;® $\C{// unreachable initialization}$856 ®x = 7;® $\C{// unreachable code without label/branch}$854 ®int y = 1;® §\C{// unreachable initialization}§ 855 ®x = 7;® §\C{// unreachable code without label/branch}§ 857 856 case 0: ... 858 857 ... 859 ®int z = 0;® $\C{// unreachable initialization, cannot appear after case}$858 ®int z = 0;® §\C{// unreachable initialization, cannot appear after case}§ 860 859 z = 2; 861 860 case 1: 862 ®x = z;® $\C{// without fall through, z is uninitialized}$861 ®x = z;® §\C{// without fall through, z is uninitialized}§ 863 862 } 864 863 \end{cfa} … … 895 894 case 1: case 2: case 3: 896 895 ... 897 $\R{\LstCommentStyle{// implicit end of switch (break)}}$896 §\R{\LstCommentStyle{// implicit end of switch (break)}}§ 898 897 case 5: 899 898 ... 900 ®fallthru®; $\C{// explicit fall through}$899 ®fallthru®; §\C{// explicit fall through}§ 901 900 case 7: 902 901 ... 903 ®break® $\C{// explicit end of switch (redundant)}$902 ®break® §\C{// explicit end of switch (redundant)}§ 904 903 default: 905 904 j = 3; … … 922 921 \begin{cfa} 923 922 switch ( x ) { 924 ®int i = 0;® $\C{// allowed only at start}$923 ®int i = 0;® §\C{// allowed only at start}§ 925 924 case 0: 926 925 ... 927 ®int j = 0;® $\C{// disallowed}$926 ®int j = 0;® §\C{// disallowed}§ 928 927 case 1: 929 928 { 930 ®int k = 0;® $\C{// allowed at different nesting levels}$929 ®int k = 0;® §\C{// allowed at different nesting levels}§ 931 930 ... 932 ®case 2:® $\C{// disallow case in nested statements}$931 ®case 2:® §\C{// disallow case in nested statements}§ 933 932 } 934 933 ... … … 1004 1003 while () { sout | "empty"; break; } 1005 1004 do { sout | "empty"; break; } while (); 1006 for () { sout | "empty"; break; } $\C[3in]{sout | nl | nlOff;}$1007 1008 for ( 0 ) { sout | "A"; } sout | "zero"; $\C{sout | nl;}$1009 for ( 1 ) { sout | "A"; } $\C{sout | nl;}$1010 for ( 10 ) { sout | "A"; } $\C{sout | nl;}$1011 for ( ~= 10 ) { sout | "A"; } $\C{sout | nl;}$1012 for ( 1 ~= 10 ~ 2 ) { sout | "B"; } $\C{sout | nl;}$1013 for ( 1 -~= 10 ~ 2 ) { sout | "C"; } $\C{sout | nl;}$1014 for ( 0.5 ~ 5.5 ) { sout | "D"; } $\C{sout | nl;}$1015 for ( 0.5 -~ 5.5 ) { sout | "E"; } $\C{sout | nl;}$1016 for ( i; 10 ) { sout | i; } $\C{sout | nl;}$1017 for ( i; ~= 10 ) { sout | i; } $\C{sout | nl;}$1018 for ( i; 1 ~= 10 ~ 2 ) { sout | i; } $\C{sout | nl;}$1019 for ( i; 1 -~= 10 ~ 2 ) { sout | i; } $\C{sout | nl;}$1020 for ( i; 0.5 ~ 5.5 ) { sout | i; } $\C{sout | nl;}$1021 for ( i; 0.5 -~ 5.5 ) { sout | i; } $\C{sout | nl;}$1022 for ( ui; 2u ~= 10u ~ 2u ) { sout | ui; } $\C{sout | nl;}$1023 for ( ui; 2u -~= 10u ~ 2u ) { sout | ui; } $\C{sout | nl | nl | nl;}$1005 for () { sout | "empty"; break; } §\C[3in]{sout | nl | nlOff;}§ 1006 1007 for ( 0 ) { sout | "A"; } sout | "zero"; §\C{sout | nl;}§ 1008 for ( 1 ) { sout | "A"; } §\C{sout | nl;}§ 1009 for ( 10 ) { sout | "A"; } §\C{sout | nl;}§ 1010 for ( ~= 10 ) { sout | "A"; } §\C{sout | nl;}§ 1011 for ( 1 ~= 10 ~ 2 ) { sout | "B"; } §\C{sout | nl;}§ 1012 for ( 1 -~= 10 ~ 2 ) { sout | "C"; } §\C{sout | nl;}§ 1013 for ( 0.5 ~ 5.5 ) { sout | "D"; } §\C{sout | nl;}§ 1014 for ( 0.5 -~ 5.5 ) { sout | "E"; } §\C{sout | nl;}§ 1015 for ( i; 10 ) { sout | i; } §\C{sout | nl;}§ 1016 for ( i; ~= 10 ) { sout | i; } §\C{sout | nl;}§ 1017 for ( i; 1 ~= 10 ~ 2 ) { sout | i; } §\C{sout | nl;}§ 1018 for ( i; 1 -~= 10 ~ 2 ) { sout | i; } §\C{sout | nl;}§ 1019 for ( i; 0.5 ~ 5.5 ) { sout | i; } §\C{sout | nl;}§ 1020 for ( i; 0.5 -~ 5.5 ) { sout | i; } §\C{sout | nl;}§ 1021 for ( ui; 2u ~= 10u ~ 2u ) { sout | ui; } §\C{sout | nl;}§ 1022 for ( ui; 2u -~= 10u ~ 2u ) { sout | ui; } §\C{sout | nl | nl | nl;}§ 1024 1023 1025 1024 enum { N = 10 }; 1026 for ( N ) { sout | "N"; } $\C{sout | nl;}$1027 for ( i; N ) { sout | i; } $\C{sout | nl;}$1028 for ( i; -~ N ) { sout | i; } $\C{sout | nl | nl | nl;}$1025 for ( N ) { sout | "N"; } §\C{sout | nl;}§ 1026 for ( i; N ) { sout | i; } §\C{sout | nl;}§ 1027 for ( i; -~ N ) { sout | i; } §\C{sout | nl | nl | nl;}§ 1029 1028 1030 1029 const int low = 3, high = 10, inc = 2; 1031 for ( i; low ~ high ~ inc + 1 ) { sout | i; } $\C{sout | nl;}$1032 for ( i; 1 ~ @ ) { if ( i > 10 ) break; sout | i; } $\C{sout | nl;}$1033 for ( i; @ -~ 10 ) { if ( i < 0 ) break; sout | i; } $\C{sout | nl;}$1034 for ( i; 2 ~ @ ~ 2 ) { if ( i > 10 ) break; sout | i; } $\C{sout | nl;}$1035 for ( i; 2.1 ~ @ ~ @ ) { if ( i > 10.5 ) break; sout | i; i += 1.7; } $\C{sout | nl;}$1036 for ( i; @ -~ 10 ~ 2 ) { if ( i < 0 ) break; sout | i; } $\C{sout | nl;}$1037 for ( i; 12.1 ~ @ ~ @ ) { if ( i < 2.5 ) break; sout | i; i -= 1.7; } $\C{sout | nl;}$1038 for ( i; 5 : j; -5 ~ @ ) { sout | i | j; } $\C{sout | nl;}$1039 for ( i; 5 : j; @ -~ -5 ) { sout | i | j; } $\C{sout | nl;}$1040 for ( i; 5 : j; -5 ~ @ ~ 2 ) { sout | i | j; } $\C{sout | nl;}$1041 for ( i; 5 : j; @ -~ -5 ~ 2 ) { sout | i | j; } $\C{sout | nl;}$1042 for ( i; 5 : j; -5 ~ @ ) { sout | i | j; } $\C{sout | nl;}$1043 for ( i; 5 : j; @ -~ -5 ) { sout | i | j; } $\C{sout | nl;}$1044 for ( i; 5 : j; -5 ~ @ ~ 2 ) { sout | i | j; } $\C{sout | nl;}$1045 for ( i; 5 : j; @ -~ -5 ~ 2 ) { sout | i | j; } $\C{sout | nl;}$1046 for ( i; 5 : j; @ -~ -5 ~ 2 : k; 1.5 ~ @ ) { sout | i | j | k; } $\C{sout | nl;}$1047 for ( i; 5 : j; @ -~ -5 ~ 2 : k; 1.5 ~ @ ) { sout | i | j | k; } $\C{sout | nl;}$1048 for ( i; 5 : k; 1.5 ~ @ : j; @ -~ -5 ~ 2 ) { sout | i | j | k; } $\C{sout | nl;}\CRT$1030 for ( i; low ~ high ~ inc + 1 ) { sout | i; } §\C{sout | nl;}§ 1031 for ( i; 1 ~ @ ) { if ( i > 10 ) break; sout | i; } §\C{sout | nl;}§ 1032 for ( i; @ -~ 10 ) { if ( i < 0 ) break; sout | i; } §\C{sout | nl;}§ 1033 for ( i; 2 ~ @ ~ 2 ) { if ( i > 10 ) break; sout | i; } §\C{sout | nl;}§ 1034 for ( i; 2.1 ~ @ ~ @ ) { if ( i > 10.5 ) break; sout | i; i += 1.7; } §\C{sout | nl;}§ 1035 for ( i; @ -~ 10 ~ 2 ) { if ( i < 0 ) break; sout | i; } §\C{sout | nl;}§ 1036 for ( i; 12.1 ~ @ ~ @ ) { if ( i < 2.5 ) break; sout | i; i -= 1.7; } §\C{sout | nl;}§ 1037 for ( i; 5 : j; -5 ~ @ ) { sout | i | j; } §\C{sout | nl;}§ 1038 for ( i; 5 : j; @ -~ -5 ) { sout | i | j; } §\C{sout | nl;}§ 1039 for ( i; 5 : j; -5 ~ @ ~ 2 ) { sout | i | j; } §\C{sout | nl;}§ 1040 for ( i; 5 : j; @ -~ -5 ~ 2 ) { sout | i | j; } §\C{sout | nl;}§ 1041 for ( i; 5 : j; -5 ~ @ ) { sout | i | j; } §\C{sout | nl;}§ 1042 for ( i; 5 : j; @ -~ -5 ) { sout | i | j; } §\C{sout | nl;}§ 1043 for ( i; 5 : j; -5 ~ @ ~ 2 ) { sout | i | j; } §\C{sout | nl;}§ 1044 for ( i; 5 : j; @ -~ -5 ~ 2 ) { sout | i | j; } §\C{sout | nl;}§ 1045 for ( i; 5 : j; @ -~ -5 ~ 2 : k; 1.5 ~ @ ) { sout | i | j | k; } §\C{sout | nl;}§ 1046 for ( i; 5 : j; @ -~ -5 ~ 2 : k; 1.5 ~ @ ) { sout | i | j | k; } §\C{sout | nl;}§ 1047 for ( i; 5 : k; 1.5 ~ @ : j; @ -~ -5 ~ 2 ) { sout | i | j | k; } §\C{sout | nl;}\CRT§ 1049 1048 \end{cfa} 1050 1049 & … … 1117 1116 The \Indexc{for}, \Indexc{while}, and \Indexc{do} loop-control allow an empty conditional, which implies a comparison value of ©1© (true). 1118 1117 \begin{cfa} 1119 while ( ®/* empty */® ) $\C{// while ( true )}$1120 for ( ®/* empty */® ) $\C{// for ( ; true; )}$1121 do ... while ( ®/* empty */® ) $\C{// do ... while ( true )}$1118 while ( ®/* empty */® ) §\C{// while ( true )}§ 1119 for ( ®/* empty */® ) §\C{// for ( ; true; )}§ 1120 do ... while ( ®/* empty */® ) §\C{// do ... while ( true )}§ 1122 1121 \end{cfa} 1123 1122 … … 1149 1148 If no type is specified for the loop index, it is the type of the high value H (when the low value is implicit) or the low value L. 1150 1149 \begin{cfa} 1151 for ( ®5® ) $\C{// typeof(5) anonymous-index; 5 is high value}$1152 for ( i; ®1.5® ~ 5.5 ) $\C{// typeof(1.5) i; 1.5 is low value}$1153 for ( ®int i®; 0 ~ 10 ~ 2 ) $\C{// int i; type is explicit}$1150 for ( ®5® ) §\C{// typeof(5) anonymous-index; 5 is high value}§ 1151 for ( i; ®1.5® ~ 5.5 ) §\C{// typeof(1.5) i; 1.5 is low value}§ 1152 for ( ®int i®; 0 ~ 10 ~ 2 ) §\C{// int i; type is explicit}§ 1154 1153 \end{cfa} 1155 1154 … … 1159 1158 H is implicit up-to exclusive range [0,H\R{)}. 1160 1159 \begin{cfa} 1161 for ( ®5® ) $\C{// for ( typeof(5) i; i < 5; i += 1 )}$1160 for ( ®5® ) §\C{// for ( typeof(5) i; i < 5; i += 1 )}§ 1162 1161 \end{cfa} 1163 1162 \item 1164 1163 ©~=© H is implicit up-to inclusive range [0,H\R{]}. 1165 1164 \begin{cfa} 1166 for ( ®~=® 5 ) $\C{// for ( typeof(5) i; i <= 5; i += 1 )}$1165 for ( ®~=® 5 ) §\C{// for ( typeof(5) i; i <= 5; i += 1 )}§ 1167 1166 \end{cfa} 1168 1167 \item 1169 1168 L ©~©\index{~@©~©} H is explicit up-to exclusive range [L,H\R{)}. 1170 1169 \begin{cfa} 1171 for ( 1 ®~® 5 ) $\C{// for ( typeof(1) i = 1; i < 5; i += 1 )}$1170 for ( 1 ®~® 5 ) §\C{// for ( typeof(1) i = 1; i < 5; i += 1 )}§ 1172 1171 \end{cfa} 1173 1172 \item 1174 1173 L ©~=©\index{~=@©~=©} H is explicit up-to inclusive range [L,H\R{]}. 1175 1174 \begin{cfa} 1176 for ( 1 ®~=® 5 ) $\C{// for ( typeof(1) i = 1; i <= 5; i += 1 )}$1175 for ( 1 ®~=® 5 ) §\C{// for ( typeof(1) i = 1; i <= 5; i += 1 )}§ 1177 1176 \end{cfa} 1178 1177 \item 1179 1178 L ©-~©\index{-~@©-~©} H is explicit down-to exclusive range [H,L\R{)}, where L and H are implicitly interchanged to make the range down-to. 1180 1179 \begin{cfa} 1181 for ( 1 ®-~® 5 ) $\C{// for ( typeof(1) i = 5; i > 0; i -= 1 )}$1180 for ( 1 ®-~® 5 ) §\C{// for ( typeof(1) i = 5; i > 0; i -= 1 )}§ 1182 1181 \end{cfa} 1183 1182 \item 1184 1183 L ©-~=©\index{-~=@©-~=©} H is explicit down-to inclusive range [H,L\R{]}, where L and H are implicitly interchanged to make the range down-to. 1185 1184 \begin{cfa} 1186 for ( 1 ®-~=® 5 ) $\C{// for ( typeof(1) i = 5; i >= 0; i -= 1 )}$1185 for ( 1 ®-~=® 5 ) §\C{// for ( typeof(1) i = 5; i >= 0; i -= 1 )}§ 1187 1186 \end{cfa} 1188 1187 \item 1189 1188 ©@© means put nothing in this field. 1190 1189 \begin{cfa} 1191 for ( i; 1 ~ ®@® ~ 2 ) $\C{// for ( typeof(1) i = 1; \R{/* empty */}; i += 2 )}$1192 for ( i; 1 ~ 10 ~ ®@® ) $\C{// for ( typeof(1) i = 1; i < 10; \R{/* empty */} )}$1193 for ( i; 1 ~ ®@® ~ ®@® ) $\C{// for ( typeof(1) i = 1; /*empty*/; \R{/* empty */} )}$1190 for ( i; 1 ~ ®@® ~ 2 ) §\C{// for ( typeof(1) i = 1; \R{/* empty */}; i += 2 )}§ 1191 for ( i; 1 ~ 10 ~ ®@® ) §\C{// for ( typeof(1) i = 1; i < 10; \R{/* empty */} )}§ 1192 for ( i; 1 ~ ®@® ~ ®@® ) §\C{// for ( typeof(1) i = 1; /*empty*/; \R{/* empty */} )}§ 1194 1193 \end{cfa} 1195 1194 L cannot be elided for the up-to range, \lstinline{@ ~ 5}, and H for the down-to range, \lstinline{1 -~ @}, because then the loop index is uninitialized. … … 1198 1197 ©:© means low another index. 1199 1198 \begin{cfa} 1200 for ( i; 5 ®:® j; 2 ~ 12 ~ 3 ) $\C{// for ( typeof(i) i = 1, j = 2; i < 5 \&\& j < 12; i += 1, j += 3 )}$1199 for ( i; 5 ®:® j; 2 ~ 12 ~ 3 ) §\C{// for ( typeof(i) i = 1, j = 2; i < 5 \&\& j < 12; i += 1, j += 3 )}§ 1201 1200 \end{cfa} 1202 1201 \end{itemize} 1203 1202 \R{Warning}: specifying the down-to range maybe unexpected because the loop control \emph{implicitly} switches the L and H values (and toggles the increment/decrement for I): 1204 1203 \begin{cfa} 1205 for ( i; 1 ~ 10 ) ${\C{// up range}$1206 for ( i; 1 -~ 10 ) ${\C{// down range}$1207 for ( i; ®10 -~ 1® ) ${\C{// \R{WRONG down range!}}}$1204 for ( i; 1 ~ 10 ) §{\C{// up range}§ 1205 for ( i; 1 -~ 10 ) §{\C{// down range}§ 1206 for ( i; ®10 -~ 1® ) §{\C{// \R{WRONG down range!}}}§ 1208 1207 \end{cfa} 1209 1208 The reason for this semantics is that the range direction can be toggled by adding/removing the minus, ©'-'©, versus interchanging the L and H expressions, which has a greater chance of introducing errors. … … 1361 1360 Grouping heterogeneous data into an \newterm{aggregate} (structure/union) is a common programming practice, and aggregates may be nested: 1362 1361 \begin{cfa} 1363 struct Person { $\C{// aggregate}$1364 struct Name { $\C{// nesting}$1362 struct Person { §\C{// aggregate}§ 1363 struct Name { §\C{// nesting}§ 1365 1364 char first[20], last[20]; 1366 1365 } name; 1367 struct Address { $\C{// nesting}$1366 struct Address { §\C{// nesting}§ 1368 1367 ... 1369 1368 } address; … … 1374 1373 \begin{cfa} 1375 1374 Person p 1376 ®p.®name; ®p.®address; ®p.®sex; $\C{// access containing fields}$1375 ®p.®name; ®p.®address; ®p.®sex; §\C{// access containing fields}§ 1377 1376 \end{cfa} 1378 1377 which extends to multiple levels of qualification for nested aggregates and multiple aggregates. 1379 1378 \begin{cfa} 1380 1379 struct Ticket { ... } t; 1381 ®p.name®.first; ®p.address®.street; $\C{// access nested fields}$1382 ®t.®departure; ®t.®cost; $\C{// access multiple aggregate}$1380 ®p.name®.first; ®p.address®.street; §\C{// access nested fields}§ 1381 ®t.®departure; ®t.®cost; §\C{// access multiple aggregate}§ 1383 1382 \end{cfa} 1384 1383 Repeated aggregate qualification is tedious and makes code difficult to read. … … 1389 1388 \begin{cfa} 1390 1389 struct S { 1391 struct $\R{\LstCommentStyle{/* unnamed */}}${ int g, h; } __attribute__(( aligned(64) ));1390 struct §\R{\LstCommentStyle{/* unnamed */}}§ { int g, h; } __attribute__(( aligned(64) )); 1392 1391 int tag; 1393 union $\R{\LstCommentStyle{/* unnamed */}}${1392 union §\R{\LstCommentStyle{/* unnamed */}}§ { 1394 1393 struct { char c1, c2; } __attribute__(( aligned(128) )); 1395 1394 struct { int i1, i2; }; … … 1405 1404 struct S { 1406 1405 char ®c®; int ®i®; double ®d®; 1407 void f( /* S * this */ ) { $\C{// implicit ``this'' parameter}$1408 ®c®; ®i®; ®d®; $\C{// this->c; this->i; this->d;}$1406 void f( /* S * this */ ) { §\C{// implicit ``this'' parameter}§ 1407 ®c®; ®i®; ®d®; §\C{// this->c; this->i; this->d;}§ 1409 1408 } 1410 1409 } … … 1414 1413 \begin{cfa} 1415 1414 struct T { 1416 char ®m®; int ®i®; double ®n®; $\C{// derived class variables}$1415 char ®m®; int ®i®; double ®n®; §\C{// derived class variables}§ 1417 1416 }; 1418 1417 struct S : public T { 1419 char ®c®; int ®i®; double ®d®; $\C{// class variables}$1418 char ®c®; int ®i®; double ®d®; §\C{// class variables}§ 1420 1419 void g( double ®d®, T & t ) { 1421 d; ®t®.m; ®t®.i; ®t®.n; $\C{// function parameter}$1422 c; i; ®this->®d; ®S::®d; $\C{// class S variables}$1423 m; ®T::®i; n; $\C{// class T variables}$1420 d; ®t®.m; ®t®.i; ®t®.n; §\C{// function parameter}§ 1421 c; i; ®this->®d; ®S::®d; §\C{// class S variables}§ 1422 m; ®T::®i; n; §\C{// class T variables}§ 1424 1423 } 1425 1424 }; … … 1431 1430 Hence, the qualified fields become variables with the side-effect that it is simpler to write, easier to read, and optimize field references in a block. 1432 1431 \begin{cfa} 1433 void f( S & this ) ®with ( this )® { $\C{// with statement}$1434 ®c®; ®i®; ®d®; $\C{// this.c, this.i, this.d}$1432 void f( S & this ) ®with ( this )® { §\C{// with statement}§ 1433 ®c®; ®i®; ®d®; §\C{// this.c, this.i, this.d}§ 1435 1434 } 1436 1435 \end{cfa} 1437 1436 with the generality of opening multiple aggregate-parameters: 1438 1437 \begin{cfa} 1439 void g( S & s, T & t ) ®with ( s, t )® { $\C{// multiple aggregate parameters}$1440 c; ®s.®i; d; $\C{// s.c, s.i, s.d}$1441 m; ®t.®i; n; $\C{// t.m, t.i, t.n}$1438 void g( S & s, T & t ) ®with ( s, t )® {§\C{// multiple aggregate parameters}§ 1439 c; ®s.®i; d; §\C{// s.c, s.i, s.d}§ 1440 m; ®t.®i; n; §\C{// t.m, t.i, t.n}§ 1442 1441 } 1443 1442 \end{cfa} … … 1462 1461 struct R { int ®i®; int j; double ®m®; } r, w; 1463 1462 with ( r, q ) { 1464 j + k; $\C{// unambiguous, r.j + q.k}$1465 m = 5.0; $\C{// unambiguous, q.m = 5.0}$1466 m = 1; $\C{// unambiguous, r.m = 1}$1467 int a = m; $\C{// unambiguous, a = r.i }$1468 double b = m; $\C{// unambiguous, b = q.m}$1469 int c = r.i + q.i; $\C{// disambiguate with qualification}$1470 (double)m; $\C{// disambiguate with cast}$1463 j + k; §\C{// unambiguous, r.j + q.k}§ 1464 m = 5.0; §\C{// unambiguous, q.m = 5.0}§ 1465 m = 1; §\C{// unambiguous, r.m = 1}§ 1466 int a = m; §\C{// unambiguous, a = r.i }§ 1467 double b = m; §\C{// unambiguous, b = q.m}§ 1468 int c = r.i + q.i; §\C{// disambiguate with qualification}§ 1469 (double)m; §\C{// disambiguate with cast}§ 1471 1470 } 1472 1471 \end{cfa} … … 1476 1475 \begin{cfa} 1477 1476 with ( r ) { 1478 i; $\C{// unambiguous, r.i}$1477 i; §\C{// unambiguous, r.i}§ 1479 1478 with ( q ) { 1480 i; $\C{// unambiguous, q.i}$1479 i; §\C{// unambiguous, q.i}§ 1481 1480 } 1482 1481 } … … 1485 1484 A cast can also be used to disambiguate among overload variables in a ©with© \emph{expression}: 1486 1485 \begin{cfa} 1487 with ( w ) { ... } $\C{// ambiguous, same name and no context}$1488 with ( (Q)w ) { ... } $\C{// unambiguous, cast}$1486 with ( w ) { ... } §\C{// ambiguous, same name and no context}§ 1487 with ( (Q)w ) { ... } §\C{// unambiguous, cast}§ 1489 1488 \end{cfa} 1490 1489 Because there is no left-side in the ©with© expression to implicitly disambiguate between the ©w© variables, it is necessary to explicitly disambiguate by casting ©w© to type ©Q© or ©R©. … … 1493 1492 \begin{cfa} 1494 1493 void f( S & s, char c ) with ( s ) { 1495 ®s.c = c;® i = 3; d = 5.5; $\C{// initialize fields}$1494 ®s.c = c;® i = 3; d = 5.5; §\C{// initialize fields}§ 1496 1495 } 1497 1496 \end{cfa} … … 1499 1498 To solve this problem, parameters \emph{not} explicitly opened are treated like an initialized aggregate: 1500 1499 \begin{cfa} 1501 struct Params { $\C{// s explicitly opened so S \& s elided}$1500 struct Params { §\C{// s explicitly opened so S \& s elided}§ 1502 1501 char c; 1503 1502 } params; … … 1505 1504 and implicitly opened \emph{after} a function-body open, to give them higher priority: 1506 1505 \begin{cfa} 1507 void f( S & s, char ®c® ) with ( s ) ®with( $\emph{\R{params}}$)® { // syntax not allowed, illustration only1506 void f( S & s, char ®c® ) with ( s ) ®with( §\emph{\R{params}}§ )® { // syntax not allowed, illustration only 1508 1507 s.c = ®c;® i = 3; d = 5.5; 1509 1508 } … … 1538 1537 1539 1538 \begin{cfa} 1540 exception_t E {}; $\C{// exception type}$1539 exception_t E {}; §\C{// exception type}§ 1541 1540 void f(...) { 1542 ... throw E{}; ... $\C{// termination}$1543 ... throwResume E{}; ... $\C{// resumption}$1541 ... throw E{}; ... §\C{// termination}§ 1542 ... throwResume E{}; ... §\C{// resumption}§ 1544 1543 } 1545 1544 try { 1546 1545 f(...); 1547 } catch( E e ; $boolean-predicate$ ) { $\C{// termination handler}$1546 } catch( E e ; §boolean-predicate§ ) { §\C{// termination handler}§ 1548 1547 // recover and continue 1549 } catchResume( E e ; $boolean-predicate$ ) { $\C{// resumption handler}$1548 } catchResume( E e ; §boolean-predicate§ ) { §\C{// resumption handler}§ 1550 1549 // repair and return 1551 1550 } finally { … … 1624 1623 For example, a routine returning a \Index{pointer} to an array of integers is defined and used in the following way: 1625 1624 \begin{cfa} 1626 int ®(*®f®())[®5®]® {...}; $\C{// definition}$1627 ... ®(*®f®())[®3®]® += 1; $\C{// usage}$1625 int ®(*®f®())[®5®]® {...}; §\C{// definition}§ 1626 ... ®(*®f®())[®3®]® += 1; §\C{// usage}§ 1628 1627 \end{cfa} 1629 1628 Essentially, the return type is wrapped around the routine name in successive layers (like an \Index{onion}). … … 1870 1869 For example, \Index*{Algol68}~\cite{Algol68} infers pointer dereferencing to select the best meaning for each pointer usage 1871 1870 \begin{cfa} 1872 p2 = p1 + x; $\C{// compiler infers *p2 = *p1 + x;}$1871 p2 = p1 + x; §\C{// compiler infers *p2 = *p1 + x;}§ 1873 1872 \end{cfa} 1874 1873 Algol68 infers the following dereferencing ©*p2 = *p1 + x©, because adding the arbitrary integer value in ©x© to the address of ©p1© and storing the resulting address into ©p2© is an unlikely operation. … … 1878 1877 In C, objects of pointer type always manipulate the pointer object's address: 1879 1878 \begin{cfa} 1880 p1 = p2; $\C{// p1 = p2\ \ rather than\ \ *p1 = *p2}$1881 p2 = p1 + x; $\C{// p2 = p1 + x\ \ rather than\ \ *p2 = *p1 + x}$1879 p1 = p2; §\C{// p1 = p2\ \ rather than\ \ *p1 = *p2}§ 1880 p2 = p1 + x; §\C{// p2 = p1 + x\ \ rather than\ \ *p2 = *p1 + x}§ 1882 1881 \end{cfa} 1883 1882 even though the assignment to ©p2© is likely incorrect, and the programmer probably meant: 1884 1883 \begin{cfa} 1885 p1 = p2; $\C{// pointer address assignment}$1886 ®*®p2 = ®*®p1 + x; $\C{// pointed-to value assignment / operation}$1884 p1 = p2; §\C{// pointer address assignment}§ 1885 ®*®p2 = ®*®p1 + x; §\C{// pointed-to value assignment / operation}§ 1887 1886 \end{cfa} 1888 1887 The C semantics work well for situations where manipulation of addresses is the primary meaning and data is rarely accessed, such as storage management (©malloc©/©free©). … … 1901 1900 \begin{cfa} 1902 1901 int x, y, ®&® r1, ®&® r2, ®&&® r3; 1903 ®&®r1 = &x; $\C{// r1 points to x}$1904 ®&®r2 = &r1; $\C{// r2 points to x}$1905 ®&®r1 = &y; $\C{// r1 points to y}$1906 ®&&®r3 = ®&®&r2; $\C{// r3 points to r2}$1907 r2 = ((r1 + r2) * (r3 - r1)) / (r3 - 15); $\C{// implicit dereferencing}$1902 ®&®r1 = &x; §\C{// r1 points to x}§ 1903 ®&®r2 = &r1; §\C{// r2 points to x}§ 1904 ®&®r1 = &y; §\C{// r1 points to y}§ 1905 ®&&®r3 = ®&®&r2; §\C{// r3 points to r2}§ 1906 r2 = ((r1 + r2) * (r3 - r1)) / (r3 - 15); §\C{// implicit dereferencing}§ 1908 1907 \end{cfa} 1909 1908 Except for auto-dereferencing by the compiler, this reference example is the same as the previous pointer example. … … 1920 1919 For a \CFA reference type, the cancellation on the left-hand side of assignment leaves the reference as an address (\Index{lvalue}): 1921 1920 \begin{cfa} 1922 (&®*®)r1 = &x; $\C{// (\&*) cancel giving address in r1 not variable pointed-to by r1}$1921 (&®*®)r1 = &x; §\C{// (\&*) cancel giving address in r1 not variable pointed-to by r1}§ 1923 1922 \end{cfa} 1924 1923 Similarly, the address of a reference can be obtained for assignment or computation (\Index{rvalue}): 1925 1924 \begin{cfa} 1926 (&(&®*®)®*®)r3 = &(&®*®)r2; $\C{// (\&*) cancel giving address in r2, (\&(\&*)*) cancel giving address in r3}$1925 (&(&®*®)®*®)r3 = &(&®*®)r2; §\C{// (\&*) cancel giving address in r2, (\&(\&*)*) cancel giving address in r3}§ 1927 1926 \end{cfa} 1928 1927 Cancellation\index{cancellation!pointer/reference}\index{pointer!cancellation} works to arbitrary depth. … … 1932 1931 int x, *p1 = &x, **p2 = &p1, ***p3 = &p2, 1933 1932 &r1 = x, &&r2 = r1, &&&r3 = r2; 1934 ***p3 = 3; $\C{// change x}$1935 r3 = 3; $\C{// change x, ***r3}$1936 **p3 = ...; $\C{// change p1}$1937 &r3 = ...; $\C{// change r1, (\&*)**r3, 1 cancellation}$1938 *p3 = ...; $\C{// change p2}$1939 &&r3 = ...; $\C{// change r2, (\&(\&*)*)*r3, 2 cancellations}$1940 &&&r3 = p3; $\C{// change r3 to p3, (\&(\&(\&*)*)*)r3, 3 cancellations}$1933 ***p3 = 3; §\C{// change x}§ 1934 r3 = 3; §\C{// change x, ***r3}§ 1935 **p3 = ...; §\C{// change p1}§ 1936 &r3 = ...; §\C{// change r1, (\&*)**r3, 1 cancellation}§ 1937 *p3 = ...; §\C{// change p2}§ 1938 &&r3 = ...; §\C{// change r2, (\&(\&*)*)*r3, 2 cancellations}§ 1939 &&&r3 = p3; §\C{// change r3 to p3, (\&(\&(\&*)*)*)r3, 3 cancellations}§ 1941 1940 \end{cfa} 1942 1941 Furthermore, both types are equally performant, as the same amount of dereferencing occurs for both types. … … 1945 1944 As for a pointer type, a reference type may have qualifiers: 1946 1945 \begin{cfa} 1947 const int cx = 5; $\C{// cannot change cx;}$1948 const int & cr = cx; $\C{// cannot change what cr points to}$1949 ®&®cr = &cx; $\C{// can change cr}$1950 cr = 7; $\C{// error, cannot change cx}$1951 int & const rc = x; $\C{// must be initialized}$1952 ®&®rc = &x; $\C{// error, cannot change rc}$1953 const int & const crc = cx; $\C{// must be initialized}$1954 crc = 7; $\C{// error, cannot change cx}$1955 ®&®crc = &cx; $\C{// error, cannot change crc}$1946 const int cx = 5; §\C{// cannot change cx;}§ 1947 const int & cr = cx; §\C{// cannot change what cr points to}§ 1948 ®&®cr = &cx; §\C{// can change cr}§ 1949 cr = 7; §\C{// error, cannot change cx}§ 1950 int & const rc = x; §\C{// must be initialized}§ 1951 ®&®rc = &x; §\C{// error, cannot change rc}§ 1952 const int & const crc = cx; §\C{// must be initialized}§ 1953 crc = 7; §\C{// error, cannot change cx}§ 1954 ®&®crc = &cx; §\C{// error, cannot change crc}§ 1956 1955 \end{cfa} 1957 1956 Hence, for type ©& const©, there is no pointer assignment, so ©&rc = &x© is disallowed, and \emph{the address value cannot be the null pointer unless an arbitrary pointer is coerced\index{coercion} into the reference}: 1958 1957 \begin{cfa} 1959 int & const cr = *0; $\C{// where 0 is the int * zero}$1958 int & const cr = *0; §\C{// where 0 is the int * zero}§ 1960 1959 \end{cfa} 1961 1960 Note, constant reference-types do not prevent \Index{addressing errors} because of explicit storage-management: … … 1964 1963 cr = 5; 1965 1964 free( &cr ); 1966 cr = 7; $\C{// unsound pointer dereference}$1965 cr = 7; §\C{// unsound pointer dereference}§ 1967 1966 \end{cfa} 1968 1967 … … 1972 1971 \begin{cquote} 1973 1972 \begin{tabular}{@{}l@{\hspace{3em}}l@{}} 1974 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{C y}} & \multicolumn{1}{c}{\textbf{\CFA}} \\1973 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{C}} & \multicolumn{1}{c}{\textbf{\CFA}} \\ 1975 1974 \begin{cfa} 1976 1975 const int * ®const® * ®const® ccp; … … 1988 1987 Finally, like pointers, references are usable and composable with other type operators and generators. 1989 1988 \begin{cfa} 1990 int w, x, y, z, & ar[3] = { x, y, z }; $\C{// initialize array of references}$1991 &ar[1] = &w; $\C{// change reference array element}$1992 typeof( ar[1] ) p; $\C{// (gcc) is int, \ie the type of referenced object}$1993 typeof( &ar[1] ) q; $\C{// (gcc) is int \&, \ie the type of reference}$1994 sizeof( ar[1] ) == sizeof( int ); $\C{// is true, \ie the size of referenced object}$1995 sizeof( &ar[1] ) == sizeof( int *) $\C{// is true, \ie the size of a reference}$1989 int w, x, y, z, & ar[3] = { x, y, z }; §\C{// initialize array of references}§ 1990 &ar[1] = &w; §\C{// change reference array element}§ 1991 typeof( ar[1] ) p; §\C{// (gcc) is int, \ie the type of referenced object}§ 1992 typeof( &ar[1] ) q; §\C{// (gcc) is int \&, \ie the type of reference}§ 1993 sizeof( ar[1] ) == sizeof( int ); §\C{// is true, \ie the size of referenced object}§ 1994 sizeof( &ar[1] ) == sizeof( int *) §\C{// is true, \ie the size of a reference}§ 1996 1995 \end{cfa} 1997 1996 … … 2010 2009 Therefore, for pointer/reference initialization, the initializing value must be an address not a value. 2011 2010 \begin{cfa} 2012 int * p = &x; $\C{// assign address of x}$2013 ®int * p = x;® $\C{// assign value of x}$2014 int & r = x; $\C{// must have address of x}$2011 int * p = &x; §\C{// assign address of x}§ 2012 ®int * p = x;® §\C{// assign value of x}§ 2013 int & r = x; §\C{// must have address of x}§ 2015 2014 \end{cfa} 2016 2015 Like the previous example with C pointer-arithmetic, it is unlikely assigning the value of ©x© into a pointer is meaningful (again, a warning is usually given). … … 2021 2020 Similarly, when a reference type is used for a parameter/return type, the call-site argument does not require a reference operator for the same reason. 2022 2021 \begin{cfa} 2023 int & f( int & r ); $\C{// reference parameter and return}$2024 z = f( x ) + f( y ); $\C{// reference operator added, temporaries needed for call results}$2022 int & f( int & r ); §\C{// reference parameter and return}§ 2023 z = f( x ) + f( y ); §\C{// reference operator added, temporaries needed for call results}§ 2025 2024 \end{cfa} 2026 2025 Within routine ©f©, it is possible to change the argument by changing the corresponding parameter, and parameter ©r© can be locally reassigned within ©f©. … … 2049 2048 void f( int & r ); 2050 2049 void g( int * p ); 2051 f( 3 ); g( ®&®3 ); $\C{// compiler implicit generates temporaries}$2052 f( x + y ); g( ®&®(x + y) ); $\C{// compiler implicit generates temporaries}$2050 f( 3 ); g( ®&®3 ); §\C{// compiler implicit generates temporaries}§ 2051 f( x + y ); g( ®&®(x + y) ); §\C{// compiler implicit generates temporaries}§ 2053 2052 \end{cfa} 2054 2053 Essentially, there is an implicit \Index{rvalue} to \Index{lvalue} conversion in this case.\footnote{ … … 2061 2060 \begin{cfa} 2062 2061 void f( int i ); 2063 void (* fp)( int ); $\C{// routine pointer}$2064 fp = f; $\C{// reference initialization}$2065 fp = &f; $\C{// pointer initialization}$2066 fp = *f; $\C{// reference initialization}$2067 fp(3); $\C{// reference invocation}$2068 (*fp)(3); $\C{// pointer invocation}$2062 void (* fp)( int ); §\C{// routine pointer}§ 2063 fp = f; §\C{// reference initialization}§ 2064 fp = &f; §\C{// pointer initialization}§ 2065 fp = *f; §\C{// reference initialization}§ 2066 fp(3); §\C{// reference invocation}§ 2067 (*fp)(3); §\C{// pointer invocation}§ 2069 2068 \end{cfa} 2070 2069 While C's treatment of routine objects has similarity to inferring a reference type in initialization contexts, the examples are assignment not initialization, and all possible forms of assignment are possible (©f©, ©&f©, ©*f©) without regard for type. 2071 2070 Instead, a routine object should be referenced by a ©const© reference: 2072 2071 \begin{cfa} 2073 ®const® void (®&® fr)( int ) = f; $\C{// routine reference}$2074 fr = ... $\C{// error, cannot change code}$2075 &fr = ...; $\C{// changing routine reference}$2076 fr( 3 ); $\C{// reference call to f}$2077 (*fr)(3); $\C{// error, incorrect type}$2072 ®const® void (®&® fr)( int ) = f; §\C{// routine reference}§ 2073 fr = ...; §\C{// error, cannot change code}§ 2074 &fr = ...; §\C{// changing routine reference}§ 2075 fr( 3 ); §\C{// reference call to f}§ 2076 (*fr)(3); §\C{// error, incorrect type}§ 2078 2077 \end{cfa} 2079 2078 because the value of the routine object is a routine literal, \ie the routine code is normally immutable during execution.\footnote{ … … 2097 2096 int x, * px, ** ppx, *** pppx, **** ppppx; 2098 2097 int & rx = x, && rrx = rx, &&& rrrx = rrx ; 2099 x = rrrx; $\C[2.0in]{// rrrx is an lvalue with type int \&\&\& (equivalent to x)}$2100 px = &rrrx; $\C{// starting from rrrx, \&rrrx is an rvalue with type int *\&\&\& (\&x)}$2101 ppx = &&rrrx; $\C{// starting from \&rrrx, \&\&rrrx is an rvalue with type int **\&\& (\&rx)}$2102 pppx = &&&rrrx; $\C{// starting from \&\&rrrx, \&\&\&rrrx is an rvalue with type int ***\& (\&rrx)}$2103 ppppx = &&&&rrrx; $\C{// starting from \&\&\&rrrx, \&\&\&\&rrrx is an rvalue with type int **** (\&rrrx)}$2098 x = rrrx; §\C{// rrrx is an lvalue with type int \&\&\& (equivalent to x)}§ 2099 px = &rrrx; §\C{// starting from rrrx, \&rrrx is an rvalue with type int *\&\&\& (\&x)}§ 2100 ppx = &&rrrx; §\C{// starting from \&rrrx, \&\&rrrx is an rvalue with type int **\&\& (\&rx)}§ 2101 pppx = &&&rrrx; §\C{// starting from \&\&rrrx, \&\&\&rrrx is an rvalue with type int ***\& (\&rrx)}§ 2102 ppppx = &&&&rrrx; §\C{// starting from \&\&\&rrrx, \&\&\&\&rrrx is an rvalue with type int **** (\&rrrx)}§ 2104 2103 \end{cfa} 2105 2104 The following example shows the second rule applied to different \Index{lvalue} contexts: … … 2107 2106 int x, * px, ** ppx, *** pppx; 2108 2107 int & rx = x, && rrx = rx, &&& rrrx = rrx ; 2109 rrrx = 2; $\C{// rrrx is an lvalue with type int \&\&\& (equivalent to x)}$2110 &rrrx = px; $\C{// starting from rrrx, \&rrrx is an rvalue with type int *\&\&\& (rx)}$2111 &&rrrx = ppx; $\C{// starting from \&rrrx, \&\&rrrx is an rvalue with type int **\&\& (rrx)}$2112 &&&rrrx = pppx; $\C{// starting from \&\&rrrx, \&\&\&rrrx is an rvalue with type int ***\& (rrrx)}\CRT$2108 rrrx = 2; §\C{// rrrx is an lvalue with type int \&\&\& (equivalent to x)}§ 2109 &rrrx = px; §\C{// starting from rrrx, \&rrrx is an rvalue with type int *\&\&\& (rx)}§ 2110 &&rrrx = ppx; §\C{// starting from \&rrrx, \&\&rrrx is an rvalue with type int **\&\& (rrx)}§ 2111 &&&rrrx = pppx; §\C{// starting from \&\&rrrx, \&\&\&rrrx is an rvalue with type int ***\& (rrrx)}§ 2113 2112 \end{cfa} 2114 2113 … … 2123 2122 \begin{cfa} 2124 2123 int x; 2125 x + 1; $\C[2.0in]{// lvalue variable (int) converts to rvalue for expression}$2124 x + 1; §\C{// lvalue variable (int) converts to rvalue for expression}§ 2126 2125 \end{cfa} 2127 2126 An rvalue has no type qualifiers (©cv©), so the lvalue qualifiers are dropped. … … 2133 2132 \begin{cfa} 2134 2133 int x, &r = x, f( int p ); 2135 x = ®r® + f( ®r® ); $\C{// lvalue reference converts to rvalue}$2134 x = ®r® + f( ®r® ); §\C{// lvalue reference converts to rvalue}§ 2136 2135 \end{cfa} 2137 2136 An rvalue has no type qualifiers (©cv©), so the reference qualifiers are dropped. … … 2140 2139 lvalue to reference conversion: \lstinline[deletekeywords=lvalue]{lvalue-type cv1 T} converts to ©cv2 T &©, which allows implicitly converting variables to references. 2141 2140 \begin{cfa} 2142 int x, &r = ®x®, f( int & p ); $\C{// lvalue variable (int) convert to reference (int \&)}$2143 f( ®x® ); $\C{// lvalue variable (int) convert to reference (int \&)}\CRT$2141 int x, &r = ®x®, f( int & p ); §\C{// lvalue variable (int) convert to reference (int \&)}§ 2142 f( ®x® ); §\C{// lvalue variable (int) convert to reference (int \&)}§ 2144 2143 \end{cfa} 2145 2144 Conversion can restrict a type, where ©cv1© $\le$ ©cv2©, \eg passing an ©int© to a ©const volatile int &©, which has low cost. … … 2151 2150 \begin{cfa} 2152 2151 int x, & f( int & p ); 2153 f( ®x + 3® ); $\C[1.5in]{// rvalue parameter (int) implicitly converts to lvalue temporary reference (int \&)}$2154 ®&f®(...) = &x; $\C{// rvalue result (int \&) implicitly converts to lvalue temporary reference (int \&)}\CRT$2152 f( ®x + 3® ); §\C{// rvalue parameter (int) implicitly converts to lvalue temporary reference (int \&)}§ 2153 ®&f®(...) = &x; §\C{// rvalue result (int \&) implicitly converts to lvalue temporary reference (int \&)}§ 2155 2154 \end{cfa} 2156 2155 In both case, modifications to the temporary are inaccessible (\Index{warning}). … … 2319 2318 2320 2319 2320 \section{\lstinline{string} Type} 2321 \label{s:stringType} 2322 2323 The \CFA \Indexc{string} type is for manipulation of dynamically-size character-strings versus C \Indexc{char *} type for manipulation of statically-size null-terminated character-strings. 2324 That is, the amount of storage for a \CFA string changes dynamically at runtime to fit the string size, whereas the amount of storage for a C string is fixed at compile time. 2325 Hence, a ©string© declaration does not specify a maximum length; 2326 as a string dynamically grows and shrinks in size, so does its underlying storage. 2327 In contrast, a C string also dynamically grows and shrinks is size, but its underlying storage is fixed. 2328 The maximum storage for a \CFA ©string© value is ©size_t© characters, which is $2^{32}$ or $2^{64}$ respectively. 2329 A \CFA string manages its length separately from the string, so there is no null (©'\0'©) terminating value at the end of a string value. 2330 Hence, a \CFA string cannot be passed to a C string manipulation routine, such as ©strcat©. 2331 Like C strings, the characters in a ©string© are numbered starting from 0. 2332 2333 The following operations have been defined to manipulate an instance of type ©string©. 2334 The discussion assumes the following declarations and assignment statements are executed. 2335 \begin{cfa} 2336 #include ®<string.hfa>® 2337 ®string® s, peter, digit, alpha, punctuation, ifstmt; 2338 int i; 2339 peter = "PETER"; 2340 digit = "0123456789"; 2341 punctuation = "().,"; 2342 ifstmt = "IF (A > B) {"; 2343 \end{cfa} 2344 Note, the include file \Indexc{string.hfa} to access type ©string©. 2345 2346 2347 \subsection{Implicit String Conversions} 2348 2349 The types ©char©, ©char *©, ©int©, ©double©, ©_Complex©, including signness and different sizes, implicitly convert to type ©string©. 2350 \VRef[Figure]{f:ImplicitStringConversions} shows examples of implicit conversion between C strings, integral, floating-point and complex types to ©string© 2351 The implicit conversions can be specified explicitly, as in: 2352 \begin{cfa} 2353 s = string( "abc" ); // converts char * to string 2354 s = string( 5 ); // converts int to string 2355 s = string( 5.5 ); // converts double to string 2356 \end{cfa} 2357 Conversions from ©string© to ©char *© are supported but with restrictions. 2358 Explicit As well, when a string is converted to a ©char *©, the storage for the ©char *© is created by the conversion operation, which must be subsequently deleted: 2359 \begin{cfa} 2360 string x = "abc"; 2361 char *p = x; // convert from string to char * 2362 ... 2363 delete p; // free storage created for p 2364 \end{cfa} 2365 2366 \begin{figure} 2367 \begin{tabular}{@{}l@{\hspace{15pt}}|@{\hspace{15pt}}l@{}} 2368 \begin{cfa} 2369 // string s = 5; sout | s; 2370 string s; 2371 // conversion of char and char * to string 2372 s = 'x'; §\CD{sout | s;}§ 2373 s = "abc"; §\CD{sout | s;}§ 2374 char cs[5] = "abc"; 2375 s = cs; §\CD{sout | s;}§ 2376 // conversion of integral, floating-point, and complex to string 2377 s = 45hh; §\CD{sout | s;}§ 2378 s = 45h; §\CD{sout | s;}§ 2379 s = -(ssize_t)MAX - 1; §\CD{sout | s;}§ 2380 s = (size_t)MAX; §\CD{sout | s;}§ 2381 s = 5.5; §\CD{sout | s;}§ 2382 s = 5.5L; §\CD{sout | s;}§ 2383 s = 5.5+3.4i; §\CD{sout | s;}§ 2384 s = 5.5L+3.4Li; §\CD{sout | s;}§ 2385 // safe conversion from string to char * 2386 strncpy( cs, s, sizeof(cs) ); §\CD{sout | cs;}§ 2387 char * cp = s; §\CD{sout | cp; // ownership}§ 2388 delete( cp ); 2389 cp = s + ' ' + s; §\CD{sout | cp; // ownership}§ 2390 delete( cp ); 2391 \end{cfa} 2392 & 2393 \begin{cfa} 2394 2395 2396 2397 x 2398 abc 2399 2400 abc 2401 2402 45 2403 45 2404 -9223372036854775808 2405 18446744073709551615 2406 5.5 2407 5.5 2408 5.5+3.4i 2409 5.5+3.4i 2410 2411 5.5+ 2412 5.5+3.4i 2413 2414 5.5+3.4i 5.5+3.4i 2415 2416 \end{cfa} 2417 \end{tabular} 2418 \caption{Implicit String Conversions} 2419 \label{f:ImplicitStringConversions} 2420 \end{figure} 2421 2422 2423 \subsection{Comparison Operators} 2424 2425 The binary relational and equality operators ©<©, ©<=©, ©>©, ©>=©, ©==©, ©!=© compare ©string© using lexicographical ordering, where longer strings are greater than shorter strings. 2426 2427 2428 \subsection{Concatenation} 2429 2430 The binary operator ©+© concatenates two strings. 2431 \begin{cfa} 2432 s = peter + digit; §\C{// s is assigned "PETER0123456789"}§ 2433 s += peter; §\C{// s is assigned "PETER0123456789PETER"}§ 2434 \end{cfa} 2435 There is also an assignment form ©+=©. 2436 2437 2438 \subsection{Repetition} 2439 2440 The binary operator \Indexc{*} returns a string that is the string repeated ©n© times. 2441 If ©n = 0©, a zero length string, ©""© is returned. 2442 \begin{cfa} 2443 s = (peter + ' ') * 3; §\C{// s is assigned "PETER PETER PETER"}§ 2444 \end{cfa} 2445 There is also an assignment form ©*=©. 2446 2447 2448 \subsection{Length} 2449 2450 The ©length© operation 2451 \begin{cfa} 2452 int length() 2453 \end{cfa} 2454 returns the length of a string variable. 2455 \begin{cfa} 2456 i = peter.length(); §\C{// i is assigned the value 5}§ 2457 \end{cfa} 2458 2459 2460 \subsection{Substring} 2461 The substring operation: 2462 \begin{cfa} 2463 string operator () (int start, int lnth); 2464 \end{cfa} 2465 performs a substring operation that returns the string starting at a specified position (©start©) in the current string, and having the specified length (©lnth©). 2466 A negative starting position is a specification from the right end of the string. 2467 A negative length means that characters are selected in the opposite (right to left) direction from the starting position. 2468 If the substring request extends beyond the beginning or end of the string, it is clipped (shortened) to the bounds of the string. 2469 If the substring request is completely outside of the original string, a null string located at the end of the original string is returned. 2470 \begin{cfa} 2471 s = peter( 2, 3 ); §\C{// s is assigned "ETE"}§ 2472 s = peter( 4, -3 ); §\C{// s is assigned "ETE", length is opposite direction}§ 2473 s = peter( 2, 8 ); §\C{// s is assigned "ETER", length is clipped to 4}§ 2474 s = peter( 0, -1 ); §\C{// s is assigned "", beyond string so clipped to null}§ 2475 s = peter(-1, -1 ); §\C{// s is assigned "R", start and length are negative}§ 2476 \end{cfa} 2477 The substring operation can also appear on the left hand side of the assignment operator. 2478 The substring is replaced by the value on the right hand side of the assignment. 2479 The length of the right-hand-side value may be shorter, the same length, or longer than the length of the substring that is selected on the left hand side of the assignment. 2480 \begin{cfa}[mathescape=false] 2481 digit( 3, 3 ) = ""; §\C{// digit is assigned "0156789"}§ 2482 digit( 4, 3 ) = "xyz"; §\C{// digit is assigned "015xyz9"}§ 2483 digit( 7, 0 ) = "***"; §\C{// digit is assigned "015xyz***9"}§ 2484 digit(-4, 3 ) = "$$$"; §\C{// digit is assigned "015xyz\$\$\$9"}§ 2485 \end{cfa} 2486 A substring is treated as a pointer into the base (substringed) string rather than creating a copy of the subtext. 2487 As with all pointers, if the item they are pointing at is changed, then the pointer is referring to the changed item. 2488 Pointers to the result value of a substring operation are defined to always start at the same location in their base string as long as that starting location exists, independent of changes to themselves or the base string. 2489 However, if the base string value changes, this may affect the values of one or more of the substrings to that base string. 2490 If the base string value shortens so that its end is before the starting location of a substring, resulting in the substring starting location disappearing, the substring becomes a null string located at the end of the base string. 2491 2492 The following example illustrates passing the results of substring operations by reference and by value to a subprogram. 2493 Notice the side-effects to other reference parameters as one is modified. 2494 \begin{cfa} 2495 main() { 2496 string x = "xxxxxxxxxxxxx"; 2497 test( x, x(1,3), x(3,3), x(5,5), x(9,5), x(9,5) ); 2498 } 2499 2500 // x, a, b, c, & d are substring results passed by reference 2501 // e is a substring result passed by value 2502 void test(string &x, string &a, string &b, string &c, string &d, string e) { 2503 §\C{// x a b c d e}§ 2504 a( 1, 2 ) = "aaa"; §\C{// aaaxxxxxxxxxxx aaax axx xxxxx xxxxx xxxxx}§ 2505 b( 2, 12 ) = "bbb"; §\C{// aaabbbxxxxxxxxx aaab abbb bbxxx xxxxx xxxxx}§ 2506 c( 4, 5 ) = "ccc"; §\C{// aaabbbxcccxxxxxx aaab abbb bbxccc ccxxx xxxxx}§ 2507 c = "yyy"; §\C{// aaabyyyxxxxxx aaab abyy yyy xxxxx xxxxx}§ 2508 d( 1, 3 ) = "ddd"; §\C{// aaabyyyxdddxx aaab abyy yyy dddxx xxxxx}§ 2509 e( 1, 3 ) = "eee"; §\C{// aaabyyyxdddxx aaab abyy yyy dddxx eeexx}§ 2510 x = e; §\C{// eeexx eeex exx x eeexx}§ 2511 } 2512 \end{cfa} 2513 2514 There is an assignment form of substring in which only the starting position is specified and the length is assumed to be the remainder of the string. 2515 \begin{cfa} 2516 string operator () (int start); 2517 \end{cfa} 2518 For example: 2519 \begin{cfa} 2520 s = peter( 2 ); §\C{// s is assigned "ETER"}§ 2521 peter( 2 ) = "IPER"; §\C{// peter is assigned "PIPER"}§ 2522 \end{cfa} 2523 It is also possible to substring using a string as the index for selecting the substring portion of the string. 2524 \begin{cfa} 2525 string operator () (const string &index); 2526 \end{cfa} 2527 For example: 2528 \begin{cfa}[mathescape=false] 2529 digit( "xyz$$$" ) = "678"; §\C{// digit is assigned "0156789"}§ 2530 digit( "234") = "***"; §\C{// digit is assigned "0156789***"}§ 2531 \end{cfa} 2532 %$ 2533 2534 2535 \subsection{Searching} 2536 2537 The ©index© operation 2538 \begin{cfa} 2539 int index( const string &key, int start = 1, occurrence occ = first ); 2540 \end{cfa} 2541 returns the position of the first or last occurrence of the ©key© (depending on the occurrence indicator ©occ© that is either ©first© or ©last©) in the current string starting the search at position ©start©. 2542 If the ©key© does not appear in the current string, the length of the current string plus one is returned. 2543 %If the ©key© has zero length, the value 1 is returned regardless of what the current string contains. 2544 A negative starting position is a specification from the right end of the string. 2545 \begin{cfa} 2546 i = digit.index( "567" ); §\C{// i is assigned 3}§ 2547 i = digit.index( "567", 7 ); §\C{// i is assigned 11}§ 2548 i = digit.index( "567", -1, last ); §\C{// i is assigned 3}§ 2549 i = peter.index( "E", 5, last ); §\C{// i is assigned 4}§ 2550 \end{cfa} 2551 2552 The next two string operations test a string to see if it is or is not composed completely of a particular class of characters. 2553 For example, are the characters of a string all alphabetic or all numeric? 2554 Use of these operations involves a two step operation. 2555 First, it is necessary to create an instance of type ©strmask© and initialize it to a string containing the characters of the particular character class, as in: 2556 \begin{cfa} 2557 strmask digitmask = digit; 2558 strmask alphamask = string( "abcdefghijklmnopqrstuvwxyz" ); 2559 \end{cfa} 2560 Second, the character mask is used in the functions ©include© and ©exclude© to check a string for compliance of its characters with the characters indicated by the mask. 2561 2562 The ©include© operation 2563 \begin{cfa} 2564 int include( const strmask &, int = 1, occurrence occ = first ); 2565 \end{cfa} 2566 returns the position of the first or last character (depending on the occurrence indicator, which is either ©first© or ©last©) in the current string that does not appear in the ©mask© starting the search at position ©start©; 2567 hence it skips over characters in the current string that are included (in) the ©mask©. 2568 The characters in the current string do not have to be in the same order as the ©mask©. 2569 If all the characters in the current string appear in the ©mask©, the length of the current string plus one is returned, regardless of which occurrence is being searched for. 2570 A negative starting position is a specification from the right end of the string. 2571 \begin{cfa} 2572 i = peter.include( digitmask ); §\C{// i is assigned 1}§ 2573 i = peter.include( alphamask ); §\C{// i is assigned 6}§ 2574 \end{cfa} 2575 2576 The ©exclude© operation 2577 \begin{cfa} 2578 int exclude( string &mask, int start = 1, occurrence occ = first ) 2579 \end{cfa} 2580 returns the position of the first or last character (depending on the occurrence indicator, which is either ©first© or ©last©) in the current string that does appear in the ©mask© string starting the search at position ©start©; 2581 hence it skips over characters in the current string that are excluded from (not in) in the ©mask© string. 2582 The characters in the current string do not have to be in the same order as the ©mask© string. 2583 If all the characters in the current string do NOT appear in the ©mask© string, the length of the current string plus one is returned, regardless of which occurrence is being searched for. 2584 A negative starting position is a specification from the right end of the string. 2585 \begin{cfa} 2586 i = peter.exclude( digitmask ); §\C{// i is assigned 6}§ 2587 i = ifstmt.exclude( strmask( punctuation ) ); §\C{// i is assigned 4}§ 2588 \end{cfa} 2589 2590 The ©includeStr© operation: 2591 \begin{cfa} 2592 string includeStr( strmask &mask, int start = 1, occurrence occ = first ) 2593 \end{cfa} 2594 returns the longest substring of leading or trailing characters (depending on the occurrence indicator, which is either ©first© or ©last©) of the current string that ARE included in the ©mask© string starting the search at position ©start©. 2595 A negative starting position is a specification from the right end of the string. 2596 \begin{cfa} 2597 s = peter.includeStr( alphamask ); §\C{// s is assigned "PETER"}§ 2598 s = ifstmt.includeStr( alphamask ); §\C{// s is assigned "IF"}§ 2599 s = peter.includeStr( digitmask ); §\C{// s is assigned ""}§ 2600 \end{cfa} 2601 2602 The ©excludeStr© operation: 2603 \begin{cfa} 2604 string excludeStr( strmask &mask, int start = 1, occurrence = first ) 2605 \end{cfa} 2606 returns the longest substring of leading or trailing characters (depending on the occurrence indicator, which is either ©first© or ©last©) of the current string that are excluded (NOT) in the ©mask© string starting the search at position ©start©. 2607 A negative starting position is a specification from the right end of the string. 2608 \begin{cfa} 2609 s = peter.excludeStr( digitmask); §\C{// s is assigned "PETER"}§ 2610 s = ifstmt.excludeStr( strmask( punctuation ) ); §\C{// s is assigned "IF "}§ 2611 s = peter.excludeStr( alphamask); §\C{// s is assigned ""}§ 2612 \end{cfa} 2613 2614 2615 \subsection{Miscellaneous} 2616 2617 The ©trim© operation 2618 \begin{cfa} 2619 string trim( string &mask, occurrence occ = first ) 2620 \end{cfa} 2621 returns a string in that is the longest substring of leading or trailing characters (depending on the occurrence indicator, which is either ©first© or ©last©) which ARE included in the ©mask© are removed. 2622 \begin{cfa} 2623 // remove leading blanks 2624 s = string( " ABC" ).trim( " " ); §\C{// s is assigned "ABC",}§ 2625 // remove trailing blanks 2626 s = string( "ABC " ).trim( " ", last ); §\C{// s is assigned "ABC",}§ 2627 \end{cfa} 2628 2629 The ©translate© operation 2630 \begin{cfa} 2631 string translate( string &from, string &to ) 2632 \end{cfa} 2633 returns a string that is the same length as the original string in which all occurrences of the characters that appear in the ©from© string have been translated into their corresponding character in the ©to© string. 2634 Translation is done on a character by character basis between the ©from© and ©to© strings; hence these two strings must be the same length. 2635 If a character in the original string does not appear in the ©from© string, then it simply appears as is in the resulting string. 2636 \begin{cfa} 2637 // upper to lower case 2638 peter = peter.translate( "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz" ); 2639 // peter is assigned "peter" 2640 s = ifstmt.translate( "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz" ); 2641 // ifstmt is assigned "if (a > b) {" 2642 // lower to upper case 2643 peter = peter.translate( "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ); 2644 // peter is assigned "PETER" 2645 \end{cfa} 2646 2647 The ©replace© operation 2648 \begin{cfa} 2649 string replace( string &from, string &to ) 2650 \end{cfa} 2651 returns a string in which all occurrences of the ©from© string in the current string have been replaced by the ©to© string. 2652 \begin{cfa} 2653 s = peter.replace( "E", "XX" ); §\C{// s is assigned "PXXTXXR"}§ 2654 \end{cfa} 2655 The replacement is done left-to-right. 2656 When an instance of the ©from© string is found and changed to the ©to© string, it is NOT examined again for further replacement. 2657 2658 2659 \section{Returning N+1 on Failure} 2660 2661 Any of the string search routines can fail at some point during the search. 2662 When this happens it is necessary to return indicating the failure. 2663 Many string types in other languages use some special value to indicate the failure. 2664 This value is often 0 or -1 (PL/I returns 0). 2665 This section argues that a value of N+1, where N is the length of the base string in the search, is a more useful value to return. 2666 The index-of function in APL returns N+1. 2667 These are the boundary situations and are often overlooked when designing a string type. 2668 2669 The situation that can be optimized by returning N+1 is when a search is performed to find the starting location for a substring operation. 2670 For example, in a program that is extracting words from a text file, it is necessary to scan from left to right over whitespace until the first alphabetic character is found. 2671 \begin{cfa} 2672 line = line( line.exclude( alpha ) ); 2673 \end{cfa} 2674 If a text line contains all whitespaces, the exclude operation fails to find an alphabetic character. 2675 If ©exclude© returns 0 or -1, the result of the substring operation is unclear. 2676 Most string types generate an error, or clip the starting value to 1, resulting in the entire whitespace string being selected. 2677 If ©exclude© returns N+1, the starting position for the substring operation is beyond the end of the string leaving a null string. 2678 2679 The same situation occurs when scanning off a word. 2680 \begin{cfa} 2681 start = line.include(alpha); 2682 word = line(1, start - 1); 2683 \end{cfa} 2684 If the entire line is composed of a word, the include operation will fail to find a non-alphabetic character. 2685 In general, returning 0 or -1 is not an appropriate starting position for the substring, which must substring off the word leaving a null string. 2686 However, returning N+1 will substring off the word leaving a null string. 2687 2688 2689 \subsection{Input/Output Operators} 2690 2691 Both the \CC operators ©<<© and ©>>© are defined on type ©string©. 2692 However, input of a string value is different from input of a ©char *© value. 2693 When a string value is read, \emph{all} input characters from the current point in the input stream to either the end of line (©'\n'©) or the end of file are read. 2694 2695 2321 2696 \section{Enumeration} 2322 2697 … … 2332 2707 Hence, enums may be overloaded with variable, enum, and function names. 2333 2708 \begin{cfa} 2334 int Foo; $\C{// type/variable separate namespaces}$2709 int Foo; §\C{// type/variable separate namespaces}§ 2335 2710 enum Foo { Bar }; 2336 enum Goo { Bar }; $\C[1.75in]{// overload Foo.Bar}$2337 double Bar; $\C{// overload Foo.Bar, Goo.Bar}\CRT$2711 enum Goo { Bar }; §\C[1.75in]{// overload Foo.Bar}§ 2712 double Bar; §\C{// overload Foo.Bar, Goo.Bar}\CRT§ 2338 2713 \end{cfa} 2339 2714 An anonymous enumeration injects enums with specific values into a scope. … … 2408 2783 The following examples illustrate the difference between the enumeration type and the type of its enums. 2409 2784 \begin{cfa} 2410 Math m = PI; $\C[1.5in]{// allowed}$2411 double d = PI; $\C{// allowed, conversion to base type}$2412 m = E; $\C{// allowed}$2413 m = Alph; $\C{// {\color{red}disallowed}}$2414 m = 3.141597; $\C{// {\color{red}disallowed}}$2415 d = m; $\C{// allowed}$2416 d = Alph; $\C{// {\color{red}disallowed}}$2417 Letter l = A; $\C{// allowed}$2418 Greek g = Alph; $\C{// allowed}$2419 l = Alph; $\C{// allowed, conversion to base type}$2420 g = A; $\C{// {\color{red}disallowed}}\CRT$2785 Math m = PI; §\C[1.5in]{// allowed}§ 2786 double d = PI; §\C{// allowed, conversion to base type}§ 2787 m = E; §\C{// allowed}§ 2788 m = Alph; §\C{// {\color{red}disallowed}}§ 2789 m = 3.141597; §\C{// {\color{red}disallowed}}§ 2790 d = m; §\C{// allowed}§ 2791 d = Alph; §\C{// {\color{red}disallowed}}§ 2792 Letter l = A; §\C{// allowed}§ 2793 Greek g = Alph; §\C{// allowed}§ 2794 l = Alph; §\C{// allowed, conversion to base type}§ 2795 g = A; §\C{// {\color{red}disallowed}}\CRT§ 2421 2796 \end{cfa} 2422 2797 … … 2508 2883 \begin{cfa} 2509 2884 ®[ int o1, int o2, char o3 ]® f( int i1, char i2, char i3 ) { 2510 $\emph{routine body}$2885 §\emph{routine body}§ 2511 2886 } 2512 2887 \end{cfa} … … 2519 2894 Declaration qualifiers can only appear at the start of a routine definition, \eg: 2520 2895 \begin{cfa} 2521 ®extern® [ int x ] g( int y ) { $\,$}2896 ®extern® [ int x ] g( int y ) {§\,§} 2522 2897 \end{cfa} 2523 2898 Lastly, if there are no output parameters or input parameters, the brackets and/or parentheses must still be specified; 2524 2899 in both cases the type is assumed to be void as opposed to old style C defaults of int return type and unknown parameter types, respectively, as in: 2525 2900 \begin{cfa} 2526 [ $\,$] g(); $\C{// no input or output parameters}$2527 [ void ] g( void ); $\C{// no input or output parameters}$2901 [§\,§] g(); §\C{// no input or output parameters}§ 2902 [ void ] g( void ); §\C{// no input or output parameters}§ 2528 2903 \end{cfa} 2529 2904 … … 2543 2918 \begin{cfa} 2544 2919 typedef int foo; 2545 int f( int (* foo) ); $\C{// foo is redefined as a parameter name}$2920 int f( int (* foo) ); §\C{// foo is redefined as a parameter name}§ 2546 2921 \end{cfa} 2547 2922 The string ``©int (* foo)©'' declares a C-style named-parameter of type pointer to an integer (the parenthesis are superfluous), while the same string declares a \CFA style unnamed parameter of type routine returning integer with unnamed parameter of type pointer to foo. … … 2551 2926 C-style declarations can be used to declare parameters for \CFA style routine definitions, \eg: 2552 2927 \begin{cfa} 2553 [ int ] f( * int, int * ); $\C{// returns an integer, accepts 2 pointers to integers}$2554 [ * int, int * ] f( int ); $\C{// returns 2 pointers to integers, accepts an integer}$2928 [ int ] f( * int, int * ); §\C{// returns an integer, accepts 2 pointers to integers}§ 2929 [ * int, int * ] f( int ); §\C{// returns 2 pointers to integers, accepts an integer}§ 2555 2930 \end{cfa} 2556 2931 The reason for allowing both declaration styles in the new context is for backwards compatibility with existing preprocessor macros that generate C-style declaration-syntax, as in: 2557 2932 \begin{cfa} 2558 2933 #define ptoa( n, d ) int (*n)[ d ] 2559 int f( ptoa( p, 5 ) ) ... $\C{// expands to int f( int (*p)[ 5 ] )}$2560 [ int ] f( ptoa( p, 5 ) ) ... $\C{// expands to [ int ] f( int (*p)[ 5 ] )}$2934 int f( ptoa( p, 5 ) ) ... §\C{// expands to int f( int (*p)[ 5 ] )}§ 2935 [ int ] f( ptoa( p, 5 ) ) ... §\C{// expands to [ int ] f( int (*p)[ 5 ] )}§ 2561 2936 \end{cfa} 2562 2937 Again, programmers are highly encouraged to use one declaration form or the other, rather than mixing the forms. … … 2580 2955 int z; 2581 2956 ... x = 0; ... y = z; ... 2582 ®return;® $\C{// implicitly return x, y}$2957 ®return;® §\C{// implicitly return x, y}§ 2583 2958 } 2584 2959 \end{cfa} … … 2590 2965 [ int x, int y ] f() { 2591 2966 ... 2592 } $\C{// implicitly return x, y}$2967 } §\C{// implicitly return x, y}§ 2593 2968 \end{cfa} 2594 2969 In this case, the current values of ©x© and ©y© are returned to the calling routine just as if a ©return© had been encountered. … … 2599 2974 [ int x, int y ] f( int, x, int y ) { 2600 2975 ... 2601 } $\C{// implicitly return x, y}$2976 } §\C{// implicitly return x, y}§ 2602 2977 \end{cfa} 2603 2978 This notation allows the compiler to eliminate temporary variables in nested routine calls. 2604 2979 \begin{cfa} 2605 [ int x, int y ] f( int, x, int y ); $\C{// prototype declaration}$2980 [ int x, int y ] f( int, x, int y ); §\C{// prototype declaration}§ 2606 2981 int a, b; 2607 2982 [a, b] = f( f( f( a, b ) ) ); … … 2617 2992 as well, parameter names are optional, \eg: 2618 2993 \begin{cfa} 2619 [ int x ] f (); $\C{// returning int with no parameters}$2620 [ * int ] g (int y); $\C{// returning pointer to int with int parameter}$2621 [ ] h ( int, char ); $\C{// returning no result with int and char parameters}$2622 [ * int, int ] j ( int ); $\C{// returning pointer to int and int, with int parameter}$2994 [ int x ] f (); §\C{// returning int with no parameters}§ 2995 [ * int ] g (int y); §\C{// returning pointer to int with int parameter}§ 2996 [ ] h ( int, char ); §\C{// returning no result with int and char parameters}§ 2997 [ * int, int ] j ( int ); §\C{// returning pointer to int and int, with int parameter}§ 2623 2998 \end{cfa} 2624 2999 This syntax allows a prototype declaration to be created by cutting and pasting source text from the routine definition header (or vice versa). … … 2626 3001 \begin{cfa} 2627 3002 C : const double bar1(), bar2( int ), bar3( double ); 2628 $\CFA$: [const double] foo(), foo( int ), foo( double ) { return 3.0; }3003 §\CFA§: [const double] foo(), foo( int ), foo( double ) { return 3.0; } 2629 3004 \end{cfa} 2630 3005 \CFA allows the last routine in the list to define its body. … … 2641 3016 The syntax for pointers to \CFA routines specifies the pointer name on the right, \eg: 2642 3017 \begin{cfa} 2643 * [ int x ] () fp; $\C[2.25in]{// pointer to routine returning int with no parameters}$2644 * [ * int ] (int y) gp; $\C{// pointer to routine returning pointer to int with int parameter}$2645 * [ ] (int,char) hp; $\C{// pointer to routine returning no result with int and char parameters}$2646 * [ * int,int ] ( int ) jp; $\C{// pointer to routine returning pointer to int and int, with int parameter}\CRT$3018 * [ int x ] () fp; §\C[2.25in]{// pointer to routine returning int with no parameters}§ 3019 * [ * int ] (int y) gp; §\C{// pointer to routine returning pointer to int with int parameter}§ 3020 * [ ] (int,char) hp; §\C{// pointer to routine returning no result with int and char parameters}§ 3021 * [ * int,int ] ( int ) jp; §\C{// pointer to routine returning pointer to int and int, with int parameter}\CRT§ 2647 3022 \end{cfa} 2648 3023 While parameter names are optional, \emph{a routine name cannot be specified}; 2649 3024 for example, the following is incorrect: 2650 3025 \begin{cfa} 2651 * [ int x ] f () fp; $\C{// routine name "f" is not allowed}$3026 * [ int x ] f () fp; §\C{// routine name "f" is not allowed}§ 2652 3027 \end{cfa} 2653 3028 … … 2672 3047 whereas a named (keyword) call may be: 2673 3048 \begin{cfa} 2674 p( z : 3, x : 4, y : 7 ); $\C{// rewrite \(\Rightarrow\) p( 4, 7, 3 )}$3049 p( z : 3, x : 4, y : 7 ); §\C{// rewrite \(\Rightarrow\) p( 4, 7, 3 )}§ 2675 3050 \end{cfa} 2676 3051 Here the order of the arguments is unimportant, and the names of the parameters are used to associate argument values with the corresponding parameters. … … 2689 3064 For example, the following routine prototypes and definition are all valid. 2690 3065 \begin{cfa} 2691 void p( int, int, int ); $\C{// equivalent prototypes}$3066 void p( int, int, int ); §\C{// equivalent prototypes}§ 2692 3067 void p( int x, int y, int z ); 2693 3068 void p( int y, int x, int z ); 2694 3069 void p( int z, int y, int x ); 2695 void p( int q, int r, int s ) {} $\C{// match with this definition}$3070 void p( int q, int r, int s ) {} §\C{// match with this definition}§ 2696 3071 \end{cfa} 2697 3072 Forcing matching parameter names in routine prototypes with corresponding routine definitions is possible, but goes against a strong tradition in C programming. … … 2705 3080 int f( int x, double y ); 2706 3081 2707 f( j : 3, i : 4 ); $\C{// 1st f}$2708 f( x : 7, y : 8.1 ); $\C{// 2nd f}$2709 f( 4, 5 ); $\C{// ambiguous call}$3082 f( j : 3, i : 4 ); §\C{// 1st f}§ 3083 f( x : 7, y : 8.1 ); §\C{// 2nd f}§ 3084 f( 4, 5 ); §\C{// ambiguous call}§ 2710 3085 \end{cfa} 2711 3086 However, named arguments compound routine resolution in conjunction with conversions: 2712 3087 \begin{cfa} 2713 f( i : 3, 5.7 ); $\C{// ambiguous call ?}$3088 f( i : 3, 5.7 ); §\C{// ambiguous call ?}§ 2714 3089 \end{cfa} 2715 3090 Depending on the cost associated with named arguments, this call could be resolvable or ambiguous. … … 2725 3100 the allowable positional calls are: 2726 3101 \begin{cfa} 2727 p(); $\C{// rewrite \(\Rightarrow\) p( 1, 2, 3 )}$2728 p( 4 ); $\C{// rewrite \(\Rightarrow\) p( 4, 2, 3 )}$2729 p( 4, 4 ); $\C{// rewrite \(\Rightarrow\) p( 4, 4, 3 )}$2730 p( 4, 4, 4 ); $\C{// rewrite \(\Rightarrow\) p( 4, 4, 4 )}$3102 p(); §\C{// rewrite \(\Rightarrow\) p( 1, 2, 3 )}§ 3103 p( 4 ); §\C{// rewrite \(\Rightarrow\) p( 4, 2, 3 )}§ 3104 p( 4, 4 ); §\C{// rewrite \(\Rightarrow\) p( 4, 4, 3 )}§ 3105 p( 4, 4, 4 ); §\C{// rewrite \(\Rightarrow\) p( 4, 4, 4 )}§ 2731 3106 // empty arguments 2732 p( , 4, 4 ); $\C{// rewrite \(\Rightarrow\) p( 1, 4, 4 )}$2733 p( 4, , 4 ); $\C{// rewrite \(\Rightarrow\) p( 4, 2, 4 )}$2734 p( 4, 4, ); $\C{// rewrite \(\Rightarrow\) p( 4, 4, 3 )}$2735 p( 4, , ); $\C{// rewrite \(\Rightarrow\) p( 4, 2, 3 )}$2736 p( , 4, ); $\C{// rewrite \(\Rightarrow\) p( 1, 4, 3 )}$2737 p( , , 4 ); $\C{// rewrite \(\Rightarrow\) p( 1, 2, 4 )}$2738 p( , , ); $\C{// rewrite \(\Rightarrow\) p( 1, 2, 3 )}$3107 p( , 4, 4 ); §\C{// rewrite \(\Rightarrow\) p( 1, 4, 4 )}§ 3108 p( 4, , 4 ); §\C{// rewrite \(\Rightarrow\) p( 4, 2, 4 )}§ 3109 p( 4, 4, ); §\C{// rewrite \(\Rightarrow\) p( 4, 4, 3 )}§ 3110 p( 4, , ); §\C{// rewrite \(\Rightarrow\) p( 4, 2, 3 )}§ 3111 p( , 4, ); §\C{// rewrite \(\Rightarrow\) p( 1, 4, 3 )}§ 3112 p( , , 4 ); §\C{// rewrite \(\Rightarrow\) p( 1, 2, 4 )}§ 3113 p( , , ); §\C{// rewrite \(\Rightarrow\) p( 1, 2, 3 )}§ 2739 3114 \end{cfa} 2740 3115 Here the missing arguments are inserted from the default values in the parameter list. … … 2760 3135 Default values may only appear in a prototype versus definition context: 2761 3136 \begin{cfa} 2762 void p( int x, int y = 2, int z = 3 ); $\C{// prototype: allowed}$2763 void p( int, int = 2, int = 3 ); $\C{// prototype: allowed}$2764 void p( int x, int y = 2, int z = 3 ) {} $\C{// definition: not allowed}$3137 void p( int x, int y = 2, int z = 3 ); §\C{// prototype: allowed}§ 3138 void p( int, int = 2, int = 3 ); §\C{// prototype: allowed}§ 3139 void p( int x, int y = 2, int z = 3 ) {} §\C{// definition: not allowed}§ 2765 3140 \end{cfa} 2766 3141 The reason for this restriction is to allow separate compilation. … … 2777 3152 \begin{cfa} 2778 3153 p( int x, int y, int z, ... ); 2779 p( 1, 4, 5, 6, z : 3, y : 2 ); $\C{// assume p( /* positional */, ... , /* named */ );}$2780 p( 1, z : 3, y : 2, 4, 5, 6 ); $\C{// assume p( /* positional */, /* named */, ... );}$3154 p( 1, 4, 5, 6, z : 3, y : 2 ); §\C{// assume p( /* positional */, ... , /* named */ );}§ 3155 p( 1, z : 3, y : 2, 4, 5, 6 ); §\C{// assume p( /* positional */, /* named */, ... );}§ 2781 3156 \end{cfa} 2782 3157 In the first call, it is necessary for the programmer to conceptually rewrite the call, changing named arguments into positional, before knowing where the ellipse arguments begin. … … 2787 3162 \begin{cfa} 2788 3163 void p( int x, int y = 2, int z = 3... ); 2789 p( 1, 4, 5, 6, z : 3 ); $\C{// assume p( /* positional */, ... , /* named */ );}$2790 p( 1, z : 3, 4, 5, 6 ); $\C{// assume p( /* positional */, /* named */, ... );}$3164 p( 1, 4, 5, 6, z : 3 ); §\C{// assume p( /* positional */, ... , /* named */ );}§ 3165 p( 1, z : 3, 4, 5, 6 ); §\C{// assume p( /* positional */, /* named */, ... );}§ 2791 3166 \end{cfa} 2792 3167 The first call is an error because arguments 4 and 5 are actually positional not ellipse arguments; … … 2818 3193 Furthermore, overloading cannot handle accessing default arguments in the middle of a positional list, via a missing argument, such as: 2819 3194 \begin{cfa} 2820 p( 1, /* default */, 5 ); $\C{// rewrite \(\Rightarrow\) p( 1, 2, 5 )}$3195 p( 1, /* default */, 5 ); §\C{// rewrite \(\Rightarrow\) p( 1, 2, 5 )}§ 2821 3196 \end{cfa} 2822 3197 … … 2831 3206 \begin{cfa} 2832 3207 struct { 2833 int f1; $\C{// named field}$2834 int f2 : 4; $\C{// named field with bit field size}$2835 int : 3; $\C{// unnamed field for basic type with bit field size}$2836 int ; $\C{// disallowed, unnamed field}$2837 int *; $\C{// disallowed, unnamed field}$2838 int (*)( int ); $\C{// disallowed, unnamed field}$3208 int f1; §\C{// named field}§ 3209 int f2 : 4; §\C{// named field with bit field size}§ 3210 int : 3; §\C{// unnamed field for basic type with bit field size}§ 3211 int ; §\C{// disallowed, unnamed field}§ 3212 int *; §\C{// disallowed, unnamed field}§ 3213 int (*)( int ); §\C{// disallowed, unnamed field}§ 2839 3214 }; 2840 3215 \end{cfa} … … 2844 3219 \begin{cfa} 2845 3220 struct { 2846 int , , ; $\C{// 3 unnamed fields}$3221 int , , ; §\C{// 3 unnamed fields}§ 2847 3222 } 2848 3223 \end{cfa} … … 2938 3313 const unsigned int size = 5; 2939 3314 int ia[size]; 2940 ... $\C{// assign values to array ia}$2941 qsort( ia, size ); $\C{// sort ascending order using builtin ?<?}$3315 ... §\C{// assign values to array ia}§ 3316 qsort( ia, size ); §\C{// sort ascending order using builtin ?<?}§ 2942 3317 { 2943 ®int ?<?( int x, int y ) { return x > y; }® $\C{// nested routine}$2944 qsort( ia, size ); $\C{// sort descending order by local redefinition}$3318 ®int ?<?( int x, int y ) { return x > y; }® §\C{// nested routine}§ 3319 qsort( ia, size ); §\C{// sort descending order by local redefinition}§ 2945 3320 } 2946 3321 \end{cfa} … … 2950 3325 The following program in undefined in \CFA (and Indexc{gcc}) 2951 3326 \begin{cfa} 2952 [* [int]( int )] foo() { $\C{// int (* foo())( int )}$3327 [* [int]( int )] foo() { §\C{// int (* foo())( int )}§ 2953 3328 int ®i® = 7; 2954 3329 int bar( int p ) { 2955 ®i® += 1; $\C{// dependent on local variable}$3330 ®i® += 1; §\C{// dependent on local variable}§ 2956 3331 sout | ®i®; 2957 3332 } 2958 return bar; $\C{// undefined because of local dependence}$3333 return bar; §\C{// undefined because of local dependence}§ 2959 3334 } 2960 3335 int main() { 2961 * [int]( int ) fp = foo(); $\C{// int (* fp)( int )}$3336 * [int]( int ) fp = foo(); §\C{// int (* fp)( int )}§ 2962 3337 sout | fp( 3 ); 2963 3338 } … … 2972 3347 In C and \CFA, lists of elements appear in several contexts, such as the parameter list of a routine call. 2973 3348 \begin{cfa} 2974 f( ®2, x, 3 + i® ); $\C{// element list}$3349 f( ®2, x, 3 + i® ); §\C{// element list}§ 2975 3350 \end{cfa} 2976 3351 A list of elements is called a \newterm{tuple}, and is different from a \Index{comma expression}. … … 2987 3362 For example, consider C's \Indexc{div} function, which returns the quotient and remainder for a division of an integer value. 2988 3363 \begin{cfa} 2989 typedef struct { int quot, rem; } div_t; $\C[7cm]{// from include stdlib.h}$3364 typedef struct { int quot, rem; } div_t; §\C[7cm]{// from include stdlib.h}§ 2990 3365 div_t div( int num, int den ); 2991 div_t qr = div( 13, 5 ); $\C{// return quotient/remainder aggregate}$2992 printf( "%d %d\n", qr.quot, qr.rem ); $\C{// print quotient/remainder}$3366 div_t qr = div( 13, 5 ); §\C{// return quotient/remainder aggregate}§ 3367 printf( "%d %d\n", qr.quot, qr.rem ); §\C{// print quotient/remainder}§ 2993 3368 \end{cfa} 2994 3369 This approach requires a name for the return type and fields, where \Index{naming} is a common programming-language issue. … … 3000 3375 For example, consider C's \Indexc{modf} function, which returns the integral and fractional part of a floating value. 3001 3376 \begin{cfa} 3002 double modf( double x, double * i ); $\C{// from include math.h}$3003 double intp, frac = modf( 13.5, &intp ); $\C{// return integral and fractional components}$3004 printf( "%g %g\n", intp, frac ); $\C{// print integral/fractional components}$3377 double modf( double x, double * i ); §\C{// from include math.h}§ 3378 double intp, frac = modf( 13.5, &intp ); §\C{// return integral and fractional components}§ 3379 printf( "%g %g\n", intp, frac ); §\C{// print integral/fractional components}§ 3005 3380 \end{cfa} 3006 3381 This approach requires allocating storage for the return values, which complicates the call site with a sequence of variable declarations leading to the call. … … 3029 3404 When a function call is passed as an argument to another call, the best match of actual arguments to formal parameters is evaluated given all possible expression interpretations in the current scope. 3030 3405 \begin{cfa} 3031 void g( int, int ); $\C{// 1}$3032 void g( double, double ); $\C{// 2}$3033 g( div( 13, 5 ) ); $\C{// select 1}$3034 g( modf( 13.5 ) ); $\C{// select 2}$3406 void g( int, int ); §\C{// 1}§ 3407 void g( double, double ); §\C{// 2}§ 3408 g( div( 13, 5 ) ); §\C{// select 1}§ 3409 g( modf( 13.5 ) ); §\C{// select 2}§ 3035 3410 \end{cfa} 3036 3411 In this case, there are two overloaded ©g© routines. … … 3041 3416 The previous examples can be rewritten passing the multiple returned-values directly to the ©printf© function call. 3042 3417 \begin{cfa} 3043 [ int, int ] div( int x, int y ); $\C{// from include stdlib}$3044 printf( "%d %d\n", div( 13, 5 ) ); $\C{// print quotient/remainder}$3045 3046 [ double, double ] modf( double x ); $\C{// from include math}$3047 printf( "%g %g\n", modf( 13.5 ) ); $\C{// print integral/fractional components}$3418 [ int, int ] div( int x, int y ); §\C{// from include stdlib}§ 3419 printf( "%d %d\n", div( 13, 5 ) ); §\C{// print quotient/remainder}§ 3420 3421 [ double, double ] modf( double x ); §\C{// from include math}§ 3422 printf( "%g %g\n", modf( 13.5 ) ); §\C{// print integral/fractional components}§ 3048 3423 \end{cfa} 3049 3424 This approach provides the benefits of compile-time checking for appropriate return statements as in aggregation, but without the required verbosity of declaring a new named type. … … 3055 3430 \begin{cfa} 3056 3431 int quot, rem; 3057 [ quot, rem ] = div( 13, 5 ); $\C{// assign multiple variables}$3058 printf( "%d %d\n", quot, rem ); $\C{// print quotient/remainder}\CRT$3432 [ quot, rem ] = div( 13, 5 ); §\C{// assign multiple variables}§ 3433 printf( "%d %d\n", quot, rem ); §\C{// print quotient/remainder}\CRT§ 3059 3434 \end{cfa} 3060 3435 Here, the multiple return-values are matched in much the same way as passing multiple return-values to multiple parameters in a call. … … 3085 3460 In \CFA, it is possible to overcome this restriction by declaring a \newterm{tuple variable}. 3086 3461 \begin{cfa} 3087 [int, int] ®qr® = div( 13, 5 ); $\C{// initialize tuple variable}$3088 printf( "%d %d\n", ®qr® ); $\C{// print quotient/remainder}$3462 [int, int] ®qr® = div( 13, 5 ); §\C{// initialize tuple variable}§ 3463 printf( "%d %d\n", ®qr® ); §\C{// print quotient/remainder}§ 3089 3464 \end{cfa} 3090 3465 It is now possible to match the multiple return-values to a single variable, in much the same way as \Index{aggregation}. … … 3092 3467 One way to access the individual components of a tuple variable is with assignment. 3093 3468 \begin{cfa} 3094 [ quot, rem ] = qr; $\C{// assign multiple variables}$3469 [ quot, rem ] = qr; §\C{// assign multiple variables}§ 3095 3470 \end{cfa} 3096 3471 … … 3115 3490 [int, double] * p; 3116 3491 3117 int y = x.0; $\C{// access int component of x}$3118 y = f().1; $\C{// access int component of f}$3119 p->0 = 5; $\C{// access int component of tuple pointed-to by p}$3120 g( x.1, x.0 ); $\C{// rearrange x to pass to g}$3121 double z = [ x, f() ].0.1; $\C{// access second component of first component of tuple expression}$3492 int y = x.0; §\C{// access int component of x}§ 3493 y = f().1; §\C{// access int component of f}§ 3494 p->0 = 5; §\C{// access int component of tuple pointed-to by p}§ 3495 g( x.1, x.0 ); §\C{// rearrange x to pass to g}§ 3496 double z = [ x, f() ].0.1; §\C{// access second component of first component of tuple expression}§ 3122 3497 \end{cfa} 3123 3498 Tuple-index expressions can occur on any tuple-typed expression, including tuple-returning functions, square-bracketed tuple expressions, and other tuple-index expressions, provided the retrieved component is also a tuple. … … 3187 3562 double y; 3188 3563 [int, double] z; 3189 [y, x] = 3.14; $\C{// mass assignment}$3190 [x, y] = z; $\C{// multiple assignment}$3191 z = 10; $\C{// mass assignment}$3192 z = [x, y]; $\C{// multiple assignment}$3564 [y, x] = 3.14; §\C{// mass assignment}§ 3565 [x, y] = z; §\C{// multiple assignment}§ 3566 z = 10; §\C{// mass assignment}§ 3567 z = [x, y]; §\C{// multiple assignment}§ 3193 3568 \end{cfa} 3194 3569 Let $L_i$ for $i$ in $[0, n)$ represent each component of the flattened left side, $R_i$ represent each component of the flattened right side of a multiple assignment, and $R$ represent the right side of a mass assignment. … … 3198 3573 \begin{cfa} 3199 3574 [ int, int ] x, y, z; 3200 [ x, y ] = z; $\C{// multiple assignment, invalid 4 != 2}$3575 [ x, y ] = z; §\C{// multiple assignment, invalid 4 != 2}§ 3201 3576 \end{cfa} 3202 3577 Multiple assignment assigns $R_i$ to $L_i$ for each $i$. … … 3234 3609 double c, d; 3235 3610 [ void ] f( [ int, int ] ); 3236 f( [ c, a ] = [ b, d ] = 1.5 ); $\C{// assignments in parameter list}$3611 f( [ c, a ] = [ b, d ] = 1.5 ); §\C{// assignments in parameter list}§ 3237 3612 \end{cfa} 3238 3613 The tuple expression begins with a mass assignment of ©1.5© into ©[b, d]©, which assigns ©1.5© into ©b©, which is truncated to ©1©, and ©1.5© into ©d©, producing the tuple ©[1, 1.5]© as a result. … … 3247 3622 \begin{cfa} 3248 3623 struct S; 3249 void ?{}(S *); $\C{// (1)}$3250 void ?{}(S *, int); $\C{// (2)}$3251 void ?{}(S * double); $\C{// (3)}$3252 void ?{}(S *, S); $\C{// (4)}$3253 3254 [S, S] x = [3, 6.28]; $\C{// uses (2), (3), specialized constructors}$3255 [S, S] y; $\C{// uses (1), (1), default constructor}$3256 [S, S] z = x.0; $\C{// uses (4), (4), copy constructor}$3624 void ?{}(S *); §\C{// (1)}§ 3625 void ?{}(S *, int); §\C{// (2)}§ 3626 void ?{}(S * double); §\C{// (3)}§ 3627 void ?{}(S *, S); §\C{// (4)}§ 3628 3629 [S, S] x = [3, 6.28]; §\C{// uses (2), (3), specialized constructors}§ 3630 [S, S] y; §\C{// uses (1), (1), default constructor}§ 3631 [S, S] z = x.0; §\C{// uses (4), (4), copy constructor}§ 3257 3632 \end{cfa} 3258 3633 In this example, ©x© is initialized by the multiple constructor calls ©?{}(&x.0, 3)© and ©?{}(&x.1, 6.28)©, while ©y© is initialized by two default constructor calls ©?{}(&y.0)© and ©?{}(&y.1)©. … … 3295 3670 A member-access tuple may be used anywhere a tuple can be used, \eg: 3296 3671 \begin{cfa} 3297 s.[ y, z, x ] = [ 3, 3.2, 'x' ]; $\C{// equivalent to s.x = 'x', s.y = 3, s.z = 3.2}$3298 f( s.[ y, z ] ); $\C{// equivalent to f( s.y, s.z )}$3672 s.[ y, z, x ] = [ 3, 3.2, 'x' ]; §\C{// equivalent to s.x = 'x', s.y = 3, s.z = 3.2}§ 3673 f( s.[ y, z ] ); §\C{// equivalent to f( s.y, s.z )}§ 3299 3674 \end{cfa} 3300 3675 Note, the fields appearing in a record-field tuple may be specified in any order; … … 3306 3681 void f( double, long ); 3307 3682 3308 f( x.[ 0, 3 ] ); $\C{// f( x.0, x.3 )}$3309 x.[ 0, 1 ] = x.[ 1, 0 ]; $\C{// [ x.0, x.1 ] = [ x.1, x.0 ]}$3683 f( x.[ 0, 3 ] ); §\C{// f( x.0, x.3 )}§ 3684 x.[ 0, 1 ] = x.[ 1, 0 ]; §\C{// [ x.0, x.1 ] = [ x.1, x.0 ]}§ 3310 3685 [ long, int, long ] y = x.[ 2, 0, 2 ]; 3311 3686 \end{cfa} … … 3324 3699 \begin{cfa} 3325 3700 [ int, float, double ] f(); 3326 [ double, float ] x = f().[ 2, 1 ]; $\C{// f() called once}$3701 [ double, float ] x = f().[ 2, 1 ]; §\C{// f() called once}§ 3327 3702 \end{cfa} 3328 3703 … … 3337 3712 That is, a cast can be used to select the type of an expression when it is ambiguous, as in the call to an overloaded function. 3338 3713 \begin{cfa} 3339 int f(); $\C{// (1)}$3340 double f(); $\C{// (2)}$3341 3342 f(); $\C{// ambiguous - (1),(2) both equally viable}$3343 (int)f(); $\C{// choose (2)}$3714 int f(); §\C{// (1)}§ 3715 double f(); §\C{// (2)}§ 3716 3717 f(); §\C{// ambiguous - (1),(2) both equally viable}§ 3718 (int)f(); §\C{// choose (2)}§ 3344 3719 \end{cfa} 3345 3720 Since casting is a fundamental operation in \CFA, casts need to be given a meaningful interpretation in the context of tuples. … … 3349 3724 void g(); 3350 3725 3351 (void)f(); $\C{// valid, ignore results}$3352 (int)g(); $\C{// invalid, void cannot be converted to int}$3726 (void)f(); §\C{// valid, ignore results}§ 3727 (int)g(); §\C{// invalid, void cannot be converted to int}§ 3353 3728 3354 3729 struct A { int x; }; 3355 (struct A)f(); $\C{// invalid, int cannot be converted to A}$3730 (struct A)f(); §\C{// invalid, int cannot be converted to A}§ 3356 3731 \end{cfa} 3357 3732 In C, line 4 is a valid cast, which calls ©f© and discards its result. … … 3369 3744 [int, [int, int], int] g(); 3370 3745 3371 ([int, double])f(); $\C{// (1) valid}$3372 ([int, int, int])g(); $\C{// (2) valid}$3373 ([void, [int, int]])g(); $\C{// (3) valid}$3374 ([int, int, int, int])g(); $\C{// (4) invalid}$3375 ([int, [int, int, int]])g(); $\C{// (5) invalid}$3746 ([int, double])f(); §\C{// (1) valid}§ 3747 ([int, int, int])g(); §\C{// (2) valid}§ 3748 ([void, [int, int]])g(); §\C{// (3) valid}§ 3749 ([int, int, int, int])g(); §\C{// (4) invalid}§ 3750 ([int, [int, int, int]])g(); §\C{// (5) invalid}§ 3376 3751 \end{cfa} 3377 3752 … … 3433 3808 void f([int, int], int, int); 3434 3809 3435 f([0, 0], 0, 0); $\C{// no cost}$3436 f(0, 0, 0, 0); $\C{// cost for structuring}$3437 f([0, 0,], [0, 0]); $\C{// cost for flattening}$3438 f([0, 0, 0], 0); $\C{// cost for flattening and structuring}$3810 f([0, 0], 0, 0); §\C{// no cost}§ 3811 f(0, 0, 0, 0); §\C{// cost for structuring}§ 3812 f([0, 0,], [0, 0]); §\C{// cost for flattening}§ 3813 f([0, 0, 0], 0); §\C{// cost for flattening and structuring}§ 3439 3814 \end{cfa} 3440 3815 … … 3500 3875 [ unsigned int, char ] 3501 3876 [ double, double, double ] 3502 [ * int, int * ] $\C{// mix of CFA and ANSI}$3877 [ * int, int * ] §\C{// mix of CFA and ANSI}§ 3503 3878 [ * [ 5 ] int, * * char, * [ [ int, int ] ] (int, int) ] 3504 3879 \end{cfa} … … 3507 3882 Examples of declarations using tuple types are: 3508 3883 \begin{cfa} 3509 [ int, int ] x; $\C{// 2 element tuple, each element of type int}$3510 * [ char, char ] y; $\C{// pointer to a 2 element tuple}$3884 [ int, int ] x; §\C{// 2 element tuple, each element of type int}§ 3885 * [ char, char ] y; §\C{// pointer to a 2 element tuple}§ 3511 3886 [ [ int, int ] ] z ([ int, int ]); 3512 3887 \end{cfa} … … 3525 3900 [ int, int ] w1; 3526 3901 [ int, int, int ] w2; 3527 [ void ] f (int, int, int); $\C{// three input parameters of type int}$3528 [ void ] g ([ int, int, int ]); $\C{3 element tuple as input}$3902 [ void ] f (int, int, int); §\C{// three input parameters of type int}§ 3903 [ void ] g ([ int, int, int ]); §\C{3 element tuple as input}§ 3529 3904 f( [ 1, 2, 3 ] ); 3530 3905 f( w1, 3 ); … … 3607 3982 [ int, int, int, int ] w = [ 1, 2, 3, 4 ]; 3608 3983 int x = 5; 3609 [ x, w ] = [ w, x ]; $\C{// all four tuple coercions}$3984 [ x, w ] = [ w, x ]; §\C{// all four tuple coercions}§ 3610 3985 \end{cfa} 3611 3986 Starting on the right-hand tuple in the last assignment statement, w is opened, producing a tuple of four values; … … 3697 4072 both these examples produce indeterminate results: 3698 4073 \begin{cfa} 3699 f( x++, x++ ); $\C{// C routine call with side effects in arguments}$3700 [ v1, v2 ] = [ x++, x++ ]; $\C{// side effects in right-hand side of multiple assignment}$4074 f( x++, x++ ); §\C{// C routine call with side effects in arguments}§ 4075 [ v1, v2 ] = [ x++, x++ ]; §\C{// side effects in right-hand side of multiple assignment}§ 3701 4076 \end{cfa} 3702 4077 … … 3797 4172 \begin{cfa} 3798 4173 [int, [ int, int ] ] t1 = [ 1, [ 2, 3 ] ], t2 = [ 4, [ 5, 6 ] ]; 3799 sout | t1 | t2; $\C{// print tuples}$4174 sout | t1 | t2; §\C{// print tuples}§ 3800 4175 \end{cfa} 3801 4176 \begin{cfa}[showspaces=true,aboveskip=0pt] … … 3881 4256 3882 4257 int main( int argc, char * argv[] ) { 3883 ®ifstream® in = stdin; $\C{// copy default files}$4258 ®ifstream® in = stdin; §\C{// copy default files}§ 3884 4259 ®ofstream® out = stdout; 3885 4260 … … 3887 4262 choose ( argc ) { 3888 4263 case 2, 3: 3889 ®open®( in, argv[1] ); $\C{// open input file first as output creates file}$3890 if ( argc == 3 ) ®open®( out, argv[2] ); $\C{// do not create output unless input opens}$3891 case 1: ; $\C{// use default files}$4264 ®open®( in, argv[1] ); §\C{// open input file first as output creates file}§ 4265 if ( argc == 3 ) ®open®( out, argv[2] ); §\C{// do not create output unless input opens}§ 4266 case 1: ; §\C{// use default files}§ 3892 4267 default: 3893 4268 ®exit® | "Usage" | argv[0] | "[ input-file (default stdin) " 3894 4269 "[ output-file (default stdout) ] ]"; 3895 4270 } // choose 3896 } catch( ®open_failure® * ex; ex->istream == &in ) { $\C{// input file errors}$4271 } catch( ®open_failure® * ex; ex->istream == &in ) { §\C{// input file errors}§ 3897 4272 ®exit® | "Unable to open input file" | argv[1]; 3898 } catch( ®open_failure® * ex; ex->ostream == &out ) { $\C{// output file errors}$3899 ®close®( in ); $\C{// optional}$4273 } catch( ®open_failure® * ex; ex->ostream == &out ) { §\C{// output file errors}§ 4274 ®close®( in ); §\C{// optional}§ 3900 4275 ®exit® | "Unable to open output file" | argv[2]; 3901 4276 } // try 3902 4277 3903 out | nlOff; $\C{// turn off auto newline}$3904 in | nlOn; $\C{// turn on reading newline}$4278 out | nlOff; §\C{// turn off auto newline}§ 4279 in | nlOn; §\C{// turn on reading newline}§ 3905 4280 char ch; 3906 for () { $\C{// read/write characters}$4281 for () { §\C{// read/write characters}§ 3907 4282 in | ch; 3908 if ( eof( in ) ) break; $\C{// eof ?}$4283 if ( eof( in ) ) break; §\C{// eof ?}§ 3909 4284 out | ch; 3910 4285 } // for … … 3953 4328 // *********************************** ofstream *********************************** 3954 4329 3955 bool fail( ofstream & ); $\indexc{fail}\index{ofstream@©ofstream©!©fail©}$3956 void clear( ofstream & ); $\indexc{clear}\index{ofstream@©ofstream©!©clear©}$3957 int flush( ofstream & ); $\indexc{flush}\index{ofstream@©ofstream©!©flush©}$3958 void open( ofstream &, const char name[], const char mode[] = "w" ); $\indexc{open}\index{ofstream@©ofstream©!©open©}$3959 void close( ofstream & ); $\indexc{close}\index{ofstream@©ofstream©!©close©}$3960 ofstream & write( ofstream &, const char data[], size_t size ); $\indexc{write}\index{ofstream@©ofstream©!©write©}$3961 3962 void ?{}( ofstream & ); $\index{ofstream@©ofstream©!©?{}©}$4330 bool fail( ofstream & );§\indexc{fail}\index{ofstream@©ofstream©!©fail©}§ 4331 void clear( ofstream & );§\indexc{clear}\index{ofstream@©ofstream©!©clear©}§ 4332 int flush( ofstream & );§\indexc{flush}\index{ofstream@©ofstream©!©flush©}§ 4333 void open( ofstream &, const char name[], const char mode[] = "w" );§\indexc{open}\index{ofstream@©ofstream©!©open©}§ 4334 void close( ofstream & );§\indexc{close}\index{ofstream@©ofstream©!©close©}§ 4335 ofstream & write( ofstream &, const char data[], size_t size );§\indexc{write}\index{ofstream@©ofstream©!©write©}§ 4336 4337 void ?{}( ofstream & );§\index{ofstream@©ofstream©!©?{}©}§ 3963 4338 void ?{}( ofstream &, const char name[], const char mode[] = "w" ); 3964 void ^?{}( ofstream & ); $\index{ofstream@©ofstream©!©^?{}©}$4339 void ^?{}( ofstream & );§\index{ofstream@©ofstream©!©^?{}©}§ 3965 4340 3966 4341 // *********************************** ifstream *********************************** 3967 4342 3968 bool fail( ifstream & is ); $\indexc{fail}\index{ifstream@©ifstream©!©fail©}$3969 void clear( ifstream & ); $\indexc{clear}\index{ifstream@©ifstream©!©clear©}$3970 bool eof( ifstream & is ); $\indexc{eof}\index{ifstream@©ifstream©!©eof©}$3971 void open( ifstream & is, const char name[], const char mode[] = "r" ); $\indexc{open}\index{ifstream@©ifstream©!©open©}$3972 void close( ifstream & is ); $\indexc{close}\index{ifstream@©ifstream©!©close©}$3973 ifstream & read( ifstream & is, char data[], size_t size ); $\indexc{read}\index{ifstream@©ifstream©!©read©}$3974 ifstream & ungetc( ifstream & is, char c ); $\indexc{unget}\index{ifstream@©ifstream©!©unget©}$3975 3976 void ?{}( ifstream & is ); $\index{ifstream@©ifstream©!©?{}©}$4343 bool fail( ifstream & is );§\indexc{fail}\index{ifstream@©ifstream©!©fail©}§ 4344 void clear( ifstream & );§\indexc{clear}\index{ifstream@©ifstream©!©clear©}§ 4345 bool eof( ifstream & is );§\indexc{eof}\index{ifstream@©ifstream©!©eof©}§ 4346 void open( ifstream & is, const char name[], const char mode[] = "r" );§\indexc{open}\index{ifstream@©ifstream©!©open©}§ 4347 void close( ifstream & is );§\indexc{close}\index{ifstream@©ifstream©!©close©}§ 4348 ifstream & read( ifstream & is, char data[], size_t size );§\indexc{read}\index{ifstream@©ifstream©!©read©}§ 4349 ifstream & ungetc( ifstream & is, char c );§\indexc{unget}\index{ifstream@©ifstream©!©unget©}§ 4350 4351 void ?{}( ifstream & is );§\index{ifstream@©ifstream©!©?{}©}§ 3977 4352 void ?{}( ifstream & is, const char name[], const char mode[] = "r" ); 3978 void ^?{}( ifstream & is ); $\index{ifstream@©ifstream©!©^?{}©}$4353 void ^?{}( ifstream & is );§\index{ifstream@©ifstream©!©^?{}©}§ 3979 4354 \end{cfa} 3980 4355 \caption{Stream Functions} … … 4063 4438 The separator string can be at most 16 characters including the ©'\0'© string terminator (15 printable characters). 4064 4439 \begin{cfa}[belowskip=0pt] 4065 sepSet( sout, ", $\LstStringStyle{\textdollar}$" ); $\C{// set separator from " " to ", \$"}$4440 sepSet( sout, ", $\LstStringStyle{\textdollar}$" ); §\C{// set separator from " " to ", \$"}§ 4066 4441 sout | 1 | 2 | 3 | " \"" | ®sepVal® | "\""; 4067 4442 \end{cfa} … … 4070 4445 \end{cfa} 4071 4446 \begin{cfa}[belowskip=0pt] 4072 sepSet( sout, " " ); $\C{// reset separator to " "}$4447 sepSet( sout, " " ); §\C{// reset separator to " "}§ 4073 4448 sout | 1 | 2 | 3 | " \"" | ®sepGet( sout )® | "\""; 4074 4449 \end{cfa} … … 4078 4453 ©sepGet© can be used to store a separator and then restore it: 4079 4454 \begin{cfa}[belowskip=0pt] 4080 char store[®sepSize®]; $\C{// sepSize is the maximum separator size}$4081 strcpy( store, sepGet( sout ) ); $\C{// copy current separator}$4082 sepSet( sout, "_" ); $\C{// change separator to underscore}$4455 char store[®sepSize®]; §\C{// sepSize is the maximum separator size}§ 4456 strcpy( store, sepGet( sout ) ); §\C{// copy current separator}§ 4457 sepSet( sout, "_" ); §\C{// change separator to underscore}§ 4083 4458 sout | 1 | 2 | 3; 4084 4459 \end{cfa} … … 4087 4462 \end{cfa} 4088 4463 \begin{cfa}[belowskip=0pt] 4089 sepSet( sout, store ); $\C{// change separator back to original}$4464 sepSet( sout, store ); §\C{// change separator back to original}§ 4090 4465 sout | 1 | 2 | 3; 4091 4466 \end{cfa} … … 4098 4473 The tuple separator-string can be at most 16 characters including the ©'\0'© string terminator (15 printable characters). 4099 4474 \begin{cfa}[belowskip=0pt] 4100 sepSetTuple( sout, " " ); $\C{// set tuple separator from ", " to " "}$4475 sepSetTuple( sout, " " ); §\C{// set tuple separator from ", " to " "}§ 4101 4476 sout | t1 | t2 | " \"" | ®sepTupleVal® | "\""; 4102 4477 \end{cfa} … … 4105 4480 \end{cfa} 4106 4481 \begin{cfa}[belowskip=0pt] 4107 sepSetTuple( sout, ", " ); $\C{// reset tuple separator to ", "}$4482 sepSetTuple( sout, ", " ); §\C{// reset tuple separator to ", "}§ 4108 4483 sout | t1 | t2 | " \"" | ®sepGetTuple( sout )® | "\""; 4109 4484 \end{cfa} … … 4116 4491 \Indexc{sepOff}\index{manipulator!sepOff@©sepOff©} and \Indexc{sepOn}\index{manipulator!sepOn@©sepOn©} globally toggle printing the separator. 4117 4492 \begin{cfa}[belowskip=0pt] 4118 sout | ®sepOff® | 1 | 2 | 3; $\C{// turn off implicit separator}$4493 sout | ®sepOff® | 1 | 2 | 3; §\C{// turn off implicit separator}§ 4119 4494 \end{cfa} 4120 4495 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] … … 4122 4497 \end{cfa} 4123 4498 \begin{cfa}[belowskip=0pt] 4124 sout | ®sepOn® | 1 | 2 | 3; $\C{// turn on implicit separator}$4499 sout | ®sepOn® | 1 | 2 | 3; §\C{// turn on implicit separator}§ 4125 4500 \end{cfa} 4126 4501 \begin{cfa}[mathescape=off,showspaces=true,aboveskip=0pt,belowskip=0pt] … … 4131 4506 \Indexc{sep}\index{manipulator!sep@©sep©} and \Indexc{nosep}\index{manipulator!nosep@©nosep©} locally toggle printing the separator with respect to the next printed item, and then return to the global separator setting. 4132 4507 \begin{cfa}[belowskip=0pt] 4133 sout | 1 | ®nosep® | 2 | 3; $\C{// turn off implicit separator for the next item}$4508 sout | 1 | ®nosep® | 2 | 3; §\C{// turn off implicit separator for the next item}§ 4134 4509 \end{cfa} 4135 4510 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] … … 4137 4512 \end{cfa} 4138 4513 \begin{cfa}[belowskip=0pt] 4139 sout | sepOff | 1 | ®sep® | 2 | 3; $\C{// turn on implicit separator for the next item}$4514 sout | sepOff | 1 | ®sep® | 2 | 3; §\C{// turn on implicit separator for the next item}§ 4140 4515 \end{cfa} 4141 4516 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] … … 4144 4519 The tuple separator also responses to being turned on and off. 4145 4520 \begin{cfa}[belowskip=0pt] 4146 sout | t1 | ®nosep® | t2; $\C{// turn off implicit separator for the next item}$4521 sout | t1 | ®nosep® | t2; §\C{// turn off implicit separator for the next item}§ 4147 4522 \end{cfa} 4148 4523 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] … … 4152 4527 Use ©sep© to accomplish this functionality. 4153 4528 \begin{cfa}[belowskip=0pt] 4154 sout | ®sep® | 1 | 2 | 3 | ®sep®; $\C{// sep does nothing at start/end of line}$4529 sout | ®sep® | 1 | 2 | 3 | ®sep®; §\C{// sep does nothing at start/end of line}§ 4155 4530 \end{cfa} 4156 4531 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] … … 4158 4533 \end{cfa} 4159 4534 \begin{cfa}[belowskip=0pt] 4160 sout | ®sepVal® | 1 | 2 | 3 | ®sepVal® ; $\C{// use sepVal to print separator at start/end of line}$4535 sout | ®sepVal® | 1 | 2 | 3 | ®sepVal® ; §\C{// use sepVal to print separator at start/end of line}§ 4161 4536 \end{cfa} 4162 4537 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] … … 4197 4572 \Indexc{nl}\index{manipulator!nl@©nl©} inserts a newline. 4198 4573 \begin{cfa} 4199 sout | ®nl®; $\C{// only print newline}$4200 sout | 2; $\C{// implicit newline}$4201 sout | 3 | ®nl® | 4 | ®nl®; $\C{// terminating nl merged with implicit newline}$4202 sout | 5 | ®nl® | ®nl®; $\C{// again terminating nl merged with implicit newline}$4203 sout | 6; $\C{// implicit newline}$4574 sout | ®nl®; §\C{// only print newline}§ 4575 sout | 2; §\C{// implicit newline}§ 4576 sout | 3 | ®nl® | 4 | ®nl®; §\C{// terminating nl merged with implicit newline}§ 4577 sout | 5 | ®nl® | ®nl®; §\C{// again terminating nl merged with implicit newline}§ 4578 sout | 6; §\C{// implicit newline}§ 4204 4579 4205 4580 2 … … 4648 5023 ®mutex( sout )® { 4649 5024 sout | 1; 4650 ®mutex( sout ) sout® | 2 | 3; $\C{// unnecessary, but ok because of recursive lock}$5025 ®mutex( sout ) sout® | 2 | 3; §\C{// unnecessary, but ok because of recursive lock}§ 4651 5026 sout | 4; 4652 5027 } // implicitly release sout lock … … 4660 5035 int x, y, z, w; 4661 5036 sin | x; 4662 ®mutex( sin )® sin | y | z; $\C{// unnecessary, but ok because of recursive lock}$5037 ®mutex( sin )® sin | y | z; §\C{// unnecessary, but ok because of recursive lock}§ 4663 5038 sin | w; 4664 5039 } // implicitly release sin lock … … 4669 5044 \Textbf{WARNING:} The general problem of \Index{nested locking} can occur if routines are called in an I/O sequence that block, \eg: 4670 5045 \begin{cfa} 4671 ®mutex( sout )® sout | "data:" | rtn( mon ); $\C{// mutex call on monitor}$5046 ®mutex( sout )® sout | "data:" | rtn( mon ); §\C{// mutex call on monitor}§ 4672 5047 \end{cfa} 4673 5048 If the thread executing the I/O expression blocks in the monitor with the ©sout© lock, other threads writing to ©sout© also block until the thread holding the lock is unblocked and releases it. … … 4687 5062 \begin{cfa} 4688 5063 12®,®345®.®123 $\C[1.25in]{// comma separator, period decimal-point}$ 4689 12®.®345®,®123 $\C{// period separator, comma decimal-point}$4690 12$\Sp$345®,®123®.® $\C{// space separator, comma decimal-point, period terminator}\CRT$5064 12®.®345®,®123 §\C{// period separator, comma decimal-point}§ 5065 12$\Sp$345®,®123®.® §\C{// space separator, comma decimal-point, period terminator}\CRT§ 4691 5066 \end{cfa} 4692 5067 A locale is selected with function ©setlocale©, and the corresponding locale package \emph{must} be installed on the underlying system; … … 4699 5074 \begin{cfa} 4700 5075 #include <fstream.hfa> 4701 #include <locale.h> $\C{// setlocale}$4702 #include <stdlib.h> $\C{// getenv}$5076 #include <locale.h> §\C{// setlocale}§ 5077 #include <stdlib.h> §\C{// getenv}§ 4703 5078 4704 5079 int main() { … … 4772 5147 int main() { 4773 5148 enum { size = 256 }; 4774 char buf[size]; $\C{// output buffer}$4775 ®ostrstream osstr = { buf, size };® $\C{// bind output buffer/size}$5149 char buf[size]; §\C{// output buffer}§ 5150 ®ostrstream osstr = { buf, size };® §\C{// bind output buffer/size}§ 4776 5151 int i = 3, j = 5, k = 7; 4777 5152 double x = 12345678.9, y = 98765.4321e-11; 4778 5153 4779 5154 osstr | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)) | "abc"; 4780 write( osstr ); $\C{// write string to stdout}$4781 printf( "%s", buf ); $\C{// same lines of output}$5155 write( osstr ); §\C{// write string to stdout}§ 5156 printf( "%s", buf ); §\C{// same lines of output}§ 4782 5157 sout | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)) | "abc"; 4783 5158 4784 char buf2[] = "12 14 15 3.5 7e4 abc"; $\C{// input buffer}$5159 char buf2[] = "12 14 15 3.5 7e4 abc"; §\C{// input buffer}§ 4785 5160 ®istrstream isstr = { buf2 };® 4786 5161 char s[10]; … … 4934 5309 // Subsequent arguments can be specified for initialization 4935 5310 4936 void ?{}( Widget & w ) { $\C{// default constructor}$5311 void ?{}( Widget & w ) { §\C{// default constructor}§ 4937 5312 w.id = -1; 4938 5313 w.size = 0.0; … … 4948 5323 4949 5324 // ^?{} is the destructor operator identifier 4950 void ^?{}( Widget & w ) { $\C{// destructor}$5325 void ^?{}( Widget & w ) { §\C{// destructor}§ 4951 5326 w.id = 0; 4952 5327 w.size = 0.0; … … 4957 5332 } 4958 5333 4959 Widget baz; $\C{// reserve space only}$4960 Widget foo{}; $\C{// calls default constructor}$4961 Widget bar{ 23, 2.45 }; $\C{// calls constructor with values}$4962 baz{ 24, 0.91 }; $\C{// calls constructor with values}$4963 ?{}( baz, 24, 0.91 ); $\C{// explicit call to constructor}$4964 ^?{} (bar ); $\C{// explicit call to destructor}$5334 Widget baz; §\C{// reserve space only}§ 5335 Widget foo{}; §\C{// calls default constructor}§ 5336 Widget bar{ 23, 2.45 }; §\C{// calls constructor with values}§ 5337 baz{ 24, 0.91 }; §\C{// calls constructor with values}§ 5338 ?{}( baz, 24, 0.91 ); §\C{// explicit call to constructor}§ 5339 ^?{} (bar ); §\C{// explicit call to destructor}§ 4965 5340 \end{cfa} 4966 5341 \caption{Constructors and Destructors} … … 5480 5855 5481 5856 ®coroutine® Fibonacci { 5482 int fn; $\C{// used for communication}$5857 int fn; §\C{// used for communication}§ 5483 5858 }; 5484 5859 5485 void main( Fibonacci & fib ) with( fib ) { $\C{// called on first resume}$5486 int fn1, fn2; $\C{// retained between resumes}$5487 fn = 0; fn1 = fn; $\C{// 1st case}$5488 ®suspend;® $\C{// restart last resume}$5489 fn = 1; fn2 = fn1; fn1 = fn; $\C{// 2nd case}$5490 ®suspend;® $\C{// restart last resume}$5860 void main( Fibonacci & fib ) with( fib ) { §\C{// called on first resume}§ 5861 int fn1, fn2; §\C{// retained between resumes}§ 5862 fn = 0; fn1 = fn; §\C{// 1st case}§ 5863 ®suspend;® §\C{// restart last resume}§ 5864 fn = 1; fn2 = fn1; fn1 = fn; §\C{// 2nd case}§ 5865 ®suspend;® §\C{// restart last resume}§ 5491 5866 for () { 5492 fn = fn1 + fn2; fn2 = fn1; fn1 = fn; $\C{// general case}$5493 ®suspend;® $\C{// restart last resume}$5867 fn = fn1 + fn2; fn2 = fn1; fn1 = fn; §\C{// general case}§ 5868 ®suspend;® §\C{// restart last resume}§ 5494 5869 } 5495 5870 } 5496 5871 int next( Fibonacci & fib ) with( fib ) { 5497 ®resume( fib );® $\C{// restart last suspend}$5872 ®resume( fib );® §\C{// restart last suspend}§ 5498 5873 return fn; 5499 5874 } 5500 5875 int main() { 5501 5876 Fibonacci f1, f2; 5502 for ( 10 ) { $\C{// print N Fibonacci values}$5877 for ( 10 ) { §\C{// print N Fibonacci values}§ 5503 5878 sout | next( f1 ) | next( f2 ); 5504 5879 } … … 5538 5913 int inc( AtomicCnt & ®mutex® c, int inc = 1 ) with(c) { return counter += inc; } 5539 5914 int dec( AtomicCnt & ®mutex® c, int dec = 1 ) with(c) { return counter -= dec; } 5540 forall( ostype & | ostream( ostype ) ) { $\C{// print any stream}$5915 forall( ostype & | ostream( ostype ) ) { §\C{// print any stream}§ 5541 5916 ostype & ?|?( ostype & os, AtomicCnt c ) { return os | c.counter; } 5542 5917 void ?|?( ostype & os, AtomicCnt c ) { (ostype &)(os | c.counter); ends( os ); } 5543 5918 } 5544 5919 5545 AtomicCnt global; $\C{// shared}$5920 AtomicCnt global; §\C{// shared}§ 5546 5921 5547 5922 thread MyThread {}; … … 5554 5929 int main() { 5555 5930 enum { Threads = 4 }; 5556 processor p[Threads - 1]; $\C{// + starting processor}$5931 processor p[Threads - 1]; §\C{// + starting processor}§ 5557 5932 { 5558 5933 MyThread t[Threads]; 5559 5934 } 5560 sout | global; $\C{// print 0}$5935 sout | global; §\C{// print 0}§ 5561 5936 } 5562 5937 \end{cfa} … … 7031 7406 In \CFA, there are ambiguous cases with dereference and operator identifiers, \eg ©int *?*?()©, where the string ©*?*?© can be interpreted as: 7032 7407 \begin{cfa} 7033 *?$\Sp$*? $\C{// dereference operator, dereference operator}$7034 *$\Sp$?*? $\C{// dereference, multiplication operator}$7408 *?$\Sp$*? §\C{// dereference operator, dereference operator}§ 7409 *$\Sp$?*? §\C{// dereference, multiplication operator}§ 7035 7410 \end{cfa} 7036 7411 By default, the first interpretation is selected, which does not yield a meaningful parse. … … 7084 7459 \eg: 7085 7460 \begin{cfa} 7086 x; $\C{// int x}$7087 *y; $\C{// int *y}$7088 f( p1, p2 ); $\C{// int f( int p1, int p2 );}$7089 g( p1, p2 ) int p1, p2; $\C{// int g( int p1, int p2 );}$7461 x; §\C{// int x}§ 7462 *y; §\C{// int *y}§ 7463 f( p1, p2 ); §\C{// int f( int p1, int p2 );}§ 7464 g( p1, p2 ) int p1, p2; §\C{// int g( int p1, int p2 );}§ 7090 7465 \end{cfa} 7091 7466 \CFA continues to support K\&R routine definitions: 7092 7467 \begin{cfa} 7093 f( a, b, c ) $\C{// default int return}$7094 int a, b; char c $\C{// K\&R parameter declarations}$7468 f( a, b, c ) §\C{// default int return}§ 7469 int a, b; char c §\C{// K\&R parameter declarations}§ 7095 7470 { 7096 7471 ... … … 7111 7486 int rtn( int i ); 7112 7487 int rtn( char c ); 7113 rtn( 'x' ); $\C{// programmer expects 2nd rtn to be called}$7488 rtn( 'x' ); §\C{// programmer expects 2nd rtn to be called}§ 7114 7489 \end{cfa} 7115 7490 \item[Rationale:] it is more intuitive for the call to ©rtn© to match the second version of definition of ©rtn© rather than the first. … … 7133 7508 \item[Change:] make string literals ©const©: 7134 7509 \begin{cfa} 7135 char * p = "abc"; $\C{// valid in C, deprecated in \CFA}$7136 char * q = expr ? "abc" : "de"; $\C{// valid in C, invalid in \CFA}$7510 char * p = "abc"; §\C{// valid in C, deprecated in \CFA}§ 7511 char * q = expr ? "abc" : "de"; §\C{// valid in C, invalid in \CFA}§ 7137 7512 \end{cfa} 7138 7513 The type of a string literal is changed from ©[] char© to ©const [] char©. … … 7141 7516 \begin{cfa} 7142 7517 char * p = "abc"; 7143 p[0] = 'w'; $\C{// segment fault or change constant literal}$7518 p[0] = 'w'; §\C{// segment fault or change constant literal}§ 7144 7519 \end{cfa} 7145 7520 The same problem occurs when passing a string literal to a routine that changes its argument. … … 7153 7528 \item[Change:] remove \newterm{tentative definitions}, which only occurs at file scope: 7154 7529 \begin{cfa} 7155 int i; $\C{// forward definition}$7156 int *j = ®&i®; $\C{// forward reference, valid in C, invalid in \CFA}$7157 int i = 0; $\C{// definition}$7530 int i; §\C{// forward definition}§ 7531 int *j = ®&i®; §\C{// forward reference, valid in C, invalid in \CFA}§ 7532 int i = 0; §\C{// definition}§ 7158 7533 \end{cfa} 7159 7534 is valid in C, and invalid in \CFA because duplicate overloaded object definitions at the same scope level are disallowed. … … 7161 7536 \begin{cfa} 7162 7537 struct X { int i; struct X *next; }; 7163 static struct X a; $\C{// forward definition}$7164 static struct X b = { 0, ®&a® }; $\C{// forward reference, valid in C, invalid in \CFA}$7165 static struct X a = { 1, &b }; $\C{// definition}$7538 static struct X a; §\C{// forward definition}§ 7539 static struct X b = { 0, ®&a® };§\C{// forward reference, valid in C, invalid in \CFA}§ 7540 static struct X a = { 1, &b }; §\C{// definition}§ 7166 7541 \end{cfa} 7167 7542 \item[Rationale:] avoids having different initialization rules for builtin types and user-defined types. … … 7178 7553 struct Person { 7179 7554 enum ®Colour® { R, G, B }; $\C[7cm]{// nested type}$ 7180 struct Face { $\C{// nested type}$7181 ®Colour® Eyes, Hair; $\C{// type defined outside (1 level)}$7555 struct Face { §\C{// nested type}§ 7556 ®Colour® Eyes, Hair; §\C{// type defined outside (1 level)}§ 7182 7557 }; 7183 ®.Colour® shirt; $\C{// type defined outside (top level)}$7184 ®Colour® pants; $\C{// type defined same level}$7185 Face looks[10]; $\C{// type defined same level}$7558 ®.Colour® shirt; §\C{// type defined outside (top level)}§ 7559 ®Colour® pants; §\C{// type defined same level}§ 7560 Face looks[10]; §\C{// type defined same level}§ 7186 7561 }; 7187 ®Colour® c = R; $\C{// type/enum defined same level}$7188 Person®.Colour® pc = Person®.®R; $\C{// type/enum defined inside}$7189 Person®.®Face pretty; $\C{// type defined inside}\CRT$7562 ®Colour® c = R; §\C{// type/enum defined same level}§ 7563 Person®.Colour® pc = Person®.®R;§\C{// type/enum defined inside}§ 7564 Person®.®Face pretty; §\C{// type defined inside}\CRT§ 7190 7565 \end{cfa} 7191 7566 In C, the name of the nested types belongs to the same scope as the name of the outermost enclosing structure, \ie the nested types are hoisted to the scope of the outer-most type, which is not useful and confusing. … … 7204 7579 \item[Difficulty of converting:] Semantic transformation. To make the struct type name visible in the scope of the enclosing struct, the struct tag could be declared in the scope of the enclosing struct, before the enclosing struct is defined. Example: 7205 7580 \begin{cfa} 7206 struct Y; $\C{// struct Y and struct X are at the same scope}$7581 struct Y; §\C{// struct Y and struct X are at the same scope}§ 7207 7582 struct X { 7208 7583 struct Y { /* ... */ } y; … … 7219 7594 \begin{cfa} 7220 7595 void foo() { 7221 int * b = malloc( sizeof(int) ); $\C{// implicitly convert void * to int *}$7222 char * c = b; $\C{// implicitly convert int * to void *, and then void * to char *}$7596 int * b = malloc( sizeof(int) ); §\C{// implicitly convert void * to int *}§ 7597 char * c = b; §\C{// implicitly convert int * to void *, and then void * to char *}§ 7223 7598 } 7224 7599 \end{cfa} … … 7462 7837 Type-safe allocation is provided for all C allocation routines and new \CFA allocation routines, \eg in 7463 7838 \begin{cfa} 7464 int * ip = (int *)malloc( sizeof(int) ); $\C{// C}$7465 int * ip = malloc(); $\C{// \CFA type-safe version of C malloc}$7466 int * ip = alloc(); $\C{// \CFA type-safe uniform alloc}$7839 int * ip = (int *)malloc( sizeof(int) ); §\C{// C}§ 7840 int * ip = malloc(); §\C{// \CFA type-safe version of C malloc}§ 7841 int * ip = alloc(); §\C{// \CFA type-safe uniform alloc}§ 7467 7842 \end{cfa} 7468 7843 the latter two allocations determine the allocation size from the type of ©p© (©int©) and cast the pointer to the allocated storage to ©int *©. … … 7471 7846 \begin{cfa} 7472 7847 struct S { int i; } __attribute__(( aligned( 128 ) )); // cache-line alignment 7473 S * sp = malloc(); $\C{// honour type alignment}$7848 S * sp = malloc(); §\C{// honour type alignment}§ 7474 7849 \end{cfa} 7475 7850 the storage allocation is implicitly aligned to 128 rather than the default 16. … … 7486 7861 \CFA memory management extends allocation to support constructors for initialization of allocated storage, \eg in 7487 7862 \begin{cfa} 7488 struct S { int i; }; $\C{// cache-line alignment}$7863 struct S { int i; }; §\C{// cache-line alignment}§ 7489 7864 void ?{}( S & s, int i ) { s.i = i; } 7490 7865 // assume ?|? operator for printing an S 7491 7866 7492 S & sp = *®new®( 3 ); $\C{// call constructor after allocation}$7867 S & sp = *®new®( 3 ); §\C{// call constructor after allocation}§ 7493 7868 sout | sp.i; 7494 7869 ®delete®( &sp ); 7495 7870 7496 S * spa = ®anew®( 10, 5 ); $\C{// allocate array and initialize each array element}$7871 S * spa = ®anew®( 10, 5 ); §\C{// allocate array and initialize each array element}§ 7497 7872 for ( i; 10 ) sout | spa[i] | nonl; 7498 7873 sout | nl; … … 7533 7908 // $\CFA$ safe general allocation, fill, resize, alignment, array 7534 7909 T * alloc( void );$\indexc{alloc}$ $\C[3.5in]{// variable, T size}$ 7535 T * alloc( size_t dim ); $\C{// array[dim], T size elements}$7536 T * alloc( T ptr[], size_t dim ); $\C{// realloc array[dim], T size elements}$7537 7538 T * alloc_set( char fill );$\indexc{alloc_set}$ $\C{// variable, T size, fill bytes with value}$7539 T * alloc_set( T fill ); $\C{// variable, T size, fill with value}$7540 T * alloc_set( size_t dim, char fill ); $\C{// array[dim], T size elements, fill bytes with value}$7541 T * alloc_set( size_t dim, T fill ); $\C{// array[dim], T size elements, fill elements with value}$7542 T * alloc_set( size_t dim, const T fill[] ); $\C{// array[dim], T size elements, fill elements with array}$7543 T * alloc_set( T ptr[], size_t dim, char fill ); $\C{// realloc array[dim], T size elements, fill bytes with value}$7544 7545 T * alloc_align( size_t align ); $\C{// aligned variable, T size}$7546 T * alloc_align( size_t align, size_t dim ); $\C{// aligned array[dim], T size elements}$7547 T * alloc_align( T ptr[], size_t align ); $\C{// realloc new aligned array}$7548 T * alloc_align( T ptr[], size_t align, size_t dim ); $\C{// realloc new aligned array[dim]}$7549 7550 T * alloc_align_set( size_t align, char fill ); $\C{// aligned variable, T size, fill bytes with value}$7551 T * alloc_align_set( size_t align, T fill ); $\C{// aligned variable, T size, fill with value}$7552 T * alloc_align_set( size_t align, size_t dim, char fill ); $\C{// aligned array[dim], T size elements, fill bytes with value}$7553 T * alloc_align_set( size_t align, size_t dim, T fill ); $\C{// aligned array[dim], T size elements, fill elements with value}$7554 T * alloc_align_set( size_t align, size_t dim, const T fill[] ); $\C{// aligned array[dim], T size elements, fill elements with array}$7555 T * alloc_align_set( T ptr[], size_t align, size_t dim, char fill ); $\C{// realloc new aligned array[dim], fill new bytes with value}$7910 T * alloc( size_t dim ); §\C{// array[dim], T size elements}§ 7911 T * alloc( T ptr[], size_t dim ); §\C{// realloc array[dim], T size elements}§ 7912 7913 T * alloc_set( char fill );$\indexc{alloc_set}$ §\C{// variable, T size, fill bytes with value}§ 7914 T * alloc_set( T fill ); §\C{// variable, T size, fill with value}§ 7915 T * alloc_set( size_t dim, char fill ); §\C{// array[dim], T size elements, fill bytes with value}§ 7916 T * alloc_set( size_t dim, T fill ); §\C{// array[dim], T size elements, fill elements with value}§ 7917 T * alloc_set( size_t dim, const T fill[] ); §\C{// array[dim], T size elements, fill elements with array}§ 7918 T * alloc_set( T ptr[], size_t dim, char fill ); §\C{// realloc array[dim], T size elements, fill bytes with value}§ 7919 7920 T * alloc_align( size_t align ); §\C{// aligned variable, T size}§ 7921 T * alloc_align( size_t align, size_t dim ); §\C{// aligned array[dim], T size elements}§ 7922 T * alloc_align( T ptr[], size_t align ); §\C{// realloc new aligned array}§ 7923 T * alloc_align( T ptr[], size_t align, size_t dim ); §\C{// realloc new aligned array[dim]}§ 7924 7925 T * alloc_align_set( size_t align, char fill ); §\C{// aligned variable, T size, fill bytes with value}§ 7926 T * alloc_align_set( size_t align, T fill ); §\C{// aligned variable, T size, fill with value}§ 7927 T * alloc_align_set( size_t align, size_t dim, char fill ); §\C{// aligned array[dim], T size elements, fill bytes with value}§ 7928 T * alloc_align_set( size_t align, size_t dim, T fill ); §\C{// aligned array[dim], T size elements, fill elements with value}§ 7929 T * alloc_align_set( size_t align, size_t dim, const T fill[] ); §\C{// aligned array[dim], T size elements, fill elements with array}§ 7930 T * alloc_align_set( T ptr[], size_t align, size_t dim, char fill ); §\C{// realloc new aligned array[dim], fill new bytes with value}§ 7556 7931 7557 7932 // $\CFA$ safe initialization/copy, i.e., implicit size specification … … 7614 7989 \leavevmode 7615 7990 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 7616 forall( T | { int ?<?( T, T ); } ) $\C{// location}$7991 forall( T | { int ?<?( T, T ); } ) §\C{// location}§ 7617 7992 T * bsearch( T key, const T * arr, size_t dim );$\indexc{bsearch}$ 7618 7993 7619 forall( T | { int ?<?( T, T ); } ) $\C{// position}$7994 forall( T | { int ?<?( T, T ); } ) §\C{// position}§ 7620 7995 unsigned int bsearch( T key, const T * arr, size_t dim ); 7621 7996 … … 7624 7999 7625 8000 forall( E | { int ?<?( E, E ); } ) { 7626 E * bsearch( E key, const E * vals, size_t dim );$\indexc{bsearch}$ $\C{// location}$7627 size_t bsearch( E key, const E * vals, size_t dim ); $\C{// position}$8001 E * bsearch( E key, const E * vals, size_t dim );$\indexc{bsearch}$ §\C{// location}§ 8002 size_t bsearch( E key, const E * vals, size_t dim );§\C{// position}§ 7628 8003 E * bsearchl( E key, const E * vals, size_t dim );$\indexc{bsearchl}$ 7629 8004 size_t bsearchl( E key, const E * vals, size_t dim ); … … 7672 8047 void srandom( unsigned int seed );$\indexc{srandom}$ 7673 8048 char random( void );$\indexc{random}$ 7674 char random( char u ); $\C{// [0,u)}$7675 char random( char l, char u ); $\C{// [l,u]}$8049 char random( char u ); §\C{// [0,u)}§ 8050 char random( char l, char u ); §\C{// [l,u]}§ 7676 8051 int random( void ); 7677 int random( int u ); $\C{// [0,u)}$7678 int random( int l, int u ); $\C{// [l,u]}$8052 int random( int u ); §\C{// [0,u)}§ 8053 int random( int l, int u ); §\C{// [l,u]}§ 7679 8054 unsigned int random( void ); 7680 unsigned int random( unsigned int u ); $\C{// [0,u)}$7681 unsigned int random( unsigned int l, unsigned int u ); $\C{// [l,u]}$8055 unsigned int random( unsigned int u ); §\C{// [0,u)}§ 8056 unsigned int random( unsigned int l, unsigned int u ); §\C{// [l,u]}§ 7682 8057 long int random( void ); 7683 long int random( long int u ); $\C{// [0,u)}$7684 long int random( long int l, long int u ); $\C{// [l,u]}$8058 long int random( long int u ); §\C{// [0,u)}§ 8059 long int random( long int l, long int u ); §\C{// [l,u]}§ 7685 8060 unsigned long int random( void ); 7686 unsigned long int random( unsigned long int u ); $\C{// [0,u)}$7687 unsigned long int random( unsigned long int l, unsigned long int u ); $\C{// [l,u]}$7688 float random( void ); $\C{// [0.0, 1.0)}$7689 double random( void ); $\C{// [0.0, 1.0)}$7690 float _Complex random( void ); $\C{// [0.0, 1.0)+[0.0, 1.0)i}$7691 double _Complex random( void ); $\C{// [0.0, 1.0)+[0.0, 1.0)i}$7692 long double _Complex random( void ); $\C{// [0.0, 1.0)+[0.0, 1.0)i}$8061 unsigned long int random( unsigned long int u ); §\C{// [0,u)}§ 8062 unsigned long int random( unsigned long int l, unsigned long int u ); §\C{// [l,u]}§ 8063 float random( void ); §\C{// [0.0, 1.0)}§ 8064 double random( void ); §\C{// [0.0, 1.0)}§ 8065 float _Complex random( void ); §\C{// [0.0, 1.0)+[0.0, 1.0)i}§ 8066 double _Complex random( void ); §\C{// [0.0, 1.0)+[0.0, 1.0)i}§ 8067 long double _Complex random( void ); §\C{// [0.0, 1.0)+[0.0, 1.0)i}§ 7693 8068 \end{cfa} 7694 8069 … … 7889 8264 long double atan2( long double, long double ); 7890 8265 7891 float atan( float, float ); $\C{// alternative name for atan2}$8266 float atan( float, float ); §\C{// alternative name for atan2}§ 7892 8267 double atan( double, double );$\indexc{atan}$ 7893 8268 long double atan( long double, long double ); … … 8116 8491 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 8117 8492 struct Duration { 8118 int64_t tn; $\C{// nanoseconds}$8493 int64_t tn; §\C{// nanoseconds}§ 8119 8494 }; 8120 8495 … … 8261 8636 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 8262 8637 struct Time { 8263 uint64_t tn; $\C{// nanoseconds since UNIX epoch}$8638 uint64_t tn; §\C{// nanoseconds since UNIX epoch}§ 8264 8639 }; 8265 8640 … … 8326 8701 \leavevmode 8327 8702 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 8328 struct Clock { $\C{// virtual clock}$8329 Duration offset; $\C{// offset from computer real-time}$8703 struct Clock { §\C{// virtual clock}§ 8704 Duration offset; §\C{// offset from computer real-time}§ 8330 8705 }; 8331 8706 8332 void ?{}( Clock & clk ); $\C{// create no offset}$8333 void ?{}( Clock & clk, Duration adj ); $\C{// create with offset}$8334 void reset( Clock & clk, Duration adj ); $\C{// change offset}$8335 8336 Duration resolutionHi(); $\C{// clock resolution in nanoseconds (fine)}$8337 Duration resolution(); $\C{// clock resolution without nanoseconds (coarse)}$8338 8339 Time timeHiRes(); $\C{// real time with nanoseconds}$8340 Time time(); $\C{// real time without nanoseconds}$8341 Time time( Clock & clk ); $\C{// real time for given clock}$8342 Time ?()( Clock & clk ); $\C{//\ \ \ \ alternative syntax}$8343 timeval time( Clock & clk ); $\C{// convert to C time format}$8707 void ?{}( Clock & clk ); §\C{// create no offset}§ 8708 void ?{}( Clock & clk, Duration adj ); §\C{// create with offset}§ 8709 void reset( Clock & clk, Duration adj ); §\C{// change offset}§ 8710 8711 Duration resolutionHi(); §\C{// clock resolution in nanoseconds (fine)}§ 8712 Duration resolution(); §\C{// clock resolution without nanoseconds (coarse)}§ 8713 8714 Time timeHiRes(); §\C{// real time with nanoseconds}§ 8715 Time time(); §\C{// real time without nanoseconds}§ 8716 Time time( Clock & clk ); §\C{// real time for given clock}§ 8717 Time ?()( Clock & clk ); §\C{//\ \ \ \ alternative syntax}§ 8718 timeval time( Clock & clk ); §\C{// convert to C time format}§ 8344 8719 tm time( Clock & clk ); 8345 Duration processor(); $\C{// non-monotonic duration of kernel thread}$8346 Duration program(); $\C{// non-monotonic duration of program CPU}$8347 Duration boot(); $\C{// monotonic duration since computer boot}$8720 Duration processor(); §\C{// non-monotonic duration of kernel thread}§ 8721 Duration program(); §\C{// non-monotonic duration of program CPU}§ 8722 Duration boot(); §\C{// monotonic duration since computer boot}§ 8348 8723 \end{cfa} 8349 8724 … … 8386 8761 \begin{cfa} 8387 8762 struct PRNG { ... }; $\C[3.75in]{// opaque type}$ 8388 void ?{}( PRNG & prng ); $\C{// random seed}$8389 void ?{}( PRNG & prng, uint32_t seed ); $\C{// fixed seed}$8390 void set_seed( PRNG & prng, uint32_t seed ); $\C{// set seed}$8391 uint32_t get_seed( PRNG & prng ); $\C{// get seed}$8392 uint32_t prng( PRNG & prng ); $\C{// [0,UINT\_MAX]}$8393 uint32_t prng( PRNG & prng, uint32_t u ); $\C{// [0,u)}$8394 uint32_t prng( PRNG & prng, uint32_t l, uint32_t u ); $\C{// [l,u]}$8395 uint32_t calls( PRNG & prng ); $\C{// number of calls}\CRT$8763 void ?{}( PRNG & prng ); §\C{// random seed}§ 8764 void ?{}( PRNG & prng, uint32_t seed ); §\C{// fixed seed}§ 8765 void set_seed( PRNG & prng, uint32_t seed ); §\C{// set seed}§ 8766 uint32_t get_seed( PRNG & prng ); §\C{// get seed}§ 8767 uint32_t prng( PRNG & prng ); §\C{// [0,UINT\_MAX]}§ 8768 uint32_t prng( PRNG & prng, uint32_t u ); §\C{// [0,u)}§ 8769 uint32_t prng( PRNG & prng, uint32_t l, uint32_t u ); §\C{// [l,u]}§ 8770 uint32_t calls( PRNG & prng ); §\C{// number of calls}\CRT§ 8396 8771 \end{cfa} 8397 8772 A ©PRNG© object is used to randomize behaviour or values during execution, \eg in games, a character makes a random move or an object takes on a random value. … … 8447 8822 \begin{cfa} 8448 8823 void set_seed( uint32_t seed ); $\C[3.75in]{// set global seed}$ 8449 uint32_t get_seed(); $\C{// get global seed}$8824 uint32_t get_seed(); §\C{// get global seed}§ 8450 8825 // SLOWER 8451 uint32_t prng(); $\C{// [0,UINT\_MAX]}$8452 uint32_t prng( uint32_t u ); $\C{// [0,u)}$8453 uint32_t prng( uint32_t l, uint32_t u ); $\C{// [l,u]}$8826 uint32_t prng(); §\C{// [0,UINT\_MAX]}§ 8827 uint32_t prng( uint32_t u ); §\C{// [0,u)}§ 8828 uint32_t prng( uint32_t l, uint32_t u ); §\C{// [l,u]}§ 8454 8829 // FASTER 8455 uint32_t prng( $thread\LstStringStyle{\textdollar}$ & th ); $\C{// [0,UINT\_MAX]}$8456 uint32_t prng( $thread\LstStringStyle{\textdollar}$ & th, uint32_t u ); $\C{// [0,u)}$8457 uint32_t prng( $thread\LstStringStyle{\textdollar}$ & th, uint32_t l, uint32_t u ); $\C{// [l,u]}\CRT$8830 uint32_t prng( $thread\LstStringStyle{\textdollar}$ & th ); §\C{// [0,UINT\_MAX]}§ 8831 uint32_t prng( $thread\LstStringStyle{\textdollar}$ & th, uint32_t u ); §\C{// [0,u)}§ 8832 uint32_t prng( $thread\LstStringStyle{\textdollar}$ & th, uint32_t l, uint32_t u ); §\C{// [l,u]}\CRT§ 8458 8833 \end{cfa} 8459 8834 The only difference between the two sets of ©prng© routines is performance. … … 8536 8911 8537 8912 \begin{cfa} 8538 void ?{}( Int * this ); $\C{// constructor/destructor}$8913 void ?{}( Int * this ); §\C{// constructor/destructor}§ 8539 8914 void ?{}( Int * this, Int init ); 8540 8915 void ?{}( Int * this, zero_t ); … … 8545 8920 void ^?{}( Int * this ); 8546 8921 8547 Int ?=?( Int * lhs, Int rhs ); $\C{// assignment}$8922 Int ?=?( Int * lhs, Int rhs ); §\C{// assignment}§ 8548 8923 Int ?=?( Int * lhs, long int rhs ); 8549 8924 Int ?=?( Int * lhs, unsigned long int rhs ); … … 8562 8937 unsigned long int narrow( Int val ); 8563 8938 8564 int ?==?( Int oper1, Int oper2 ); $\C{// comparison}$8939 int ?==?( Int oper1, Int oper2 ); §\C{// comparison}§ 8565 8940 int ?==?( Int oper1, long int oper2 ); 8566 8941 int ?==?( long int oper2, Int oper1 ); … … 8598 8973 int ?>=?( unsigned long int oper1, Int oper2 ); 8599 8974 8600 Int +?( Int oper ); $\C{// arithmetic}$8975 Int +?( Int oper ); §\C{// arithmetic}§ 8601 8976 Int -?( Int oper ); 8602 8977 Int ~?( Int oper ); … … 8680 9055 Int ?>>=?( Int * lhs, mp_bitcnt_t shift ); 8681 9056 8682 Int abs( Int oper ); $\C{// number functions}$9057 Int abs( Int oper ); §\C{// number functions}§ 8683 9058 Int fact( unsigned long int N ); 8684 9059 Int gcd( Int oper1, Int oper2 ); … … 8692 9067 Int sqrt( Int oper ); 8693 9068 8694 forall( dtype istype | istream( istype ) ) istype * ?|?( istype * is, Int * mp ); $\C{// I/O}$9069 forall( dtype istype | istream( istype ) ) istype * ?|?( istype * is, Int * mp ); §\C{// I/O}§ 8695 9070 forall( dtype ostype | ostream( ostype ) ) ostype * ?|?( ostype * os, Int mp ); 8696 9071 \end{cfa} … … 8791 9166 // implementation 8792 9167 struct Rational {$\indexc{Rational}$ 8793 long int numerator, denominator; $\C{// invariant: denominator > 0}$9168 long int numerator, denominator; §\C{// invariant: denominator > 0}§ 8794 9169 }; // Rational 8795 9170 8796 Rational rational(); $\C{// constructors}$9171 Rational rational(); §\C{// constructors}§ 8797 9172 Rational rational( long int n ); 8798 9173 Rational rational( long int n, long int d ); … … 8800 9175 void ?{}( Rational * r, one_t ); 8801 9176 8802 long int numerator( Rational r ); $\C{// numerator/denominator getter/setter}$9177 long int numerator( Rational r ); §\C{// numerator/denominator getter/setter}§ 8803 9178 long int numerator( Rational r, long int n ); 8804 9179 long int denominator( Rational r ); 8805 9180 long int denominator( Rational r, long int d ); 8806 9181 8807 int ?==?( Rational l, Rational r ); $\C{// comparison}$9182 int ?==?( Rational l, Rational r ); §\C{// comparison}§ 8808 9183 int ?!=?( Rational l, Rational r ); 8809 9184 int ?<?( Rational l, Rational r ); … … 8812 9187 int ?>=?( Rational l, Rational r ); 8813 9188 8814 Rational -?( Rational r ); $\C{// arithmetic}$9189 Rational -?( Rational r ); §\C{// arithmetic}§ 8815 9190 Rational ?+?( Rational l, Rational r ); 8816 9191 Rational ?-?( Rational l, Rational r ); … … 8818 9193 Rational ?/?( Rational l, Rational r ); 8819 9194 8820 double widen( Rational r ); $\C{// conversion}$9195 double widen( Rational r ); §\C{// conversion}§ 8821 9196 Rational narrow( double f, long int md ); 8822 9197 -
libcfa/src/Makefile.am
r59c8dff rf988834 48 48 math.trait.hfa \ 49 49 math.hfa \ 50 raii.hfa \ 50 51 time_t.hfa \ 51 52 virtual_dtor.hfa \ -
libcfa/src/collections/array.hfa
r59c8dff rf988834 131 131 132 132 static inline void __taglen( tag(arpk(N, S, Timmed, Tbase)), tag(N) ) {} 133 134 // workaround #226 (and array relevance thereof demonstrated in mike102/otype-slow-ndims.cfa) 135 static inline void ?{}( arpk(N, S, Timmed, Tbase) & this ) { 136 void ?{}( S (&inner)[N] ) {} 137 ?{}(this.strides); 138 } 139 static inline void ^?{}( arpk(N, S, Timmed, Tbase) & this ) { 140 void ^?{}( S (&inner)[N] ) {} 141 ^?{}(this.strides); 133 } 134 135 // RAII pattern has workarounds for 136 // - Trac 226: Simplest handling would be, require immediate element to be otype, let autogen 137 // raii happen. Performance on even a couple dimensions is unacceptable because of exponential 138 // thunk creation: ?{}() needs all four otype funcs from next level, so does ^?{}(), so do the 139 // other two. This solution offers ?{}() that needs only ?{}(), and similar for ^?{}. 140 141 forall( [N], S & | sized(S), Timmed &, Tbase & | { void ?{}( Timmed & ); } ) 142 static inline void ?{}( arpk(N, S, Timmed, Tbase) & this ) { 143 void ?{}( S (&)[N] ) {} 144 ?{}(this.strides); 145 146 for (i; N) ?{}( (Timmed &) this.strides[i] ); 147 } 148 149 forall( [N], S & | sized(S), Timmed &, Tbase & | { void ^?{}( Timmed & ); } ) 150 static inline void ^?{}( arpk(N, S, Timmed, Tbase) & this ) { 151 void ^?{}( S (&)[N] ) {} 152 ^?{}(this.strides); 153 154 for (i; N ) { 155 ^?{}( (Timmed &) this.strides[N-i-1] ); 142 156 } 143 157 } … … 147 161 // 148 162 149 forall( Te )163 forall( Te * ) 150 164 static inline Te mkar_( tag(Te) ) {} 151 165 -
libcfa/src/collections/string.cfa
r59c8dff rf988834 10 10 // Created On : Fri Sep 03 11:00:00 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Oct 18 21:52:09 202313 // Update Count : 2 0812 // Last Modified On : Sun Jan 14 12:03:47 2024 13 // Update Count : 240 14 14 // 15 15 … … 29 29 // string RAII 30 30 31 32 void ?{}( string & this ) {33 (this.inner) { malloc() };34 ?{}( *this.inner );35 }36 37 31 // private (not in header) 38 static void ?{}( string & this, string_res & src, size_t start, size_t end ) { 39 (this.inner) { malloc() }; 40 ?{}( *this.inner, src, SHARE_EDITS, start, end ); 41 } 42 43 void ?{}( string & this, const string & other ) { 44 (this.inner) { malloc() }; 45 ?{}( *this.inner, *other.inner, COPY_VALUE ); 46 } 47 48 void ?{}( string & this, string & other ) { 49 ?{}( this, (const string &) other ); 50 } 51 52 void ?{}( string & this, const char * val ) { 53 (this.inner) { malloc() }; 54 ?{}( *this.inner, val ); 55 } 56 57 void ?{}( string & this, const char * buffer, size_t bsize) { 58 (this.inner) { malloc() }; 59 ?{}( *this.inner, buffer, bsize ); 60 } 61 62 void ^?{}( string & this ) { 63 ^(*this.inner){}; 64 free( this.inner ); 65 this.inner = 0p; 32 static void ?{}( string & s, string_res & src, size_t start, size_t len ) { 33 (s.inner) { malloc() }; 34 ?{}( *s.inner, src, SHARE_EDITS, start, len ); 35 } 36 37 void ?{}( string & s ) { 38 (s.inner) { malloc() }; 39 ?{}( *s.inner ); 40 } 41 42 void ?{}( string & s, const string & c ) { 43 (s.inner) { malloc() }; 44 ?{}( *s.inner, *c.inner, COPY_VALUE ); 45 } 46 47 void ?{}( string & s, const string & s2, size_t maxlen) { 48 (s.inner) { malloc() }; 49 ?{}( *s.inner, *s2.inner, COPY_VALUE, maxlen ); 50 } 51 52 53 void ?{}( string & s, string & c ) { 54 ?{}( s, (const string &) c ); 55 } 56 57 void ?{}( string & s, const char c ) { 58 (s.inner) { malloc() }; 59 ?{}( *s.inner, c ); 60 } 61 62 void ?{}( string & s, const char * c ) { 63 (s.inner) { malloc() }; 64 ?{}( *s.inner, c ); 65 } 66 67 void ?{}( string & s, const char * c, size_t size) { 68 (s.inner) { malloc() }; 69 ?{}( *s.inner, c, size ); 70 } 71 72 void ^?{}( string & s ) { 73 ^(*s.inner){}; 74 free( s.inner ); 75 s.inner = 0p; 66 76 } 67 77 … … 69 79 // Alternate construction: request shared edits 70 80 71 string_WithSharedEdits ?`shareEdits( string & this ) {72 string_WithSharedEdits ret = { & this };73 return ret; 74 } 75 76 void ?{}( string & this, string_WithSharedEdits src ) {77 ?{}( this, *src.s->inner, 0, src.s->inner->Handle.lnth);81 string_WithSharedEdits ?`shareEdits( string & s ) { 82 string_WithSharedEdits ret = { &s }; 83 return ret; 84 } 85 86 void ?{}( string & s, string_WithSharedEdits src ) { 87 ?{}( s, *src.s->inner, 0, src.s->inner->Handle.lnth); 78 88 } 79 89 … … 81 91 // Assignment 82 92 83 void ?=?( string & this, const char * val ) { 84 (*this.inner) = val; 85 } 86 87 void ?=?(string & this, const string & other) { 88 (*this.inner) = (*other.inner); 89 } 90 91 void ?=?( string & this, char val ) { 92 (*this.inner) = val; 93 } 94 95 string & ?=?(string & this, string & other) { //// <---- straw man change 96 (*this.inner) = (*other.inner); 97 return this; 93 void ?=?( string & s, const char * val ) { 94 (*s.inner) = val; 95 } 96 97 // with and without const on "other" argument helps keep prevent autogen ?=? calls 98 void ?=?(string & s, const string & c) { 99 (*s.inner) = (*c.inner); 100 } 101 string & ?=?(string & s, string & c) { 102 (*s.inner) = (*c.inner); 103 return s; 104 } 105 106 void ?=?( string & s, char val ) { 107 (*s.inner) = val; 108 } 109 110 void assign(string & s, const string & c, size_t n) { 111 assign(*s.inner, *c.inner, n); 112 } 113 void assign(string & s, const char * c, size_t n) { 114 assign(*s.inner, c, n); 98 115 } 99 116 … … 102 119 // Input-Output 103 120 104 ofstream & ?|?( ofstream & out, const string & this ) {105 return out | (* this.inner); // print internal string_res106 } 107 108 void ?|?( ofstream & out, const string & this ) {109 (ofstream &)(out | (* this.inner)); ends( out );121 ofstream & ?|?( ofstream & out, const string & s ) { 122 return out | (*s.inner); // print internal string_res 123 } 124 125 void ?|?( ofstream & out, const string & s ) { 126 (ofstream &)(out | (*s.inner)); ends( out ); 110 127 } 111 128 … … 124 141 } 125 142 126 ifstream & ?|?(ifstream & in, string & this) {127 return in | (* this.inner); // read to internal string_res128 } 129 130 void ?|?( ifstream & in, string & this ) {131 in | (* this.inner);143 ifstream & ?|?(ifstream & in, string & s) { 144 return in | (*s.inner); // read to internal string_res 145 } 146 147 void ?|?( ifstream & in, string & s ) { 148 in | (*s.inner); 132 149 } 133 150 … … 144 161 // Slicing 145 162 146 string ?()( string & this, size_t start, size_t end) {147 string ret = { * this.inner, start, end};163 string ?()( string & s, size_t start, size_t len ) { 164 string ret = { *s.inner, start, len }; 148 165 return ret`shareEdits; 149 166 } 150 167 151 string ?()( string & this, size_t start ) {152 string ret = { * this.inner, start, size( this )};168 string ?()( string & s, size_t start ) { 169 string ret = { *s.inner, start, size( s ) - start }; 153 170 return ret`shareEdits; 154 171 } … … 157 174 // Comparison 158 175 159 int cmp (const string &s1, const string &s2) { return cmp(*s1.inner ,*s2.inner); }160 bool ?==?(const string & s1, const string &s2) { return *s1.inner == *s2.inner; }161 bool ?!=?(const string & s1, const string &s2) { return *s1.inner != *s2.inner; }162 bool ?>? (const string & s1, const string &s2) { return *s1.inner > *s2.inner; }163 bool ?>=?(const string & s1, const string &s2) { return *s1.inner >= *s2.inner; }164 bool ?<=?(const string & s1, const string &s2) { return *s1.inner <= *s2.inner; }165 bool ?<? (const string & s1, const string &s2) { return *s1.inner < *s2.inner; }166 167 int cmp (const string &s1, const char* s2) { return cmp(*s1.inner , s2); }168 bool ?==?(const string & s1, const char* s2) { return *s1.inner == s2; }169 bool ?!=?(const string & s1, const char* s2) { return *s1.inner != s2; }170 bool ?>? (const string & s1, const char* s2) { return *s1.inner > s2; }171 bool ?>=?(const string & s1, const char* s2) { return *s1.inner >= s2; }172 bool ?<=?(const string & s1, const char* s2) { return *s1.inner <= s2; }173 bool ?<? (const string & s1, const char* s2) { return *s1.inner < s2; }174 175 int cmp (const char* s1, const string &s2) { return cmp( s1 ,*s2.inner); }176 bool ?==?(const char * s1, const string &s2) { return s1 == *s2.inner; }177 bool ?!=?(const char * s1, const string &s2) { return s1 != *s2.inner; }178 bool ?>? (const char * s1, const string &s2) { return s1 > *s2.inner; }179 bool ?>=?(const char * s1, const string &s2) { return s1 >= *s2.inner; }180 bool ?<=?(const char * s1, const string &s2) { return s1 <= *s2.inner; }181 bool ?<? (const char * s1, const string &s2) { return s1 < *s2.inner; }176 int strcmp(const string & s1, const string & s2) { return strcmp(*s1.inner, *s2.inner); } 177 bool ?==?(const string & s1, const string & s2) { return *s1.inner == *s2.inner; } 178 bool ?!=?(const string & s1, const string & s2) { return *s1.inner != *s2.inner; } 179 bool ?>? (const string & s1, const string & s2) { return *s1.inner > *s2.inner; } 180 bool ?>=?(const string & s1, const string & s2) { return *s1.inner >= *s2.inner; } 181 bool ?<=?(const string & s1, const string & s2) { return *s1.inner <= *s2.inner; } 182 bool ?<? (const string & s1, const string & s2) { return *s1.inner < *s2.inner; } 183 184 int strcmp(const string & s1, const char * s2) { return strcmp(*s1.inner, s2 ); } 185 bool ?==?(const string & s1, const char * s2) { return *s1.inner == s2; } 186 bool ?!=?(const string & s1, const char * s2) { return *s1.inner != s2; } 187 bool ?>? (const string & s1, const char * s2) { return *s1.inner > s2; } 188 bool ?>=?(const string & s1, const char * s2) { return *s1.inner >= s2; } 189 bool ?<=?(const string & s1, const char * s2) { return *s1.inner <= s2; } 190 bool ?<? (const string & s1, const char * s2) { return *s1.inner < s2; } 191 192 int strcmp(const char * s1, const string & s2) { return strcmp( s1, *s2.inner); } 193 bool ?==?(const char * s1, const string & s2) { return s1 == *s2.inner; } 194 bool ?!=?(const char * s1, const string & s2) { return s1 != *s2.inner; } 195 bool ?>? (const char * s1, const string & s2) { return s1 > *s2.inner; } 196 bool ?>=?(const char * s1, const string & s2) { return s1 >= *s2.inner; } 197 bool ?<=?(const char * s1, const string & s2) { return s1 <= *s2.inner; } 198 bool ?<? (const char * s1, const string & s2) { return s1 < *s2.inner; } 182 199 183 200 … … 186 203 187 204 size_t size(const string & s) { 188 return size( * 205 return size( *s.inner ); 189 206 } 190 207 … … 192 209 // Concatenation 193 210 194 void ?+=?(string & s, char other) {195 (*s.inner) += other;211 void ?+=?(string & s, char c) { 212 (*s.inner) += c; 196 213 } 197 214 … … 200 217 } 201 218 202 void ?+=?(string & s, const char * other) { 203 (*s.inner) += other; 204 } 205 206 string ?+?(const string & s, char other) { 219 void append(string & s, const string & s2, size_t maxlen) { 220 append( (*s.inner), (*s2.inner), maxlen ); 221 } 222 223 void ?+=?(string & s, const char * c) { 224 (*s.inner) += c; 225 } 226 227 void append(string & s, const char * buffer, size_t bsize) { 228 append( (*s.inner), buffer, bsize ); 229 } 230 231 string ?+?(const string & s, char c) { 207 232 string ret = s; 208 ret += other;233 ret += c; 209 234 return ret; 210 235 } … … 222 247 } 223 248 224 string ?+?(const string & s, const char * other) {249 string ?+?(const string & s, const char * c) { 225 250 string ret = s; 226 ret += other;251 ret += c; 227 252 return ret; 228 253 } … … 231 256 // Repetition 232 257 258 void ?*=?(string & s, size_t factor) { 259 (*s.inner) *= factor; 260 } 261 233 262 string ?*?(const string & s, size_t factor) { 234 string ret = ""; 235 for (factor) ret += s; 236 return ret; 237 } 238 239 string ?*?(char c, size_t size) { 240 string ret = ""; 241 for ((size_t)size) ret += c; 242 return ret; 243 } 244 245 string ?*?(const char *s, size_t factor) { 246 string ss = s; 247 return ss * factor; 263 string ret = s; 264 ret *= factor; 265 return ret; 266 } 267 268 string ?*?(char c, size_t factor) { 269 string ret = c; 270 ret *= factor; 271 return ret; 272 } 273 274 string ?*?(const char * s, size_t factor) { 275 string ret = s; 276 ret *= factor; 277 return ret; 248 278 } 249 279 … … 256 286 257 287 string ?[?](string & s, size_t index) { 258 string ret = { *s.inner, index, index +1 };288 string ret = { *s.inner, index, 1 }; 259 289 return ret`shareEdits; 260 290 } … … 339 369 // charclass, include, exclude 340 370 341 void ?{}( charclass & this, const string & chars) {342 ( this.inner) { malloc() };343 ?{}( * this.inner, *(const string_res *)chars.inner );344 } 345 346 void ?{}( charclass & this, const char * chars ) {347 ( this.inner) { malloc() };348 ?{}( * this.inner, chars );349 } 350 351 void ?{}( charclass & this, const char * chars, size_t charssize ) {352 ( this.inner) { malloc() };353 ?{}( * this.inner, chars, charssize );354 } 355 356 void ^?{}( charclass & this ) {357 ^(* this.inner){};358 free( this.inner );359 this.inner = 0p;371 void ?{}( charclass & s, const string & chars) { 372 (s.inner) { malloc() }; 373 ?{}( *s.inner, *(const string_res *)chars.inner ); 374 } 375 376 void ?{}( charclass & s, const char * chars ) { 377 (s.inner) { malloc() }; 378 ?{}( *s.inner, chars ); 379 } 380 381 void ?{}( charclass & s, const char * chars, size_t charssize ) { 382 (s.inner) { malloc() }; 383 ?{}( *s.inner, chars, charssize ); 384 } 385 386 void ^?{}( charclass & s ) { 387 ^(*s.inner){}; 388 free( s.inner ); 389 s.inner = 0p; 360 390 } 361 391 -
libcfa/src/collections/string.hfa
r59c8dff rf988834 10 10 // Created On : Fri Sep 03 11:00:00 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : S at Sep 2 11:26:28 202313 // Update Count : 5512 // Last Modified On : Sun Jan 14 12:03:46 2024 13 // Update Count : 81 14 14 // 15 15 … … 29 29 // Getters 30 30 size_t size(const string & s); 31 static inline size_t strlen(const string & s) { return size( s ); } 31 32 32 33 // RAII, assignment 33 void ?{}(string & this); // empty string 34 void ?{}(string & s, const char * initial); // copy from string literal (NULL-terminated) 35 void ?{}(string & s, const char * buffer, size_t bsize); // copy specific length from buffer 36 34 void ?{}(string & s); // empty string 37 35 void ?{}(string & s, const string & s2); 36 void ?{}(string & s, const string & s2, size_t maxlen); 38 37 void ?{}(string & s, string & s2); 39 38 40 void ?=?(string & s, const char * other); // copy assignment from literal 41 void ?=?(string & s, const string & other); 42 void ?=?(string & s, char other); 43 string & ?=?(string & s, string & other); // surprising ret seems to help avoid calls to autogen 39 void ?{}(string & s, char); 40 void ?{}(string & s, const char * c); // copy from string literal (NULL-terminated) 41 void ?{}(string & s, const char * c, size_t size); // copy specific length from buffer 42 43 void ?=?(string & s, const char * c); // copy assignment from literal 44 void ?=?(string & s, const string & c); 45 void ?=?(string & s, char c); 46 string & ?=?(string & s, string & c); // surprising ret seems to help avoid calls to autogen 47 void assign(string & s, const string & c, size_t n); 48 void assign(string & s, const char * c, size_t n); 44 49 //string ?=?( string &, string ) = void; 50 51 static inline string & strcpy(string & s, const char * c) { s = c; return s; } 52 static inline string & strncpy(string & s, const char * c, size_t n) { assign( s, c, n); return s; } 53 static inline string & strcpy(string & s, const string & c) { s = c; return s; } 54 static inline string & strncpy(string & s, const string & c, size_t n) { assign(s, c, n); return s; } 55 45 56 void ^?{}(string & s); 46 57 … … 49 60 string * s; 50 61 }; 51 string_WithSharedEdits ?`shareEdits( string & this );52 void ?{}( string & this, string_WithSharedEdits src );62 string_WithSharedEdits ?`shareEdits( string & s ); 63 void ?{}( string & s, string_WithSharedEdits src ); 53 64 54 65 // IO Operator … … 56 67 void ?|?(ofstream & out, const string & s); 57 68 ifstream & ?|?(ifstream & in, string & s); 58 void ?|?( ifstream & in, string & this );69 void ?|?( ifstream & in, string & s ); 59 70 60 71 static inline { … … 81 92 _Istream_Sstr wdi( unsigned int rwd, string & s ) { return (_Istream_Sstr)@{ s, {{0p}, rwd, {.flags.rwd : true}} }; } 82 93 _Istream_Sstr getline( string & s, const char delimiter = '\n' ) { 83 return (_Istream_Sstr)@{ s, {{.delimiter : { delimiter, '\0' } }, -1, {.flags.delimiter : true, .flags.inex : true}} };94 return (_Istream_Sstr)@{ s, {{.delimiters : { delimiter, '\0' } }, -1, {.flags.delimiter : true, .flags.inex : true}} }; 84 95 } 85 96 _Istream_Sstr & getline( _Istream_Sstr & fmt, const char delimiter = '\n' ) { 86 fmt.delimiter [0] = delimiter; fmt.delimiter[1] = '\0'; fmt.flags.delimiter = true; fmt.flags.inex = true; return fmt;97 fmt.delimiters[0] = delimiter; fmt.delimiters[1] = '\0'; fmt.flags.delimiter = true; fmt.flags.inex = true; return fmt; 87 98 } 88 99 _Istream_Sstr incl( const char scanset[], string & s ) { return (_Istream_Sstr)@{ s, {{scanset}, -1, {.flags.inex : false}} }; } … … 97 108 98 109 // Concatenation 99 void ?+=?(string & s, char other); // append a character110 void ?+=?(string & s, char c); // append a character 100 111 void ?+=?(string & s, const string & s2); // append-concatenate to first string 101 void ?+=?(string & s, const char * other); // append-concatenate to first string 102 string ?+?(const string & s, char other); // add a character to a copy of the string 112 void append(string & s, const string & s2, size_t maxlen); // append-concatenate to first string, up to maxlen 113 void ?+=?(string & s, const char * s2); // append-concatenate NULL-terminated string to first string 114 void append(string & s, const char * buffer, size_t bsize); // append-concatenate given range to first string 115 116 string ?+?(const string & s, char c); // add a character to a copy of the string 103 117 string ?+?(const string & s, const string & s2); // copy and concatenate both strings 104 string ?+?(const char * s1, const char * s2); // concatenate both strings 105 string ?+?(const string & s, const char * other); // copy and concatenate with NULL-terminated string 118 string ?+?(const char * s1, const char * s2); // copy and concatenate both strings 119 string ?+?(const string & s, const char * c); // copy and concatenate with NULL-terminated string 120 121 static inline string & strcat(string & s, const string & s2) { s += s2; return s; } 122 static inline string & strcat(string & s, const char * c) { s += c; return s; } 123 static inline string & strncat(string & s, const string & s2, size_t maxlen) { append(s, s2, maxlen); return s; } 124 static inline string & strncat(string & s, const char * buffer, size_t bsize) { append(s, buffer, bsize); return s; } 106 125 107 126 // Repetition 108 127 string ?*?(const string & s, size_t factor); 109 string ?*?(char c, size_t size); 110 string ?*?(const char *s, size_t size); 128 void ?*=?(string & s, size_t factor); 129 string ?*?(char c, size_t factor); 130 string ?*?(const char *s, size_t factor); 111 131 112 132 // Character access … … 116 136 117 137 // Comparisons 118 int cmp (const string &, const string &);138 int strcmp (const string &, const string &); 119 139 bool ?==?(const string &, const string &); 120 140 bool ?!=?(const string &, const string &); … … 124 144 bool ?<? (const string &, const string &); 125 145 126 int cmp (const string &, const char*);127 bool ?==?(const string &, const char *);128 bool ?!=?(const string &, const char *);129 bool ?>? (const string &, const char *);130 bool ?>=?(const string &, const char *);131 bool ?<=?(const string &, const char *);132 bool ?<? (const string &, const char *);133 134 int cmp (const char*, const string &);135 bool ?==?(const char *, const string &);136 bool ?!=?(const char *, const string &);137 bool ?>? (const char *, const string &);138 bool ?>=?(const char *, const string &);139 bool ?<=?(const char *, const string &);140 bool ?<? (const char *, const string &);146 int strcmp (const string &, const char *); 147 bool ?==?(const string &, const char *); 148 bool ?!=?(const string &, const char *); 149 bool ?>? (const string &, const char *); 150 bool ?>=?(const string &, const char *); 151 bool ?<=?(const string &, const char *); 152 bool ?<? (const string &, const char *); 153 154 int strcmp (const char *, const string &); 155 bool ?==?(const char *, const string &); 156 bool ?!=?(const char *, const string &); 157 bool ?>? (const char *, const string &); 158 bool ?>=?(const char *, const string &); 159 bool ?<=?(const char *, const string &); 160 bool ?<? (const char *, const string &); 141 161 142 162 143 163 // Slicing 144 string ?()( string & this, size_t start, size_t end); // TODO const?145 string ?()( string & this, size_t start);164 string ?()( string & s, size_t start, size_t len ); // TODO const? 165 string ?()( string & s, size_t start); 146 166 147 167 // String search … … 177 197 178 198 179 180 199 struct charclass { 181 200 charclass_res * inner; -
libcfa/src/collections/string_res.cfa
r59c8dff rf988834 10 10 // Created On : Fri Sep 03 11:00:00 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Oct 18 21:54:54 202313 // Update Count : 1512 // Last Modified On : Tue Jan 16 22:19:27 2024 13 // Update Count : 35 14 14 // 15 15 … … 22 22 // Workaround is: EndVbyte = TEMP_ALLOC(char, CurrSize) 23 23 // Should be: EndVbyte = alloc(CurrSize) 24 #define TEMP_ALLOC(T, n) (( T * ) malloc( n * sizeof( T ) ))24 #define TEMP_ALLOC(T, n) (( T * ) malloc( n * sizeof( T ) )) 25 25 26 26 #include <assert.h> … … 33 33 34 34 struct VbyteHeap { 35 36 int NoOfCompactions; // number of compactions of the byte area 37 int NoOfExtensions; // number of extensions in the size of the byte area 38 int NoOfReductions; // number of reductions in the size of the byte area 35 int NoOfCompactions; // number of compactions of the byte area 36 int NoOfExtensions; // number of extensions in the size of the byte area 37 int NoOfReductions; // number of reductions in the size of the byte area 39 38 40 int InitSize; // initial number of bytes in the byte-string area41 int CurrSize; // current number of bytes in the byte-string area42 char *StartVbyte; // pointer to the `st byte of the start of the byte-string area43 char *EndVbyte; // pointer to the next byte after the end of the currently used portion of byte-string area44 void *ExtVbyte; // pointer to the next byte after the end of the byte-string area45 46 HandleNode Header; // header node for handle list39 int InitSize; // initial number of bytes in the byte-string area 40 int CurrSize; // current number of bytes in the byte-string area 41 char *StartVbyte; // pointer to the `st byte of the start of the byte-string area 42 char *EndVbyte; // pointer to the next byte after the end of the currently used portion of byte-string area 43 void *ExtVbyte; // pointer to the next byte after the end of the byte-string area 44 45 HandleNode Header; // header node for handle list 47 46 }; // VbyteHeap 48 47 49 48 50 static void compaction( VbyteHeap & ); 51 static void garbage( VbyteHeap &, int ); 49 static void compaction( VbyteHeap & ); // compaction of the byte area 50 static void garbage( VbyteHeap &, int ); // garbage collect the byte area 52 51 static void extend( VbyteHeap &, int ); // extend the size of the byte area 53 52 static void reduce( VbyteHeap &, int ); // reduce the size of the byte area … … 67 66 // Allocate the storage for the variable sized area and intialize the heap variables. 68 67 69 static void ?{}( VbyteHeap & this, size_t Size ) with(this) {70 #ifdef VbyteDebug 71 serr | "enter:VbyteHeap::VbyteHeap, this:" | &this | " Size:" | Size;68 static void ?{}( VbyteHeap & s, size_t Size ) with(s) { 69 #ifdef VbyteDebug 70 serr | "enter:VbyteHeap::VbyteHeap, s:" | &s | " Size:" | Size; 72 71 #endif // VbyteDebug 73 72 NoOfCompactions = NoOfExtensions = NoOfReductions = 0; … … 76 75 ExtVbyte = (void *)( StartVbyte + CurrSize ); 77 76 Header.flink = Header.blink = &Header; 78 Header.ulink = & this;77 Header.ulink = &s; 79 78 #ifdef VbyteDebug 80 79 HeaderPtr = &Header; 81 serr | "exit:VbyteHeap::VbyteHeap, this:" | &this;80 serr | "exit:VbyteHeap::VbyteHeap, s:" | &s; 82 81 #endif // VbyteDebug 83 82 } // VbyteHeap … … 86 85 // Release the dynamically allocated storage for the byte area. 87 86 88 static void ^?{}( VbyteHeap & this ) with(this) {87 static void ^?{}( VbyteHeap & s ) with(s) { 89 88 free( StartVbyte ); 90 89 } // ~VbyteHeap … … 97 96 // creator. 98 97 99 static void ?{}( HandleNode & this ) with(this) {100 #ifdef VbyteDebug 101 serr | "enter:HandleNode::HandleNode, this:" | &this;98 static void ?{}( HandleNode & s ) with(s) { 99 #ifdef VbyteDebug 100 serr | "enter:HandleNode::HandleNode, s:" | &s; 102 101 #endif // VbyteDebug 103 102 s = 0; 104 103 lnth = 0; 105 104 #ifdef VbyteDebug 106 serr | "exit:HandleNode::HandleNode, this:" | &this;105 serr | "exit:HandleNode::HandleNode, s:" | &s; 107 106 #endif // VbyteDebug 108 107 } // HandleNode … … 112 111 // collection. 113 112 114 static void ?{}( HandleNode & this, VbyteHeap & vh ) with(this) {115 #ifdef VbyteDebug 116 serr | "enter:HandleNode::HandleNode, this:" | &this;113 static void ?{}( HandleNode & s, VbyteHeap & vh ) with(s) { 114 #ifdef VbyteDebug 115 serr | "enter:HandleNode::HandleNode, s:" | &s; 117 116 #endif // VbyteDebug 118 117 s = 0; 119 118 lnth = 0; 120 119 ulink = &vh; 121 AddThisAfter( this, *vh.Header.blink );122 #ifdef VbyteDebug 123 serr | "exit:HandleNode::HandleNode, this:" | &this;120 AddThisAfter( s, *vh.Header.blink ); 121 #ifdef VbyteDebug 122 serr | "exit:HandleNode::HandleNode, s:" | &s; 124 123 #endif // VbyteDebug 125 124 } // HandleNode … … 129 128 // is the responsibility of the creator to destroy it. 130 129 131 static void ^?{}( HandleNode & this ) with(this) {132 #ifdef VbyteDebug 133 serr | "enter:HandleNode::~HandleNode, this:" | & this;130 static void ^?{}( HandleNode & s ) with(s) { 131 #ifdef VbyteDebug 132 serr | "enter:HandleNode::~HandleNode, s:" | & s; 134 133 { 135 134 serr | nlOff; … … 142 141 } 143 142 #endif // VbyteDebug 144 DeleteNode( this );143 DeleteNode( s ); 145 144 } // ~HandleNode 146 145 … … 151 150 static string_sharectx default_string_sharectx = {NEW_SHARING}; // stable bottom of stack 152 151 153 void ?{}( string_sharectx & this, StringSharectx_Mode mode ) with( this ) {152 void ?{}( string_sharectx & s, StringSharectx_Mode mode ) with( s ) { 154 153 (older){ ambient_string_sharectx }; 155 154 if ( mode == NEW_SHARING ) { … … 159 158 (activeHeap){ 0p }; 160 159 } 161 ambient_string_sharectx = & this;162 } 163 164 void ^?{}( string_sharectx & this ) with( this ) {160 ambient_string_sharectx = & s; 161 } 162 163 void ^?{}( string_sharectx & s ) with( s ) { 165 164 if ( activeHeap ) delete( activeHeap ); 166 165 167 // unlink this from older-list starting from ambient_string_sharectx168 // usually, this==ambient_string_sharectx and the loop runs zero times166 // unlink s from older-list starting from ambient_string_sharectx 167 // usually, s==ambient_string_sharectx and the loop runs zero times 169 168 string_sharectx *& c = ambient_string_sharectx; 170 while ( c != & this ) &c = &c->older; // find this171 c = this.older; // unlink169 while ( c != &s ) &c = &c->older; // find s 170 c = s.older; // unlink 172 171 } 173 172 … … 181 180 182 181 size_t DEBUG_string_bytes_avail_until_gc( VbyteHeap * heap ) { 183 return ((char *)heap->ExtVbyte) - heap->EndVbyte;182 return ((char *)heap->ExtVbyte) - heap->EndVbyte; 184 183 } 185 184 … … 193 192 194 193 // Returns the size of the string in bytes 195 size_t size(const string_res & s) with(s) {194 size_t size(const string_res & s) with(s) { 196 195 return Handle.lnth; 197 196 } 198 197 199 198 // Output operator 200 ofstream & ?|?(ofstream & out, const string_res &s) {199 ofstream & ?|?(ofstream & out, const string_res & s) { 201 200 // CFA string is NOT null terminated, so print exactly lnth characters in a minimum width of 0. 202 201 out | wd( 0, s.Handle.lnth, s.Handle.s ) | nonl; … … 204 203 } 205 204 206 void ?|?(ofstream & out, const string_res &s) {205 void ?|?(ofstream & out, const string_res & s) { 207 206 (ofstream &)(out | s); ends( out ); 208 207 } 209 208 210 209 // Input operator 211 ifstream & ?|?(ifstream &in, string_res &s) { 212 210 ifstream & ?|?(ifstream & in, string_res & s) { 213 211 // Reading into a temp before assigning to s is near zero overhead in typical cases because of sharing. 214 212 // If s is a substring of something larger, simple assignment takes care of that case correctly. … … 231 229 232 230 // rest of heap is available to read into 233 int lenReadable = (char *)temp.Handle.ulink->ExtVbyte - temp.Handle.ulink->EndVbyte;231 int lenReadable = (char *)temp.Handle.ulink->ExtVbyte - temp.Handle.ulink->EndVbyte; 234 232 assert (lenReadable >= 2); 235 233 … … 238 236 *(temp.Handle.ulink->EndVbyte) = '\0'; // pre-assign empty cstring 239 237 in | wdi( lenReadable, temp.Handle.ulink->EndVbyte ); 240 } catch (cstring_length *) {238 } catch (cstring_length *) { 241 239 cont = true; 242 240 } … … 252 250 } 253 251 254 void ?|?( ifstream & in, string_res & this ) {255 (ifstream &)(in | this);252 void ?|?( ifstream & in, string_res & s ) { 253 (ifstream &)(in | s); 256 254 } 257 255 … … 274 272 cont = true; 275 273 } finally { 276 if ( ! cf.flags.ignore && // ok to initialize string 277 cstr[0] != '\0' ) { // something was read 274 if ( ! cf.flags.ignore // ok to initialize string 275 // && cstr[0] != '\0' // something was read 276 ) { 278 277 *(f.s) = cstr; 279 278 } … … 287 286 cont = true; // continue not allowed 288 287 } finally { 289 if ( ! cf.flags.ignore && 290 cstr[0] != '\0' ) { // something was read 288 if ( ! cf.flags.ignore && cstr[0] != '\0' ) { // something was read 291 289 *(f.s) += cstr; // build string chunk at a time 292 290 } … … 302 300 303 301 // Empty constructor 304 void ?{}(string_res & s) with(s) {302 void ?{}(string_res & s) with(s) { 305 303 if( ambient_string_sharectx->activeHeap ) { 306 304 (Handle){ * ambient_string_sharectx->activeHeap }; … … 317 315 } 318 316 319 static void eagerCopyCtorHelper(string_res & s, const char* rhs, size_t rhslnth) with(s) {317 static void eagerCopyCtorHelper(string_res & s, const char * rhs, size_t rhslnth) with(s) { 320 318 if( ambient_string_sharectx->activeHeap ) { 321 319 (Handle){ * ambient_string_sharectx->activeHeap }; … … 333 331 334 332 // Constructor from a raw buffer and size 335 void ?{}(string_res & s, const char* rhs, size_t rhslnth) with(s) {333 void ?{}(string_res & s, const char * rhs, size_t rhslnth) with(s) { 336 334 eagerCopyCtorHelper(s, rhs, rhslnth); 337 335 } 338 336 339 337 // private ctor (not in header): use specified heap (ignore ambient) and copy chars in 340 void ?{}( string_res & s, VbyteHeap & heap, const char* rhs, size_t rhslnth ) with(s) {338 void ?{}( string_res & s, VbyteHeap & heap, const char * rhs, size_t rhslnth ) with(s) { 341 339 (Handle){ heap }; 342 340 Handle.s = VbyteAlloc(*Handle.ulink, rhslnth); … … 348 346 } 349 347 348 350 349 // General copy constructor 351 void ?{}(string_res &s, const string_res & s2, StrResInitMode mode, size_t start, size_t end ) { 352 350 void ?{}(string_res & s, const string_res & s2, StrResInitMode mode, size_t start, size_t len ) { 351 352 size_t end = start + len; 353 353 verify( start <= end && end <= s2.Handle.lnth ); 354 354 … … 394 394 } 395 395 396 static void assignEditSet(string_res & this, string_res * shareEditSetStartPeer, string_res * shareEditSetEndPeer,396 static void assignEditSet(string_res & s, string_res * shareEditSetStartPeer, string_res * shareEditSetEndPeer, 397 397 char * resultSesStart, 398 398 size_t resultSesLnth, … … 400 400 401 401 char * beforeBegin = shareEditSetStartPeer->Handle.s; 402 size_t beforeLen = this.Handle.s - beforeBegin;403 404 char * afterBegin = this.Handle.s + this.Handle.lnth;402 size_t beforeLen = s.Handle.s - beforeBegin; 403 404 char * afterBegin = s.Handle.s + s.Handle.lnth; 405 405 size_t afterLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - afterBegin; 406 406 407 size_t oldLnth = this.Handle.lnth;408 409 this.Handle.s = resultSesStart + beforeLen;410 this.Handle.lnth = bsize;407 size_t oldLnth = s.Handle.lnth; 408 409 s.Handle.s = resultSesStart + beforeLen; 410 s.Handle.lnth = bsize; 411 411 if (resultPadPosition) 412 MoveThisAfter( this.Handle, *resultPadPosition );412 MoveThisAfter( s.Handle, *resultPadPosition ); 413 413 414 414 // adjust all substring string and handle locations, and check if any substring strings are outside the new base string 415 415 char *limit = resultSesStart + resultSesLnth; 416 for ( string_res * p = this.shareEditSet_next; p != &this; p = p->shareEditSet_next ) {416 for ( string_res * p = s.shareEditSet_next; p != &s; p = p->shareEditSet_next ) { 417 417 verify (p->Handle.s >= beforeBegin); 418 418 if ( p->Handle.s >= afterBegin ) { … … 439 439 // take end as end-anchored 440 440 // stretch-shrink p according to the edit 441 p->Handle.lnth += this.Handle.lnth;441 p->Handle.lnth += s.Handle.lnth; 442 442 p->Handle.lnth -= oldLnth; 443 443 } … … 452 452 // p ends during the edit; p does not include the last character replaced 453 453 // set p to empty string at start of edit 454 p->Handle.s = this.Handle.s;454 p->Handle.s = s.Handle.s; 455 455 p->Handle.lnth = 0; 456 456 } else { … … 458 458 // clip start of p to start at end of edit 459 459 int charsToClip = afterBegin - p->Handle.s; 460 p->Handle.s = this.Handle.s + this.Handle.lnth;460 p->Handle.s = s.Handle.s + s.Handle.lnth; 461 461 p->Handle.lnth -= charsToClip; 462 462 } … … 467 467 } 468 468 469 // traverse the share-edit set (SES) to recover the range of a base string to which ` this` belongs470 static void locateInShareEditSet( string_res & this, string_res *&shareEditSetStartPeer, string_res *&shareEditSetEndPeer ) {471 shareEditSetStartPeer = & this;472 shareEditSetEndPeer = & this;473 for (string_res * editPeer = this.shareEditSet_next; editPeer != &this; editPeer = editPeer->shareEditSet_next) {469 // traverse the share-edit set (SES) to recover the range of a base string to which `s` belongs 470 static void locateInShareEditSet( string_res & s, string_res *& shareEditSetStartPeer, string_res *& shareEditSetEndPeer ) { 471 shareEditSetStartPeer = & s; 472 shareEditSetEndPeer = & s; 473 for (string_res * editPeer = s.shareEditSet_next; editPeer != &s; editPeer = editPeer->shareEditSet_next) { 474 474 if ( editPeer->Handle.s < shareEditSetStartPeer->Handle.s ) { 475 475 shareEditSetStartPeer = editPeer; … … 481 481 } 482 482 483 static string_res & assign_(string_res & this, const char* buffer, size_t bsize, const string_res & valSrc) {483 static string_res & assign_(string_res & s, const char * buffer, size_t bsize, const string_res & valSrc) { 484 484 485 485 string_res * shareEditSetStartPeer; 486 486 string_res * shareEditSetEndPeer; 487 locateInShareEditSet( this, shareEditSetStartPeer, shareEditSetEndPeer );487 locateInShareEditSet( s, shareEditSetStartPeer, shareEditSetEndPeer ); 488 488 489 489 verify( shareEditSetEndPeer->Handle.s >= shareEditSetStartPeer->Handle.s ); 490 490 size_t origEditSetLength = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - shareEditSetStartPeer->Handle.s; 491 verify( origEditSetLength >= this.Handle.lnth );492 493 if ( this.shareEditSet_owns_ulink ) { // assigning to private context491 verify( origEditSetLength >= s.Handle.lnth ); 492 493 if ( s.shareEditSet_owns_ulink ) { // assigning to private context 494 494 // ok to overwrite old value within LHS 495 495 char * prefixStartOrig = shareEditSetStartPeer->Handle.s; 496 int prefixLen = this.Handle.s - prefixStartOrig;497 char * suffixStartOrig = this.Handle.s + this.Handle.lnth;496 int prefixLen = s.Handle.s - prefixStartOrig; 497 char * suffixStartOrig = s.Handle.s + s.Handle.lnth; 498 498 int suffixLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - suffixStartOrig; 499 499 500 int delta = bsize - this.Handle.lnth;501 if ( char * oldBytes = VbyteTryAdjustLast( * this.Handle.ulink, delta ) ) {500 int delta = bsize - s.Handle.lnth; 501 if ( char * oldBytes = VbyteTryAdjustLast( *s.Handle.ulink, delta ) ) { 502 502 // growing: copy from old to new 503 char * dest = VbyteAlloc( * this.Handle.ulink, origEditSetLength + delta );503 char * dest = VbyteAlloc( *s.Handle.ulink, origEditSetLength + delta ); 504 504 char *destCursor = dest; memcpy(destCursor, prefixStartOrig, prefixLen); 505 505 destCursor += prefixLen; memcpy(destCursor, buffer , bsize ); 506 506 destCursor += bsize; memcpy(destCursor, suffixStartOrig, suffixLen); 507 assignEditSet( this, shareEditSetStartPeer, shareEditSetEndPeer,507 assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 508 508 dest, 509 509 origEditSetLength + delta, … … 513 513 // room is already allocated in-place: bubble suffix and overwite middle 514 514 memmove( suffixStartOrig + delta, suffixStartOrig, suffixLen ); 515 memcpy( this.Handle.s, buffer, bsize );516 517 assignEditSet( this, shareEditSetStartPeer, shareEditSetEndPeer,515 memcpy( s.Handle.s, buffer, bsize ); 516 517 assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 518 518 shareEditSetStartPeer->Handle.s, 519 519 origEditSetLength + delta, … … 522 522 523 523 } else if ( // assigning to shared context 524 this.Handle.lnth == origEditSetLength && // overwriting entire run of SES524 s.Handle.lnth == origEditSetLength && // overwriting entire run of SES 525 525 & valSrc && // sourcing from a managed string 526 valSrc.Handle.ulink == this.Handle.ulink ) { // sourcing from same heap526 valSrc.Handle.ulink == s.Handle.ulink ) { // sourcing from same heap 527 527 528 528 // SES's result will only use characters from the source string => reuse source 529 assignEditSet( this, shareEditSetStartPeer, shareEditSetEndPeer,529 assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 530 530 valSrc.Handle.s, 531 531 valSrc.Handle.lnth, … … 537 537 538 538 // full string is from start of shareEditSetStartPeer thru end of shareEditSetEndPeer 539 // ` this` occurs in the middle of it, to be replaced539 // `s` occurs in the middle of it, to be replaced 540 540 // build up the new text in `pasting` 541 541 542 542 string_res pasting = { 543 * this.Handle.ulink, // maintain same heap, regardless of context543 * s.Handle.ulink, // maintain same heap, regardless of context 544 544 shareEditSetStartPeer->Handle.s, // start of SES 545 this.Handle.s - shareEditSetStartPeer->Handle.s }; // length of SES, before this545 s.Handle.s - shareEditSetStartPeer->Handle.s }; // length of SES, before s 546 546 append( pasting, 547 buffer, // start of replacement for this548 bsize ); // length of replacement for this547 buffer, // start of replacement for s 548 bsize ); // length of replacement for s 549 549 append( pasting, 550 this.Handle.s + this.Handle.lnth, // start of SES after this550 s.Handle.s + s.Handle.lnth, // start of SES after s 551 551 shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - 552 ( this.Handle.s + this.Handle.lnth) ); // length of SES, after this552 (s.Handle.s + s.Handle.lnth) ); // length of SES, after s 553 553 554 554 // The above string building can trigger compaction. 555 555 // The reference points (that are arguments of the string building) may move during that building. 556 // From this point on, they are stable.557 558 assignEditSet( this, shareEditSetStartPeer, shareEditSetEndPeer,556 // From s point on, they are stable. 557 558 assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 559 559 pasting.Handle.s, 560 560 pasting.Handle.lnth, … … 562 562 } 563 563 564 return this; 565 } 566 567 string_res & assign(string_res &this, const char* buffer, size_t bsize) { 568 return assign_(this, buffer, bsize, *0p); 569 } 570 571 string_res & ?=?(string_res &s, char other) { 572 return assign(s, &other, 1); 564 return s; 565 } 566 567 string_res & assign(string_res & s, const string_res & src, size_t maxlen) { 568 return assign_(s, src.Handle.s, min(src.Handle.lnth, maxlen), *0p); 569 } 570 571 string_res & assign(string_res & s, const char * buffer, size_t bsize) { 572 return assign_(s, buffer, bsize, *0p); 573 } 574 575 string_res & ?=?(string_res & s, char c) { 576 return assign(s, &c, 1); 573 577 } 574 578 575 579 // Copy assignment operator 576 string_res & ?=?(string_res & this, const string_res & rhs) with( this ) {577 return assign_( this, rhs.Handle.s, rhs.Handle.lnth, rhs);578 } 579 580 string_res & ?=?(string_res & this, string_res & rhs) with( this ) {580 string_res & ?=?(string_res & s, const string_res & rhs) with( s ) { 581 return assign_(s, rhs.Handle.s, rhs.Handle.lnth, rhs); 582 } 583 584 string_res & ?=?(string_res & s, string_res & rhs) with( s ) { 581 585 const string_res & rhs2 = rhs; 582 return this = rhs2;586 return s = rhs2; 583 587 } 584 588 585 589 586 590 // Destructor 587 void ^?{}(string_res & s) with(s) {591 void ^?{}(string_res & s) with(s) { 588 592 // much delegated to implied ^VbyteSM 589 593 … … 603 607 // With unicode support, this may be different from just the byte at the given 604 608 // offset from the start of the string. 605 char ?[?](const string_res & s, size_t index) with(s) {609 char ?[?](const string_res & s, size_t index) with(s) { 606 610 //TODO: Check if index is valid (no exceptions yet) 607 611 return Handle.s[index]; 608 612 } 609 613 610 void assignAt(const string_res &s, size_t index, char val) { 611 string_res editZone = { s, SHARE_EDITS, index, index+1 }; 614 void assignAt(const string_res & s, size_t index, char val) { 615 // caution: not tested (not reachable by string-api-coverage interface) 616 // equivalent form at string level is `s[index] = val`, 617 // which uses the overload that returns a length-1 string 618 string_res editZone = { s, SHARE_EDITS, index, 1 }; 612 619 assign(editZone, &val, 1); 613 620 } … … 617 624 // Concatenation 618 625 619 void append(string_res & str1, const char * buffer, size_t bsize) {626 void append(string_res & str1, const char * buffer, size_t bsize) { 620 627 size_t clnth = str1.Handle.lnth + bsize; 621 628 if ( str1.Handle.s + str1.Handle.lnth == buffer ) { // already juxtapose ? … … 635 642 } 636 643 637 void ?+=?(string_res & str1, const string_res &str2) {644 void ?+=?(string_res & str1, const string_res & str2) { 638 645 append( str1, str2.Handle.s, str2.Handle.lnth ); 639 646 } 640 647 641 void ?+=?(string_res &s, char other) { 642 append( s, &other, 1 ); 643 } 644 645 646 647 648 void append(string_res & str1, const string_res & str2, size_t maxlen) { 649 append( str1, str2.Handle.s, min(str2.Handle.lnth, maxlen) ); 650 } 651 652 void ?+=?(string_res & s, char c) { 653 append( s, & c, 1 ); 654 } 655 void ?+=?(string_res & s, const char * c) { 656 append( s, c, strlen(c) ); 657 } 658 659 /////////////////////////////////////////////////////////////////// 660 // Repetition 661 662 void ?*=?(string_res & s, size_t factor) { 663 string_res s2 = { s, COPY_VALUE }; 664 s = ""; 665 for (factor) s += s2; 666 } 648 667 649 668 ////////////////////////////////////////////////////////// 650 669 // Comparisons 651 670 652 int cmp(const string_res &s1, const string_res &s2) {671 int strcmp(const string_res & s1, const string_res & s2) { 653 672 // return 0; 654 673 int ans1 = memcmp(s1.Handle.s, s2.Handle.s, min(s1.Handle.lnth, s2.Handle.lnth)); … … 657 676 } 658 677 659 bool ?==?(const string_res & s1, const string_res &s2) { returncmp(s1, s2) == 0; }660 bool ?!=?(const string_res & s1, const string_res &s2) { returncmp(s1, s2) != 0; }661 bool ?>? (const string_res & s1, const string_res &s2) { returncmp(s1, s2) > 0; }662 bool ?>=?(const string_res & s1, const string_res &s2) { returncmp(s1, s2) >= 0; }663 bool ?<=?(const string_res & s1, const string_res &s2) { returncmp(s1, s2) <= 0; }664 bool ?<? (const string_res & s1, const string_res &s2) { returncmp(s1, s2) < 0; }665 666 int cmp (const string_res &s1, const char* s2) {678 bool ?==?(const string_res & s1, const string_res & s2) { return strcmp(s1, s2) == 0; } 679 bool ?!=?(const string_res & s1, const string_res & s2) { return strcmp(s1, s2) != 0; } 680 bool ?>? (const string_res & s1, const string_res & s2) { return strcmp(s1, s2) > 0; } 681 bool ?>=?(const string_res & s1, const string_res & s2) { return strcmp(s1, s2) >= 0; } 682 bool ?<=?(const string_res & s1, const string_res & s2) { return strcmp(s1, s2) <= 0; } 683 bool ?<? (const string_res & s1, const string_res & s2) { return strcmp(s1, s2) < 0; } 684 685 int strcmp (const string_res & s1, const char * s2) { 667 686 string_res s2x = s2; 668 return cmp(s1, s2x);669 } 670 671 bool ?==?(const string_res & s1, const char* s2) { returncmp(s1, s2) == 0; }672 bool ?!=?(const string_res & s1, const char* s2) { returncmp(s1, s2) != 0; }673 bool ?>? (const string_res & s1, const char* s2) { returncmp(s1, s2) > 0; }674 bool ?>=?(const string_res & s1, const char* s2) { returncmp(s1, s2) >= 0; }675 bool ?<=?(const string_res & s1, const char* s2) { returncmp(s1, s2) <= 0; }676 bool ?<? (const string_res & s1, const char* s2) { returncmp(s1, s2) < 0; }677 678 int cmp (const char* s1, const string_res & s2) {687 return strcmp(s1, s2x); 688 } 689 690 bool ?==?(const string_res & s1, const char * s2) { return strcmp(s1, s2) == 0; } 691 bool ?!=?(const string_res & s1, const char * s2) { return strcmp(s1, s2) != 0; } 692 bool ?>? (const string_res & s1, const char * s2) { return strcmp(s1, s2) > 0; } 693 bool ?>=?(const string_res & s1, const char * s2) { return strcmp(s1, s2) >= 0; } 694 bool ?<=?(const string_res & s1, const char * s2) { return strcmp(s1, s2) <= 0; } 695 bool ?<? (const string_res & s1, const char * s2) { return strcmp(s1, s2) < 0; } 696 697 int strcmp (const char * s1, const string_res & s2) { 679 698 string_res s1x = s1; 680 return cmp(s1x, s2);681 } 682 683 bool ?==?(const char * s1, const string_res &s2) { returncmp(s1, s2) == 0; }684 bool ?!=?(const char * s1, const string_res &s2) { returncmp(s1, s2) != 0; }685 bool ?>? (const char * s1, const string_res &s2) { returncmp(s1, s2) > 0; }686 bool ?>=?(const char * s1, const string_res &s2) { returncmp(s1, s2) >= 0; }687 bool ?<=?(const char * s1, const string_res &s2) { returncmp(s1, s2) <= 0; }688 bool ?<? (const char * s1, const string_res &s2) { returncmp(s1, s2) < 0; }699 return strcmp(s1x, s2); 700 } 701 702 bool ?==?(const char * s1, const string_res & s2) { return strcmp(s1, s2) == 0; } 703 bool ?!=?(const char * s1, const string_res & s2) { return strcmp(s1, s2) != 0; } 704 bool ?>? (const char * s1, const string_res & s2) { return strcmp(s1, s2) > 0; } 705 bool ?>=?(const char * s1, const string_res & s2) { return strcmp(s1, s2) >= 0; } 706 bool ?<=?(const char * s1, const string_res & s2) { return strcmp(s1, s2) <= 0; } 707 bool ?<? (const char * s1, const string_res & s2) { return strcmp(s1, s2) < 0; } 689 708 690 709 … … 693 712 // Search 694 713 695 bool contains(const string_res & s, char ch) {714 bool contains(const string_res & s, char ch) { 696 715 for ( i; size(s) ) { 697 716 if (s[i] == ch) return true; … … 700 719 } 701 720 702 int find(const string_res & s, char search) {721 int find(const string_res & s, char search) { 703 722 return findFrom(s, 0, search); 704 723 } 705 724 706 int findFrom(const string_res & s, size_t fromPos, char search) {725 int findFrom(const string_res & s, size_t fromPos, char search) { 707 726 // FIXME: This paricular overload (find of single char) is optimized to use memchr. 708 727 // The general overload (find of string, memchr applying to its first character) and `contains` should be adjusted to match. … … 715 734 } 716 735 717 int find(const string_res & s, const string_res &search) {736 int find(const string_res & s, const string_res & search) { 718 737 return findFrom(s, 0, search); 719 738 } 720 739 721 int findFrom(const string_res & s, size_t fromPos, const string_res &search) {740 int findFrom(const string_res & s, size_t fromPos, const string_res & search) { 722 741 return findFrom(s, fromPos, search.Handle.s, search.Handle.lnth); 723 742 } 724 743 725 int find(const string_res & s, const char* search) {744 int find(const string_res & s, const char * search) { 726 745 return findFrom(s, 0, search); 727 746 } 728 int findFrom(const string_res & s, size_t fromPos, const char* search) {747 int findFrom(const string_res & s, size_t fromPos, const char * search) { 729 748 return findFrom(s, fromPos, search, strlen(search)); 730 749 } 731 750 732 int find(const string_res & s, const char* search, size_t searchsize) {751 int find(const string_res & s, const char * search, size_t searchsize) { 733 752 return findFrom(s, 0, search, searchsize); 734 753 } 735 754 736 int findFrom(const string_res & s, size_t fromPos, const char* search, size_t searchsize) {755 int findFrom(const string_res & s, size_t fromPos, const char * search, size_t searchsize) { 737 756 738 757 /* Remaining implementations essentially ported from Sunjay's work */ … … 771 790 } 772 791 773 bool includes(const string_res & s, const string_res &search) {792 bool includes(const string_res & s, const string_res & search) { 774 793 return includes(s, search.Handle.s, search.Handle.lnth); 775 794 } 776 795 777 bool includes(const string_res & s, const char* search) {796 bool includes(const string_res & s, const char * search) { 778 797 return includes(s, search, strlen(search)); 779 798 } 780 799 781 bool includes(const string_res & s, const char* search, size_t searchsize) {800 bool includes(const string_res & s, const char * search, size_t searchsize) { 782 801 return find(s, search, searchsize) < s.Handle.lnth; 783 802 } 784 803 785 bool startsWith(const string_res & s, const string_res &prefix) {804 bool startsWith(const string_res & s, const string_res & prefix) { 786 805 return startsWith(s, prefix.Handle.s, prefix.Handle.lnth); 787 806 } 788 807 789 bool startsWith(const string_res & s, const char* prefix) {808 bool startsWith(const string_res & s, const char * prefix) { 790 809 return startsWith(s, prefix, strlen(prefix)); 791 810 } 792 811 793 bool startsWith(const string_res & s, const char* prefix, size_t prefixsize) {812 bool startsWith(const string_res & s, const char * prefix, size_t prefixsize) { 794 813 if (s.Handle.lnth < prefixsize) { 795 814 return false; … … 798 817 } 799 818 800 bool endsWith(const string_res & s, const string_res &suffix) {819 bool endsWith(const string_res & s, const string_res & suffix) { 801 820 return endsWith(s, suffix.Handle.s, suffix.Handle.lnth); 802 821 } 803 822 804 bool endsWith(const string_res & s, const char* suffix) {823 bool endsWith(const string_res & s, const char * suffix) { 805 824 return endsWith(s, suffix, strlen(suffix)); 806 825 } 807 826 808 bool endsWith(const string_res & s, const char* suffix, size_t suffixsize) {827 bool endsWith(const string_res & s, const char * suffix, size_t suffixsize) { 809 828 if (s.Handle.lnth < suffixsize) { 810 829 return false; … … 822 841 // charclass, include, exclude 823 842 824 void ?{}( charclass_res & this, const string_res & chars) {825 ( this){ chars.Handle.s, chars.Handle.lnth };826 } 827 828 void ?{}( charclass_res & this, const char * chars ) {829 ( this){ chars, strlen(chars) };830 } 831 832 void ?{}( charclass_res & this, const char * chars, size_t charssize ) {833 ( this.chars){ chars, charssize };843 void ?{}( charclass_res & s, const string_res & chars) { 844 (s){ chars.Handle.s, chars.Handle.lnth }; 845 } 846 847 void ?{}( charclass_res & s, const char * chars ) { 848 (s){ chars, strlen(chars) }; 849 } 850 851 void ?{}( charclass_res & s, const char * chars, size_t charssize ) { 852 (s.chars){ chars, charssize }; 834 853 // now sort it ? 835 854 } 836 855 837 void ^?{}( charclass_res & this ) {838 ^( this.chars){};856 void ^?{}( charclass_res & s ) { 857 ^(s.chars){}; 839 858 } 840 859 … … 844 863 } 845 864 846 int exclude(const string_res & s, const charclass_res &mask) {865 int exclude(const string_res & s, const charclass_res & mask) { 847 866 for ( i; size(s) ) { 848 867 if ( test(mask, s[i]) ) return i; … … 851 870 } 852 871 853 int include(const string_res & s, const charclass_res &mask) {872 int include(const string_res & s, const charclass_res & mask) { 854 873 for ( i; size(s) ) { 855 874 if ( ! test(mask, s[i]) ) return i; … … 863 882 // Add a new HandleNode node n after the current HandleNode node. 864 883 865 static void AddThisAfter( HandleNode & this, HandleNode & n ) with(this) {866 #ifdef VbyteDebug 867 serr | "enter:AddThisAfter, this:" | &this | " n:" | &n;884 static void AddThisAfter( HandleNode & s, HandleNode & n ) with(s) { 885 #ifdef VbyteDebug 886 serr | "enter:AddThisAfter, s:" | &s | " n:" | &n; 868 887 #endif // VbyteDebug 869 888 // Performance note: we are on the critical path here. MB has ensured that the verifies don't contribute to runtime (are compiled away, like they're supposed to be). 870 889 verify( n.ulink != 0p ); 871 verify( this.ulink == n.ulink );890 verify( s.ulink == n.ulink ); 872 891 flink = n.flink; 873 892 blink = &n; 874 n.flink->blink = & this;875 n.flink = & this;893 n.flink->blink = &s; 894 n.flink = &s; 876 895 #ifdef VbyteDebug 877 896 { … … 894 913 // Delete the current HandleNode node. 895 914 896 static void DeleteNode( HandleNode & this ) with(this) {897 #ifdef VbyteDebug 898 serr | "enter:DeleteNode, this:" | &this;915 static void DeleteNode( HandleNode & s ) with(s) { 916 #ifdef VbyteDebug 917 serr | "enter:DeleteNode, s:" | &s; 899 918 #endif // VbyteDebug 900 919 flink->blink = blink; … … 906 925 907 926 908 909 927 // Allocates specified storage for a string from byte-string area. If not enough space remains to perform the 910 928 // allocation, the garbage collection routine is called. 911 929 912 static char * VbyteAlloc( VbyteHeap & this, int size ) with(this) {930 static char * VbyteAlloc( VbyteHeap & s, int size ) with(s) { 913 931 #ifdef VbyteDebug 914 932 serr | "enter:VbyteAlloc, size:" | size; … … 918 936 919 937 NoBytes = ( uintptr_t )EndVbyte + size; 920 if ( NoBytes > ( uintptr_t )ExtVbyte ) { // enough room for new byte-string ?921 garbage( this, size );// firer up the garbage collector938 if ( NoBytes > ( uintptr_t )ExtVbyte ) { // enough room for new byte-string ? 939 garbage( s, size ); // firer up the garbage collector 922 940 verify( (( uintptr_t )EndVbyte + size) <= ( uintptr_t )ExtVbyte && "garbage run did not free up required space" ); 923 941 } // if … … 939 957 // VbyteAlloc to claim the new space, while doing optimal copying from old to new, then free old. 940 958 941 static char * VbyteTryAdjustLast( VbyteHeap & this, int delta ) with(this) { 942 959 static char * VbyteTryAdjustLast( VbyteHeap & s, int delta ) with(s) { 943 960 if ( ( uintptr_t )EndVbyte + delta <= ( uintptr_t )ExtVbyte ) { 944 961 // room available … … 961 978 // the address in the byte string area. 962 979 963 static void MoveThisAfter( HandleNode & this, const HandleNode & h ) with(this) {964 #ifdef VbyteDebug 965 serr | "enter:MoveThisAfter, this:" | & this | " h:" | & h;980 static void MoveThisAfter( HandleNode & s, const HandleNode & h ) with(s) { 981 #ifdef VbyteDebug 982 serr | "enter:MoveThisAfter, s:" | & s | " h:" | & h; 966 983 #endif // VbyteDebug 967 984 verify( h.ulink != 0p ); 968 verify( this.ulink == h.ulink );985 verify( s.ulink == h.ulink ); 969 986 if ( s < h.s ) { // check argument values 970 987 // serr | "VbyteSM: Error - Cannot move byte string starting at:" | s | " after byte string starting at:" … … 976 993 HandleNode *i; 977 994 for ( i = h.flink; i->s != 0 && s > ( i->s ); i = i->flink ); // find the position for this node after h 978 if ( & this != i->blink ) {979 DeleteNode( this );980 AddThisAfter( this, *i->blink );995 if ( & s != i->blink ) { 996 DeleteNode( s ); 997 AddThisAfter( s, *i->blink ); 981 998 } // if 982 999 #ifdef VbyteDebug … … 1058 1075 // the containing string has been moved. Hence, they only require that their string pointers be adjusted. 1059 1076 1060 void compaction(VbyteHeap & this) with(this) {1077 void compaction(VbyteHeap & s) with(s) { 1061 1078 HandleNode *h; 1062 1079 char *obase, *nbase, *limit; … … 1098 1115 // the heap. The heap is then compacted in the existing heap or into the newly allocated heap. 1099 1116 1100 void garbage(VbyteHeap & this, int minreq ) with(this) {1117 void garbage(VbyteHeap & s, int minreq ) with(s) { 1101 1118 #ifdef VbyteDebug 1102 1119 serr | "enter:garbage"; … … 1124 1141 if ( ( double ) AmountFree < ( CurrSize * heap_expansion_freespace_threshold ) || AmountFree < minreq ) { // free space less than threshold or not enough to serve cur request 1125 1142 1126 extend( this, max( CurrSize, minreq ) ); // extend the heap1143 extend( s, max( CurrSize, minreq ) ); // extend the heap 1127 1144 1128 1145 // Peter says, "This needs work before it should be used." … … 1133 1150 1134 1151 } else { 1135 compaction( this); // in-place1152 compaction(s); // in-place 1136 1153 }// if 1137 1154 #ifdef VbyteDebug … … 1159 1176 // area is deleted. 1160 1177 1161 void extend( VbyteHeap & this, int size ) with (this) {1178 void extend( VbyteHeap & s, int size ) with (s) { 1162 1179 #ifdef VbyteDebug 1163 1180 serr | "enter:extend, size:" | size; … … 1171 1188 StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize); 1172 1189 ExtVbyte = (void *)( StartVbyte + CurrSize ); 1173 compaction( this); // copy from old heap to new & adjust pointers to new heap1190 compaction(s); // copy from old heap to new & adjust pointers to new heap 1174 1191 free( OldStartVbyte ); // release old heap 1175 1192 #ifdef VbyteDebug -
libcfa/src/collections/string_res.hfa
r59c8dff rf988834 10 10 // Created On : Fri Sep 03 11:00:00 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Aug 12 15:45:47 202313 // Update Count : 2 12 // Last Modified On : Thu Jan 4 11:28:06 2024 13 // Update Count : 27 14 14 // 15 15 … … 70 70 71 71 // Getters 72 size_t size(const string_res & s);72 size_t size(const string_res & s); 73 73 74 74 // Constructors, Assignment Operators, Destructor 75 void ?{}(string_res & s); // empty string76 void ?{}(string_res & s, const char* buffer, size_t bsize); // copy specific length from buffer77 static inline void ?{}(string_res & s, const char* rhs) { // copy from string literal (NULL-terminated)75 void ?{}(string_res & s); // empty string 76 void ?{}(string_res & s, const char * buffer, size_t bsize); // copy specific length from buffer 77 static inline void ?{}(string_res & s, const char * rhs) { // copy from string literal (NULL-terminated) 78 78 (s){ rhs, strlen(rhs) }; 79 79 } 80 81 void ?{}(string_res &s, const string_res & s2) = void; 82 void ?{}(string_res &s, string_res & s2) = void; 80 static inline void ?{}(string_res & s, char c ) { 81 ?{}( s, &c, 1); 82 } 83 84 // Deleting the copy constructors makes the compiler reject an attempt to call/return by value 85 void ?{}(string_res & s, const string_res & s2) = void; 86 void ?{}(string_res & s, string_res & s2) = void; 83 87 84 88 enum StrResInitMode { COPY_VALUE, SHARE_EDITS }; 85 void ?{}(string_res & s, const string_res & src, StrResInitMode, size_t start, size_t end);86 static inline void ?{}(string_res & s, const string_res & src, StrResInitMode mode ) {89 void ?{}(string_res & s, const string_res & src, StrResInitMode, size_t start, size_t len ); 90 static inline void ?{}(string_res & s, const string_res & src, StrResInitMode mode ) { 87 91 ?{}( s, src, mode, 0, size(src)); 88 92 } 89 90 string_res & assign(string_res &s, const char* buffer, size_t bsize); // copy specific length from buffer 91 static inline string_res & ?=?(string_res &s, const char* other) { // copy from string literal (NULL-terminated) 92 return assign(s, other, strlen(other)); 93 } 94 string_res & ?=?(string_res &s, const string_res &other); 95 string_res & ?=?(string_res &s, string_res &other); 96 string_res & ?=?(string_res &s, char other); 97 98 void ^?{}(string_res &s); 93 static inline void ?{}(string_res & s, const string_res & src, StrResInitMode mode, size_t maxlen ) { 94 ?{}( s, src, mode, 0, (size(src) > maxlen)?maxlen:size(src) ); 95 } 96 97 string_res & assign(string_res & s, const string_res & src, size_t maxlen); // copy specific length from other string 98 string_res & assign(string_res & s, const char * buffer, size_t bsize); // copy specific length from buffer 99 static inline string_res & ?=?(string_res & s, const char * c) { // copy from string literal (NULL-terminated) 100 return assign(s, c, strlen(c)); 101 } 102 string_res & ?=?(string_res & s, const string_res & c); 103 string_res & ?=?(string_res & s, string_res & c); 104 string_res & ?=?(string_res & s, char c); 105 106 void ^?{}(string_res & s); 99 107 100 108 // IO Operator 101 ofstream & ?|?(ofstream & out, const string_res &s);102 void ?|?(ofstream & out, const string_res &s);103 ifstream & ?|?(ifstream & in, string_res &s);104 void ?|?( ifstream & in, string_res & this );109 ofstream & ?|?(ofstream & out, const string_res & s); 110 void ?|?(ofstream & out, const string_res & s); 111 ifstream & ?|?(ifstream & in, string_res & s); 112 void ?|?( ifstream & in, string_res & s ); 105 113 106 114 struct _Istream_Rstr { … … 113 121 _Istream_Rstr wdi( unsigned int rwd, string_res & s ) { return (_Istream_Rstr)@{ &s, {{0p}, rwd, {.flags.rwd : true}} }; } 114 122 _Istream_Rstr getline( string_res & s, const char delimiter = '\n' ) { 115 return (_Istream_Rstr)@{ &s, {{.delimiter : { delimiter, '\0' } }, -1, {.flags.delimiter : true, .flags.inex : true}} };123 return (_Istream_Rstr)@{ &s, {{.delimiters : { delimiter, '\0' } }, -1, {.flags.delimiter : true, .flags.inex : true}} }; 116 124 } 117 125 _Istream_Rstr & getline( _Istream_Rstr & fmt, const char delimiter = '\n' ) { 118 fmt.delimiter [0] = delimiter; fmt.delimiter[1] = '\0'; fmt.flags.delimiter = true; fmt.flags.inex = true; return fmt;126 fmt.delimiters[0] = delimiter; fmt.delimiters[1] = '\0'; fmt.flags.delimiter = true; fmt.flags.inex = true; return fmt; 119 127 } 120 128 _Istream_Rstr incl( const char scanset[], string_res & s ) { return (_Istream_Rstr)@{ &s, {{scanset}, -1, {.flags.inex : false}} }; } … … 129 137 130 138 // Concatenation 131 void append(string_res &s, const char* buffer, size_t bsize); 132 void ?+=?(string_res &s, char other); // append a character 133 void ?+=?(string_res &s, const string_res &s2); // append-concatenate to first string 134 static inline void ?+=?(string_res &s, const char* other) { 135 append( s, other, strlen(other) ); 136 } 139 void ?+=?(string_res & s, const string_res & s2); 140 void ?+=?(string_res & s, char c); 141 void append(string_res & s, const string_res & s2, size_t maxlen); 142 void ?+=?(string_res & s, const char * c); 143 void append(string_res & s, const char * buffer, size_t bsize); 144 145 static inline string_res & strcat(string_res & s, const string_res & s2) { s += s2; return s; } 146 static inline string_res & strcat(string_res & s, const char * c) { s += c; return s; } 147 static inline string_res & strncat(string_res & s, const string_res & s2, size_t maxlen) { append(s, s2, maxlen); return s; } 148 static inline string_res & strncat(string_res & s, const char * buffer, size_t bsize) { append(s, buffer, bsize); return s; } 149 150 // Repetition 151 void ?*=?(string_res & s, size_t factor); 137 152 138 153 // Character access 139 void assignAt(const string_res & s, size_t index, char val);140 char ?[?](const string_res & s, size_t index); // Mike changed to ret by val from Sunjay's ref, to match Peter's141 //char codePointAt(const string_res & s, size_t index); // revisit under Unicode154 void assignAt(const string_res & s, size_t index, char val); 155 char ?[?](const string_res & s, size_t index); // Mike changed to ret by val from Sunjay's ref, to match Peter's 156 //char codePointAt(const string_res & s, size_t index); // revisit under Unicode 142 157 143 158 // Comparisons 144 int cmp (const string_res &, const string_res &);159 int strcmp (const string_res &, const string_res &); 145 160 bool ?==?(const string_res &, const string_res &); 146 161 bool ?!=?(const string_res &, const string_res &); … … 150 165 bool ?<? (const string_res &, const string_res &); 151 166 152 int cmp (const string_res &, const char*);153 bool ?==?(const string_res &, const char *);154 bool ?!=?(const string_res &, const char *);155 bool ?>? (const string_res &, const char *);156 bool ?>=?(const string_res &, const char *);157 bool ?<=?(const string_res &, const char *);158 bool ?<? (const string_res &, const char *);159 160 int cmp (const char*, const string_res &);161 bool ?==?(const char *, const string_res &);162 bool ?!=?(const char *, const string_res &);163 bool ?>? (const char *, const string_res &);164 bool ?>=?(const char *, const string_res &);165 bool ?<=?(const char *, const string_res &);166 bool ?<? (const char *, const string_res &);167 int strcmp(const string_res &, const char *); 168 bool ?==?(const string_res &, const char *); 169 bool ?!=?(const string_res &, const char *); 170 bool ?>? (const string_res &, const char *); 171 bool ?>=?(const string_res &, const char *); 172 bool ?<=?(const string_res &, const char *); 173 bool ?<? (const string_res &, const char *); 174 175 int strcmp(const char *, const string_res &); 176 bool ?==?(const char *, const string_res &); 177 bool ?!=?(const char *, const string_res &); 178 bool ?>? (const char *, const string_res &); 179 bool ?>=?(const char *, const string_res &); 180 bool ?<=?(const char *, const string_res &); 181 bool ?<? (const char *, const string_res &); 167 182 168 183 // String search 169 bool contains(const string_res & s, char ch); // single character170 171 int find(const string_res & s, char search);172 int find(const string_res & s, const string_res &search);173 int find(const string_res & s, const char* search);174 int find(const string_res & s, const char* search, size_t searchsize);175 176 int findFrom(const string_res & s, size_t fromPos, char search);177 int findFrom(const string_res & s, size_t fromPos, const string_res &search);178 int findFrom(const string_res & s, size_t fromPos, const char* search);179 int findFrom(const string_res & s, size_t fromPos, const char* search, size_t searchsize);180 181 bool includes(const string_res & s, const string_res &search);182 bool includes(const string_res & s, const char* search);183 bool includes(const string_res & s, const char* search, size_t searchsize);184 185 bool startsWith(const string_res & s, const string_res &prefix);186 bool startsWith(const string_res & s, const char* prefix);187 bool startsWith(const string_res & s, const char* prefix, size_t prefixsize);188 189 bool endsWith(const string_res & s, const string_res &suffix);190 bool endsWith(const string_res & s, const char* suffix);191 bool endsWith(const string_res & s, const char* suffix, size_t suffixsize);192 193 int include(const string_res & s, const charclass_res &mask);194 int exclude(const string_res & s, const charclass_res &mask);184 bool contains(const string_res & s, char ch); // single character 185 186 int find(const string_res & s, char search); 187 int find(const string_res & s, const string_res & search); 188 int find(const string_res & s, const char * search); 189 int find(const string_res & s, const char * search, size_t searchsize); 190 191 int findFrom(const string_res & s, size_t fromPos, char search); 192 int findFrom(const string_res & s, size_t fromPos, const string_res & search); 193 int findFrom(const string_res & s, size_t fromPos, const char * search); 194 int findFrom(const string_res & s, size_t fromPos, const char * search, size_t searchsize); 195 196 bool includes(const string_res & s, const string_res & search); 197 bool includes(const string_res & s, const char * search); 198 bool includes(const string_res & s, const char * search, size_t searchsize); 199 200 bool startsWith(const string_res & s, const string_res & prefix); 201 bool startsWith(const string_res & s, const char * prefix); 202 bool startsWith(const string_res & s, const char * prefix, size_t prefixsize); 203 204 bool endsWith(const string_res & s, const string_res & suffix); 205 bool endsWith(const string_res & s, const char * suffix); 206 bool endsWith(const string_res & s, const char * suffix, size_t suffixsize); 207 208 int include(const string_res & s, const charclass_res & mask); 209 int exclude(const string_res & s, const charclass_res & mask); 195 210 196 211 // Modifiers 197 void padStart(string_res & s, size_t n);198 void padStart(string_res & s, size_t n, char padding);199 void padEnd(string_res & s, size_t n);212 void padStart(string_res & s, size_t n); 213 void padStart(string_res & s, size_t n, char padding); 214 void padEnd(string_res & s, size_t n); 200 215 void padEnd(string_res &s, size_t n, char padding); 201 216 -
libcfa/src/heap.cfa
r59c8dff rf988834 10 10 // Created On : Tue Dec 19 21:58:35 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Sep 30 17:31:15 202313 // Update Count : 161 712 // Last Modified On : Wed Jan 3 21:30:54 2024 13 // Update Count : 1619 14 14 // 15 15 … … 27 27 #include "bits/align.hfa" // libAlign 28 28 #include "bits/defs.hfa" // likely, unlikely 29 #include "concurrency/kernel/fwd.hfa" // __POLL_PREEMPTION29 #include "concurrency/kernel/fwd.hfa" // disable_interrupts, enable_interrupts 30 30 #include "startup.hfa" // STARTUP_PRIORITY_MEMORY 31 31 #include "math.hfa" // ceiling, min -
libcfa/src/interpose.cfa
r59c8dff rf988834 10 10 // Created On : Wed Mar 29 16:10:31 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Mar 27 21:09:03 202313 // Update Count : 19612 // Last Modified On : Thu Jan 11 18:45:31 2024 13 // Update Count : 218 14 14 // 15 15 … … 18 18 extern "C" { 19 19 #include <dlfcn.h> // dlopen, dlsym 20 //#include <link.h> // dl_iterate_phdr 21 struct dl_phdr_info; 22 int dl_iterate_phdr( int (*)( struct dl_phdr_info *, size_t, void * ), void * ); 20 23 #include <execinfo.h> // backtrace, messages 21 24 } … … 23 26 #include "bits/defs.hfa" 24 27 #include "bits/signal.hfa" // sigHandler_? 28 #include "concurrency/kernel/fwd.hfa" // disable_interrupts, enable_interrupts 25 29 #include "startup.hfa" // STARTUP_PRIORITY_CORE 26 30 #include <assert.h> … … 87 91 void (* exit)( int ) __attribute__(( __noreturn__ )); 88 92 void (* abort)( void ) __attribute__(( __noreturn__ )); 93 int (* dl_iterate_phdr)( int (*)( struct dl_phdr_info *, size_t, void * ), void * ); 89 94 } __cabi_libc; 90 95 … … 102 107 #pragma GCC diagnostic ignored "-Wdiscarded-qualifiers" 103 108 INTERPOSE_LIBC( abort, version ); 104 INTERPOSE_LIBC( exit , version ); 109 INTERPOSE_LIBC( exit, version ); 110 INTERPOSE_LIBC( dl_iterate_phdr, version ); 105 111 #pragma GCC diagnostic pop 106 112 … … 150 156 } 151 157 } 158 159 extern "C" int dl_iterate_phdr( int (* callback)( struct dl_phdr_info *, size_t, void * ), void * data ) { 160 disable_interrupts(); 161 int ret = __cabi_libc.dl_iterate_phdr( callback, data ); // call real routine 162 enable_interrupts( false ); 163 return ret; 164 } // dl_iterate_phdr 152 165 153 166 //============================================================================================= -
libcfa/src/iostream.cfa
r59c8dff rf988834 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Nov 17 13:33:12 202313 // Update Count : 18 5312 // Last Modified On : Wed Jan 3 10:53:13 2024 13 // Update Count : 1898 14 14 // 15 15 … … 984 984 } 985 985 986 istype & ?|?( istype & is, _Istream_Cquoted f ) {986 istype & ?|?( istype & is, _Istream_Cquoted f ) with( f ) { 987 987 char fmtstr[32]; // storage scanset and format codes 988 988 fmtstr[0] = '%'; … … 992 992 bool check = true; 993 993 994 if ( f.flags.ignore ) { check = false; fmtstr[1] = '*'; pos += 1; }995 int rwd = f.wd;996 if ( f.wd != -1 ) {// => just ignore versus ignore with width994 if ( cstr.flags.ignore ) { check = false; fmtstr[1] = '*'; pos += 1; } 995 int rwd = cstr.wd; 996 if ( cstr.wd != -1 ) { // => just ignore versus ignore with width 997 997 // wd is buffer bytes available (for input chars + null terminator) 998 998 // rwd is count of input chars 999 999 // no maximum width necessary because text ignored => width is read width 1000 if ( f.flags.rwd ) check = false;1001 else rwd = f.wd - 1;1000 if ( cstr.flags.rwd ) check = false; 1001 else rwd = cstr.wd - 1; 1002 1002 pos += sprintf( &fmtstr[pos], "%d", rwd ); 1003 1003 } // if 1004 1004 1005 1005 int len = 0; // may not be set in fmt 1006 if ( ! f.flags.inex ) { // => quoted getline1007 // fprintf( stderr, "quoted\n" );1006 char enddelim; 1007 if ( ! cstr.flags.inex ) { // => quoted getline 1008 1008 args = fmt( is, "%*[ \f\n\r\t\v]" ); // remove leading whitespace 1009 1009 if ( eof( is ) ) goto Eof; 1010 // args = fmt( is, (const char *)f.delimiter ); // remove leading quote 1011 args = fmt( is, "'%n", &len ); // remove leading quote 1012 fprintf( stderr, "quoted %d %d\n", args, len ); 1010 char rfmt[4] = { cstr.delimiters[0], '%', 'n', '\0' }; 1011 args = fmt( is, rfmt, &len ); // remove leading quote 1013 1012 if ( len == 0 || eof( is ) ) goto Eof; 1014 1013 } // if 1015 sprintf( &fmtstr[pos], "[^%c]%%n", f.delimiter[0] ); 1016 // fprintf( stderr, "getline %s %d\n", fmtstr, f.wd ); 1017 if ( f.flags.ignore ) args = fmt( is, fmtstr, &len ); // no string argument for '*' 1018 else args = fmt( is, fmtstr, f.s, &len ); 1019 // fprintf( stderr, "getline %s %d %d %d\n", fmtstr, args, f.wd, eof( is ) ); 1014 enddelim = cstr.delimiters[1] == '\0' ? cstr.delimiters[0] : cstr.delimiters[1]; 1015 sprintf( &fmtstr[pos], "[^%c]%%n", enddelim ); 1016 if ( cstr.flags.ignore ) args = fmt( is, fmtstr, &len ); // no string argument for '*' 1017 else args = fmt( is, fmtstr, cstr.s, &len ); 1020 1018 if ( check && len == rwd && ! eof( is ) ) { // might not fit 1021 1019 char peek; 1022 1020 fmt( is, "%c", &peek ); // check for delimiter 1023 // fprintf( stderr, "peek %d '%c'\n", args, peek );1024 1021 if ( ! eof( is ) ) { 1025 if ( peek != f.delimiter[0]) {1022 if ( peek != enddelim ) { 1026 1023 ungetc( is, peek ); 1027 1024 throwResume ExceptionInst( cstring_length ); … … 1030 1027 } else fmt( is, "%*c" ); // remove delimiter 1031 1028 Eof: ; 1032 if ( rwd > 0 && args == 0 ) f.s[0] = '\0';// read failed => no pattern match => set string to null1029 if ( rwd > 0 && args == 0 ) cstr.s[0] = '\0'; // read failed => no pattern match => set string to null 1033 1030 if ( args == 1 && eof( is ) ) { // data but scan ended at EOF 1034 // fprintf( stderr, "clear\n" );1035 1031 clear( is ); // => reset EOF => detect again on next read 1036 1032 } // if … … 1038 1034 } 1039 1035 1040 istype & ?|?( istype & is, _Istream_Cstr f ) {1036 istype & ?|?( istype & is, _Istream_Cstr f ) with( f ) { 1041 1037 const char * scanset; 1042 1038 size_t nscanset = 0; 1043 if ( f .flags.delimiter ) scanset = f.delimiter; // getline ?1039 if ( flags.delimiter ) scanset = delimiters; // getline ? 1044 1040 else scanset = f.scanset; 1045 1041 if ( scanset ) nscanset = strlen( scanset ); … … 1084 1080 if ( f.flags.delimiter ) { // getline 1085 1081 int len = 0; // may not be set in fmt 1086 if ( ! f.flags.inex ) { // => quoted getline 1087 // fprintf( stderr, "quoted\n" ); 1088 args = fmt( is, "%*[ \f\n\r\t\v]" ); // remove leading whitespace 1089 if ( eof( is ) ) goto X; 1090 args = fmt( is, "\"" ); // remove leading quote 1091 if ( eof( is ) ) goto X; 1092 } // if 1093 // fprintf( stderr, "getline\n" ); 1094 // sprintf( &fmtstr[pos], "[%s%s]%%n", f.flags.inex ? "^" : "", scanset ); 1095 sprintf( &fmtstr[pos], "[^%s]%%n", scanset ); 1096 // fprintf( stderr, "getline %s %d\n", fmtstr, f.wd ); 1082 sprintf( &fmtstr[pos], "[^%c]%%n", f.delimiters[0] ); 1097 1083 if ( f.flags.ignore ) args = fmt( is, fmtstr, &len ); // no string argument for '*' 1098 1084 else args = fmt( is, fmtstr, f.s, &len ); 1099 // fprintf( stderr, "getline %s %d %d %d\n", fmtstr, args, f.wd, eof( is ) );1100 1085 if ( check && len == rwd && ! eof( is ) ) { // might not fit 1101 char peek; 1102 fmt( is, "%c", &peek ); // check for delimiter 1103 // fprintf( stderr, "peek %d '%c'\n", args, peek ); 1086 fmtstr[0] = f.delimiters[0]; fmtstr[1] = '%'; fmtstr[2] = 'n'; fmtstr[3] = '\0'; 1087 fmt( is, fmtstr, &len ); // remove delimiter 1104 1088 if ( ! eof( is ) ) { 1105 if ( peek != f.delimiter[0] ) { 1106 ungetc( is, peek ); 1089 // if ( peek != f.delimiter[0] ) { 1090 if ( len != 1 ) { 1091 // ungetc( is, peek ); 1107 1092 throwResume ExceptionInst( cstring_length ); 1108 1093 } // if 1109 1094 } // if 1110 } else fmt( is, "%*c" ); // remove delimiter 1111 X: ; 1095 } else fmt( is, "%*c" ); // remove delimiter 1112 1096 } else { 1113 1097 // incl %[xxx], %*[xxx], %w[xxx], %*w[xxx] -
libcfa/src/iostream.hfa
r59c8dff rf988834 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Nov 15 17:55:31 202313 // Update Count : 59612 // Last Modified On : Wed Jan 3 10:53:18 2024 13 // Update Count : 610 14 14 // 15 15 … … 392 392 union { 393 393 const char * scanset; 394 char delimiter [2];394 char delimiters[3]; // [0] => left, [1] => right 395 395 }; 396 396 int wd; // width … … 412 412 413 413 struct _Istream_Cquoted { 414 char * s; 415 inline _Istream_str_base; 414 _Istream_Cstr cstr; 416 415 }; // _Istream_Cquoted 417 416 … … 419 418 // width must include room for null terminator 420 419 _Istream_Cstr wdi( unsigned int wd, char s[] ) { return (_Istream_Cstr)@{ s, { {0p}, wd, {.all : 0} } }; } 421 // read width does not include null terminator422 420 _Istream_Cstr wdi( unsigned int wd, unsigned int rwd, char s[] ) { 423 421 if ( wd <= rwd ) throw (cstring_length){ &cstring_length_vt }; 424 422 return (_Istream_Cstr)@{ s, { {0p}, rwd, {.flags.rwd : true} } }; 425 423 } 426 _Istream_Cquoted & quoted( _Istream_Cstr & fmt, const char delimiter = '"' ) {427 fmt.delimiter [0] = delimiter; fmt.delimiter[1] = '\0';424 _Istream_Cquoted & quoted( _Istream_Cstr & fmt, const char Ldelimiter = '"', const char Rdelimiter = '\0' ) { 425 fmt.delimiters[0] = Ldelimiter; fmt.delimiters[1] = Rdelimiter; fmt.delimiters[2] = '\0'; 428 426 return (_Istream_Cquoted &)fmt; 429 427 } 430 428 _Istream_Cstr & getline( _Istream_Cstr & fmt, const char delimiter = '\n' ) { 431 fmt.delimiter[0] = delimiter; fmt.delimiter[1] = '\0'; fmt.flags.delimiter = true; fmt.flags.inex = true; return fmt; } 429 fmt.delimiters[0] = delimiter; fmt.delimiters[1] = '\0'; fmt.flags.delimiter = true; fmt.flags.inex = true; return fmt; 430 } 432 431 _Istream_Cstr & incl( const char scanset[], _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = false; return fmt; } 433 432 _Istream_Cstr & excl( const char scanset[], _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = true; return fmt; } -
src/AST/Attribute.cpp
r59c8dff rf988834 38 38 39 39 bool Attribute::isValidOnFuncParam() const { 40 // attributes such as aligned, cleanup, etc. produce GCC errors when they appear41 // on function parameters. Maintain here a whitelist of attribute names that are42 // allowed to appear on parameters.40 // Attributes produce GCC errors when they appear on function 41 // parameters. Names on the previous allow-list implementation: 42 // unused, noreturn, __vector_size__ 43 43 std::string norm = normalizedName(); 44 return norm == "unused" || norm == "noreturn";44 return norm != "aligned" && norm != "packed" && norm != "used"; 45 45 } 46 46 -
src/AST/Decl.hpp
r59c8dff rf988834 29 29 #include "StorageClasses.hpp" 30 30 #include "Visitor.hpp" 31 #include "Common/utility.h"32 31 33 32 // Must be included in *all* AST classes; should be #undef'd at the end of the file -
src/AST/Pass.proto.hpp
r59c8dff rf988834 19 19 #include "Common/Iterate.hpp" 20 20 #include "Common/Stats/Heap.h" 21 #include "Common/utility.h" 21 22 namespace ast { 22 23 template<typename core_t> class Pass; -
src/CodeGen/CodeGenerator.hpp
r59c8dff rf988834 21 21 #include "AST/Pass.hpp" // for WithGuards, WithShortCircuiting, ... 22 22 #include "CodeGen/Options.h" // for Options 23 #include "Common/Indenter.h" // for Indenter 23 24 24 25 -
src/Common/utility.h
r59c8dff rf988834 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Feb 17 15:25:00 202313 // Update Count : 5 312 // Last Modified On : Wed Jan 17 14:40:00 2024 13 // Update Count : 54 14 14 // 15 15 … … 17 17 18 18 #include <cassert> 19 #include <cctype>20 19 #include <algorithm> 21 #include <iostream>22 20 #include <list> 23 #include <memory>24 21 #include <string> 25 22 #include <type_traits> 26 23 #include <vector> 27 #include <cstring> // memcmp28 29 #include "Common/Indenter.h"30 31 class Expression;32 33 /// bring std::move into global scope34 using std::move;35 24 36 25 /// partner to move that copies any copyable type 37 26 template<typename T> 38 27 T copy( const T & x ) { return x; } 39 40 template< typename T >41 static inline T * maybeClone( const T *orig ) {42 if ( orig ) {43 return orig->clone();44 } else {45 return 0;46 } // if47 }48 49 template< typename Input_iterator >50 void printEnums( Input_iterator begin, Input_iterator end, const char * const *name_array, std::ostream &os ) {51 for ( Input_iterator i = begin; i != end; ++i ) {52 os << name_array[ *i ] << ' ';53 } // for54 }55 56 template< typename Container >57 void deleteAll( const Container &container ) {58 for ( const auto &i : container ) {59 delete i;60 } // for61 }62 63 template< typename Container >64 void printAll( const Container &container, std::ostream &os, Indenter indent = {} ) {65 for ( typename Container::const_iterator i = container.begin(); i != container.end(); ++i ) {66 if ( *i ) {67 os << indent;68 (*i)->print( os, indent );69 // need an endl after each element because it's not easy to know when each individual item should end70 os << std::endl;71 } // if72 } // for73 }74 75 template< typename SrcContainer, typename DestContainer >76 void cloneAll( const SrcContainer &src, DestContainer &dest ) {77 typename SrcContainer::const_iterator in = src.begin();78 std::back_insert_iterator< DestContainer > out( dest );79 while ( in != src.end() ) {80 *out++ = (*in++)->clone();81 } // while82 }83 84 template< typename SrcContainer, typename DestContainer, typename Predicate >85 void cloneAll_if( const SrcContainer &src, DestContainer &dest, Predicate pred ) {86 std::back_insert_iterator< DestContainer > out( dest );87 for ( auto x : src ) {88 if ( pred(x) ) {89 *out++ = x->clone();90 }91 } // while92 }93 94 template< typename Container >95 void assertAll( const Container &container ) {96 int count = 0;97 for ( typename Container::const_iterator i = container.begin(); i != container.end(); ++i ) {98 if ( !(*i) ) {99 std::cerr << count << " is null" << std::endl;100 } // if101 } // for102 }103 104 template < typename T >105 std::list<T> tail( std::list<T> l ) {106 if ( ! l.empty() ) {107 std::list<T> ret(++(l.begin()), l.end());108 return ret;109 } // if110 }111 112 template < typename T >113 std::list<T> flatten( std::list < std::list<T> > l) {114 typedef std::list <T> Ts;115 116 Ts ret;117 118 switch ( l.size() ) {119 case 0:120 return ret;121 case 1:122 return l.front();123 default:124 ret = flatten(tail(l));125 ret.insert(ret.begin(), l.front().begin(), l.front().end());126 return ret;127 } // switch128 }129 28 130 29 /// Splice src onto the end of dst, clearing src … … 143 42 } 144 43 145 template< typename... Args > 146 auto filter(Args&&... args) -> decltype(std::copy_if(std::forward<Args>(args)...)) { 147 return std::copy_if(std::forward<Args>(args)...); 148 } 149 150 template <typename E, typename UnaryPredicate, template< typename, typename...> class Container, typename... Args > 151 void filter( Container< E *, Args... > & container, UnaryPredicate pred, bool doDelete ) { 152 auto i = begin( container ); 153 while ( i != end( container ) ) { 154 auto it = next( i ); 155 if ( pred( *i ) ) { 156 if ( doDelete ) { 157 delete *i; 158 } // if 159 container.erase( i ); 160 } // if 161 i = it; 162 } // while 163 } 164 44 /// Remove elements that match pred from the container. 165 45 template<typename Container, typename Pred> 166 46 void erase_if( Container & cont, Pred && pred ) { -
src/InitTweak/FixInit.cpp
r59c8dff rf988834 581 581 } 582 582 583 if ( ! dtor->env ) dtor->env = maybeClone( env ); 583 if ( nullptr == dtor->env && nullptr != env ) { 584 dtor->env = ast::shallowCopy( env ); 585 } 584 586 auto dtorFunc = getDtorFunc( ret, new ast::ExprStmt(loc, dtor ), stmtsToAddBefore ); 585 587 -
src/Parser/DeclarationNode.cc
r59c8dff rf988834 35 35 #include "Common/SemanticError.h" // for SemanticError 36 36 #include "Common/UniqueName.h" // for UniqueName 37 #include "Common/utility.h" // for maybeClone37 #include "Common/utility.h" // for copy, spliceBegin 38 38 #include "Parser/ExpressionNode.h" // for ExpressionNode 39 39 #include "Parser/InitializerNode.h"// for InitializerNode … … 41 41 #include "TypeData.h" // for TypeData, TypeData::Aggregate_t 42 42 #include "TypedefTable.h" // for TypedefTable 43 44 class Initializer;45 43 46 44 extern TypedefTable typedefTable; … … 101 99 DeclarationNode * DeclarationNode::clone() const { 102 100 DeclarationNode * newnode = new DeclarationNode; 103 newnode->set_next( maybeC lone( get_next() ) );101 newnode->set_next( maybeCopy( get_next() ) ); 104 102 newnode->name = name ? new string( *name ) : nullptr; 105 103 106 104 newnode->builtin = NoBuiltinType; 107 newnode->type = maybeC lone( type );105 newnode->type = maybeCopy( type ); 108 106 newnode->inLine = inLine; 109 107 newnode->storageClasses = storageClasses; 110 108 newnode->funcSpecs = funcSpecs; 111 newnode->bitfieldWidth = maybeC lone( bitfieldWidth );112 newnode->enumeratorValue.reset( maybeC lone( enumeratorValue.get() ) );109 newnode->bitfieldWidth = maybeCopy( bitfieldWidth ); 110 newnode->enumeratorValue.reset( maybeCopy( enumeratorValue.get() ) ); 113 111 newnode->hasEllipsis = hasEllipsis; 114 112 newnode->linkage = linkage; 115 113 newnode->asmName = maybeCopy( asmName ); 116 114 newnode->attributes = attributes; 117 newnode->initializer = maybeC lone( initializer );115 newnode->initializer = maybeCopy( initializer ); 118 116 newnode->extension = extension; 119 newnode->asmStmt = maybeC lone( asmStmt );117 newnode->asmStmt = maybeCopy( asmStmt ); 120 118 newnode->error = error; 121 119 122 120 // newnode->variable.name = variable.name ? new string( *variable.name ) : nullptr; 123 121 newnode->variable.tyClass = variable.tyClass; 124 newnode->variable.assertions = maybeC lone( variable.assertions );125 newnode->variable.initializer = maybeC lone( variable.initializer );126 127 newnode->assert.condition = maybeC lone( assert.condition );122 newnode->variable.assertions = maybeCopy( variable.assertions ); 123 newnode->variable.initializer = maybeCopy( variable.initializer ); 124 125 newnode->assert.condition = maybeCopy( assert.condition ); 128 126 newnode->assert.message = maybeCopy( assert.message ); 129 127 return newnode; … … 664 662 dst->base->aggInst.aggregate = src; 665 663 if ( src->kind == TypeData::Aggregate ) { 666 dst->base->aggInst.params = maybeC lone( src->aggregate.actuals );664 dst->base->aggInst.params = maybeCopy( src->aggregate.actuals ); 667 665 } // if 668 666 dst->base->qualifiers |= src->qualifiers; … … 694 692 if ( o->type->kind == TypeData::Aggregate ) { 695 693 type->aggInst.hoistType = o->type->aggregate.body; 696 type->aggInst.params = maybeC lone( o->type->aggregate.actuals );694 type->aggInst.params = maybeCopy( o->type->aggregate.actuals ); 697 695 } else { 698 696 type->aggInst.hoistType = o->type->enumeration.body; … … 860 858 p->type->base->aggInst.aggregate = type; 861 859 if ( type->kind == TypeData::Aggregate ) { 862 p->type->base->aggInst.params = maybeC lone( type->aggregate.actuals );860 p->type->base->aggInst.params = maybeCopy( type->aggregate.actuals ); 863 861 } // if 864 862 p->type->base->qualifiers |= type->qualifiers; … … 897 895 lastArray->base->aggInst.aggregate = type; 898 896 if ( type->kind == TypeData::Aggregate ) { 899 lastArray->base->aggInst.params = maybeC lone( type->aggregate.actuals );897 lastArray->base->aggInst.params = maybeCopy( type->aggregate.actuals ); 900 898 } // if 901 899 lastArray->base->qualifiers |= type->qualifiers; … … 950 948 DeclarationNode * DeclarationNode::cloneType( string * name ) { 951 949 DeclarationNode * newnode = newName( name ); 952 newnode->type = maybeC lone( type );950 newnode->type = maybeCopy( type ); 953 951 newnode->copySpecifiers( this ); 954 952 return newnode; … … 984 982 } // if 985 983 986 newType->forall = maybeC lone( type->forall );984 newType->forall = maybeCopy( type->forall ); 987 985 if ( ! o->type ) { 988 986 o->type = newType; -
src/Parser/ParseNode.h
r59c8dff rf988834 30 30 #include "Common/SemanticError.h" // for SemanticError 31 31 #include "Common/UniqueName.h" // for UniqueName 32 #include "Common/utility.h" // for maybeClone33 32 #include "Parser/parserutility.h" // for maybeBuild, maybeCopy 34 33 -
src/Parser/TypeData.cc
r59c8dff rf988834 167 167 TypeData * newtype = new TypeData( kind ); 168 168 newtype->qualifiers = qualifiers; 169 newtype->base = maybeC lone( base );170 newtype->forall = maybeC lone( forall );169 newtype->base = maybeCopy( base ); 170 newtype->forall = maybeCopy( forall ); 171 171 172 172 switch ( kind ) { … … 185 185 break; 186 186 case Array: 187 newtype->array.dimension = maybeC lone( array.dimension );187 newtype->array.dimension = maybeCopy( array.dimension ); 188 188 newtype->array.isVarLen = array.isVarLen; 189 189 newtype->array.isStatic = array.isStatic; 190 190 break; 191 191 case Function: 192 newtype->function.params = maybeC lone( function.params );193 newtype->function.idList = maybeC lone( function.idList );194 newtype->function.oldDeclList = maybeC lone( function.oldDeclList );195 newtype->function.body = maybeC lone( function.body );196 newtype->function.withExprs = maybeC lone( function.withExprs );192 newtype->function.params = maybeCopy( function.params ); 193 newtype->function.idList = maybeCopy( function.idList ); 194 newtype->function.oldDeclList = maybeCopy( function.oldDeclList ); 195 newtype->function.body = maybeCopy( function.body ); 196 newtype->function.withExprs = maybeCopy( function.withExprs ); 197 197 break; 198 198 case Aggregate: 199 199 newtype->aggregate.kind = aggregate.kind; 200 200 newtype->aggregate.name = aggregate.name ? new string( *aggregate.name ) : nullptr; 201 newtype->aggregate.params = maybeC lone( aggregate.params );202 newtype->aggregate.actuals = maybeC lone( aggregate.actuals );203 newtype->aggregate.fields = maybeC lone( aggregate.fields );201 newtype->aggregate.params = maybeCopy( aggregate.params ); 202 newtype->aggregate.actuals = maybeCopy( aggregate.actuals ); 203 newtype->aggregate.fields = maybeCopy( aggregate.fields ); 204 204 newtype->aggregate.body = aggregate.body; 205 205 newtype->aggregate.anon = aggregate.anon; … … 208 208 break; 209 209 case AggregateInst: 210 newtype->aggInst.aggregate = maybeC lone( aggInst.aggregate );211 newtype->aggInst.params = maybeC lone( aggInst.params );210 newtype->aggInst.aggregate = maybeCopy( aggInst.aggregate ); 211 newtype->aggInst.params = maybeCopy( aggInst.params ); 212 212 newtype->aggInst.hoistType = aggInst.hoistType; 213 213 break; 214 214 case Enum: 215 215 newtype->enumeration.name = enumeration.name ? new string( *enumeration.name ) : nullptr; 216 newtype->enumeration.constants = maybeC lone( enumeration.constants );216 newtype->enumeration.constants = maybeCopy( enumeration.constants ); 217 217 newtype->enumeration.body = enumeration.body; 218 218 newtype->enumeration.anon = enumeration.anon; … … 221 221 case SymbolicInst: 222 222 newtype->symbolic.name = symbolic.name ? new string( *symbolic.name ) : nullptr; 223 newtype->symbolic.params = maybeC lone( symbolic.params );224 newtype->symbolic.actuals = maybeC lone( symbolic.actuals );225 newtype->symbolic.assertions = maybeC lone( symbolic.assertions );223 newtype->symbolic.params = maybeCopy( symbolic.params ); 224 newtype->symbolic.actuals = maybeCopy( symbolic.actuals ); 225 newtype->symbolic.assertions = maybeCopy( symbolic.assertions ); 226 226 newtype->symbolic.isTypedef = symbolic.isTypedef; 227 227 break; 228 228 case Tuple: 229 newtype->tuple = maybeC lone( tuple );229 newtype->tuple = maybeCopy( tuple ); 230 230 break; 231 231 case Typeof: 232 232 case Basetypeof: 233 newtype->typeexpr = maybeC lone( typeexpr );233 newtype->typeexpr = maybeCopy( typeexpr ); 234 234 break; 235 235 case Vtable: … … 240 240 break; 241 241 case Qualified: 242 newtype->qualified.parent = maybeC lone( qualified.parent );243 newtype->qualified.child = maybeC lone( qualified.child );242 newtype->qualified.parent = maybeCopy( qualified.parent ); 243 newtype->qualified.child = maybeCopy( qualified.child ); 244 244 break; 245 245 } // switch -
src/Parser/parser.yy
r59c8dff rf988834 1960 1960 // Append the return type at the start (left-hand-side) to each identifier in the list. 1961 1961 DeclarationNode * ret = new DeclarationNode; 1962 ret->type = maybeC lone( $1->type->base );1962 ret->type = maybeCopy( $1->type->base ); 1963 1963 $$ = $1->appendList( DeclarationNode::newFunction( $3, ret, $6, nullptr ) ); 1964 1964 } -
src/Parser/parserutility.h
r59c8dff rf988834 36 36 37 37 template<typename node_t> 38 node_t * maybeCopy( node_t const * node ) {38 static inline node_t * maybeCopy( node_t const * node ) { 39 39 return node ? ast::shallowCopy( node ) : nullptr; 40 40 } -
src/SymTab/GenImplicitCall.cpp
r59c8dff rf988834 25 25 #include "CodeGen/OperatorTable.h" // for isCtorDtor 26 26 #include "Common/UniqueName.h" // for UniqueName 27 #include "Common/utility.h" // for splice 27 28 28 29 namespace SymTab { -
src/Validate/Autogen.cpp
r59c8dff rf988834 445 445 446 446 auto * paramType = ast::deepCopy( member->get_type() ); 447 paramType->attributes.clear(); 447 erase_if( paramType->attributes, []( ast::Attribute const * attr ){ 448 return !attr->isValidOnFuncParam(); 449 } ); 448 450 ast::ObjectDecl * param = new ast::ObjectDecl( 449 451 getLocation(), member->name, paramType ); -
src/Validate/ReplaceTypedef.cpp
r59c8dff rf988834 25 25 26 26 namespace { 27 28 bool isNonParameterAttribute( ast::Attribute const * attr ) {29 static const std::vector<std::string> bad_names = {30 "aligned", "__aligned__",31 };32 for ( auto name : bad_names ) {33 if ( name == attr->name ) {34 return true;35 }36 }37 return false;38 }39 27 40 28 struct ReplaceTypedefCore final : … … 101 89 // by typedef. GCC appears to do the same thing. 102 90 if ( isAtFunctionTop ) { 103 erase_if( ret->attributes, isNonParameterAttribute ); 91 erase_if( ret->attributes, []( ast::Attribute const * attr ){ 92 return !attr->isValidOnFuncParam(); 93 } ); 104 94 } 105 95 for ( const auto & attribute : type->attributes ) { -
tests/Makefile.am
r59c8dff rf988834 92 92 concurrency/channels/parallel_harness.hfa \ 93 93 array-collections/dimexpr-match.hfa \ 94 array-collections/dimexpr-match-detail.sh 94 array-collections/dimexpr-match-detail.sh \ 95 array-collections/array-raii.hfa 95 96 96 97 dist-hook: -
tests/collections/.expect/string-api-coverage.txt
r59c8dff rf988834 14 14 true false 15 15 true false 16 1234567 16 17 123 17 18 hello 19 hell 18 20 hello 19 21 world 20 22 hello 21 23 world 24 Q 25 1234567 26 hello 27 Q 28 123 29 hell 30 1234567 31 hello 32 123 33 hell 22 34 5 23 35 helloworld … … 29 41 hello, friend 30 42 bye, friend 43 ohello 44 ohell 45 ohell 46 omydarling 47 omy 48 omy 49 hellohellohellohello 31 50 hellohellohello 32 51 QQQ 33 52 asdfasdfasdf 53 lo 54 hello heliocentric 34 55 e 35 56 help!!!o -
tests/collections/.expect/string-compare.txt
r59c8dff rf988834 1 1 ------- string ------- 2 ( cmp(s_, s_) == 0) ok2 (strcmp(s_, s_) == 0) ok 3 3 (s_ == s_) ok 4 4 !(s_ != s_) ok … … 7 7 (s_ <= s_) ok 8 8 !(s_ < s_) ok 9 ( cmp("", s_) == 0) ok9 (strcmp("", s_) == 0) ok 10 10 ("" == s_) ok 11 11 !("" != s_) ok … … 14 14 ("" <= s_) ok 15 15 !("" < s_) ok 16 ( cmp(s_, "") == 0) ok16 (strcmp(s_, "") == 0) ok 17 17 (s_ == "") ok 18 18 !(s_ != "") ok … … 21 21 (s_ <= "") ok 22 22 !(s_ < "") ok 23 ( cmp(s_, s_a) < 0) ok23 (strcmp(s_, s_a) < 0) ok 24 24 !(s_ == s_a) ok 25 25 (s_ != s_a) ok … … 28 28 (s_ <= s_a) ok 29 29 (s_ < s_a) ok 30 ( cmp("", s_a) < 0) ok30 (strcmp("", s_a) < 0) ok 31 31 !("" == s_a) ok 32 32 ("" != s_a) ok … … 35 35 ("" <= s_a) ok 36 36 ("" < s_a) ok 37 ( cmp(s_, "a") < 0) ok37 (strcmp(s_, "a") < 0) ok 38 38 !(s_ == "a") ok 39 39 (s_ != "a") ok … … 42 42 (s_ <= "a") ok 43 43 (s_ < "a") ok 44 ( cmp(s_a, s_) > 0) ok44 (strcmp(s_a, s_) > 0) ok 45 45 !(s_a == s_) ok 46 46 (s_a != s_) ok … … 49 49 !(s_a <= s_) ok 50 50 !(s_a < s_) ok 51 ( cmp("a", s_) > 0) ok51 (strcmp("a", s_) > 0) ok 52 52 !("a" == s_) ok 53 53 ("a" != s_) ok … … 56 56 !("a" <= s_) ok 57 57 !("a" < s_) ok 58 ( cmp(s_a, "") > 0) ok58 (strcmp(s_a, "") > 0) ok 59 59 !(s_a == "") ok 60 60 (s_a != "") ok … … 63 63 !(s_a <= "") ok 64 64 !(s_a < "") ok 65 ( cmp(s_, s_aa) < 0) ok65 (strcmp(s_, s_aa) < 0) ok 66 66 !(s_ == s_aa) ok 67 67 (s_ != s_aa) ok … … 70 70 (s_ <= s_aa) ok 71 71 (s_ < s_aa) ok 72 ( cmp("", s_aa) < 0) ok72 (strcmp("", s_aa) < 0) ok 73 73 !("" == s_aa) ok 74 74 ("" != s_aa) ok … … 77 77 ("" <= s_aa) ok 78 78 ("" < s_aa) ok 79 ( cmp(s_, "aa") < 0) ok79 (strcmp(s_, "aa") < 0) ok 80 80 !(s_ == "aa") ok 81 81 (s_ != "aa") ok … … 84 84 (s_ <= "aa") ok 85 85 (s_ < "aa") ok 86 ( cmp(s_aa, s_) > 0) ok86 (strcmp(s_aa, s_) > 0) ok 87 87 !(s_aa == s_) ok 88 88 (s_aa != s_) ok … … 91 91 !(s_aa <= s_) ok 92 92 !(s_aa < s_) ok 93 ( cmp("aa", s_) > 0) ok93 (strcmp("aa", s_) > 0) ok 94 94 !("aa" == s_) ok 95 95 ("aa" != s_) ok … … 98 98 !("aa" <= s_) ok 99 99 !("aa" < s_) ok 100 ( cmp(s_aa, "") > 0) ok100 (strcmp(s_aa, "") > 0) ok 101 101 !(s_aa == "") ok 102 102 (s_aa != "") ok … … 105 105 !(s_aa <= "") ok 106 106 !(s_aa < "") ok 107 ( cmp(s_a, s_aa) < 0) ok107 (strcmp(s_a, s_aa) < 0) ok 108 108 !(s_a == s_aa) ok 109 109 (s_a != s_aa) ok … … 112 112 (s_a <= s_aa) ok 113 113 (s_a < s_aa) ok 114 ( cmp("a", s_aa) < 0) ok114 (strcmp("a", s_aa) < 0) ok 115 115 !("a" == s_aa) ok 116 116 ("a" != s_aa) ok … … 119 119 ("a" <= s_aa) ok 120 120 ("a" < s_aa) ok 121 ( cmp(s_a, "aa") < 0) ok121 (strcmp(s_a, "aa") < 0) ok 122 122 !(s_a == "aa") ok 123 123 (s_a != "aa") ok … … 126 126 (s_a <= "aa") ok 127 127 (s_a < "aa") ok 128 ( cmp(s_aa, s_a) > 0) ok128 (strcmp(s_aa, s_a) > 0) ok 129 129 !(s_aa == s_a) ok 130 130 (s_aa != s_a) ok … … 133 133 !(s_aa <= s_a) ok 134 134 !(s_aa < s_a) ok 135 ( cmp("aa", s_a) > 0) ok135 (strcmp("aa", s_a) > 0) ok 136 136 !("aa" == s_a) ok 137 137 ("aa" != s_a) ok … … 140 140 !("aa" <= s_a) ok 141 141 !("aa" < s_a) ok 142 ( cmp(s_aa, "a") > 0) ok142 (strcmp(s_aa, "a") > 0) ok 143 143 !(s_aa == "a") ok 144 144 (s_aa != "a") ok … … 147 147 !(s_aa <= "a") ok 148 148 !(s_aa < "a") ok 149 ( cmp(s_a, s_a) == 0) ok149 (strcmp(s_a, s_a) == 0) ok 150 150 (s_a == s_a) ok 151 151 !(s_a != s_a) ok … … 154 154 (s_a <= s_a) ok 155 155 !(s_a < s_a) ok 156 ( cmp("a", s_a) == 0) ok156 (strcmp("a", s_a) == 0) ok 157 157 ("a" == s_a) ok 158 158 !("a" != s_a) ok … … 161 161 ("a" <= s_a) ok 162 162 !("a" < s_a) ok 163 ( cmp(s_a, "a") == 0) ok163 (strcmp(s_a, "a") == 0) ok 164 164 (s_a == "a") ok 165 165 !(s_a != "a") ok … … 168 168 (s_a <= "a") ok 169 169 !(s_a < "a") ok 170 ( cmp(s_aa, s_aa) == 0) ok170 (strcmp(s_aa, s_aa) == 0) ok 171 171 (s_aa == s_aa) ok 172 172 !(s_aa != s_aa) ok … … 175 175 (s_aa <= s_aa) ok 176 176 !(s_aa < s_aa) ok 177 ( cmp("aa", s_aa) == 0) ok177 (strcmp("aa", s_aa) == 0) ok 178 178 ("aa" == s_aa) ok 179 179 !("aa" != s_aa) ok … … 182 182 ("aa" <= s_aa) ok 183 183 !("aa" < s_aa) ok 184 ( cmp(s_aa, "aa") == 0) ok184 (strcmp(s_aa, "aa") == 0) ok 185 185 (s_aa == "aa") ok 186 186 !(s_aa != "aa") ok … … 189 189 (s_aa <= "aa") ok 190 190 !(s_aa < "aa") ok 191 ( cmp(s_a, s_b) < 0) ok191 (strcmp(s_a, s_b) < 0) ok 192 192 !(s_a == s_b) ok 193 193 (s_a != s_b) ok … … 196 196 (s_a <= s_b) ok 197 197 (s_a < s_b) ok 198 ( cmp("a", s_b) < 0) ok198 (strcmp("a", s_b) < 0) ok 199 199 !("a" == s_b) ok 200 200 ("a" != s_b) ok … … 203 203 ("a" <= s_b) ok 204 204 ("a" < s_b) ok 205 ( cmp(s_a, "b") < 0) ok205 (strcmp(s_a, "b") < 0) ok 206 206 !(s_a == "b") ok 207 207 (s_a != "b") ok … … 210 210 (s_a <= "b") ok 211 211 (s_a < "b") ok 212 ( cmp(s_b, s_a) > 0) ok212 (strcmp(s_b, s_a) > 0) ok 213 213 !(s_b == s_a) ok 214 214 (s_b != s_a) ok … … 217 217 !(s_b <= s_a) ok 218 218 !(s_b < s_a) ok 219 ( cmp("b", s_a) > 0) ok219 (strcmp("b", s_a) > 0) ok 220 220 !("b" == s_a) ok 221 221 ("b" != s_a) ok … … 224 224 !("b" <= s_a) ok 225 225 !("b" < s_a) ok 226 ( cmp(s_b, "a") > 0) ok226 (strcmp(s_b, "a") > 0) ok 227 227 !(s_b == "a") ok 228 228 (s_b != "a") ok … … 231 231 !(s_b <= "a") ok 232 232 !(s_b < "a") ok 233 ( cmp(s_a, s_ba) < 0) ok233 (strcmp(s_a, s_ba) < 0) ok 234 234 !(s_a == s_ba) ok 235 235 (s_a != s_ba) ok … … 238 238 (s_a <= s_ba) ok 239 239 (s_a < s_ba) ok 240 ( cmp("a", s_ba) < 0) ok240 (strcmp("a", s_ba) < 0) ok 241 241 !("a" == s_ba) ok 242 242 ("a" != s_ba) ok … … 245 245 ("a" <= s_ba) ok 246 246 ("a" < s_ba) ok 247 ( cmp(s_a, "ba") < 0) ok247 (strcmp(s_a, "ba") < 0) ok 248 248 !(s_a == "ba") ok 249 249 (s_a != "ba") ok … … 252 252 (s_a <= "ba") ok 253 253 (s_a < "ba") ok 254 ( cmp(s_ba, s_a) > 0) ok254 (strcmp(s_ba, s_a) > 0) ok 255 255 !(s_ba == s_a) ok 256 256 (s_ba != s_a) ok … … 259 259 !(s_ba <= s_a) ok 260 260 !(s_ba < s_a) ok 261 ( cmp("ba", s_a) > 0) ok261 (strcmp("ba", s_a) > 0) ok 262 262 !("ba" == s_a) ok 263 263 ("ba" != s_a) ok … … 266 266 !("ba" <= s_a) ok 267 267 !("ba" < s_a) ok 268 ( cmp(s_ba, "a") > 0) ok268 (strcmp(s_ba, "a") > 0) ok 269 269 !(s_ba == "a") ok 270 270 (s_ba != "a") ok … … 273 273 !(s_ba <= "a") ok 274 274 !(s_ba < "a") ok 275 ( cmp(s_aa, s_ab) < 0) ok275 (strcmp(s_aa, s_ab) < 0) ok 276 276 !(s_aa == s_ab) ok 277 277 (s_aa != s_ab) ok … … 280 280 (s_aa <= s_ab) ok 281 281 (s_aa < s_ab) ok 282 ( cmp("aa", s_ab) < 0) ok282 (strcmp("aa", s_ab) < 0) ok 283 283 !("aa" == s_ab) ok 284 284 ("aa" != s_ab) ok … … 287 287 ("aa" <= s_ab) ok 288 288 ("aa" < s_ab) ok 289 ( cmp(s_aa, "ab") < 0) ok289 (strcmp(s_aa, "ab") < 0) ok 290 290 !(s_aa == "ab") ok 291 291 (s_aa != "ab") ok … … 294 294 (s_aa <= "ab") ok 295 295 (s_aa < "ab") ok 296 ( cmp(s_ab, s_aa) > 0) ok296 (strcmp(s_ab, s_aa) > 0) ok 297 297 !(s_ab == s_aa) ok 298 298 (s_ab != s_aa) ok … … 301 301 !(s_ab <= s_aa) ok 302 302 !(s_ab < s_aa) ok 303 ( cmp("ab", s_aa) > 0) ok303 (strcmp("ab", s_aa) > 0) ok 304 304 !("ab" == s_aa) ok 305 305 ("ab" != s_aa) ok … … 308 308 !("ab" <= s_aa) ok 309 309 !("ab" < s_aa) ok 310 ( cmp(s_ab, "aa") > 0) ok310 (strcmp(s_ab, "aa") > 0) ok 311 311 !(s_ab == "aa") ok 312 312 (s_ab != "aa") ok … … 315 315 !(s_ab <= "aa") ok 316 316 !(s_ab < "aa") ok 317 ( cmp(s_ba, s_bb) < 0) ok317 (strcmp(s_ba, s_bb) < 0) ok 318 318 !(s_ba == s_bb) ok 319 319 (s_ba != s_bb) ok … … 322 322 (s_ba <= s_bb) ok 323 323 (s_ba < s_bb) ok 324 ( cmp("ba", s_bb) < 0) ok324 (strcmp("ba", s_bb) < 0) ok 325 325 !("ba" == s_bb) ok 326 326 ("ba" != s_bb) ok … … 329 329 ("ba" <= s_bb) ok 330 330 ("ba" < s_bb) ok 331 ( cmp(s_ba, "bb") < 0) ok331 (strcmp(s_ba, "bb") < 0) ok 332 332 !(s_ba == "bb") ok 333 333 (s_ba != "bb") ok … … 336 336 (s_ba <= "bb") ok 337 337 (s_ba < "bb") ok 338 ( cmp(s_bb, s_ba) > 0) ok338 (strcmp(s_bb, s_ba) > 0) ok 339 339 !(s_bb == s_ba) ok 340 340 (s_bb != s_ba) ok … … 343 343 !(s_bb <= s_ba) ok 344 344 !(s_bb < s_ba) ok 345 ( cmp("bb", s_ba) > 0) ok345 (strcmp("bb", s_ba) > 0) ok 346 346 !("bb" == s_ba) ok 347 347 ("bb" != s_ba) ok … … 350 350 !("bb" <= s_ba) ok 351 351 !("bb" < s_ba) ok 352 ( cmp(s_bb, "ba") > 0) ok352 (strcmp(s_bb, "ba") > 0) ok 353 353 !(s_bb == "ba") ok 354 354 (s_bb != "ba") ok … … 357 357 !(s_bb <= "ba") ok 358 358 !(s_bb < "ba") ok 359 ( cmp(s_aa, s_b) < 0) ok359 (strcmp(s_aa, s_b) < 0) ok 360 360 !(s_aa == s_b) ok 361 361 (s_aa != s_b) ok … … 364 364 (s_aa <= s_b) ok 365 365 (s_aa < s_b) ok 366 ( cmp("aa", s_b) < 0) ok366 (strcmp("aa", s_b) < 0) ok 367 367 !("aa" == s_b) ok 368 368 ("aa" != s_b) ok … … 371 371 ("aa" <= s_b) ok 372 372 ("aa" < s_b) ok 373 ( cmp(s_aa, "b") < 0) ok373 (strcmp(s_aa, "b") < 0) ok 374 374 !(s_aa == "b") ok 375 375 (s_aa != "b") ok … … 378 378 (s_aa <= "b") ok 379 379 (s_aa < "b") ok 380 ( cmp(s_b, s_aa) > 0) ok380 (strcmp(s_b, s_aa) > 0) ok 381 381 !(s_b == s_aa) ok 382 382 (s_b != s_aa) ok … … 385 385 !(s_b <= s_aa) ok 386 386 !(s_b < s_aa) ok 387 ( cmp("b", s_aa) > 0) ok387 (strcmp("b", s_aa) > 0) ok 388 388 !("b" == s_aa) ok 389 389 ("b" != s_aa) ok … … 392 392 !("b" <= s_aa) ok 393 393 !("b" < s_aa) ok 394 ( cmp(s_b, "aa") > 0) ok394 (strcmp(s_b, "aa") > 0) ok 395 395 !(s_b == "aa") ok 396 396 (s_b != "aa") ok … … 400 400 !(s_b < "aa") ok 401 401 ------- string_res ------- 402 ( cmp(s_, s_) == 0) ok402 (strcmp(s_, s_) == 0) ok 403 403 (s_ == s_) ok 404 404 !(s_ != s_) ok … … 407 407 (s_ <= s_) ok 408 408 !(s_ < s_) ok 409 ( cmp("", s_) == 0) ok409 (strcmp("", s_) == 0) ok 410 410 ("" == s_) ok 411 411 !("" != s_) ok … … 414 414 ("" <= s_) ok 415 415 !("" < s_) ok 416 ( cmp(s_, "") == 0) ok416 (strcmp(s_, "") == 0) ok 417 417 (s_ == "") ok 418 418 !(s_ != "") ok … … 421 421 (s_ <= "") ok 422 422 !(s_ < "") ok 423 ( cmp(s_, s_a) < 0) ok423 (strcmp(s_, s_a) < 0) ok 424 424 !(s_ == s_a) ok 425 425 (s_ != s_a) ok … … 428 428 (s_ <= s_a) ok 429 429 (s_ < s_a) ok 430 ( cmp("", s_a) < 0) ok430 (strcmp("", s_a) < 0) ok 431 431 !("" == s_a) ok 432 432 ("" != s_a) ok … … 435 435 ("" <= s_a) ok 436 436 ("" < s_a) ok 437 ( cmp(s_, "a") < 0) ok437 (strcmp(s_, "a") < 0) ok 438 438 !(s_ == "a") ok 439 439 (s_ != "a") ok … … 442 442 (s_ <= "a") ok 443 443 (s_ < "a") ok 444 ( cmp(s_a, s_) > 0) ok444 (strcmp(s_a, s_) > 0) ok 445 445 !(s_a == s_) ok 446 446 (s_a != s_) ok … … 449 449 !(s_a <= s_) ok 450 450 !(s_a < s_) ok 451 ( cmp("a", s_) > 0) ok451 (strcmp("a", s_) > 0) ok 452 452 !("a" == s_) ok 453 453 ("a" != s_) ok … … 456 456 !("a" <= s_) ok 457 457 !("a" < s_) ok 458 ( cmp(s_a, "") > 0) ok458 (strcmp(s_a, "") > 0) ok 459 459 !(s_a == "") ok 460 460 (s_a != "") ok … … 463 463 !(s_a <= "") ok 464 464 !(s_a < "") ok 465 ( cmp(s_, s_aa) < 0) ok465 (strcmp(s_, s_aa) < 0) ok 466 466 !(s_ == s_aa) ok 467 467 (s_ != s_aa) ok … … 470 470 (s_ <= s_aa) ok 471 471 (s_ < s_aa) ok 472 ( cmp("", s_aa) < 0) ok472 (strcmp("", s_aa) < 0) ok 473 473 !("" == s_aa) ok 474 474 ("" != s_aa) ok … … 477 477 ("" <= s_aa) ok 478 478 ("" < s_aa) ok 479 ( cmp(s_, "aa") < 0) ok479 (strcmp(s_, "aa") < 0) ok 480 480 !(s_ == "aa") ok 481 481 (s_ != "aa") ok … … 484 484 (s_ <= "aa") ok 485 485 (s_ < "aa") ok 486 ( cmp(s_aa, s_) > 0) ok486 (strcmp(s_aa, s_) > 0) ok 487 487 !(s_aa == s_) ok 488 488 (s_aa != s_) ok … … 491 491 !(s_aa <= s_) ok 492 492 !(s_aa < s_) ok 493 ( cmp("aa", s_) > 0) ok493 (strcmp("aa", s_) > 0) ok 494 494 !("aa" == s_) ok 495 495 ("aa" != s_) ok … … 498 498 !("aa" <= s_) ok 499 499 !("aa" < s_) ok 500 ( cmp(s_aa, "") > 0) ok500 (strcmp(s_aa, "") > 0) ok 501 501 !(s_aa == "") ok 502 502 (s_aa != "") ok … … 505 505 !(s_aa <= "") ok 506 506 !(s_aa < "") ok 507 ( cmp(s_a, s_aa) < 0) ok507 (strcmp(s_a, s_aa) < 0) ok 508 508 !(s_a == s_aa) ok 509 509 (s_a != s_aa) ok … … 512 512 (s_a <= s_aa) ok 513 513 (s_a < s_aa) ok 514 ( cmp("a", s_aa) < 0) ok514 (strcmp("a", s_aa) < 0) ok 515 515 !("a" == s_aa) ok 516 516 ("a" != s_aa) ok … … 519 519 ("a" <= s_aa) ok 520 520 ("a" < s_aa) ok 521 ( cmp(s_a, "aa") < 0) ok521 (strcmp(s_a, "aa") < 0) ok 522 522 !(s_a == "aa") ok 523 523 (s_a != "aa") ok … … 526 526 (s_a <= "aa") ok 527 527 (s_a < "aa") ok 528 ( cmp(s_aa, s_a) > 0) ok528 (strcmp(s_aa, s_a) > 0) ok 529 529 !(s_aa == s_a) ok 530 530 (s_aa != s_a) ok … … 533 533 !(s_aa <= s_a) ok 534 534 !(s_aa < s_a) ok 535 ( cmp("aa", s_a) > 0) ok535 (strcmp("aa", s_a) > 0) ok 536 536 !("aa" == s_a) ok 537 537 ("aa" != s_a) ok … … 540 540 !("aa" <= s_a) ok 541 541 !("aa" < s_a) ok 542 ( cmp(s_aa, "a") > 0) ok542 (strcmp(s_aa, "a") > 0) ok 543 543 !(s_aa == "a") ok 544 544 (s_aa != "a") ok … … 547 547 !(s_aa <= "a") ok 548 548 !(s_aa < "a") ok 549 ( cmp(s_a, s_a) == 0) ok549 (strcmp(s_a, s_a) == 0) ok 550 550 (s_a == s_a) ok 551 551 !(s_a != s_a) ok … … 554 554 (s_a <= s_a) ok 555 555 !(s_a < s_a) ok 556 ( cmp("a", s_a) == 0) ok556 (strcmp("a", s_a) == 0) ok 557 557 ("a" == s_a) ok 558 558 !("a" != s_a) ok … … 561 561 ("a" <= s_a) ok 562 562 !("a" < s_a) ok 563 ( cmp(s_a, "a") == 0) ok563 (strcmp(s_a, "a") == 0) ok 564 564 (s_a == "a") ok 565 565 !(s_a != "a") ok … … 568 568 (s_a <= "a") ok 569 569 !(s_a < "a") ok 570 ( cmp(s_aa, s_aa) == 0) ok570 (strcmp(s_aa, s_aa) == 0) ok 571 571 (s_aa == s_aa) ok 572 572 !(s_aa != s_aa) ok … … 575 575 (s_aa <= s_aa) ok 576 576 !(s_aa < s_aa) ok 577 ( cmp("aa", s_aa) == 0) ok577 (strcmp("aa", s_aa) == 0) ok 578 578 ("aa" == s_aa) ok 579 579 !("aa" != s_aa) ok … … 582 582 ("aa" <= s_aa) ok 583 583 !("aa" < s_aa) ok 584 ( cmp(s_aa, "aa") == 0) ok584 (strcmp(s_aa, "aa") == 0) ok 585 585 (s_aa == "aa") ok 586 586 !(s_aa != "aa") ok … … 589 589 (s_aa <= "aa") ok 590 590 !(s_aa < "aa") ok 591 ( cmp(s_a, s_b) < 0) ok591 (strcmp(s_a, s_b) < 0) ok 592 592 !(s_a == s_b) ok 593 593 (s_a != s_b) ok … … 596 596 (s_a <= s_b) ok 597 597 (s_a < s_b) ok 598 ( cmp("a", s_b) < 0) ok598 (strcmp("a", s_b) < 0) ok 599 599 !("a" == s_b) ok 600 600 ("a" != s_b) ok … … 603 603 ("a" <= s_b) ok 604 604 ("a" < s_b) ok 605 ( cmp(s_a, "b") < 0) ok605 (strcmp(s_a, "b") < 0) ok 606 606 !(s_a == "b") ok 607 607 (s_a != "b") ok … … 610 610 (s_a <= "b") ok 611 611 (s_a < "b") ok 612 ( cmp(s_b, s_a) > 0) ok612 (strcmp(s_b, s_a) > 0) ok 613 613 !(s_b == s_a) ok 614 614 (s_b != s_a) ok … … 617 617 !(s_b <= s_a) ok 618 618 !(s_b < s_a) ok 619 ( cmp("b", s_a) > 0) ok619 (strcmp("b", s_a) > 0) ok 620 620 !("b" == s_a) ok 621 621 ("b" != s_a) ok … … 624 624 !("b" <= s_a) ok 625 625 !("b" < s_a) ok 626 ( cmp(s_b, "a") > 0) ok626 (strcmp(s_b, "a") > 0) ok 627 627 !(s_b == "a") ok 628 628 (s_b != "a") ok … … 631 631 !(s_b <= "a") ok 632 632 !(s_b < "a") ok 633 ( cmp(s_a, s_ba) < 0) ok633 (strcmp(s_a, s_ba) < 0) ok 634 634 !(s_a == s_ba) ok 635 635 (s_a != s_ba) ok … … 638 638 (s_a <= s_ba) ok 639 639 (s_a < s_ba) ok 640 ( cmp("a", s_ba) < 0) ok640 (strcmp("a", s_ba) < 0) ok 641 641 !("a" == s_ba) ok 642 642 ("a" != s_ba) ok … … 645 645 ("a" <= s_ba) ok 646 646 ("a" < s_ba) ok 647 ( cmp(s_a, "ba") < 0) ok647 (strcmp(s_a, "ba") < 0) ok 648 648 !(s_a == "ba") ok 649 649 (s_a != "ba") ok … … 652 652 (s_a <= "ba") ok 653 653 (s_a < "ba") ok 654 ( cmp(s_ba, s_a) > 0) ok654 (strcmp(s_ba, s_a) > 0) ok 655 655 !(s_ba == s_a) ok 656 656 (s_ba != s_a) ok … … 659 659 !(s_ba <= s_a) ok 660 660 !(s_ba < s_a) ok 661 ( cmp("ba", s_a) > 0) ok661 (strcmp("ba", s_a) > 0) ok 662 662 !("ba" == s_a) ok 663 663 ("ba" != s_a) ok … … 666 666 !("ba" <= s_a) ok 667 667 !("ba" < s_a) ok 668 ( cmp(s_ba, "a") > 0) ok668 (strcmp(s_ba, "a") > 0) ok 669 669 !(s_ba == "a") ok 670 670 (s_ba != "a") ok … … 673 673 !(s_ba <= "a") ok 674 674 !(s_ba < "a") ok 675 ( cmp(s_aa, s_ab) < 0) ok675 (strcmp(s_aa, s_ab) < 0) ok 676 676 !(s_aa == s_ab) ok 677 677 (s_aa != s_ab) ok … … 680 680 (s_aa <= s_ab) ok 681 681 (s_aa < s_ab) ok 682 ( cmp("aa", s_ab) < 0) ok682 (strcmp("aa", s_ab) < 0) ok 683 683 !("aa" == s_ab) ok 684 684 ("aa" != s_ab) ok … … 687 687 ("aa" <= s_ab) ok 688 688 ("aa" < s_ab) ok 689 ( cmp(s_aa, "ab") < 0) ok689 (strcmp(s_aa, "ab") < 0) ok 690 690 !(s_aa == "ab") ok 691 691 (s_aa != "ab") ok … … 694 694 (s_aa <= "ab") ok 695 695 (s_aa < "ab") ok 696 ( cmp(s_ab, s_aa) > 0) ok696 (strcmp(s_ab, s_aa) > 0) ok 697 697 !(s_ab == s_aa) ok 698 698 (s_ab != s_aa) ok … … 701 701 !(s_ab <= s_aa) ok 702 702 !(s_ab < s_aa) ok 703 ( cmp("ab", s_aa) > 0) ok703 (strcmp("ab", s_aa) > 0) ok 704 704 !("ab" == s_aa) ok 705 705 ("ab" != s_aa) ok … … 708 708 !("ab" <= s_aa) ok 709 709 !("ab" < s_aa) ok 710 ( cmp(s_ab, "aa") > 0) ok710 (strcmp(s_ab, "aa") > 0) ok 711 711 !(s_ab == "aa") ok 712 712 (s_ab != "aa") ok … … 715 715 !(s_ab <= "aa") ok 716 716 !(s_ab < "aa") ok 717 ( cmp(s_ba, s_bb) < 0) ok717 (strcmp(s_ba, s_bb) < 0) ok 718 718 !(s_ba == s_bb) ok 719 719 (s_ba != s_bb) ok … … 722 722 (s_ba <= s_bb) ok 723 723 (s_ba < s_bb) ok 724 ( cmp("ba", s_bb) < 0) ok724 (strcmp("ba", s_bb) < 0) ok 725 725 !("ba" == s_bb) ok 726 726 ("ba" != s_bb) ok … … 729 729 ("ba" <= s_bb) ok 730 730 ("ba" < s_bb) ok 731 ( cmp(s_ba, "bb") < 0) ok731 (strcmp(s_ba, "bb") < 0) ok 732 732 !(s_ba == "bb") ok 733 733 (s_ba != "bb") ok … … 736 736 (s_ba <= "bb") ok 737 737 (s_ba < "bb") ok 738 ( cmp(s_bb, s_ba) > 0) ok738 (strcmp(s_bb, s_ba) > 0) ok 739 739 !(s_bb == s_ba) ok 740 740 (s_bb != s_ba) ok … … 743 743 !(s_bb <= s_ba) ok 744 744 !(s_bb < s_ba) ok 745 ( cmp("bb", s_ba) > 0) ok745 (strcmp("bb", s_ba) > 0) ok 746 746 !("bb" == s_ba) ok 747 747 ("bb" != s_ba) ok … … 750 750 !("bb" <= s_ba) ok 751 751 !("bb" < s_ba) ok 752 ( cmp(s_bb, "ba") > 0) ok752 (strcmp(s_bb, "ba") > 0) ok 753 753 !(s_bb == "ba") ok 754 754 (s_bb != "ba") ok … … 757 757 !(s_bb <= "ba") ok 758 758 !(s_bb < "ba") ok 759 ( cmp(s_aa, s_b) < 0) ok759 (strcmp(s_aa, s_b) < 0) ok 760 760 !(s_aa == s_b) ok 761 761 (s_aa != s_b) ok … … 764 764 (s_aa <= s_b) ok 765 765 (s_aa < s_b) ok 766 ( cmp("aa", s_b) < 0) ok766 (strcmp("aa", s_b) < 0) ok 767 767 !("aa" == s_b) ok 768 768 ("aa" != s_b) ok … … 771 771 ("aa" <= s_b) ok 772 772 ("aa" < s_b) ok 773 ( cmp(s_aa, "b") < 0) ok773 (strcmp(s_aa, "b") < 0) ok 774 774 !(s_aa == "b") ok 775 775 (s_aa != "b") ok … … 778 778 (s_aa <= "b") ok 779 779 (s_aa < "b") ok 780 ( cmp(s_b, s_aa) > 0) ok780 (strcmp(s_b, s_aa) > 0) ok 781 781 !(s_b == s_aa) ok 782 782 (s_b != s_aa) ok … … 785 785 !(s_b <= s_aa) ok 786 786 !(s_b < s_aa) ok 787 ( cmp("b", s_aa) > 0) ok787 (strcmp("b", s_aa) > 0) ok 788 788 !("b" == s_aa) ok 789 789 ("b" != s_aa) ok … … 792 792 !("b" <= s_aa) ok 793 793 !("b" < s_aa) ok 794 ( cmp(s_b, "aa") > 0) ok794 (strcmp(s_b, "aa") > 0) ok 795 795 !(s_b == "aa") ok 796 796 (s_b != "aa") ok -
tests/collections/.expect/string-istream-manip.txt
r59c8dff rf988834 69 69 13 wwwwwwww 70 70 14 cccc 71 15 q71 15 72 72 1 yyyyyyyyyyyyyyyyyyyy 73 73 2 abcxxx … … 84 84 13 wwwwwwww 85 85 14 cccc 86 15 q86 15 -
tests/collections/string-api-coverage.cfa
r59c8dff rf988834 51 51 sout | (s == "hello") | (s == "world"); 52 52 sout | (s != "world") | (s != "hello"); 53 sout | ( frag == s(1, 4) ) | ( s3 == s(1,4) );54 sout | ( s3 != s(1, 4) ) | ( frag != s(1,4) );55 sout | ( s2(1, 4) == s(1,4) ) | ( s3(1,4) == s(1,4) );56 sout | ( s3(1, 4) != s(1,4) ) | ( s2(1,4) != s(1,4) );57 sout | ( s(1, 4) == frag ) | ( s(1,4) == s3 );58 sout | ( s(1, 4) != s3 ) | ( s(1,4) != frag );59 sout | ( s(1, 4) == "ell" ) | ( s(1,4) == "world" );60 sout | ( s(1, 4) != "world" ) | ( s(1,4) != "ell" );53 sout | ( frag == s(1,3) ) | ( s3 == s(1,3) ); 54 sout | ( s3 != s(1,3) ) | ( frag != s(1,3) ); 55 sout | ( s2(1,3) == s(1,3) ) | ( s3(1,3) == s(1,3) ); 56 sout | ( s3(1,3) != s(1,3) ) | ( s2(1,3) != s(1,3) ); 57 sout | ( s(1,3) == frag ) | ( s(1,3) == s3 ); 58 sout | ( s(1,3) != s3 ) | ( s(1,3) != frag ); 59 sout | ( s(1,3) == "ell" ) | ( s(1,3) == "world" ); 60 sout | ( s(1,3) != "world" ) | ( s(1,3) != "ell" ); 61 61 62 62 … … 66 66 // 67 67 { 68 string b1 = { "1234567", 3 }; 69 sout | b1; // 123 68 string b1 = "1234567"; 69 sout | b1; // 1234567 70 71 string b1x = { "1234567", 3 }; 72 sout | b1x; // 123 70 73 71 74 string b2 = s; 72 75 sout | b2; // hello 76 77 string b2x = { s, 4 }; 78 sout | b2x; // hell 73 79 74 80 // todo: a plain string & … … 88 94 b4 = s_constref; 89 95 sout | b4; // world 96 97 string b5 = 'Q'; 98 sout | b5; // Q 99 100 90 101 } 91 102 assertWellFormedHandleList( 10 ); 103 // 104 // Assignments 105 // 106 { 107 string b = "xxx"; 108 109 b = "1234567"; 110 sout | b; // 1234567 111 112 b = "xxx"; 113 b = s; 114 sout | b; // hello 115 116 b = "xxx"; 117 b = 'Q'; 118 sout | b; // Q 119 120 b = "xxx"; 121 assign( b, "1234567", 3 ); 122 sout | b; // 123 123 124 b = "xxx"; 125 assign( b, s, 4 ); 126 sout | b; // hell 127 128 b = "xxx"; 129 strcpy(b, "1234567"); 130 sout | b; // 1234567 131 132 b = "xxx"; 133 strcpy(b, s); 134 sout | b; // hello 135 136 b = "xxx"; 137 strncpy( b, "1234567", 3 ); 138 sout | b; // 123 139 140 b = "xxx"; 141 strncpy( b, s, 4 ); 142 sout | b; // hell 143 } 144 assertWellFormedHandleList( 10 ); 145 146 92 147 93 148 sout | size(s); // 5 … … 126 181 sout | sx; // bye, friend 127 182 183 sx = "o"; 184 strcat( sx, s ); 185 sout | sx; // ohello 186 187 sx = "o"; 188 append( sx, s, 4 ); 189 sout | sx; // ohell 190 191 sx = "o"; 192 strncat( sx, s, 4 ); 193 sout | sx; // ohell 194 195 sx = "o"; 196 strcat( sx, "mydarling" ); 197 sout | sx; // omydarling 198 199 sx = "o"; 200 append( sx, "mydarling", 2 ); 201 sout | sx; // omy 202 203 sx = "o"; 204 strncat( sx, "mydarling", 2 ); 205 sout | sx; // omy 206 128 207 // 129 208 // repetition 130 209 // 210 211 sx = s; 212 sx *= 4; 213 sout | sx; // hellohellohellohello 214 131 215 sx = s * 3; 132 216 sout | sx; // hellohellohello … … 142 226 // 143 227 144 //... 228 // Range cases treated thoroughly in "string-overwrite" test. 229 // Composability with comparison and search are demoed above and below. 230 // Coverage here adds the single-argument ("rest of string") overload. 231 232 sx = s; 233 sout | sx(3); // lo 234 sx(3) = "iocentric"; 235 sout | s | sx; // hello heliocentric 145 236 146 237 // … … 244 335 | find( alphabet , "def") // 3 245 336 | find( alphabet( 0, 26), "def") // 3 246 | find( alphabet( 2, 2 6), "def") // 1247 | find( alphabet( 3, 2 6), "def") // 0248 | find( alphabet( 4, 2 6), "def") // 22, not found249 | find( alphabet( 4, 2 6), "ef") // 0337 | find( alphabet( 2, 24), "def") // 1 338 | find( alphabet( 3, 23), "def") // 0 339 | find( alphabet( 4, 22), "def") // 22, not found 340 | find( alphabet( 4, 22), "ef") // 0 250 341 | find( alphabet( 0, 6), "def") // 3 251 342 | find( alphabet( 0, 5), "def") // 5, not found … … 255 346 | includes( alphabet , "def") // true 256 347 | includes( alphabet( 0, 26), "def") // true 257 | includes( alphabet( 2, 2 6), "def") // true258 | includes( alphabet( 3, 2 6), "def") // true259 | includes( alphabet( 4, 2 6), "def") // false260 | includes( alphabet( 4, 2 6), "ef") // true348 | includes( alphabet( 2, 24), "def") // true 349 | includes( alphabet( 3, 23), "def") // true 350 | includes( alphabet( 4, 22), "def") // false 351 | includes( alphabet( 4, 22), "ef") // true 261 352 | includes( alphabet( 0, 6), "def") // true 262 353 | includes( alphabet( 0, 5), "def") // false … … 266 357 | startsWith( alphabet , "abc") // true 267 358 | startsWith( alphabet( 0, 26), "abc") // true 268 | startsWith( alphabet( 1, 2 6), "abc") // false269 | startsWith( alphabet( 1, 2 6), "bc") // true359 | startsWith( alphabet( 1, 25), "abc") // false 360 | startsWith( alphabet( 1, 25), "bc") // true 270 361 | startsWith( alphabet( 0, 26), "abc") // true 271 362 | startsWith( alphabet( 0, 4), "abc") // true … … 281 372 | endsWith( alphabet( 0, 25), "xy" ) // true 282 373 | endsWith( alphabet( 0, 26), "xyz") // true 283 | endsWith( alphabet(23, 26), "xyz") // true284 | endsWith( alphabet(24, 26), "xyz") // false285 | endsWith( alphabet(24, 26), "yz") // true374 | endsWith( alphabet(23, 3), "xyz") // true 375 | endsWith( alphabet(24, 2), "xyz") // false 376 | endsWith( alphabet(24, 2), "yz") // true 286 377 | endsWith( alphabet , "abc"); // false 287 378 -
tests/collections/string-compare.cfa
r59c8dff rf988834 3 3 4 4 #define test_eq_(l, r) \ 5 chk( ( cmp(l, r) == 0) ) \5 chk( (strcmp(l, r) == 0) ) \ 6 6 chk( (l == r) ) \ 7 7 chk( !(l != r) ) \ … … 17 17 18 18 #define test_lt_(l, r) \ 19 chk( ( cmp(l, r) < 0) ) \19 chk( (strcmp(l, r) < 0) ) \ 20 20 chk( !(l == r) ) \ 21 21 chk( (l != r) ) \ … … 26 26 27 27 #define test_gt_(l, r) \ 28 chk( ( cmp(l, r) > 0) ) \28 chk( (strcmp(l, r) > 0) ) \ 29 29 chk( !(l == r) ) \ 30 30 chk( (l != r) ) \ -
tests/collections/string-overwrite.cfa
r59c8dff rf988834 9 9 MS = modifier start 10 10 ME = modifier end 11 ML = modifier length 11 12 WS = witness start 12 13 WE = witness end 14 WL = witness length 13 15 14 16 The test does: … … 71 73 72 74 73 void showOneReplacement(string & s, int ms, int me, int ws, int we, const char* replaceWith) { 75 void showOneReplacement(string & s, int ms, int ml, int ws, int wl, const char* replaceWith) { 76 77 int me = ms + ml; 78 int we = ws + wl; 74 79 75 80 assert( ms >= 0 && ms <= me && me <= size(s) ); 76 81 assert( ws >= 0 && ws <= we && we <= size(s) ); 77 82 78 string mod = s(ms, m e)`shareEdits;79 string wit = s(ws, w e)`shareEdits;83 string mod = s(ms, ml)`shareEdits; 84 string wit = s(ws, wl)`shareEdits; 80 85 81 86 string modOld = mod; … … 118 123 void runReplaceCases() { 119 124 char * alphabetTemplate = "abcdefghijklmnopqrstuvwxyz"; 120 struct { int ms; int m e; int ws; int we; char *replaceWith; char *label; } cases[] = {121 { 12, 14, 10, 20, "xxxxx", "warmup" },122 { 10, 10, 10, 10, "=====", "1" },123 { 10, 10, 10, 10, "==" , "" },124 { 10, 10, 10, 10, "=" , "" },125 { 10, 10, 10, 10, "" , "" },126 { 10, 12, 12, 12, "=====", "2" },127 { 10, 12, 12, 12, "==" , "" },128 { 10, 12, 12, 12, "=" , "" },129 { 10, 12, 12, 12, "" , "" },130 { 12, 12, 10, 12, "=====", "3" },131 { 12, 12, 10, 12, "==" , "" },132 { 12, 12, 10, 12, "=" , "" },133 { 12, 12, 10, 12, "" , "" },134 { 10, 10, 12, 12, "=====", "4" },135 { 10, 10, 12, 12, "==" , "" },136 { 10, 10, 12, 12, "=" , "" },137 { 10, 10, 12, 12, "" , "" },138 { 12, 12, 10, 10, "=====", "5" },139 { 12, 12, 10, 10, "==" , "" },140 { 12, 12, 10, 10, "=" , "" },141 { 12, 12, 10, 10, "" , "" },142 { 10, 12, 10, 12, "=====", "6" },143 { 10, 12, 10, 12, "==" , "" },144 { 10, 12, 10, 12, "=" , "" },145 { 10, 12, 10, 12, "" , "" },146 { 10, 12, 10, 10, "=====", "7" },147 { 10, 12, 10, 10, "==" , "" },148 { 10, 12, 10, 10, "=" , "" },149 { 10, 12, 10, 10, "" , "" },150 { 10, 10, 10, 12, "=====", "8" },151 { 10, 10, 10, 12, "==" , "" },152 { 10, 10, 10, 12, "=" , "" },153 { 10, 10, 10, 12, "" , "" },154 { 10, 12, 14, 14, "=====", "9" },155 { 10, 12, 14, 14, "==" , "" },156 { 10, 12, 14, 14, "=" , "" },157 { 10, 12, 14, 14, "" , "" },158 { 10, 14, 12, 14, "=====", "10" },159 { 10, 14, 12, 14, "==" , "" },160 { 10, 14, 12, 14, "=" , "" }, // FORMERLY unrunnable bug: tries to print seemingly infinite string161 { 10, 14, 12, 14, "" , "" }, // ditto162 { 14, 14, 10, 12, "=====", "11" },163 { 14, 14, 10, 12, "==" , "" },164 { 14, 14, 10, 12, "=" , "" },165 { 14, 14, 10, 12, "" , "" },166 { 12, 14, 10, 14, "=====", "12" }, // correctness observation: watching klmn while mn |-> xxx gives klxxx because the mn is inside what I'm watching167 { 12, 14, 10, 14, "==" , "" },168 { 12, 14, 10, 14, "=" , "" },169 { 12, 14, 10, 14, "" , "" },170 { 10, 12, 12, 14, "=====", "13" },171 { 10, 12, 12, 14, "==" , "" },172 { 10, 12, 12, 14, "=" , "" },173 { 10, 12, 12, 14, "" , "" },174 { 10, 14, 12, 12, "=====", "14" },175 { 10, 14, 12, 12, "==" , "" },176 { 10, 14, 12, 12, "=" , "" },177 { 10, 14, 12, 12, "" , "" },178 { 12, 14, 10, 12, "=====", "15" },179 { 12, 14, 10, 12, "==" , "" },180 { 12, 14, 10, 12, "=" , "" },181 { 12, 14, 10, 12, "" , "" },182 { 12, 12, 10, 14, "=====", "16" },183 { 12, 12, 10, 14, "==" , "" },184 { 12, 12, 10, 14, "=" , "" },185 { 12, 12, 10, 14, "" , "" },186 { 10, 14, 10, 12, "=====", "17" },187 { 10, 14, 10, 12, "==" , "" },188 { 10, 14, 10, 12, "=" , "" },189 { 10, 14, 10, 12, "" , "" },190 { 10, 10, 12, 14, "=====", "18" },191 { 10, 10, 12, 14, "==" , "" },192 { 10, 10, 12, 14, "=" , "" },193 { 10, 10, 12, 14, "" , "" },194 { 10, 12, 10, 14, "=====", "19" },195 { 10, 12, 10, 14, "==" , "" },196 { 10, 12, 10, 14, "=" , "" },197 { 10, 12, 10, 14, "" , "" },198 { 12, 14, 10, 10, "=====", "20" },199 { 12, 14, 10, 10, "==" , "" },200 { 12, 14, 10, 10, "=" , "" },201 { 12, 14, 10, 10, "" , "" },202 { 10, 12, 14, 16, "=====", "21" },203 { 10, 12, 14, 16, "==" , "" },204 { 10, 12, 14, 16, "=" , "" },205 { 10, 12, 14, 16, "" , "" },206 { 10, 14, 12, 16, "=====", "22" },207 { 10, 14, 12, 16, "==" , "" },208 { 10, 14, 12, 16, "=" , "" },209 { 10, 14, 12, 16, "" , "" },210 { 10, 16, 12, 14, "=====", "23" },211 { 10, 16, 12, 14, "==" , "" },212 { 10, 16, 12, 14, "=" , "" },213 { 10, 16, 12, 14, "" , "" },214 { 14, 16, 10, 12, "=====", "24" },215 { 14, 16, 10, 12, "==" , "" },216 { 14, 16, 10, 12, "=" , "" },217 { 14, 16, 10, 12, "" , "" },218 { 12, 16, 10, 14, "=====", "25" },219 { 12, 16, 10, 14, "==" , "" },220 { 12, 16, 10, 14, "=" , "" },221 { 12, 16, 10, 14, "" , "" },222 { 12, 14, 10, 16, "=====", "26" },223 { 12, 14, 10, 16, "==" , "" },224 { 12, 14, 10, 16, "=" , "" },225 { 12, 14, 10, 16, "" , "" },125 struct { int ms; int ml; int ws; int wl; char *replaceWith; char *label; } cases[] = { 126 { 12, 2, 10, 10, "xxxxx", "warmup" }, 127 { 10, 0, 10, 0, "=====", "1" }, 128 { 10, 0, 10, 0, "==" , "" }, 129 { 10, 0, 10, 0, "=" , "" }, 130 { 10, 0, 10, 0, "" , "" }, 131 { 10, 2, 12, 0, "=====", "2" }, 132 { 10, 2, 12, 0, "==" , "" }, 133 { 10, 2, 12, 0, "=" , "" }, 134 { 10, 2, 12, 0, "" , "" }, 135 { 12, 0, 10, 2, "=====", "3" }, 136 { 12, 0, 10, 2, "==" , "" }, 137 { 12, 0, 10, 2, "=" , "" }, 138 { 12, 0, 10, 2, "" , "" }, 139 { 10, 0, 12, 0, "=====", "4" }, 140 { 10, 0, 12, 0, "==" , "" }, 141 { 10, 0, 12, 0, "=" , "" }, 142 { 10, 0, 12, 0, "" , "" }, 143 { 12, 0, 10, 0, "=====", "5" }, 144 { 12, 0, 10, 0, "==" , "" }, 145 { 12, 0, 10, 0, "=" , "" }, 146 { 12, 0, 10, 0, "" , "" }, 147 { 10, 2, 10, 2, "=====", "6" }, 148 { 10, 2, 10, 2, "==" , "" }, 149 { 10, 2, 10, 2, "=" , "" }, 150 { 10, 2, 10, 2, "" , "" }, 151 { 10, 2, 10, 0, "=====", "7" }, 152 { 10, 2, 10, 0, "==" , "" }, 153 { 10, 2, 10, 0, "=" , "" }, 154 { 10, 2, 10, 0, "" , "" }, 155 { 10, 0, 10, 2, "=====", "8" }, 156 { 10, 0, 10, 2, "==" , "" }, 157 { 10, 0, 10, 2, "=" , "" }, 158 { 10, 0, 10, 2, "" , "" }, 159 { 10, 2, 14, 0, "=====", "9" }, 160 { 10, 2, 14, 0, "==" , "" }, 161 { 10, 2, 14, 0, "=" , "" }, 162 { 10, 2, 14, 0, "" , "" }, 163 { 10, 4, 12, 2, "=====", "10" }, 164 { 10, 4, 12, 2, "==" , "" }, 165 { 10, 4, 12, 2, "=" , "" }, // FORMERLY unrunnable bug: tries to print seemingly infinite string 166 { 10, 4, 12, 2, "" , "" }, // ditto 167 { 14, 0, 10, 2, "=====", "11" }, 168 { 14, 0, 10, 2, "==" , "" }, 169 { 14, 0, 10, 2, "=" , "" }, 170 { 14, 0, 10, 2, "" , "" }, 171 { 12, 2, 10, 4, "=====", "12" }, // correctness observation: watching klmn while mn |-> xxx gives klxxx because the mn is inside what I'm watching 172 { 12, 2, 10, 4, "==" , "" }, 173 { 12, 2, 10, 4, "=" , "" }, 174 { 12, 2, 10, 4, "" , "" }, 175 { 10, 2, 12, 2, "=====", "13" }, 176 { 10, 2, 12, 2, "==" , "" }, 177 { 10, 2, 12, 2, "=" , "" }, 178 { 10, 2, 12, 2, "" , "" }, 179 { 10, 4, 12, 0, "=====", "14" }, 180 { 10, 4, 12, 0, "==" , "" }, 181 { 10, 4, 12, 0, "=" , "" }, 182 { 10, 4, 12, 0, "" , "" }, 183 { 12, 2, 10, 2, "=====", "15" }, 184 { 12, 2, 10, 2, "==" , "" }, 185 { 12, 2, 10, 2, "=" , "" }, 186 { 12, 2, 10, 2, "" , "" }, 187 { 12, 0, 10, 4, "=====", "16" }, 188 { 12, 0, 10, 4, "==" , "" }, 189 { 12, 0, 10, 4, "=" , "" }, 190 { 12, 0, 10, 4, "" , "" }, 191 { 10, 4, 10, 2, "=====", "17" }, 192 { 10, 4, 10, 2, "==" , "" }, 193 { 10, 4, 10, 2, "=" , "" }, 194 { 10, 4, 10, 2, "" , "" }, 195 { 10, 0, 12, 2, "=====", "18" }, 196 { 10, 0, 12, 2, "==" , "" }, 197 { 10, 0, 12, 2, "=" , "" }, 198 { 10, 0, 12, 2, "" , "" }, 199 { 10, 2, 10, 4, "=====", "19" }, 200 { 10, 2, 10, 4, "==" , "" }, 201 { 10, 2, 10, 4, "=" , "" }, 202 { 10, 2, 10, 4, "" , "" }, 203 { 12, 2, 10, 0, "=====", "20" }, 204 { 12, 2, 10, 0, "==" , "" }, 205 { 12, 2, 10, 0, "=" , "" }, 206 { 12, 2, 10, 0, "" , "" }, 207 { 10, 2, 14, 2, "=====", "21" }, 208 { 10, 2, 14, 2, "==" , "" }, 209 { 10, 2, 14, 2, "=" , "" }, 210 { 10, 2, 14, 2, "" , "" }, 211 { 10, 4, 12, 4, "=====", "22" }, 212 { 10, 4, 12, 4, "==" , "" }, 213 { 10, 4, 12, 4, "=" , "" }, 214 { 10, 4, 12, 4, "" , "" }, 215 { 10, 6, 12, 2, "=====", "23" }, 216 { 10, 6, 12, 2, "==" , "" }, 217 { 10, 6, 12, 2, "=" , "" }, 218 { 10, 6, 12, 2, "" , "" }, 219 { 14, 2, 10, 2, "=====", "24" }, 220 { 14, 2, 10, 2, "==" , "" }, 221 { 14, 2, 10, 2, "=" , "" }, 222 { 14, 2, 10, 2, "" , "" }, 223 { 12, 4, 10, 4, "=====", "25" }, 224 { 12, 4, 10, 4, "==" , "" }, 225 { 12, 4, 10, 4, "=" , "" }, 226 { 12, 4, 10, 4, "" , "" }, 227 { 12, 2, 10, 6, "=====", "26" }, 228 { 12, 2, 10, 6, "==" , "" }, 229 { 12, 2, 10, 6, "=" , "" }, 230 { 12, 2, 10, 6, "" , "" }, 226 231 }; 227 232 for ( i; sizeof(cases)/sizeof(cases[0]) ) { 228 233 sout | "------------------------------------------------------------------------" | cases[i].label; 229 234 string replaceIn = alphabetTemplate; 230 showOneReplacement( replaceIn, cases[i].ms, cases[i].m e, cases[i].ws, cases[i].we, cases[i].replaceWith );235 showOneReplacement( replaceIn, cases[i].ms, cases[i].ml, cases[i].ws, cases[i].wl, cases[i].replaceWith ); 231 236 } 232 237 } … … 244 249 string s = "abcdefghijklmnopqrstuvwxyz"; 245 250 246 s(5, 10) = "qqqqq"; // start=5, end=10, len=5247 248 sout | s; 249 250 251 s(5, 5) = "-----"; // start=5, end=5, len=0251 s(5,5) = "qqqqq"; // start=5, end=10, len=5 252 253 sout | s; 254 255 256 s(5,0) = "-----"; // start=5, end=5, len=0 252 257 253 258 sout | s; -
tests/concurrency/examples/quickSort.cfa
r59c8dff rf988834 11 11 // Created On : Wed Dec 6 12:15:52 2017 12 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Wed Feb 12 18:24:47 2020 14 // Update Count : 177 15 // 16 17 #include <fstream.hfa> 18 #include <stdlib.hfa> 19 #include <kernel.hfa> 13 // Last Modified On : Mon Jan 1 12:07:59 2024 14 // Update Count : 188 15 // 16 17 #include <fstream.hfa> // sin/sout 18 #include <stdlib.hfa> // convert 20 19 #include <thread.hfa> 20 #include <math.hfa> // sqrt 21 21 #include <string.h> // strcmp 22 22 … … 82 82 } // main 83 83 84 85 bool convert( int & val, const char * nptr ) { // convert C string to integer 86 char * eptr; 87 int temp = strto( nptr, &eptr, 10 ); // do not change val on false 88 // true => entire string valid with no extra characters 89 return *nptr != '\0' && *eptr == '\0' ? val = temp, true : false; 90 } // convert 91 92 void usage( char * argv[] ) { 93 sout | "Usage:" | argv[0] | "( -s unsorted-file [ sorted-file ] | -t size (>= 0) [ depth (>= 0) ] )"; 94 exit( EXIT_FAILURE ); // TERMINATE! 95 } // usage 96 84 // convert(...) throws out_of_range or invalid_argument 85 ExceptionDecl( cmd_error ); 97 86 98 87 int main( int argc, char * argv[] ) { 99 ifstream & unsortedfile = sin;100 ofstream & sortedfile = sout; // default value101 int depth = 0, size;102 103 i f ( argc != 1 ) { // do not use defaults104 if ( argc < 2 || argc > 4 ) usage( argv ); // wrong number of options 105 if ( strcmp( argv[1], "-t" ) == 0 ) { // timing ?106 &unsortedfile = (ifstream *)0; // no input88 ifstream unsortedfile = sin; // default values 89 ofstream sortedfile = sout; 90 // Must be signed because of the conversion routine. 91 intmax_t depth = 0; 92 intmax_t size = -1; // -1 means time mode not activated 93 94 try { 95 if ( 1 < argc && strcmp( argv[1], "-t" ) == 0 ) { // time mode ? 107 96 choose ( argc ) { 108 97 case 4: 109 if ( ! convert( depth, argv[3] ) || depth < 0 ) usage( argv ); 98 depth = convert( argv[3] ); // invalid integer ? 99 if ( depth < 0 ) throw ExceptionInst( cmd_error ); 110 100 fallthrough; 111 101 case 3: 112 if ( ! convert( size, argv[2] ) || size < 0 ) usage( argv ); 102 size = convert( argv[2] ); // invalid integer ? 103 if ( size < 0 ) throw ExceptionInst( cmd_error ); 104 default: // wrong number of options 105 throw ExceptionInst( cmd_error ); 113 106 } // choose 114 107 } else { // sort file 115 108 choose ( argc ) { 116 case 3: 117 &sortedfile = new( (const char *)argv[2] ); // open the output file 118 if ( fail( sortedfile ) ) { 119 serr | "Error! Could not open sorted output file \"" | argv[2] | "\""; 120 usage( argv ); 109 case 4: 110 depth = convert( argv[3] ); // invalid integer ? 111 if ( depth < 0 ) throw ExceptionInst( cmd_error ); 112 fallthrough; 113 case 3: case 2: 114 if ( strcmp( argv[1], "d" ) != 0 ) { 115 try { // open input file first as output creates file 116 open( unsortedfile, argv[1] ); 117 } catch( open_failure * ) { // open failed ? 118 serr | "Error! Could not open unsorted input file \"" | argv[1] | "\""; 119 throw ExceptionInst( cmd_error ); 120 } // try 121 } // if 122 if ( argc > 2 && strcmp( argv[2], "d" ) != 0 ) { 123 try { 124 open( sortedfile, argv[2] ); 125 } catch( open_failure * ) { // open failed ? 126 serr | "Error! Could not open sorted output file \"" | argv[2] | "\""; 127 throw ExceptionInst( cmd_error ); 128 } // try 121 129 } // if 122 130 fallthrough; 123 case 2: 124 &unsortedfile = new( (const char *)argv[1] ); // open the input file 125 if ( fail( unsortedfile ) ) { 126 serr | "Error! Could not open unsorted input file \"" | argv[1] | "\""; 127 usage( argv ); 128 } // if 131 case 1: ; // defaults 132 default: // wrong number of options 133 throw ExceptionInst( cmd_error ); 129 134 } // choose 130 135 } // if 131 } // if 136 } catch( exception_t * ) { // catch any 137 exit | "Usage: " | argv[0] | // TERMINATE 138 " ( [ unsorted-file | 'd' [ sorted-file | 'd' [ depth (>= 0) ] ] ]" 139 " | -t size (>= 0) [ depth (>= 0) ] )"; 140 } // try 141 142 enum { ValuesPerLine = 22 }; // number of values printed per line 143 132 144 sortedfile | nlOff; // turn off auto newline 133 145 134 enum { ValuesPerLine = 22 }; // number of values printed per line 135 136 if ( &unsortedfile ) { // generate output ? 146 if ( size == -1 ) { // generate output ? 137 147 for () { 138 148 unsortedfile | size; // read number of elements in the list 139 149 if ( eof( unsortedfile ) ) break; 140 int * values = alloc( size ); // values to be sorted, too large to put on stack 150 151 int * values = aalloc( size ); // values to be sorted, too large to put on stack 141 152 for ( counter; size ) { // read unsorted numbers 142 153 unsortedfile | values[counter]; … … 146 157 } // for 147 158 sortedfile | nl; 159 148 160 if ( size > 0 ) { // values to sort ? 149 161 Quicksort QS = { values, size - 1, 0 }; // sort values … … 158 170 delete( values ); 159 171 } // for 160 if ( &unsortedfile != &sin ) delete( &unsortedfile ); // close input/output files 161 if ( &sortedfile != &sout ) delete( &sortedfile ); 162 } else { 172 } else { // timing 173 PRNG prng; 163 174 processor processors[ (1 << depth) - 1 ] __attribute__(( unused )); // create 2^depth-1 kernel threads 164 165 int * values = alloc( size ); // values to be sorted, too large to put on stack 175 int * values = aalloc( size ); // values to be sorted, too large to put on stack 176 166 177 for ( counter; size ) { // generate unsorted numbers 167 178 values[counter] = size - counter; // descending values 168 179 } // for 169 for ( i; 200 ) { // random shuffle a few values 170 swap( values[rand() % size], values[rand() % size] ); 180 181 unsigned int times = sqrt( size ); 182 for ( unsigned int counter = 0; counter < times; counter += 1 ) { 183 swap( values[0], values[prng(size)] ); // randomize unsorted numbers 171 184 } // for 172 185 { -
tests/exceptions/hotpotato.cfa
r59c8dff rf988834 5 5 6 6 struct Potato { 7 8 unsigned int deadline;// when timer goes off9 unsigned int timer;// up counter to deadline7 PRNG & prng; 8 unsigned int deadline; // when timer goes off 9 unsigned int timer; // up counter to deadline 10 10 }; // Potato 11 11 … … 16 16 &potato.prng = &prng; 17 17 reset( potato, maxTicks ); 18 } // Potato18 } // Potato 19 19 20 20 coroutine Player { 21 22 int id;// player identity23 Potato & potato;// potato being tossed24 Player * partner[2];// left and right player21 PRNG & prng; 22 int id; // player identity 23 Potato & potato; // potato being tossed 24 Player * partner[2]; // left and right player 25 25 }; // Player 26 26 … … 29 29 player.id = id; 30 30 &player.potato = &potato; 31 } // Player31 } // Player 32 32 33 33 Player & umpire; … … 39 39 40 40 void reset( Potato & potato, unsigned int maxTicks ) with(potato) { 41 41 if ( maxTicks < 2 ) abort( "Hot Potato initialized with less than 2 ticks" ); // optional 42 42 deadline = prng( prng, 1, maxTicks ); 43 43 timer = 0; … … 60 60 enum { LEFT = 0, RIGHT = 1 }; 61 61 62 static void vote( Player & player, Election & election ) { 63 62 static void vote( Player & player, Election & election ) { // cause partner to vote 63 resumeAt( player, election ); 64 64 resume( player ); 65 65 } // vote … … 76 76 77 77 void main( Player & player ) with(player) { 78 suspend;// return immediately after establishing starter78 suspend; // return immediately after establishing starter 79 79 try { 80 81 poll();// check for non-local exceptions before proceeding82 83 84 85 86 87 88 countdown( potato );// player is eliminated if countdown() returned true89 90 91 92 resume( *partner[ side ] );// random toss left/right93 80 for ( ;; ) { 81 poll(); // check for non-local exceptions before proceeding 82 83 if ( partner[LEFT] == &player ) { // stop when only one player 84 sout | id | " wins the Match!"; 85 return; 86 } // exit 87 88 countdown( potato ); // player is eliminated if countdown() returned true 89 90 size_t side = prng( prng, 2 ); 91 sout | id | " -> " | nonl; 92 resume( *partner[ side ] ); // random toss left/right 93 } // for 94 94 } catchResume( Terminate * v ) { 95 95 v->victim->partner[LEFT]->partner[RIGHT] = v->victim->partner[RIGHT]; // unlink node 96 96 v->victim->partner[RIGHT]->partner[LEFT] = v->victim->partner[LEFT]; 97 97 delete( v->victim ); 98 98 reset( potato ); 99 99 sout | "U " | nonl; // start new game … … 102 102 sout | "election"; 103 103 sout | " -> " | id | nonl; 104 if ( id > getId( umpire ) ) &umpire = &player; 104 if ( id > getId( umpire ) ) &umpire = &player; // set umpire to highest id so far 105 105 vote( *partner[RIGHT], *election ); 106 106 } catchResume ( Explode * ) { 107 108 109 id = -1;// remove from election110 vote( *partner[RIGHT], ExceptionInst( Election ) );// start election111 112 113 114 115 resume( umpire );// resume umpire to terminate this player116 assert( false );// no return117 107 sout | id | " is eliminated"; 108 if ( &player == &umpire ) { 109 id = -1; // remove from election 110 vote( *partner[RIGHT], ExceptionInst( Election ) ); // start election 111 try { poll(); } catchResume( Election * election ) {} // handle end of election 112 sout | " : umpire " | getId( umpire ); 113 } // if 114 resumeAt( umpire, ExceptionInst( Terminate, &player ) ); 115 resume( umpire ); // resume umpire to terminate this player 116 assert( false ); // no return 117 } // try 118 118 } // main 119 119 … … 151 151 case 1: ; // defaults 152 152 default: // too many arguments 153 throw ExceptionInst( cmd_error );153 throw ExceptionInst( cmd_error ); 154 154 } // choose 155 155 } catch( exception_t * ) { // catch any 156 156 exit | "Usage: " | argv[0] 157 158 159 157 | " [ games (>=0) | 'd' (default " | DefaultGames 158 | ") [ players (>=2) | 'd' (random " | MinNoPlayers | "-" | MaxNoPlayers 159 | ") [ seed (>0) | 'd' (random) ] ] ]"; 160 160 } // try 161 161 sout | numGames | numPlayers | seed; -
tests/exceptions/hotpotato_checked.cfa
r59c8dff rf988834 5 5 6 6 struct Potato { 7 8 unsigned int deadline;// when timer goes off9 unsigned int timer;// up counter to deadline7 PRNG & prng; 8 unsigned int deadline; // when timer goes off 9 unsigned int timer; // up counter to deadline 10 10 }; // Potato 11 11 … … 16 16 &potato.prng = &prng; 17 17 reset( potato, maxTicks ); 18 } // Potato18 } // Potato 19 19 20 20 coroutine Player { 21 22 int id;// player identity23 Potato & potato;// potato being tossed24 Player * partner[2];// left and right player21 PRNG & prng; 22 int id; // player identity 23 Potato & potato; // potato being tossed 24 Player * partner[2]; // left and right player 25 25 }; // Player 26 26 … … 29 29 player.id = id; 30 30 &player.potato = &potato; 31 } // Player31 } // Player 32 32 33 33 Player & umpire; … … 39 39 40 40 void reset( Potato & potato, unsigned int maxTicks ) with(potato) { 41 41 if ( maxTicks < 2 ) abort( "Hot Potato initialized with less than 2 ticks" ); // optional 42 42 deadline = prng( prng, 1, maxTicks ); 43 43 timer = 0; … … 66 66 static void terminate( Player & player ) { // resume umpire 67 67 resume( player ); 68 69 68 checked_poll(); 69 sout | "THIS SHOULD NOT BE REACHED"; 70 70 } // terminate 71 71 … … 74 74 partner[RIGHT] = &rp; 75 75 resume( player ); // establish main as starter for termination 76 76 checked_poll(); 77 77 } // init 78 78 … … 82 82 83 83 void toss( Player & player ) { // tossed the potato 84 84 resume( player ); 85 85 checked_poll(); 86 86 } // toss … … 88 88 void main( Player & player ) with(player) { 89 89 try { 90 enable_ehm();// allow delivery of nonlocal exceptions91 suspend;// return immediately after establishing starter92 93 94 95 96 97 98 99 100 101 countdown( potato );// player is eliminated if countdown() returned true102 103 104 105 toss( *partner[ side ] );// random toss left/right106 107 90 enable_ehm(); // allow delivery of nonlocal exceptions 91 suspend; // return immediately after establishing starter 92 checked_poll(); 93 94 for ( ;; ) { 95 checked_poll(); 96 if ( partner[LEFT] == &player ) { // stop when only one player 97 sout | id | " wins the Match!"; 98 return; 99 } // exit 100 101 countdown( potato ); // player is eliminated if countdown() returned true 102 103 size_t side = prng( prng, 2 ); 104 sout | id | " -> " | nonl; 105 toss( *partner[ side ] ); // random toss left/right 106 } // for 107 disable_ehm(); 108 108 } catchResume( Terminate * v ) { 109 109 v->victim->partner[LEFT]->partner[RIGHT] = v->victim->partner[RIGHT]; // unlink node 110 110 v->victim->partner[RIGHT]->partner[LEFT] = v->victim->partner[LEFT]; 111 111 delete( v->victim ); 112 112 reset( potato ); 113 113 sout | "U " | nonl; // start new game … … 116 116 sout | "election"; 117 117 sout | " -> " | id | nonl; 118 if ( id > getId( umpire ) ) &umpire = &player; 119 120 disable_ehm();// disable ehm since we can't handle execption thrown in vote here and want to poll later118 if ( id > getId( umpire ) ) &umpire = &player; // set umpire to highest id so far 119 resumeAt( *partner[RIGHT], *election ); 120 disable_ehm(); // disable ehm since we can't handle execption thrown in vote here and want to poll later 121 121 vote( *partner[RIGHT] ); 122 enable_ehm();// enable after vote122 enable_ehm(); // enable after vote 123 123 } catchResume( Explode * ) { 124 125 126 127 id = -1;// remove from election128 129 vote( *partner[RIGHT] );// start election130 131 132 133 134 135 136 137 assert( false );// no return138 124 sout | id | " is eliminated"; 125 if ( &player == &umpire ) { 126 try { 127 id = -1; // remove from election 128 resumeAt( *partner[RIGHT], ExceptionInst( Election ) ); 129 vote( *partner[RIGHT] ); // start election 130 checked_poll(); 131 } catchResume( Election * election ) { 132 sout | " : umpire " | getId( umpire ); 133 } // try 134 } // if 135 resumeAt( umpire, ExceptionInst( Terminate, &player ) ); 136 terminate( umpire ); 137 assert( false ); // no return 138 } // try 139 139 } // main 140 140 … … 172 172 case 1: ; // defaults 173 173 default: // too many arguments 174 throw ExceptionInst( cmd_error );174 throw ExceptionInst( cmd_error ); 175 175 } // choose 176 176 } catch( exception_t * ) { // catch any 177 177 exit | "Usage: " | argv[0] 178 179 180 178 | " [ games (>=0) | 'd' (default " | DefaultGames 179 | ") [ players (>=2) | 'd' (random " | MinNoPlayers | "-" | MaxNoPlayers 180 | ") [ seed (>0) | 'd' (random) ] ] ]"; 181 181 } // try 182 182 sout | numGames | numPlayers | seed; -
tests/io/.expect/manipulatorsInput.arm64.txt
r59c8dff rf988834 20 20 14 rc=1, cccc 21 21 15 rc=0, q 22 16 get this line 23 17 @# this line 1)-{} 24 18 abc 25 19 abc 26 20 d d 27 28 d 29 21 ZC44% 22 30 1 yyyyyyyyyyyyyyyyyyyy 23 31 2 abcxxx … … 35 43 14 cccc 36 44 15 45 16 get this line 46 17 @# this line 1)-{} 47 18 abc 48 19 abc 49 20 d d 50 51 d 52 21 ZC44% 37 53 a 38 54 a -
tests/io/.expect/manipulatorsInput.x64.txt
r59c8dff rf988834 20 20 14 rc=1, cccc 21 21 15 rc=0, q 22 16 get this line 23 17 @# this line 1)-{} 24 18 abc 25 19 abc 26 20 d d 27 28 d 29 21 ZC44% 22 30 1 yyyyyyyyyyyyyyyyyyyy 23 31 2 abcxxx … … 35 43 14 cccc 36 44 15 45 16 get this line 46 17 @# this line 1)-{} 47 18 abc 48 19 abc 49 20 d d 50 51 d 52 21 ZC44% 37 53 a 38 54 a -
tests/io/.expect/manipulatorsInput.x86.txt
r59c8dff rf988834 20 20 14 rc=1, cccc 21 21 15 rc=0, q 22 16 get this line 23 17 @# this line 1)-{} 24 18 abc 25 19 abc 26 20 d d 27 28 d 29 21 ZC44% 22 30 1 yyyyyyyyyyyyyyyyyyyy 23 31 2 abcxxx … … 35 43 14 cccc 36 44 15 45 16 get this line 46 17 @# this line 1)-{} 47 18 abc 48 19 abc 49 20 d d 50 51 d 52 21 ZC44% 37 53 a 38 54 a -
tests/io/.in/manipulatorsInput.txt
r59c8dff rf988834 10 10 aaaaaaaaxxxxxxxxaabbccbbdddwwwbbbbbbbbwwwwwwwwaaaaaaaawwwwwwww 11 11 uuuuuccccuuuuu 12 get this line 13 @# this line 1)-{}% 14 "abc" 15 'abc ' 16 { d d 17 18 d } 19 X ZC44%Y 12 20 abc 13 21 cccccb … … 17 25 aaaaaaaaxxxxxxxxaabbccbbdddwwwbbbbbbbbwwwwwwwwaaaaaaaawwwwwwww 18 26 uuuuuccccuuuuu 27 get this line 28 @# this line 1)-{}% 29 "abc" 30 'abc ' 31 { d d 32 33 d } 34 X ZC44%Y 19 35 ab 20 36 0xff 017 15-15 -
tests/io/manipulatorsInput.cfa
r59c8dff rf988834 7 7 // Created On : Sat Jun 8 17:58:54 2019 8 8 // Last Modified By : Peter A. Buhr 9 // Last Modified On : Sat Sep 2 14:27:46 202310 // Update Count : 659 // Last Modified On : Wed Jan 3 11:15:04 2024 10 // Update Count : 103 11 11 // 12 12 … … 77 77 s[0] = 'q'; s[1] = '\0'; rc = 99; 78 78 rc = scanf( "%[^u]", s ); printf( "15 rc=%d, %s\n", rc, s ); 79 scanf( "%*[u]" ); 80 scanf("\n"); 79 scanf( "%*[u]\n" ); 80 scanf( "%[^\n]\n", s ); printf( "16 %s\n", s ); 81 scanf( "%[^%%]%%\n", s ); printf( "17 %s\n", s ); 82 83 scanf( "%*[ \f\n\r\t\v]" ); // ignore whitespace 84 scanf( "\"%[^\"]\"", s ); printf( "18 %s\n", s ); 85 scanf( "%*[ \f\n\r\t\v]" ); // ignore whitespace 86 scanf( "'%[^']'", s ); printf( "19 %s\n", s ); 87 scanf( "%*[ \f\n\r\t\v]" ); // ignore whitespace 88 scanf( "{%[^}]}", s ); printf( "20 %s\n", s ); 89 scanf( "%*[ \f\n\r\t\v]" ); // ignore whitespace 90 scanf( "X%[^Y]Y", s ); printf( "21 %s\n", s ); 91 scanf( "\n" ); // must start next line 81 92 } 82 93 { … … 102 113 s[0] = 'q'; s[1] = '\0'; 103 114 sin | excl( "u", wdi( sizeof(s), s ) ); sout | "15" | s; 104 sin | skip( "u" ); 105 sin | "\n"; 106 } 107 /* Keep harmonized with collections/string-istream-manip */ 115 sin | skip( "u" ) | "\n"; 116 sin | getline( wdi( sizeof(s), s ) ); sout | "16" | s; 117 sin | getline( wdi( sizeof(s), s ), '%' ) | "\n"; sout | "17" | s; 118 119 sin | quoted( wdi( sizeof(s), s ) ); sout | "18" | s; 120 sin | quoted( wdi( sizeof(s), s ), '\'' ); sout | "19" | s; 121 sin | quoted( wdi( sizeof(s), s ), '{', '}' ); sout | "20" | s; 122 sin | quoted( wdi( sizeof(s), s ), 'X', 'Y' ); sout | "21" | s; 123 } 124 // Keep harmonized with collections/string-istream-manip 108 125 { 109 126 char c;
Note:
See TracChangeset
for help on using the changeset viewer.