source: libcfa/src/collections/string.cfa@ 570e7ad

stuck-waitfor-destruct
Last change on this file since 570e7ad was 570e7ad, checked in by Michael Brooks <mlbrooks@…>, 11 months ago

Make string operator-overload costs match their intuitively equivalent arithmetics.

Replace many by-reference string args with by-value args to work around noise from the reference-cost column.

Use a special arithmetic type for the factor argument of ?*? to match conversion cost of (char*int=int).

Removes cost-function noise of char-arithmetic operators being preferred over their string-concatenation equivalents in the reference-cost column.

Notably, all former Spanish-A and numeric outputs have become ambiguous or been associated with a reproducible bug.

  • Property mode set to 100644
File size: 13.0 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// string -- variable-length, mutable run of text, with value semantics
8//
9// Author : Michael L. Brooks
10// Created On : Fri Sep 03 11:00:00 2021
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Wed Apr 9 22:27:40 2025
13// Update Count : 368
14//
15
16#include "string.hfa"
17#include "string_res.hfa"
18#include <stdlib.hfa>
19
20#pragma GCC visibility push(default)
21
22/*
23Implementation Principle: typical operation translates to the equivalent
24operation on `inner`. Exceptions are implementing new RAII pattern for value
25semantics and some const-hell handling.
26*/
27
28////////////////////////////////////////////////////////
29// string RAII
30
31// private (not in header)
32static 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
37void ?{}( string & s ) {
38 (s.inner) { malloc() };
39 ?{}( *s.inner );
40}
41
42void ?{}( string & s, string c ) { // c is a memcpy of the real src string
43 (s.inner) { malloc() };
44 ?{}( *s.inner, *c.inner, COPY_VALUE );
45}
46
47void ?{}( string & s, string s2, size_t maxlen ) {
48 (s.inner) { malloc() };
49 ?{}( *s.inner, *s2.inner, COPY_VALUE, maxlen );
50}
51
52void ?{}( string & s, char c ) {
53 (s.inner) { malloc() };
54 ?{}( *s.inner, c );
55}
56
57void ?{}( string & s, const char * c ) {
58 (s.inner) { malloc() };
59 ?{}( *s.inner, c );
60}
61
62void ?{}( string & s, const char * c, size_t size ) {
63 (s.inner) { malloc() };
64 ?{}( *s.inner, c, size );
65}
66
67void ?{}( string & s, signed long int rhs ) {
68 (s.inner) { malloc() };
69 ?{}( *s.inner, rhs );
70}
71
72void ?{}( string & s, size_t rhs ) {
73 (s.inner) { malloc() };
74 ?{}( *s.inner, rhs );
75}
76
77void ?{}( string & s, double rhs ) {
78 (s.inner) { malloc() };
79 ?{}( *s.inner, rhs );
80}
81
82void ?{}( string & s, long double rhs ) {
83 (s.inner) { malloc() };
84 ?{}( *s.inner, rhs );
85}
86
87void ?{}( string & s, double _Complex rhs ) {
88 (s.inner) { malloc() };
89 ?{}( *s.inner, rhs );
90}
91
92void ?{}( string & s, long double _Complex rhs ) {
93 (s.inner) { malloc() };
94 ?{}( *s.inner, rhs );
95}
96
97string str( ssize_t rhs ) {
98 string s = rhs;
99 return s;
100}
101
102string str( size_t rhs ) {
103 string s = rhs;
104 return s;
105}
106
107string str( double rhs ) {
108 string s = rhs;
109 return s;
110}
111
112string str( long double rhs ) {
113 string s = rhs;
114 return s;
115}
116
117string str( double _Complex rhs ) {
118 string s = rhs;
119 return s;
120}
121
122string str( long double _Complex rhs ) {
123 string s = rhs;
124 return s;
125}
126
127void ^?{}( string & s ) {
128 ^(*s.inner){};
129 free( s.inner );
130 s.inner = 0p;
131}
132
133////////////////////////////////////////////////////////
134// Alternate construction: request shared edits
135
136string_Share ?`share( string & s ) {
137 string_Share ret = { &s };
138 return ret;
139}
140
141void ?{}( string & s, string_Share src ) {
142 ?{}( s, *src.s->inner, 0, src.s->inner->Handle.lnth );
143}
144
145////////////////////////////////////////////////////////
146// Assignment
147
148string & ?=?( string & s, string c ) {
149 (*s.inner) = (*c.inner);
150 return s;
151}
152
153string & ?=?( string & s, const char * val ) {
154 (*s.inner) = val;
155 return s;
156}
157
158string & ?=?( string & s, char val ) {
159 (*s.inner) = val;
160 return s;
161}
162
163string & assign( string & s, const string & c, size_t n ) {
164 assign( *s.inner, *c.inner, n );
165 return s;
166}
167
168string & assign( string & s, const char * c, size_t n ) {
169 assign( *s.inner, c, n );
170 return s;
171}
172
173string & ?=?( string & s, signed long int rhs ) {
174 (*s.inner) = rhs;
175 return s;
176}
177
178string & ?=?( string & s, size_t rhs ) {
179 (*s.inner) = rhs;
180 return s;
181}
182
183string & ?=?( string & s, double rhs ) {
184 (*s.inner) = rhs;
185 return s;
186}
187
188string & ?=?( string & s, long double rhs ) {
189 (*s.inner) = rhs;
190 return s;
191}
192
193string & ?=?( string & s, double _Complex rhs ) {
194 (*s.inner) = rhs;
195 return s;
196}
197
198string & ?=?( string & s, long double _Complex rhs ) {
199 (*s.inner) = rhs;
200 return s;
201}
202
203////////////////////////////////////////////////////////
204// Input-Output
205
206forall( ostype & | basic_ostream( ostype ) ) {
207
208 ostype & ?|?( ostype & out, string s ) {
209 return out | (*s.inner); // print internal string_res
210 }
211
212 void ?|?( ostype & out, string s ) {
213 (ostype &)(out | (*s.inner)); ends( out );
214 }
215
216 ostype & ?|?( ostype & os, _Ostream_Manip(string) f ) {
217 size_t l = len( f.val );
218 char cstr[l + 1]; // room for null terminator
219 for ( i; l ) cstr[i] = f.val[i]; // copy string
220 cstr[l] = '\0'; // terminate
221 _Ostream_Manip(const char *) cf @= { cstr, f.wd, f.pc, f.base, {f.all} };
222 return os | cf | nonl;
223 } // ?|?
224
225 void ?|?( ostype & os, _Ostream_Manip(string) f ) {
226 (ostype &)(os | f); ends( os );
227 }
228}
229
230forall( istype & | basic_istream( istype ) ) {
231
232 istype & ?|?( istype & in, string & s ) {
233 return in | (*s.inner); // read to internal string_res
234 }
235
236 istype & ?|?( istype & is, _Istream_Squoted f ) {
237 _Istream_Rquoted f2 = { { f.sstr.s.inner, (_Istream_str_base)f.sstr } };
238 return is | f2;
239 } // ?|?
240
241 istype & ?|?( istype & is, _Istream_Sstr f ) {
242 // _Istream_Rstr f2 = {f.sstr.s.inner, (_Istream_str_base)f.sstr};
243 _Istream_Rstr f2 = {f.s.inner, (_Istream_str_base)f};
244 return is | f2;
245 } // ?|?
246}
247
248////////////////////////////////////////////////////////
249// Slicing
250
251string ?()( string & s, ssize_t start, ssize_t len ) {
252 if ( start < 0 ) { start += len( s ); }
253 if ( len < 0 ) { len = -len; start -= len; }
254 if ( start >= len( s ) ) return (string){ "" };
255 if ( start + len > len( s ) ) len = len( s ) - start;
256 string ret = { *s.inner, start, len };
257 return ret`share;
258}
259
260string ?()( string & s, ssize_t start ) {
261 if ( start < 0 ) { start += len( s ); }
262 string ret = { *s.inner, start, len( s ) - start };
263 return ret`share;
264}
265
266////////////////////////////////////////////////////////
267// Comparison
268
269int strcmp( const string & s1, const string & s2 ) { return strcmp( *s1.inner, *s2.inner ); }
270bool ?==?( const string & s1, const string & s2 ) { return *s1.inner == *s2.inner; }
271bool ?!=?( const string & s1, const string & s2 ) { return *s1.inner != *s2.inner; }
272bool ?>? ( const string & s1, const string & s2 ) { return *s1.inner > *s2.inner; }
273bool ?>=?( const string & s1, const string & s2 ) { return *s1.inner >= *s2.inner; }
274bool ?<=?( const string & s1, const string & s2 ) { return *s1.inner <= *s2.inner; }
275bool ?<? ( const string & s1, const string & s2 ) { return *s1.inner < *s2.inner; }
276
277int strcmp( const string & s1, const char * s2 ) { return strcmp( *s1.inner, s2 ); }
278bool ?==?( const string & s1, const char * s2 ) { return *s1.inner == s2; }
279bool ?!=?( const string & s1, const char * s2 ) { return *s1.inner != s2; }
280bool ?>? ( const string & s1, const char * s2 ) { return *s1.inner > s2; }
281bool ?>=?( const string & s1, const char * s2 ) { return *s1.inner >= s2; }
282bool ?<=?( const string & s1, const char * s2 ) { return *s1.inner <= s2; }
283bool ?<? ( const string & s1, const char * s2 ) { return *s1.inner < s2; }
284
285int strcmp( const char * s1, const string & s2 ) { return strcmp( s1, *s2.inner ); }
286bool ?==?( const char * s1, const string & s2 ) { return s1 == *s2.inner; }
287bool ?!=?( const char * s1, const string & s2 ) { return s1 != *s2.inner; }
288bool ?>? ( const char * s1, const string & s2 ) { return s1 > *s2.inner; }
289bool ?>=?( const char * s1, const string & s2 ) { return s1 >= *s2.inner; }
290bool ?<=?( const char * s1, const string & s2 ) { return s1 <= *s2.inner; }
291bool ?<? ( const char * s1, const string & s2 ) { return s1 < *s2.inner; }
292
293////////////////////////////////////////////////////////
294// Concatenation
295
296void ?+=?( string & s, char c ) {
297 (*s.inner) += c;
298}
299
300void ?+=?( string & s, const string & s2 ) {
301 (*s.inner) += (*s2.inner);
302}
303
304void append( string & s, const string & s2, size_t maxlen ) {
305 append( (*s.inner), (*s2.inner), maxlen );
306}
307
308void ?+=?( string & s, const char * c ) {
309 (*s.inner) += c;
310}
311
312void append( string & s, const char * buffer, size_t bsize ) {
313 append( (*s.inner), buffer, bsize );
314}
315
316string ?+?( string s, char c ) {
317 string ret = s;
318 ret += c;
319 return ret;
320}
321
322string ?+?( char c, string s ) {
323 string ret = c;
324 ret += s;
325 return ret;
326}
327
328string ?+?( string s, string s2 ) {
329 string ret = s;
330 ret += s2;
331 return ret;
332}
333
334string ?+?( const char * s, char c ) {
335 string ret = s;
336 ret += c;
337 return ret;
338}
339
340string ?+?( char c, const char * s ) {
341 string ret = c;
342 ret += s;
343 return ret;
344}
345
346string ?+?( const char * s1, const char * s2 ) {
347 string ret = s1;
348 ret += s2;
349 return ret;
350}
351
352string ?+?( const char * s1, string s2 ) {
353 string ret = s1;
354 ret += s2;
355 return ret;
356}
357
358string ?+?( string s, const char * c ) {
359 string ret = s;
360 ret += c;
361 return ret;
362}
363
364string ?+?( char c1, char c2 ) {
365 string ret = c1;
366 ret += c2;
367 return ret;
368}
369
370////////////////////////////////////////////////////////
371// Repetition
372
373void ?*=?( string & s, strmul_factor_t factor ) {
374 (*s.inner) *= factor;
375}
376
377string ?*?( string s, strmul_factor_t factor ) {
378 string ret = s;
379 ret *= factor;
380 return ret;
381}
382
383string ?*?( char c, strmul_factor_t factor ) {
384 string ret = c;
385 ret *= factor;
386 return ret;
387}
388
389string ?*?( const char * s, strmul_factor_t factor ) {
390 string ret = s;
391 ret *= factor;
392 return ret;
393}
394
395////////////////////////////////////////////////////////
396// Character access
397
398char ?[?]( const string & s, size_t index ) {
399 return (*s.inner)[index];
400}
401
402string ?[?]( string & s, size_t index ) {
403 string ret = { *s.inner, index, 1 };
404 return ret`share;
405}
406
407////////////////////////////////////////////////////////
408// Search
409
410bool contains( const string & s, char ch ) {
411 return contains( *s.inner, ch );
412}
413
414size_t find( const string & s, size_t start, size_t len, const string & key, size_t kstart, size_t klen ) {
415 if ( start < 0 ) { start += len( s ); }
416 if ( len < 0 ) { len = -len; start -= len; }
417 if ( start >= len( s ) ) return 0;
418 if ( start + len > len( s ) ) len = len( s ) - start;
419
420 if ( kstart < 0 ) { kstart += len( key ); }
421 if ( klen < 0 ) { klen = -klen; kstart -= klen; }
422 if ( kstart >= len( key ) ) return 0;
423 if ( kstart + klen > len( key ) ) klen = len( key ) - kstart;
424
425 return findFrom( *s.inner, start, *key.inner );
426}
427
428size_t find( const string & s, char key ) {
429 return find( *s.inner, key );
430}
431
432size_t find( const string & s, const string & key ) {
433 return find( *s.inner, *key.inner );
434}
435
436size_t find( const string & s, const char * key ) {
437 return find( *s.inner, key );
438}
439
440size_t find( const string & s, const char * key, size_t keysize ) {
441 return find( *s.inner, key, keysize );
442}
443
444size_t find( const string & s, size_t start, char key ) {
445 return findFrom( *s.inner, start, key );
446}
447
448size_t find( const string & s, size_t start, const char * key ) {
449 return findFrom( *s.inner, start, key );
450}
451
452size_t find( const string & s, size_t start, const char * key, size_t keysize ) {
453 return findFrom( *s.inner, start, key, keysize );
454}
455
456bool includes( const string & s, const string & mask ) {
457 return includes( *s.inner, *mask.inner );
458}
459
460bool includes( const string & s, const char * mask ) {
461 return includes( *s.inner, mask );
462}
463
464bool includes( const string & s, const char * mask, size_t masksize ) {
465 return includes( *s.inner, mask, masksize );
466}
467
468bool startsWith( const string & s, const string & prefix ) {
469 return startsWith( *s.inner, *prefix.inner );
470}
471
472bool startsWith( const string & s, const char * prefix ) {
473 return startsWith( *s.inner, prefix );
474}
475
476bool startsWith( const string & s, const char * prefix, size_t prefixsize ) {
477 return startsWith( *s.inner, prefix, prefixsize );
478}
479
480bool endsWith( const string & s, const string & suffix ) {
481 return endsWith( *s.inner, *suffix.inner );
482}
483
484bool endsWith( const string & s, const char * suffix ) {
485 return endsWith( *s.inner, suffix );
486}
487
488bool endsWith( const string & s, const char * suffix, size_t suffixsize ) {
489 return endsWith( *s.inner, suffix, suffixsize );
490}
491
492
493///////////////////////////////////////////////////////////////////////////
494// charclass, include, exclude
495
496void ?{}( charclass & s, const string & chars ) {
497 (s.inner) { malloc() };
498 ?{}( *s.inner, *(const string_res *)chars.inner );
499}
500
501void ?{}( charclass & s, const char * chars ) {
502 (s.inner) { malloc() };
503 ?{}( *s.inner, chars );
504}
505
506void ?{}( charclass & s, const char * chars, size_t charssize ) {
507 (s.inner) { malloc() };
508 ?{}( *s.inner, chars, charssize );
509}
510
511void ^?{}( charclass & s ) {
512 ^(*s.inner){};
513 free( s.inner );
514 s.inner = 0p;
515}
516
517size_t exclude( const string & s, const charclass & mask ) {
518 return exclude( *s.inner, *mask.inner );
519}
520
521size_t include( const string & s, const charclass & mask ) {
522 return include( *s.inner, *mask.inner );
523}
524
525size_t test( const string & s, int (*f)( int ) ) {
526 size_t l = len( s );
527 for ( i; l ) {
528 if ( ! f( s[i] ) ) return i;
529 } // for
530 return l;
531}
532
533string replace( string & s, const string & from, const string & to ) {
534 ssize_t pos;
535 string r;
536
537 pos = find( s, from );
538 if ( pos < len( s ) ) {
539 r = s( 0, pos ) + to + replace( s( pos + (ssize_t)len( from ) ), from, to );
540 string front = s( 0, pos );
541 string back = s( pos + (ssize_t)len( from ) );
542 r = front + to + replace( back, from, to );
543 } else {
544 r = s;
545 } // if
546 return r;
547}
548
549string translate( const string & s, int (*f)( int ) ) {
550 string r = s;
551 size_t l = len( r );
552 for ( i; l ) {
553 r[i] = (char)f( r[i] );
554 } // for
555 return r;
556}
Note: See TracBrowser for help on using the repository browser.