source: doc/theses/mike_brooks_MMath/string.tex@ b195498

Last change on this file since b195498 was d9aee90, checked in by Peter A. Buhr <pabuhr@…>, 5 months ago

small proofreading changes for string chapter

  • Property mode set to 100644
File size: 71.8 KB
Line 
1\chapter{String}
2
3\vspace*{-20pt}
4This chapter presents my work on designing and building a modern string type in \CFA.
5The discussion starts with an overview of the string API, then a number of interesting string problems, followed by how these issues are resolved in this work.
6
7
8\section{String Operations}
9
10% https://en.wikipedia.org/wiki/Comparison_of_programming_languages_(string_functions)
11
12\VRef[Figure]{f:StrApiCompare} shows a general comparison of string APIs for C, \CC, Java and \CFA.
13It provides a classic ``cheat sheet'', summarizing the names of the most-common closely-equivalent operations.
14The over-arching commonality is that operations work on groups of characters for assigning, copying, scanning, and updating.
15
16\begin{figure}[h]
17\begin{cquote}
18\begin{tabular}{@{}l|l|l|l@{}}
19C @char [ ]@ & \CC @string@ & Java @String@ & \CFA @string@ \\
20\hline
21@strcpy@, @strncpy@ & @=@ & @=@ & @=@ \\
22@strcat@, @strncat@ & @+@ & @+@ & @+@ \\
23@strcmp@, @strncmp@ & @==@, @!=@, @<@, @<=@, @>@, @>=@
24 & @equals@, @compareTo@ & @==@, @!=@, @<@, @<=@, @>@, @>=@ \\
25@strlen@ & @length@, @size@ & @length@ & @size@ \\
26@[ ]@ & @[ ]@ & @charAt@ & @[ ]@ \\
27@strncpy@ & @substr@ & @substring@ & @( )@ RHS @=@ \\
28@strncpy@ & @replace@ & @replace@ & @( )@ LHS @=@ \\
29@strstr@ & @find@ & @indexOf@ & @find@ \\
30@strcspn@ & @find_first_of@ & @matches@ & @include@ \\
31@strspn@ & @find_first_not_of@ & @matches@ & @exclude@ \\
32n/a & @c_str@, @data@ & n/a & @strcpy@, @strncpy@ \\
33\end{tabular}
34\end{cquote}
35\caption{Language comparison of string API}
36\label{f:StrApiCompare}
37\end{figure}
38
39As mentioned in \VRef{s:String}, a C string uses null termination rather than a length, which leads to explicit storage management;
40hence, most of its group operations are error prone and expensive due to copying.
41Most high-level string libraries use a separate length field and specialized storage management to implement group operations.
42Interestingly, \CC strings retain null termination in case it is needed to interface with C library functions.
43\begin{cfa}
44int open( @const char * pathname@, int flags );
45string fname{ "test.cc" );
46open( fname.@c_str()@, O_RDONLY ); // null terminated value of string
47\end{cfa}
48Here, the \CC @c_str@ function does not create a new null-terminated C string from the \CC string, as that requires passing ownership of the C string to the caller for eventual deletion.\footnote{
49C functions like \lstinline{strdup} do return allocated storage that must be freed by the caller.}
50% Instead, each \CC string is null terminated just in case it might be needed for this purpose.
51Providing this backwards compatibility with C has a ubiquitous performance and storage cost.
52
53
54\section{\CFA \lstinline{string} type}
55\label{s:stringType}
56
57The \CFA string type is for manipulation of dynamically-sized character-strings versus C @char *@ type for manipulation of statically-sized null-terminated character-strings.
58Hence, 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.
59As a result, a @string@ declaration does not specify a maximum length, where a C string must.
60The maximum storage for a \CFA @string@ value is @size_t@ characters, which is $2^{32}$ or $2^{64}$ respectively.
61A \CFA string manages its length separately from the string, so there is no null (@'\0'@) terminating value at the end of a string value.
62Hence, a \CFA string cannot be passed to a C string manipulation function, such as @strcat@.
63Like C strings, characters in a @string@ are numbered from the left starting at 0 (because subscripting is zero-origin), and in \CFA numbered from the right starting at -1.
64\begin{cquote}
65\rm
66\begin{tabular}{@{}rrrrll@{}}
67\small\tt "a & \small\tt b & \small\tt c & \small\tt d & \small\tt e" \\
680 & 1 & 2 & 3 & 4 & left to right index \\
69-5 & -4 & -3 & -2 & -1 & right to left index
70\end{tabular}
71\end{cquote}
72The following operations manipulate an instance of type @string@, where the discussion assumes the following declarations.
73\begin{cfa}
74#include @<string.hfa>@
75@string@ s = "abcde", name = "MIKE", digit = "0123456789";
76const char cs[$\,$] = "abc";
77int i;
78\end{cfa}
79Note, the include file @<string.hfa>@ to access type @string@.
80
81
82\subsection{Implicit String Conversions}
83
84The ability to convert from internal (machine) to external (human) format is useful in situations other than I/O.
85Hence, the basic types @char@, @char *@, @int@, @double@, @_Complex@, including any signness and size variations, implicitly convert to type @string@ (as in Java).
86\begin{cquote}
87\setlength{\tabcolsep}{15pt}
88\begin{tabular}{@{}l|ll|l@{}}
89\begin{cfa}
90string s;
91s = 'x';
92s = "abc";
93s = cs;
94s = 45hh;
95s = 45h;
96\end{cfa}
97&
98\begin{cfa}
99
100"x"
101"abc"
102"abc"
103"45"
104"45"
105\end{cfa}
106&
107\begin{cfa}
108 s = (ssize_t)MIN;
109 s = (size_t)MAX;
110 s = 5.5;
111 s = 5.5L;
112 s = 5.5+3.4i;
113 s = 5.5L+3.4Li;
114\end{cfa}
115&
116\begin{cfa}
117"-9223372036854775808"
118"18446744073709551615"
119"5.5"
120"5.5"
121"5.5+3.4i"
122"5.5+3.4i"
123\end{cfa}
124\end{tabular}
125\end{cquote}
126Conversions can be explicitly specified using a compound literal.
127\begin{cfa}
128s = (string){ "abc" }; $\C{// converts char * to string}$
129s = (string){ 5 }; $\C{// converts int to string}$
130s = (string){ 5.5 }; $\C{// converts double to string}$
131\end{cfa}
132
133Conversions from @string@ to @char *@ attempt to be safe:
134either by requiring the maximum length of the @char *@ storage (@strncpy@) or allocating the @char *@ storage for the string characters (ownership), meaning the programmer must free the storage.
135Note, a C string is always null terminated, implying a minimum size of 1 character.
136\begin{cquote}
137\setlength{\tabcolsep}{15pt}
138\begin{tabular}{@{}l|l@{}}
139\begin{cfa}
140strncpy( cs, s, sizeof(cs) );
141char * cp = s;
142delete( cp );
143cp = s + ' ' + s;
144delete( cp );
145\end{cfa}
146&
147\begin{cfa}
148"abc\0", in place
149"abcde\0", malloc
150ownership
151"abcde abcde\0", malloc
152ownership
153\end{cfa}
154\end{tabular}
155\end{cquote}
156
157
158\subsection{Length}
159
160The @len@ operation (short for @strlen@) returns the length of a C or \CFA string.
161For compatibility, @strlen@ also works with \CFA strings.
162\begin{cquote}
163\setlength{\tabcolsep}{15pt}
164\begin{tabular}{@{}l|l@{}}
165\begin{cfa}
166i = len( "" );
167i = len( "abc" );
168i = len( cs );
169i = strlen( cs );
170i = len( name );
171i = strlen( name );
172\end{cfa}
173&
174\begin{cfa}
1750
1763
1773
1783
1794
1804
181\end{cfa}
182\end{tabular}
183\end{cquote}
184
185
186\subsection{Comparison Operators}
187
188The binary relational, @<@, @<=@, @>@, @>=@, and equality, @==@, @!=@, operators compare \CFA string values using lexicographical ordering, where longer strings are greater than shorter strings.
189In C, these operators compare the C string pointer not its value, which does not match programmer expectation.
190C strings use function @strcmp@ to lexicographically compare the string value.
191Java has the same issue with @==@ and @.equals@.
192
193
194\subsection{Concatenation}
195
196The binary operators @+@ and @+=@ concatenate C @char@, @char *@ and \CFA strings, creating the sum of the characters.
197\par\noindent
198\begin{tabular}{@{}l|l@{\hspace{15pt}}l|l@{\hspace{15pt}}l|l@{}}
199\begin{cfa}
200s = "";
201s = 'a' + 'b';
202s = 'a' + "b";
203s = "a" + 'b';
204s = "a" + "b";
205\end{cfa}
206&
207\begin{cfa}
208
209"ab"
210"ab"
211"ab"
212"ab"
213\end{cfa}
214&
215\begin{cfa}
216s = "";
217s = 'a' + 'b' + s;
218s = 'a' + 'b' + s;
219s = 'a' + "b" + s;
220s = "a" + 'b' + s;
221\end{cfa}
222&
223\begin{cfa}
224
225"ab"
226"abab"
227"ababab"
228"abababab"
229\end{cfa}
230&
231\begin{cfa}
232s = "";
233s = s + 'a' + 'b';
234s = s + 'a' + "b";
235s = s + "a" + 'b';
236s = s + "a" + "b";
237\end{cfa}
238&
239\begin{cfa}
240
241"ab"
242"abab"
243"ababab"
244"abababab"
245\end{cfa}
246\end{tabular}
247\par\noindent
248However, including @<string.hfa>@ can result in ambiguous uses of the overloaded @+@ operator.\footnote{Combining multiple packages in any programming language can result in name clashes or ambiguities.}
249While subtracting characters or pointers has a low-level use-case
250\begin{cfa}
251ch - '0' $\C[2in]{// find character offset}$
252cs - cs2; $\C{// find pointer offset}\CRT$
253\end{cfa}
254addition is less obvious
255\begin{cfa}
256ch + 'b' $\C[2in]{// add character values}$
257cs + 'a'; $\C{// move pointer cs['a']}\CRT$
258\end{cfa}
259There are legitimate use cases for arithmetic with @signed@/@unsigned@ characters (bytes), and these types are treated differently from @char@ in \CC and \CFA.
260However, backwards compatibility makes it impossible to restrict or remove addition on type @char@.
261Similarly, it is impossible to restrict or remove addition on type @char *@ because (unfortunately) it is subscripting: @cs + 'a'@ implies @cs['a']@ or @'a'[cs]@.
262
263The prior \CFA concatenation examples show complex mixed-mode interactions among @char@, @char *@, and @string@ (variables are the same as constants) work correctly.
264The reason is that the \CFA type-system handles this kind of overloading well using the left-hand assignment-type and complex conversion costs.
265Hence, the type system correctly handles all uses of addition (explicit or implicit) for @char *@.
266\begin{cfa}
267printf( "%s %s %s %c %c\n", "abc", cs, cs + 3, cs['a'], 'a'[cs] );
268\end{cfa}
269Only @char@ addition can result in ambiguities, and only when there is no left-hand information.
270\begin{cfa}
271ch = ch + 'b'; $\C[2in]{// LHS disambiguate, add character values}$
272s = 'a' + 'b'; $\C{// LHS disambiguate, concatenate characters}$
273printf( "%c\n", @'a' + 'b'@ ); $\C[2in]{// no LHS information, ambiguous}$
274printf( "%c\n", @(return char)@('a' + 'b') ); $\C{// disambiguate with ascription cast}$
275\end{cfa}
276The ascription cast, @(return T)@, disambiguates by stating a (LHS) type to use during expression resolution (not a conversion).
277Fortunately, character addition without LHS information is rare in C/\CFA programs, so repurposing the operator @+@ for @string@ types is not a problem.
278Note, other programming languages that repurpose @+@ for concatenation, could have similar ambiguity issues.
279
280Interestingly, \CC cannot support this generality because it does not use the left-hand side of assignment in expression resolution.
281While it can special case some combinations:
282\begin{c++}
283s = 'a' + s; $\C[2in]{// compiles in C++}$
284s = "a" + s;
285\end{c++}
286it cannot generalize to any number of steps:
287\begin{c++}
288s = 'a' + 'b' + s; $\C{// does not compile in C++}\CRT$
289s = "a" + "b" + s;
290\end{c++}
291
292
293\subsection{Repetition}
294
295The binary operators @*@ and @*=@ repeat a string $N$ times.
296If $N = 0$, a zero length string, @""@, is returned.
297\begin{cquote}
298\setlength{\tabcolsep}{15pt}
299\begin{tabular}{@{}l|l@{}}
300\begin{cfa}
301s = 'x' * 0;
302s = 'x' * 3;
303s = "abc" * 3;
304s = (name + ' ') * 3;
305\end{cfa}
306&
307\begin{cfa}
308"
309"xxx"
310"abcabcabc"
311"MIKE MIKE MIKE "
312\end{cfa}
313\end{tabular}
314\end{cquote}
315Like concatenation, there is a potential ambiguity with multiplication of characters;
316multiplication for pointers does not exist in C.
317\begin{cfa}
318ch = ch * 3; $\C[2in]{// LHS disambiguate, multiply character values}$
319s = 'a' * 3; $\C{// LHS disambiguate, concatenate characters}$
320printf( "%c\n", @'a' * 3@ ); $\C[2in]{// no LHS information, ambiguous}$
321printf( "%c\n", @(return char)@('a' * 3) ); $\C{// disambiguate with ascription cast}$
322\end{cfa}
323Fortunately, character multiplication without LHS information is even rarer than addition, so repurposing the operator @*@ for @string@ types is not a problem.
324
325
326\subsection{Substring}
327The substring operation returns a subset of a string starting at a position in the string and traversing a length or matching a pattern string.
328\begin{cquote}
329\setlength{\tabcolsep}{10pt}
330\begin{tabular}{@{}l|ll|l@{}}
331\multicolumn{2}{c}{\textbf{length}} & \multicolumn{2}{c}{\textbf{pattern}} \\
332\begin{cfa}
333s = name( 2, 2 );
334s = name( 3, -2 );
335s = name( 2, 8 );
336s = name( 0, -1 );
337s = name( -1, -1 );
338s = name( -3 );
339\end{cfa}
340&
341\begin{cfa}
342"KE"
343"IK"
344"KE", clip length to 2
345"", beyond string clip to null
346"K"
347"IKE", to end of string
348\end{cfa}
349&
350\begin{cfa}
351s = name( "IK" );
352s = name( "WW" );
353
354
355
356
357\end{cfa}
358&
359\begin{cfa}
360"IK"
361""
362
363
364
365
366\end{cfa}
367\end{tabular}
368\end{cquote}
369A negative starting position is a specification from the right end of the string.
370A negative length means that characters are selected in the opposite (right to left) direction from the starting position.
371If the substring request extends beyond the beginning or end of the string, it is clipped (shortened) to the bounds of the string.
372If the substring request is completely outside of the original string, a null string is returned.
373The pattern-form either returns the pattern string is the pattern matches or a null string if the pattern does not match.
374The usefulness of this mechanism is discussed next.
375
376The substring operation can appear on the left side of assignment, where it defines a replacement substring.
377The length of the right string may be shorter, the same, or longer than the length of left string.
378Hence, the left string may decrease, stay the same, or increase in length.
379\begin{cquote}
380\setlength{\tabcolsep}{15pt}
381\begin{tabular}{@{}l|l@{}}
382\begin{cfa}[escapechar={}]
383digit( 3, 3 ) = "";
384digit( 4, 3 ) = "xyz";
385digit( 7, 0 ) = "***";
386digit(-4, 3 ) = "$$$";
387digit( 5 ) = "LLL";
388\end{cfa}
389&
390\begin{cfa}[escapechar={}]
391"0126789"
392"0126xyz"
393"0126xyz"
394"012$$$z"
395"012$$LLL"
396\end{cfa}
397\end{tabular}
398\end{cquote}
399Now pattern matching is useful on the left-hand side of assignment.
400\begin{cquote}
401\setlength{\tabcolsep}{15pt}
402\begin{tabular}{@{}l|l@{}}
403\begin{cfa}[escapechar={}]
404digit( "$$" ) = "345";
405digit( "LLL") = "6789";
406\end{cfa}
407&
408\begin{cfa}
409"012345LLL"
410"0123456789"
411\end{cfa}
412\end{tabular}
413\end{cquote}
414Extending the pattern to a regular expression is a possible extension.
415
416The replace operation extensions substring to substitute all occurrences.
417\begin{cquote}
418\setlength{\tabcolsep}{15pt}
419\begin{tabular}{@{}l|l@{}}
420\begin{cfa}
421s = replace( "PETER", "E", "XX" );
422s = replace( "PETER", "ET", "XX" );
423s = replace( "PETER", "W", "XX" );
424\end{cfa}
425&
426\begin{cfa}
427"PXXTXXR"
428"PXXER"
429"PETER"
430\end{cfa}
431\end{tabular}
432\end{cquote}
433The replacement is done left-to-right and substituted text is not examined for replacement.
434
435
436\subsection{Searching}
437
438The find operation returns the position of the first occurrence of a key in a string.
439If the key does not appear in the string, the length of the string is returned.
440\begin{cquote}
441\setlength{\tabcolsep}{15pt}
442\begin{tabular}{@{}l|l@{}}
443\begin{cfa}
444i = find( digit, '3' );
445i = find( digit, "45" );
446i = find( digit, "abc" );
447\end{cfa}
448&
449\begin{cfa}
4503
4514
45210
453\end{cfa}
454\end{tabular}
455\end{cquote}
456
457A character-class operation indicates if a string is composed completely of a particular class of characters, \eg, alphabetic, numeric, vowels, \etc.
458\begin{cquote}
459\setlength{\tabcolsep}{15pt}
460\begin{tabular}{@{}l|l@{}}
461\begin{cfa}
462charclass vowels{ "aeiouy" };
463i = include( "aaeiuyoo", vowels );
464i = include( "aabiuyoo", vowels );
465\end{cfa}
466&
467\begin{cfa}
468
4698 // compliant
4702 // b non-compliant
471\end{cfa}
472\end{tabular}
473\end{cquote}
474@vowels@ defines a character class and function @include@ checks if all characters in the string appear in the class (compliance).
475The position of the last character is returned if the string is compliant or the position of the first non-compliant character.
476There is no relationship between the order of characters in the two strings.
477Function @exclude@ is the reverse of @include@, checking if all characters in the string are excluded from the class (compliance).
478\begin{cquote}
479\setlength{\tabcolsep}{15pt}
480\begin{tabular}{@{}l|l@{}}
481\begin{cfa}
482i = exclude( "cdbfghmk", vowels );
483i = exclude( "cdyfghmk", vowels );
484\end{cfa}
485&
486\begin{cfa}
4878 // compliant
4882 // y non-compliant
489\end{cfa}
490\end{tabular}
491\end{cquote}
492Both forms can return the longest substring of compliant characters.
493\begin{cquote}
494\setlength{\tabcolsep}{15pt}
495\begin{tabular}{@{}l|l@{}}
496\begin{cfa}
497s = include( "aaeiuyoo", vowels );
498s = include( "aabiuyoo", vowels );
499s = exclude( "cdbfghmk", vowels );
500s = exclude( "cdyfghmk", vowels );
501\end{cfa}
502&
503\begin{cfa}
504"aaeiuyoo"
505"aa"
506"cdbfghmk"
507"cd"
508\end{cfa}
509\end{tabular}
510\end{cquote}
511
512There are also versions of @include@ and @exclude@, returning a position or string, taking a validation function, like one of the C character-class routines.\footnote{It is part of the hereditary of C that these function take and return an \lstinline{int} rather than a \lstinline{bool}, which affects the function type.}
513\begin{cquote}
514\setlength{\tabcolsep}{15pt}
515\begin{tabular}{@{}l|l@{}}
516\begin{cfa}
517i = include( "1FeC34aB", @isxdigit@ );
518i = include( ".,;'!\"", @ispunct@ );
519i = include( "XXXx", @isupper@ );
520\end{cfa}
521&
522\begin{cfa}
5238 // compliant
5246 // compliant
5253 // non-compliant
526\end{cfa}
527\end{tabular}
528\end{cquote}
529These operations perform an \emph{apply} of the validation function to each character, where the function returns a boolean indicating a stopping condition for the search.
530The position of the last character is returned if the string is compliant or the position of the first non-compliant character.
531
532The translate operation returns a string with each character transformed by one of the C character transformation functions.
533\begin{cquote}
534\setlength{\tabcolsep}{15pt}
535\begin{tabular}{@{}l|l@{}}
536\begin{cfa}
537s = translate( "abc", @toupper@ );
538s = translate( "ABC", @tolower@ );
539int tospace( int c ) { return isspace( c ) ? ' ' : c; }
540s = translate( "X X\tX\nX", @tospace@ );
541\end{cfa}
542&
543\begin{cfa}
544"ABC"
545"abc"
546
547"X X X X"
548\end{cfa}
549\end{tabular}
550\end{cquote}
551
552
553\subsection{Returning N on Search Failure}
554
555Some of the prior string operations are composite, \eg string operations returning the longest substring of compliant characters (@include@) are built using a search and then substring the appropriate text.
556However, string search can fail, which is reported as an alternate search outcome, possibly an exception.
557Many string libraries use a return code to indicate search failure, with a failure value of @0@ or @-1@ (PL/I~\cite{PLI} returns @0@).
558This semantics leads to the awkward pattern, which can appear many times in a string library or user code.
559\begin{cfa}
560i = exclude( s, alpha );
561if ( i != -1 ) return s( 0, i );
562else return "";
563\end{cfa}
564
565\CFA adopts a return code but the failure value is taken from the index-of function in APL~\cite{apl}, which returns the length of the target string $N$ (or $N+1$ for 1 origin).
566This semantics allows many search and substring functions to be written without conditions, \eg:
567\begin{cfa}
568string include( const string & s, int (*f)( int ) ) { return @s( 0, include( s, f ) )@; }
569string exclude( const string & s, int (*f)( int ) ) { return @s( 0, exclude( s, f ) )@; }
570\end{cfa}
571In string systems with an $O(1)$ length operator, checking for failure is low cost.
572\begin{cfa}
573if ( include( line, alpha ) == len( line ) ) ... // not found, 0 origin
574\end{cfa}
575\VRef[Figure]{f:ExtractingWordsText} compares \CC and \CFA string code for extracting words from a line of text, repeatedly removing non-word text and then a word until the line is empty.
576The \CFA code is simpler solely because of the choice for indicating search failure.
577(A simplification of the \CC version is to concatenate a sentinel character at the end of the line so the call to @find_first_not_of@ does not fail.)
578
579\begin{figure}
580\begin{cquote}
581\setlength{\tabcolsep}{15pt}
582\begin{tabular}{@{}l|l@{}}
583\multicolumn{1}{c}{\textbf{\CC}} & \multicolumn{1}{c}{\textbf{\CFA}} \\
584\begin{cfa}
585for ( ;; ) {
586 string::size_type posn = line.find_first_of( alpha );
587 if ( posn == string::npos ) break;
588 line = line.substr( posn );
589 posn = line.find_first_not_of( alpha );
590 if ( posn != string::npos ) {
591 cout << line.substr( 0, posn ) << endl;
592 line = line.substr( posn );
593 } else {
594 cout << line << endl;
595 line = "";
596 }
597}
598\end{cfa}
599&
600\begin{cfa}
601for ( ;; ) {
602 size_t posn = exclude( line, alpha );
603 if ( posn == len( line ) ) break;
604 line = line( posn );
605 posn = include( line, alpha );
606
607 sout | line( 0, posn );
608 line = line( posn );
609
610
611
612
613}
614\end{cfa}
615\end{tabular}
616\end{cquote}
617\caption{Extracting Words from Line of Text}
618\label{f:ExtractingWordsText}
619\end{figure}
620
621
622\subsection{C Compatibility}
623
624To ease conversion from C to \CFA, \CFA provides companion C @string@ functions.
625Hence, it is possible to convert a block of C string operations to \CFA strings just by changing the type @char *@ to @string@.
626\begin{cquote}
627\setlength{\tabcolsep}{15pt}
628\begin{tabular}{@{}ll@{}}
629\begin{cfa}
630char s[32]; // string s;
631strlen( s );
632strnlen( s, 3 );
633strcmp( s, "abc" );
634strncmp( s, "abc", 3 );
635\end{cfa}
636&
637\begin{cfa}
638
639strcpy( s, "abc" );
640strncpy( s, "abcdef", 3 );
641strcat( s, "xyz" );
642strncat( s, "uvwxyz", 3 );
643\end{cfa}
644\end{tabular}
645\end{cquote}
646However, the conversion fails with I/O because @printf@ cannot print a @string@ using format code @%s@ because \CFA strings are not null terminated.
647Nevertheless, this capability does provide a useful starting point for conversion to safer \CFA strings.
648
649
650\subsection{I/O Operators}
651
652The ability to input and output strings is as essential as for any other type.
653The goal for character I/O is to also work with groups rather than individual characters.
654A comparison with \CC string I/O is presented as a counterpoint to \CFA string I/O.
655
656The \CC output @<<@ and input @>>@ operators are defined on type @string@.
657\CC output for @char@, @char *@, and @string@ are similar.
658The \CC manipulators are @setw@, and its associated width controls @left@, @right@ and @setfill@.
659\begin{cquote}
660\setlength{\tabcolsep}{15pt}
661\begin{tabular}{@{}l|l@{}}
662\begin{c++}
663string s = "abc";
664cout << setw(10) << left << setfill( 'x' ) << s << endl;
665\end{c++}
666&
667\begin{c++}
668
669"abcxxxxxxx"
670\end{c++}
671\end{tabular}
672\end{cquote}
673
674The \CFA input/output operator @|@ is defined on type @string@.
675\CFA output for @char@, @char *@, and @string@ are similar.
676The \CFA manipulators are @bin@, @oct@, @hex@, @wd@, and its associated width control and @left@.
677\begin{cquote}
678\setlength{\tabcolsep}{15pt}
679\begin{tabular}{@{}l|l@{}}
680\begin{cfa}
681string s = "abc";
682sout | bin( s ) | nl
683 | oct( s ) | nl
684 | hex( s ) | nl
685 | wd( 10, s ) | nl
686 | wd( 10, 2, s ) | nl
687 | left( wd( 10, s ) );
688\end{cfa}
689&
690\begin{cfa}
691
692"0b1100001 0b1100010 0b1100011"
693"0141 0142 0143"
694"0x61 0x62 0x63"
695" abc"
696" ab"
697"abc "
698\end{cfa}
699\end{tabular}
700\end{cquote}
701
702\CC input matching for @char@, @char *@, and @string@ are similar, where \emph{all} input characters are read from the current point in the input stream to the end of the type size, format width, whitespace, end of line (@'\n'@), or end of file.
703The \CC manipulator is @setw@ to restrict the size.
704Reading into a @char@ is safe as the size is 1, @char *@ is unsafe without using @setw@ to constraint the length (which includes @'\0'@), @string@ is safe as its grows dynamically as characters are read.
705\begin{cquote}
706\setlength{\tabcolsep}{15pt}
707\begin{tabular}{@{}l|l@{}}
708\begin{c++}
709char ch, c[10];
710string s;
711cin >> ch >> setw( 5 ) >> c >> s;
712@abcde fg@
713\end{c++}
714&
715\begin{c++}
716
717
718'a' "bcde" "fg"
719
720\end{c++}
721\end{tabular}
722\end{cquote}
723Input text can be gulped, including whitespace, from the current point to an arbitrary delimiter character using @getline@.
724
725The \CFA philosophy for input is that, for every constant type in C, these constants should be usable as input.
726For example, the complex constant @3.5+4.1i@ can appear as input to a complex variable.
727\CFA input matching for @char@, @char *@, and @string@ are similar.
728C-strings may only be read with a width field, which should match the string size.
729Certain input manipulators support a scanset, which is a simple regular expression from @printf@.
730The \CFA manipulators for these types are @wdi@,\footnote{Due to an overloading issue in the type-resolver, the input width name must be temporarily different from the output, \lstinline{wdi} versus \lstinline{wd}.} and its associated width control and @left@, @quote@, @incl@, @excl@, and @getline@.
731\begin{cquote}
732\setlength{\tabcolsep}{10pt}
733\begin{tabular}{@{}l|l@{}}
734\begin{c++}
735char ch, c[10];
736string s;
737sin | ch | wdi( 5, c ) | s;
738@abcde fg@
739sin | quote( ch ) | quote( wdi( sizeof(c), c ) ) | quote( s, '[', ']' ) | nl;
740@'a' "bcde" [fg]@
741sin | incl( "a-zA-Z0-9 ?!&\n", s ) | nl;
742@x?&000xyz TOM !.@
743sin | excl( "a-zA-Z0-9 ?!&\n", s );
744@<>{}{}STOP@
745\end{c++}
746&
747\begin{c++}
748
749
750'a' "bcde" "fg"
751
752'a' "bcde" "fg"
753
754"x?&000xyz TOM !"
755
756"<>{}{}"
757
758\end{c++}
759\end{tabular}
760\end{cquote}
761Note, the ability to read in quoted strings to match with program string constants.
762The @nl@ at the end of an input ignores the rest of the line.
763
764
765\subsection{Assignment}
766
767While \VRef[Figure]{f:StrApiCompare} emphasizes cross-language similarities, it elides many specific operational differences.
768For example, the \CC @replace@ function selects a substring in the target and substitutes it with the source string, which can be smaller or larger than the substring.
769\CC modifies the mutable receiver object, replacing by position (zero origin) and length.
770\begin{cquote}
771\setlength{\tabcolsep}{15pt}
772\begin{tabular}{@{}l|l@{}}
773\begin{c++}
774string s1 = "abcde";
775s1.replace( 2, 3, "xy" );
776\end{c++}
777&
778\begin{c++}
779
780"abxy"
781\end{c++}
782\end{tabular}
783\end{cquote}
784Java cannot modify the receiver (immutable strings) so it returns a new string, replacing by text.
785\label{p:JavaReplace}
786\begin{cquote}
787\setlength{\tabcolsep}{15pt}
788\begin{tabular}{@{}l|l@{}}
789\begin{java}
790String s = "abcde";
791String r = s.replace( "cde", "xy" );
792\end{java}
793&
794\begin{java}
795
796"abxy"
797\end{java}
798\end{tabular}
799\end{cquote}
800Java also provides a mutable @StringBuffer@, replacing by position (zero origin) and length.
801\begin{cquote}
802\setlength{\tabcolsep}{15pt}
803\begin{tabular}{@{}l|l@{}}
804\begin{java}
805StringBuffer sb = new StringBuffer( "abcde" );
806sb.replace( 2, 5, "xy" );
807\end{java}
808&
809\begin{java}
810
811"abxy"
812\end{java}
813\end{tabular}
814\end{cquote}
815However, there are anomalies.
816@StringBuffer@'s @substring@ returns a @String@ copy that is immutable rather than modifying the receiver.
817As well, the operations are asymmetric, \eg @String@ has @replace@ by text but not replace by position and vice versa for @StringBuffer@.
818
819More significant operational differences relate to storage management, often appearing through assignment (@target = source@), and are summarized in \VRef[Figure]{f:StrSemanticCompare}, which defines properties type abstraction, state, symmetry, and referent.
820The following discussion justifies the figure's yes/no entries per language.
821
822\begin{figure}
823\setlength{\extrarowheight}{2pt}
824\begin{tabularx}{\textwidth}{@{}p{0.6in}XXcccc@{}}
825 & & & \multicolumn{4}{@{}c@{}}{\underline{Supports Helpful?}} \\
826 & Required & Helpful & C & \CC & Java & \CFA \\
827\hline
828Type abst'n
829 & Low-level: The string type is a varying amount of text communicated via a parameter or return.
830 & High-level: The string-typed relieves the user of managing memory for the text.
831 & no & yes & yes & yes \\
832\hline
833State
834 & \multirow{2}{2in}
835 {Fast Initialize: The target receives the characters of the source without copying the characters, resulting in an Alias or Snapshot.}
836 & Alias: The target name is within the source text; changes made in either variable are visible in both.
837 & yes & yes & no & yes \\
838\cline{3-7}
839 &
840 & Snapshot: The target is an alias within the source until the target changes (copy on write).
841 & no & no & yes & yes \\
842\hline
843Symmetry
844 & Laxed: The target's type is anything string-like; it may have a different status concerning ownership.
845 & Strict: The target's type is the same as the source; both strings are equivalent peers concerning ownership.
846 & N/A & no & yes & yes \\
847\hline
848Referent
849 & Variable-Constrained: The target can accept the entire text of the source.
850 & Fragment: The target can accept an arbitrary substring of the source.
851 & no & no & yes & yes
852\end{tabularx}
853
854\noindent
855Notes
856\begin{itemize}[parsep=0pt]
857\item
858 All languages support Required in all criteria.
859\item
860 A language gets ``Supports Helpful'' in one criterion if it can do so without sacrificing the Required achievement on all other criteria.
861\item
862 The C ``string'' is actually @char []@, under the conventions that @<string.h>@ requires. Hence, there is no actual string type in C, so symmetry does not apply.
863\item
864 The Java @String@ class is analyzed; its @StringBuffer@ class behaves similarly to @C++@.
865\end{itemize}
866\caption{Comparison of languages' strings, storage management perspective.}
867\label{f:StrSemanticCompare}
868\end{figure}
869
870In C, the declaration
871\begin{cfa}
872char s[$\,$] = "abcde";
873\end{cfa}
874creates a second-class fixed-sized string-variable, as it can only be used in its lexical context, \ie it cannot be passed by value to string operations or user functions.
875The reason is that there is no implicit mechanism to pass the string-length information to the function.
876Therefore, only pointers to strings are first-class, and discussed further.
877\begin{cfa}
878(const) char * s = "abcde"; $\C[2.25in]{// alias state, n/a symmetry, variable-constrained referent}$
879char * s1 = s; $\C{// alias state, n/a symmetry, variable-constrained referent}$
880char * s2 = s; $\C{// alias state, n/a symmetry, variable-constrained referent}$
881char * s3 = &s[1]; $\C{// alias state, n/a symmetry, variable-constrained referent}$
882char * s4 = &s3[1]; $\C{// alias state, n/a symmetry, variable-constrained referent}\CRT$
883printf( "%s %s %s %s %s\n", s, s1, s2, s3, s4 );
884$\texttt{\small abcde abcde abcde bcde cde}$
885\end{cfa}
886Note, all of these aliased strings rely on the single null termination character at the end of @s@.
887The issue of symmetry does not apply to C strings because the value and pointer strings are essentially different types, and so this feature is scored as not applicable for C.
888With the type not managing the text storage, there is no ownership question, \ie operations on @s1@ or @s2@ never leads to their memory becoming reusable.
889While @s3@ is a valid C-string that contains a proper substring of @s1@, the @s3@ technique does not constitute having a fragment referent because null termination implies the substring cannot be chosen arbitrarily; the technique works only for suffixes.
890
891In \CC, @string@ offers a high-level abstraction.
892\begin{cfa}
893string s = "abcde";
894string & s1 = s; $\C[2.25in]{// alias state, lax symmetry, variable-constrained referent}$
895string s2 = s; $\C{// copy (strict symmetry, variable-constrained referent)}$
896string s3 = s.substr( 1, 2 ); $\C{// copy (strict symmetry, fragment referent)}$
897string s4 = s3.substr( 1, 1 ); $\C{// copy (strict symmetry, fragment referent)}$
898cout << s << ' ' << s1 << ' ' << s2 << ' ' << s3 << ' ' << s4 << endl;
899$\texttt{\small abcde abcde abcde bc c}$
900string & s5 = s.substr(2,4); $\C{// error: cannot point to temporary}\CRT$
901\end{cfa}
902The lax symmetry reflects how the validity of @s1@ depends on the content and lifetime of @s@.
903It is common practice in \CC to use the @s1@-style pass by reference, with the understanding that the callee only uses the referenced string for the duration of the call, \ie no side-effect using the parameter.
904So, when the called function is a constructor, it is typical to use an @s2@-style copy-initialization.
905Exceptions to this pattern are possible, but require the programmer to assure safety where the type system does not.
906The @s3@ initialization is constrained to copy the substring because @c_str@ always provides a null-terminated character, which may be different from the source string.
907@s3@ assignment could be fast by reference counting the text area and using copy-on-write, but would require an implementation upgrade.
908
909In Java, @String@ also offers a high-level abstraction:
910\begin{java}
911String s = "abcde";
912String s1 = s; $\C[2.25in]{// snapshot state, strict symmetry, variable-constrained referent}$
913String s2 = s.substring( 1, 3 ); $\C{// snapshot state (possible), strict symmetry, fragment referent}$
914String s3 = s2.substring( 1, 2 ); $\C{// snapshot state (possible), strict symmetry, fragment referent}\CRT$
915System.out.println( s + ' ' + s1 + ' ' + s2 + ' ' + s3 );
916System.out.println( (s == s1) + " " + (s == s2) + " " + (s2 == s3) );
917$\texttt{\small abcde abcde bc c}$
918$\texttt{\small true false false}$
919\end{java}
920Note, @substring@ takes a start and end position, rather than a start position and length.
921Here, facts about Java's implicit pointers and pointer equality can over complicate the picture, and so are ignored.
922Furthermore, Java's string immutability means string variables behave as simple values.
923The result in @s1@ is the pointer in @s@, and their pointer equality confirm no time is spent copying characters.
924With @s2@, the case for fast-copy is more subtle.
925Certainly, its value is not pointer-equal to @s@, implying at least a further allocation.
926\PAB{TODO: finish the fast-copy case.}
927Java does not meet the aliasing requirement because immutability make it impossible to modify.
928Java's @StringBuffer@ provides aliasing (see @replace@ example on \VPageref{p:JavaReplace}), though without supporting symmetric treatment of a fragment referent, \eg @substring@ of a @StringBuffer@ is a @String@;
929as a result, @StringBuffer@ scores as \CC.
930The easy symmetry that the Java string enjoys is aided by Java's garbage collection; Java's @s2@ is doing effectively the operation of \CC's @s3@, though without the consequence of complicating memory management.
931\PAB{What complex storage management is going on here?}
932
933Finally, in \CFA, @string@ also offers a high-level abstraction:
934\begin{cfa}
935string s = "abcde";
936string & s1 = s; $\C[2.25in]{// alias state, strict symmetry, variable-constrained referent}$
937string s2 = s; $\C{// snapshot state, strict symmetry, variable-constrained referent}$
938string s3 = s`share; $\C{// alias state, strict symmetry, variable-constrained referent}\CRT$
939string s4 = s( 1, 2 );
940string s5 = s4( 1, 1 );
941sout | s | s1 | s2 | s3 | s4 | s5;
942$\texttt{\small abcde abcde abcde abcde bc c}$
943\end{cfa}
944% all helpful criteria of \VRef[Figure]{f:StrSemanticCompare} are satisfied.
945The \CFA string manages storage, handles all assignments, including those of fragment referents with fast initialization, provides the choice between snapshot and alias semantics, and does so symmetrically with one type (which assures text validity according to the lifecycles of the string variables).
946The intended metaphor for \CFA stings is similar to a GUI text-editor or web browser.
947Select a consecutive block of text using the mouse generates an aliased substring in the file/dialog-box.
948Typing into the selected area is like assigning to an aliased substring, where the highlighted text is replaced with more or less text;
949depending on the text entered, the file/dialog-box content grows or shrinks.
950\PAB{Need to discuss the example, as for the other languages.}
951
952The remainder of this chapter explains how the \CFA string achieves this usage style.
953
954
955\section{Storage Management}
956
957This section discusses issues related to storage management of strings.
958Specifically, it is common for strings to logically overlap partially or completely.
959\begin{cfa}
960string s1 = "abcdef";
961string s2 = s1; $\C{// complete overlap, s2 == "abcdef"}$
962string s3 = s1.substr( 0, 3 ); $\C{// partial overlap, s3 == "abc"}$
963\end{cfa}
964This raises the question of how strings behave when an overlapping component is changed,
965\begin{cfa}
966s3[1] = 'w'; $\C{// what happens to s1 and s2?}$
967\end{cfa}
968which is restricted by a string's mutable or immutable property.
969For example, Java's immutable strings require copy-on-write when any overlapping string changes.
970Note, the notion of underlying string mutability is not specified by @const@; \eg in \CC:
971\begin{cfa}
972const string s1 = "abc";
973\end{cfa}
974the @const@ applies to the @s1@ pointer to @"abc"@, and @"abc"@ is an immutable constant that is \emph{copied} into the string's storage.
975Hence, @s1@ is not pointing at an immutable constant, meaning its underlying string can be mutable, unless some other designation is specified, such as Java's global immutable rule.
976
977
978\subsection{Logical overlap}
979
980\CFA provides a dynamic mechanism to indicate mutable or immutable using the attribute @`share@.
981This aliasing relationship is a sticky-property established at initialization.
982For example, here strings @s1@ and @s1a@ are in an aliasing relationship, while @s2@ is in a copy relationship.
983\input{sharing1.tex}
984Here, the aliasing (@`share@) causes partial changes (subscripting) to flow in both directions.
985(In the following examples, watch how @s1@ and @s1a@ change together, and @s2@ is independent.)
986\input{sharing2.tex}
987Similarly for complete changes.
988\input{sharing3.tex}
989Because string assignment copies the value, RHS aliasing is irrelevant.
990Hence, aliasing of the LHS is unaffected.
991\input{sharing4.tex}
992
993Now, consider string @s1_mid@ being an alias in the middle of @s1@, along with @s2@, made by a simple copy from the middle of @s1@.
994\input{sharing5.tex}
995Again, @`share@ passes changes in both directions; copy does not.
996As a result, the index values for the position of @b@ are 1 in the longer string @"abcd"@ and 0 in the shorter aliased string @"bc"@.
997This alternate positioning also applies to subscripting.
998\input{sharing6.tex}
999
1000Finally, assignment flows through the aliasing relationship without affecting its structure.
1001\input{sharing7.tex}
1002In the @"ff"@ assignment, the result is straightforward to accept because the flow direction is from contained (small) to containing (large).
1003The following rules explain aliasing substrings that flow in the opposite direction, large to small.
1004
1005Growth and shrinkage are natural extensions, as for the text-editor example mentioned earlier, where an empty substring is as real as an empty string.
1006\input{sharing8.tex}
1007
1008Multiple portions of a string can be aliased.
1009% When there are several aliasing substrings at once, the text editor analogy becomes an online multi-user editor.
1010%I should be able to edit a paragraph in one place (changing the document's length), without my edits affecting which letters are within a mouse-selection that you had made previously, somewhere else.
1011\input{sharing9.tex}
1012When @s1_bgn@'s size increases by 3, @s1_mid@'s starting location moves from 1 to 4 and @s1_end@'s from 3 to 6,
1013
1014When changes happens on an aliasing substring that overlap.
1015\input{sharing10.tex}
1016Strings @s1_crs@ and @s1_mid@ overlap at character 4, @j@ because the substrings are 3,2 and 4,2.
1017When @s1_crs@'s size increases by 1, @s1_mid@'s starting location moves from 4 to 5, but the overlapping character remains, changing to @'+'@.
1018
1019\PAB{TODO: finish typesetting the demo}
1020
1021%\input{sharing-demo.tex}
1022
1023\VRef[Figure]{f:ParameterPassing} shows similar relationships when passing the results of substring operations by reference and by value to a subprogram.
1024Again, notice the side-effects to other reference parameters as one is modified.
1025
1026\begin{figure}
1027\begin{cfa}
1028// x, a, b, c, & d are substring results passed by reference
1029// e is a substring result passed by value
1030void test( string & x, string & a, string & b, string & c, string & d, string e ) {
1031\end{cfa}
1032\begin{cquote}
1033\setlength{\tabcolsep}{2pt}
1034\begin{tabular}{@{}ll@{}}
1035\begin{cfa}
1036
1037 a( 0, 2 ) = "aaa";
1038 b( 1, 12 ) = "bbb";
1039 c( 4, 5 ) = "ccc";
1040 c = "yyy";
1041 d( 0, 3 ) = "ddd";
1042 e( 0, 3 ) = "eee";
1043 x = e;
1044}
1045\end{cfa}
1046&
1047\sf
1048\setlength{\extrarowheight}{-0.5pt}
1049\begin{tabular}{@{}llllll@{}}
1050x & a & b & c & d & e \\
1051@"aaaxxxxxxxxx"@ & @"aaax"@ & @"xxx"@ & @"xxxxx"@ & @"xxx"@ & @"xxx"@ \\
1052@"aaaxbbbxxxxxx"@ & @"aaax"@ & @"xbbb"@ & @"xxxx"@ & @"xxx"@ & @"xxx"@ \\
1053@"aaaxbbbxxxcccxx"@ & @"aaax"@ & @"xbbb"@ & @"xxxccc"@& @"cccxx"@ & @"xxx"@ \\
1054@"aaaxbbbyyyxx"@ & @"aaax"@ & @"aaab"@ & @"yyy"@ & @"xx"@ & @"xxx"@ \\
1055@"aaaxbbbyyyddd"@ & @"aaax"@ & @"xbbb"@ & @"yyy"@ & @"ddd"@ & @"xxx"@ \\
1056@"aaaxbbbyyyddd"@ & @"aaax"@ & @"xbbb"@ & @"yyy"@ & @"ddd"@ & @"eee"@ \\
1057@"eee"@ & @""@ & @""@ & @""@ & @"eee"@ \\
1058 & \\
1059\end{tabular}
1060\end{tabular}
1061\end{cquote}
1062\begin{cfa}
1063int main() {
1064 string x = "xxxxxxxxxxx";
1065 test( x, x(0, 3), x(2, 3), x(4, 5), x(8, 5), x(8, 5) );
1066}
1067\end{cfa}
1068\caption{Parameter Passing}
1069\label{f:ParameterPassing}
1070\end{figure}
1071
1072
1073\subsection{RAII limitations}
1074
1075Earlier work on \CFA~\cite[ch.~2]{Schluntz17} implemented object constructors and destructors for all types (basic and user defined).
1076A constructor is a user-defined function run implicitly \emph{after} an object's declaration-storage is created, and a destructor is a user-defined function run \emph{before} an object's declaration-storage is deleted.
1077This feature, called RAII~\cite[p.~389]{Stroustrup94}, guarantees pre-invariants for users before accessing an object and post invariants for the programming environment after an object terminates.
1078
1079The purposes of these invariants goes beyond ensuring authentic values inside an object.
1080Invariants can also track occurrences of managed objects in other data structures.
1081For example, reference counting is a typical application of an invariant outside of the data values.
1082With a reference-counting smart-pointer, the constructor and destructor \emph{of a pointer type} tracks the life cycle of the object it points to.
1083Both \CC and \CFA RAII systems are powerful enough to achieve reference counting.
1084
1085In general, a lifecycle function has access to an object by location, \ie constructors and destructors receive a @this@ parameter providing an object's memory address.
1086\begin{cfa}
1087struct S { int * ip; };
1088void ?{}( S & @this@ ) { this.ip = new(); } $\C[3in]{// default constructor}$
1089void ?{}( S & @this@, int i ) { ?{}(this); *this.ip = i; } $\C{// initializing constructor}$
1090void ?{}( S & @this@, S s ) { this = s; } $\C{// copy constructor}$
1091void ^?{}( S & @this@ ) { delete( this.ip ); } $\C{// destructor}\CRT$
1092\end{cfa}
1093The lifecycle implementation can then add this object to a collection at creation and remove it at destruction.
1094A module providing lifecycle semantics can traverse the collection at relevant times to keep the objects ``good.''
1095Hence, declaring such an object not only ensures ``good'' authentic values, but also an implicit subscription to a service that keeps the value ``good'' across its lifetime.
1096
1097In many cases, the relationship between memory location and lifecycle is straightforward.
1098For example, stack-allocated objects being used as parameters and returns, with a sender version in one stack frame and a receiver version in another, as opposed to assignment where sender and receiver are in the same stack frame.
1099What is crucial for lifecycle management is knowing if the receiver is initialized or uninitialized, \ie an object is or is not currently associated with management.
1100To provide this knowledge, languages differentiate between initialization and assignment to a left-hand side.
1101\begin{cfa}
1102Obj obj2 = obj1; $\C[1.5in]{// initialization, obj2 is initialized}$
1103obj2 = obj1; $\C{// assignment, obj2 must be initialized for management to work}\CRT$
1104\end{cfa}
1105Initialization occurs at declaration by value, parameter by argument, return temporary by function call.
1106Hence, it is necessary to have two kinds of constructors: by value or object.
1107\begin{cfa}
1108Obj obj1{ 1, 2, 3 }; $\C[1.5in]{// by value, management is initialized}$
1109Obj obj2 = obj1; $\C{// by obj, management is updated}\CRT$
1110\end{cfa}
1111When no object management is required, initialization copies the right-hand value.
1112Hence, the calling convention remains uniform, where the unmanaged case uses @memcpy@ as the initialization constructor and managed uses the specified initialization constructor.
1113
1114The \CFA RAII system supports lifecycle functions, except for returning a value from a function to a temporary.
1115For example, in \CC:
1116\begin{c++}
1117struct S {...};
1118S identity( S s ) { return s; }
1119S s;
1120s = identity( s ); // S temp = identity( s ); s = temp;
1121\end{c++}
1122the generated code for the function call created a temporary with initialization from the function call, and then assigns the temporary to the object.
1123This two step approach means extra storage for the temporary and two copies to get the result into the object variable.
1124\CC{17} introduced return value-optimization (RVO)~\cite{RVO20} to ``avoid copying an object that a function returns as its value, including avoiding creation of a temporary object''.
1125\CFA uses C semantics for function return giving direct value-assignment, which eliminates unnecessary code, but skips an essential feature needed by lifetime management.
1126The following discusses the consequences of this semantics with respect to lifetime management of \CFA strings.
1127
1128The present string-API contribution provides lifetime management with initialization semantics on function return.
1129The workaround to achieve the full lifetime semantics does have a runtime performance penalty.
1130An alternative API sacrifices return initialization semantics to recover full runtime performance.
1131These APIs are layered, with the slower, friendlier High Level API (HL) wrapping the faster, more primitive Low Level API (LL).
1132Both API present the same features, up to lifecycle management, with return initialization being disabled in LL and implemented with the workaround in HL.
1133The intention is for most future code to target HL.
1134When \CFA becomes a full compiler, it can provide return initialization with RVO optimizations.
1135Then, programs written with the HL API will simply run faster.
1136In the meantime, performance-critical sections of applications use LL.
1137Subsequent performance experiments \see{\VRef{s:PerformanceAssessment}} with other string libraries has \CFA strings using the LL API.
1138These measurement gives a fair estimate of the goal state for \CFA.
1139
1140
1141\subsection{Memory management}
1142
1143A centrepiece of the string module is its memory manager.
1144The management scheme defines a shared buffer for string text.
1145Allocation in this buffer is via a bump-pointer;
1146the buffer is compacted and/or relocated with growth when it fills.
1147A string is a smart pointer into this buffer.
1148
1149This cycle of frequent cheap allocations, interspersed with infrequent expensive compactions, has obvious similarities to a general-purpose memory manager based on garbage collection (GC).
1150A few differences are noteworthy.
1151First, in a general purpose manager, the allocated objects may contain pointers to other objects, making the transitive reachability of these objects a crucial property.
1152Here, the allocations are text, so one allocation never keeps another alive.
1153Second, in a general purpose manager, the handle that keeps an allocation alive is just a lean pointer.
1154For strings, a fatter representation is acceptable because there are fewer string head pointers versus chained pointers within nodes as for linked containers.
1155
1156\begin{figure}
1157\includegraphics{memmgr-basic.pdf}
1158\caption{String memory-management data structures}
1159\label{f:memmgr-basic}
1160\end{figure}
1161
1162\VRef[Figure]{f:memmgr-basic} shows the representation.
1163The heap header and text buffer define a sharing context.
1164Normally, one global sharing context is appropriate for an entire program;
1165concurrent exceptions are discussed in \VRef{s:ControllingImplicitSharing}.
1166A string is a handle into the buffer and linked into a list.
1167The list is doubly linked for $O(1)$ insertion and removal at any location.
1168Strings are orders in the list by string-text address, where there is no overlapping, and approximately, where there is.
1169The header maintains a next-allocation pointer, @alloc@, pointing to the last live allocation in the buffer.
1170No external references point into the buffer and the management procedure relocates the text allocations as needed.
1171A string handle references a containing string, while its string is contiguous and not null terminated.
1172The length sets an upper limit on the string size, but is large (4 or 8 bytes).
1173String handles can be allocated in the stack or heap, and represent the string variables in a program.
1174Normal C life-time rules apply to guarantee correctness of the string linked-list.
1175The text buffer is large enough with good management so that often only one dynamic allocation is necessary during program execution.
1176% During this period, strings can vary in size dynamically.
1177
1178When the text buffer fills, \ie the next new string allocation causes @alloc@ to point beyond the end of the buffer, the strings are compacted.
1179The linked handles define all live strings in the buffer, which indirectly defines the allocated and free space in the buffer.
1180Since the string handles are in (roughly) sorted order, the handle list can be traversed copying the first text to the start of the buffer and subsequent strings after each over.
1181After compaction, if the amount of free storage is still less than the new string allocation, a larger text buffer is heap allocated, the current buffer is copies into the new buffer, and the original buffer is freed.
1182Note, the list of string handles is unaffected during a compaction;
1183only the string pointers in the handles are modified to new buffer locations.
1184
1185Object lifecycle events are the \emph{subscription-management} triggers in such a service.
1186There are two fundamental string-creation functions: importing external text like a C-string or reading a string, and initialization from an existing \CFA string.
1187When importing, storage comes from the end of the buffer, into which the text is copied.
1188The new string handle is inserted at the end of the handle list because the new text is at the end of the buffer.
1189When initializing from text already in the text buffer, the new handle is a second reference into the original run of characters.
1190In this case, the new handle's linked-list position is after the original handle.
1191Both string initialization styles preserve the string module's internal invariant that the linked-list order matches the buffer order.
1192For string destruction, handles are removed from the list.
1193
1194Certain string operations can results in a subset (substring) of another string.
1195The resulting handle is then placed in the correct sorted position in the list, possible with a short linear search to locate the position.
1196For string operations resulting in a new string, that string is allocated at the end of the buffer.
1197For shared-edit strings, handles that originally referenced containing locations need to see the new value at the new buffer location.
1198These strings are moved to appropriate locations at the end of the list \see{[xref: TBD]}.
1199For nonshared-edit strings, a containing string can be moved and the nonshared strings can remain in the same position.
1200String assignment words similarly to string initialization, maintain the invariant of linked-list order matching buffer order.
1201
1202At the level of the memory manager, these modifications can always be explained as assignments and appendment;
1203for example, an append is an assignment into the empty substring at the end of the buffer.
1204Favourable conditions allow for in-place editing: where there is room for the resulting value in the original buffer location, and where all handles referring to the original buffer location see the new value.
1205However, the general case requires a new buffer allocation: where the new value does not fit in the old place, or if other handles are still using the old value.
1206
1207
1208\subsection{Sharing implementation}
1209
1210The \CFA string module has two mechanisms to handle the case when string handles share a string of text.
1211
1212The first type of sharing is the user requests both string handles be views of the same logical, modifiable string.
1213This state is typically produced by the substring operation.
1214\begin{cfa}
1215string s = "abcde";
1216string s1 = s( 1, 2 )@`share@; $\C[2.25in]{// explicit sharing}$
1217s[1] = 'x'; $\C{// change s and s1}\CRT$
1218sout | s | s1;
1219$\texttt{\small axcde xc}$
1220\end{cfa}
1221In a typical substring call, the source string-handle is referencing an entire string, and the resulting, newly made, string handle is referencing a portion of the original.
1222In this state, a subsequent modification made by either is visible in both.
1223
1224The second type of sharing happens when the system implicitly delays the physical execution of a logical \emph{copy} operation, as part of its copy-on-write optimization.
1225This state is typically produced by constructing a new string, using an original string as its initialization source.
1226\begin{cfa}
1227string s = "abcde";
1228string s1 = s( 1, 2 )@@; $\C[2.25in]{// no sharing}$
1229s[1] = 'x'; $\C{// copy-on-write s1}\CRT$
1230sout | s | s1;
1231$\texttt{\small axcde bc}$
1232\end{cfa}
1233In this state, a subsequent modification done on one handle triggers the deferred copy action, leaving the handles referencing different text within the buffer, holding distinct values.
1234
1235A further abstraction, in the string module's implementation, helps distinguish the two senses of sharing.
1236A share-edit set (SES) is an equivalence class over string handles, being the reflexive, symmetric and transitive closure of the relationship of one string being constructed from another, with the ``share'' opt-in given.
1237The SES is represented by a second linked list among the handles.
1238A string that shares edits with no other is in a SES by itself.
1239Inside a SES, a logical modification of one substring portion may change the logical value in another, depending on whether the two actually overlap.
1240Conversely, no logical value change can flow outside of a SES.
1241Even if a modification on one string handle does not reveal itself \emph{logically} to anther handle in the same SES (because they do not overlap), if the modification is length-changing, completing the modification requires visiting the second handle to adjust its location in the sliding text.
1242
1243
1244\subsection{Controlling implicit sharing}
1245\label{s:ControllingImplicitSharing}
1246
1247There are tradeoffs associated with sharing and its implicit copy-on-write mechanism.
1248Several qualitative matters are detailed in \VRef{s:PerformanceAssessment}.
1249In detail, string sharing has inter-linked string handles, so managing one string is also managing the neighbouring strings, and from there, a data structure of the ``set of all strings.''
1250Therefore, it is useful to toggle this capability on or off when it is not providing any application benefit.
1251
1252\begin{figure}
1253 \begin{tabular}{ll}
1254 \lstinputlisting[language=CFA, firstline=10, lastline=55]{sharectx.run.cfa}
1255 &
1256 \raisebox{-0.17\totalheight}{\includegraphics{string-sharectx.pdf}} % lower
1257 \end{tabular}
1258 \caption{Controlling copying vs sharing of strings using \lstinline{string_sharectx}.}
1259 \label{fig:string-sharectx}
1260\end{figure}
1261
1262The \CFA string library provides the type @string_sharectx@ to control an ambient sharing context.
1263It allows two adjustments: to opt out of sharing entirely or to begin sharing within a private context.
1264Running with sharing disabled can be thought of as a \CC STL-emulation mode, where each string is dynamically allocated.
1265The chosen mode applies for the duration of the lifetime of the created @string_sharectx@ object, up to being suspended by child lifetimes of different contexts.
1266\VRef[Figure]{fig:string-sharectx} illustrates this behaviour by showing the stack frames of a program in execution.
1267In this example, the single-letter functions are called in alphabetic order.
1268The functions @a@, @b@ and @g@ share string character ranges with each other, because they occupy a common sharing-enabled context.
1269The function @e@ shares within itself (because its is in a sharing-enabled context), but not with the rest of the program (because its context is not occupied by any of the rest of the program).
1270The functions @c@, @d@ and @f@ never share anything, because they are in a sharing-disabled context.
1271Executing the example does not produce an interesting outcome, but the comments in the picture indicate when the logical copy operation runs with
1272\begin{description}
1273 \item[share:] the copy being deferred, as described through the rest of this section (fast), or
1274 \item[copy:] the copy performed eagerly (slow).
1275\end{description}
1276Only eager copies can cross @string_sharectx@ boundaries.
1277The intended use is with stack-managed lifetimes, in which the established context lasts until the current function returns, and affects all functions called that do not create their own contexts.
1278
1279[ TODO: true up with ``is thread local'' (implement that and expand this discussion to give a concurrent example, or adjust this wording) ]
1280
1281
1282\subsection{Sharing and threading}
1283
1284The \CFA string library provides no thread safety, the same as \CC string, providing similar performance goals.
1285Threads can create their own string buffers and avoid passing these strings to other threads, or require that shared strings be immutable, as concurrent reading is safe.
1286A positive consequence of this approach is that independent threads can use the sharing buffer without locking overhead.
1287When string sharing amongst threads is required, program-wide string-management can toggled to non-sharing using @malloc@/@free@, where the storage allocator is assumed to be thread-safe.
1288Finally, concurrent users of string objects can provide their own mutual exclusion.
1289
1290
1291\subsection{Future work}
1292
1293Implementing the small-string optimization is straightforward, as a string header contains a pointer to the string text in the buffer.
1294This pointer could be marked with a flag and contain a small string.
1295However, there is now a conditional check required on the fast-path to switch between small and large string operations.
1296
1297It might be possible to pack 16- or 32-bit Unicode characters within the same string buffer as 8-bit characters.
1298Again, locations for identification flags must be found and checked along the fast path to select the correct actions.
1299Handling utf8 (variable length), is more problematic because simple pointer arithmetic cannot be used to stride through the variable-length characters.
1300Trying to use a secondary array of fixed-sized pointers/offsets to the characters is possible, but raises the question of storage management for the utf8 characters themselves.
1301
1302
1303\section{Performance assessment}
1304\label{s:PerformanceAssessment}
1305
1306I assessed the \CFA string library's speed and memory usage against strings in \CC STL.
1307The results are presented in even equivalent cases, due to either micro-optimizations foregone, or fundamental costs of the added functionality.
1308They also show the benefits and tradeoffs, as >100\% effects, of switching to \CFA, with the tradeoff points quantified.
1309The final test shows the overall win of the \CFA text-sharing mechanism.
1310It exercises several operations together, showing \CFA enabling clean user code to achieve performance that STL requires less-clean user code to achieve.
1311
1312To discuss: general goal of ...
1313while STL makes you think about memory management, all the time, and if you do, your performance can be great ...
1314\CFA sacrifices this advantage modestly in exchange for big wins when you're not thinking about memory management.
1315[Does this position cover all of it?]
1316
1317To discuss: revisit HL v LL APIs
1318
1319To discuss: revisit no-sharing as STL emulation modes
1320
1321
1322\subsection{Methodology}
1323
1324These tests use a \emph{corpus} of strings (string content is immaterial).
1325For varying-length strings, the mean length comes from a geometric distribution, which implies that lengths much longer than the mean occur frequently.
1326The string sizes are:
1327\begin{description}
1328 \item [Fixed-size] all string lengths are of the stated size.
1329 \item [Varying from 1 to N] means the string lengths are drawn from the geometric distribution with a stated mean and all lengths occur.
1330 \item [Varying from 16 to N] means string lengths are drawn from the geometric distribution with the stated mean, but only lengths 16 and above occur; thus, the stated mean is above 16.
1331\end{description}
1332The means for the geometric distribution are the X-axis values in experiments.
1333The special treatment of length 16 deals with the short-string optimization (SSO) in STL @string@, currently not implemented in \CFA.
1334When an STL string can fit into a heap pointer, the optimization uses the pointer storage to eliminate using the heap.
1335\begin{c++}
1336class string {
1337 union {
1338 struct { $\C{// long string, string storage in heap}$
1339 size_t size;
1340 char * strptr;
1341 } lstr;
1342 char sstr[sizeof(lstr)]; $\C{// short string 8-16 characters, in situ}$
1343 };
1344 bool tag; $\C{// string kind, short or long}$
1345 ... $\C{// other storage}$
1346};
1347\end{c++}
1348
1349When success is illustrated, notwithstanding SSO, a fixed-size or from-16 distribution ensures that extra-optimized cases are not part of the mix on the STL side.
1350In all experiments that use a corpus, its text is generated and loaded into the system under test before the timed phase begins.
1351
1352To discuss: vocabulary for reused case variables
1353
1354To discuss: common approach to iteration and quoted rates
1355
1356To discuss: hardware and such
1357
1358To ensure comparable results, a common memory allocator is used for \CFA and \CC.
1359The llheap allocator~\cite{Zulfiqar22} is embedded into \CFA and is used standalone with \CC.
1360
1361
1362\subsection{Test: Append}
1363
1364This test measures the speed of appending randomly-size text onto a growing string.
1365\begin{cquote}
1366\setlength{\tabcolsep}{20pt}
1367\begin{tabular}{@{}ll@{}}
1368% \multicolumn{1}{c}{\textbf{fresh}} & \multicolumn{1}{c}{\textbf{reuse}} \\
1369\begin{cfa}
1370
1371for ( ... ) {
1372 @string x;@ // fresh
1373 for ( ... )
1374 x @+=@ ...
1375}
1376\end{cfa}
1377&
1378\begin{cfa}
1379string x;
1380for ( ... ) {
1381 @x = "";@ $\C[1in]{// reuse}$
1382 for ( ... )
1383 x @+=@ ... $\C{// append, alternative x = x + ...}\CRT$
1384}
1385\end{cfa}
1386\end{tabular}
1387\end{cquote}
1388The benchmark's outer loop executes ``until a sample-worthy amount of execution has happened'' and an inner loop for ``building up the desired-length string.''
1389Its subcases include,
1390\begin{enumerate}[leftmargin=*]
1391\item
1392\CFA nosharing/sharing \vs \CC nosharing.
1393\item
1394Difference between the logically equivalent operations @x += ...@ \vs @x = x + ...@.
1395For numeric types, the generated code is equivalence, giving identical performance.
1396However, for string types there can be a significant difference in performance, especially if this code appears in a loop iterating a large number of times.
1397This difference might not be intuitive to beginners.
1398\item
1399Coding practice where the user's logical allocation is fresh \vs reused.
1400Here, \emph{reusing a logical allocation}, means that the program variable, into which the user is concatenating, previously held a long string.
1401In general, a user should not have to care about this difference, yet the STL performs differently in these cases.
1402Furthermore, if a function takes a string by reference, if cannot use the fresh approach.
1403Concretely, both cases incur the cost of copying characters into the target string, but only the allocation-fresh case incurs a further reallocation cost, which is generally paid at points of doubling the length.
1404For the STL, this cost includes obtaining a fresh buffer from the memory allocator and copying older characters into the new buffer, while \CFA-sharing hides such a cost entirely.
1405%The fresh \vs reuse distinction is only relevant in the \emph{append} tests.
1406\end{enumerate}
1407
1408\begin{figure}
1409\centering
1410 \includegraphics{string-graph-peq-cppemu.pdf}
1411% \includegraphics[width=\textwidth]{string-graph-peq-cppemu.png}
1412 \caption{Average time per iteration (lower is better) with one \lstinline{x += y} invocation, comparing \CFA with STL implementations (given \CFA running in STL emulation mode), and comparing the ``fresh'' with ``reused'' reset styles, at various string sizes.}
1413 \label{fig:string-graph-peq-cppemu}
1414\end{figure}
1415
1416This tests use the varying-from-1 corpus construction, \ie it assumes the STL's advantage of small-string optimization.
1417\PAB{To discuss: any other case variables introduced in the performance intro}
1418\VRef[Figure]{fig:string-graph-peq-cppemu} shows this behaviour, by the STL and by \CFA in STL emulation mode.
1419\CFA reproduces STL's performance, up to a 15\% penalty averaged over the cases shown, diminishing with larger strings, and 50\% in the worst case.
1420This penalty characterizes the amount of implementation fine tuning done with STL and not done with \CFA in present state.
1421There is a larger penalty for redeclaring the string each loop iteration (fresh) versus hosting it out of the loop and reseting it to the null string (reuse).
1422The cost is 40\% averaged over the cases shown and minimally 24\%, and shows up consistently between the \CFA and STL implementations, and increases with larger strings.
1423
1424\begin{figure}
1425\centering
1426 \includegraphics{string-graph-peq-sharing.pdf}
1427% \includegraphics[width=\textwidth]{string-graph-peq-sharing.png}
1428 \caption{Average time per iteration (lower is better) with one \lstinline{x += y} invocation, comparing \CFA (having implicit sharing activated) with STL, and comparing the ``fresh'' with ``reused'' reset styles, at various string sizes.}
1429 \label{fig:string-graph-peq-sharing}
1430\end{figure}
1431
1432In sharing mode, \CFA makes the fresh/reuse difference disappear, as shown in \VRef[Figure]{fig:string-graph-peq-sharing}.
1433At append lengths 5 and above, \CFA not only splits the two baseline STL cases, but its slowdown of 16\% over (STL with user-managed reuse) is close to the \CFA-v-STL implementation difference seen with \CFA in STL-emulation mode.
1434
1435\begin{figure}
1436\centering
1437 \includegraphics{string-graph-pta-sharing.pdf}
1438% \includegraphics[width=\textwidth]{string-graph-pta-sharing.png}
1439 \caption{Average time per iteration (lower is better) with one \lstinline{x = x + y} invocation, comparing \CFA (having implicit sharing activated) with STL.
1440For context, the results from \VRef[Figure]{fig:string-graph-peq-sharing} are repeated as the bottom bands.
1441While not a design goal, and not graphed out, \CFA in STL-emulation mode outperformed STL in this case; user-managed allocation reuse did not affect any of the implementations in this case.}
1442 \label{fig:string-graph-pta-sharing}
1443\end{figure}
1444
1445When the user takes a further step beyond the STL's optimal zone, by running @x = x + y@, as in \VRef[Figure]{fig:string-graph-pta-sharing}, the STL's penalty is above $15 \times$ while \CFA's (with sharing) is under $2 \times$, averaged across the cases shown here.
1446Moreover, the STL's gap increases with string size, while \CFA's converges.
1447
1448
1449\subsubsection{Test: Pass argument}
1450
1451STL has a penalty for passing a string by value, which indirectly forces users to think about memory management when communicating values to a function.
1452\begin{cfa}
1453void foo( string s );
1454string s = "abc";
1455foo( s );
1456\end{cfa}
1457With implicit sharing active, \CFA treats this operation as normal and supported.
1458This test illustrates a main advantage of the \CFA sharing algorithm.
1459It also has a case in which STL's small-string optimization provides a successful mitigation.
1460
1461\begin{figure}
1462\centering
1463 \includegraphics{string-graph-pbv.pdf}
1464% \includegraphics[width=\textwidth]{string-graph-pbv.png}
1465 \caption{Average time per iteration (lower is better) with one call to a function that takes a by-value string argument, comparing \CFA (having implicit sharing activated) with STL.
1466(a) With \emph{Varying-from-1} corpus construction, in which the STL-only benefit of small-string optimization occurs, in varying degrees, at all string sizes.
1467(b) With \emph{Fixed-size} corpus construction, in which this benefit applies exactly to strings with length below 16.
1468[TODO: show version (b)]}
1469 \label{fig:string-graph-pbv}
1470\end{figure}
1471
1472\VRef[Figure]{fig:string-graph-pbv} shows the costs for calling a function that receives a string argument by value.
1473STL's performance worsens as string length increases, while \CFA has the same performance at all sizes.
1474
1475The \CFA cost to pass a string is nontrivial.
1476The contributor is adding and removing the callee's string handle from the global list.
1477This cost is $1.5 \times$ to $2 \times$ over STL's when small-string optimization applies, though this cost should be avoidable in the same case, given a \CFA realization of this optimization.
1478At the larger sizes, when STL has to manage storage for the string, STL runs more than $3 \times$ slower, mainly due to time spent in the general-purpose memory allocator.
1479
1480
1481\subsubsection{Test: Allocate}
1482
1483This test directly compares the allocation schemes of the \CFA string with sharing, compared with the STL string.
1484It treats the \CFA scheme as a form of garbage collection, and the STL scheme as an application of malloc-free.
1485The test shows that \CFA enables faster speed at a cost in memory usage.
1486
1487A garbage collector, afforded the freedom of managed memory, often runs faster than malloc-free (in an amortized analysis, even though it must occasionally stop to collect) because it is able to use its collection time to move objects.
1488(In the case of the mini-allocator powering the \CFA string library, objects are runs of text.) Moving objects lets fresh allocations consume from a large contiguous store of available memory; the ``bump pointer'' book-keeping for such a scheme is very light.
1489A malloc-free implementation without the freedom to move objects must, in the general case, allocate in the spaces between existing objects; doing so entails the heavier book-keeping to navigate and maintain a linked structure.
1490
1491A garbage collector keeps allocations around for longer than the using program can reach them.
1492By contrast, a program using malloc-free (correctly) releases allocations exactly when they are no longer reachable.
1493Therefore, the same harness will use more memory while running under garbage collection.
1494A garbage collector can minimize the memory overhead by searching for these dead allocations aggressively, that is, by collecting more often.
1495Tuned in this way, it spends a lot of time collecting, easily so much as to overwhelm its speed advantage from bump-pointer allocation.
1496If it is tuned to collect rarely, then it leaves a lot of garbage allocated (waiting to be collected) but gains the advantage of little time spent doing collection.
1497
1498[TODO: find citations for the above knowledge]
1499
1500The speed for memory tradeoff is, therefore, standard for comparisons like \CFA--STL string allocations.
1501The test verifies that it is so and quantifies the returns available.
1502
1503These tests manipulate a tuning knob that controls how much extra space to use.
1504Specific values of this knob are not user-visible and are not presented in the results here.
1505Instead, its two effects (amount of space used and time per operation) are shown.
1506The independent variable is the liveness target, which is the fraction of the text buffer that is in use at the end of a collection.
1507The allocator will expand its text buffer during a collection if the actual fraction live exceeds this target.
1508
1509This experiment's driver allocates strings by constructing a string handle as a local variable then looping over recursive calls.
1510The time measurement is of nanoseconds per such allocating call.
1511The arrangement of recursive calls and their fan-out (iterations per recursion level) makes some of the strings long-lived and some of them short-lived.
1512String lifetime (measured in number of subsequent string allocations) is ?? distributed, because each node in the call tree survives as long as its descendent calls.
1513The run presented in this section used a call depth of 1000 and a fan-out of 1.006, which means that approximately one call in 167 makes two recursive calls, while the rest make one.
1514This sizing was chosen to keep the amounts of consumed memory within the machine's last-level cache.
1515
1516\begin{figure}
1517\centering
1518 \includegraphics{string-graph-allocn.pdf}
1519% \includegraphics[width=\textwidth]{string-graph-allocn.png}
1520 \caption{Space and time performance, under varying fraction-live targets, for the five string lengths shown, at (\emph{Fixed-size} corpus construction.
1521[MISSING] The identified clusters are for the default fraction-live target, which is 30\%.
1522MISSING: STL results, typically just below the 0.5--0.9 \CFA segment.
1523All runs keep an average of 836 strings live, and the median string lifetime is ?? allocations.}
1524 \label{fig:string-graph-allocn}
1525\end{figure}
1526
1527\VRef[Figure]{fig:string-graph-allocn} shows the results of this experiment.
1528At all string sizes, varying the liveness threshold gives offers speed-for-space tradeoffs relative to STL.
1529At the default liveness threshold, all measured string sizes see a ??\%--??\% speedup for a ??\%--??\% increase in memory footprint.
1530
1531
1532\subsubsection{Test: Normalize}
1533
1534This test is more applied than the earlier ones.
1535It combines the effects of several operations.
1536It also demonstrates a case of the \CFA API allowing user code to perform well, while being written without overt memory management, while achieving similar performance in STL requires adding memory-management complexity.
1537
1538To motivate: edits being rare
1539
1540The program is doing a specialized find-replace operation on a large body of text.
1541In the program under test, the replacement is just to erase a magic character.
1542But in the larger software problem represented, the rewrite logic belongs to a module that was originally intended to operate on simple, modest-length strings.
1543The challenge is to apply this packaged function across chunks taken from the large body.
1544Using the \CFA string library, the most natural way to write the helper module's function also works well in the adapted context.
1545Using the STL string, the most natural ways to write the helper module's function, given its requirements in isolation, slow down when it is driven in the adapted context.
1546
1547\begin{lstlisting}
1548void processItem( string & item ) {
1549 // find issues in item and fix them
1550}
1551\end{lstlisting}
Note: See TracBrowser for help on using the repository browser.