source: libcfa/src/collections/string.cfa@ 2df85ce

Last change on this file since 2df85ce was 829a955, checked in by Peter A. Buhr <pabuhr@…>, 4 weeks ago

update strings, update for-control and string documentation

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