Changeset 211def2 for libcfa/src
- Timestamp:
- Feb 7, 2024, 10:54:16 PM (10 months ago)
- Branches:
- master
- Children:
- 956299b
- Parents:
- a22d148
- Location:
- libcfa/src
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/collections/string.cfa
ra22d148 r211def2 10 10 // Created On : Fri Sep 03 11:00:00 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Jan 14 12:03:47202413 // Update Count : 2 4012 // Last Modified On : Wed Feb 7 21:17:06 2024 13 // Update Count : 259 14 14 // 15 15 … … 210 210 } 211 211 212 void ?|?( ifstream & in, string & s ) { 213 in | (*s.inner); 214 } 212 ifstream & ?|?( ifstream & is, _Istream_Squoted f ) { 213 _Istream_Rquoted f2 = { { f.sstr.s.inner, (_Istream_str_base)f.sstr } }; 214 return is | f2; 215 } // ?|? 215 216 216 217 ifstream & ?|?( ifstream & is, _Istream_Sstr f ) { 218 // _Istream_Rstr f2 = {f.sstr.s.inner, (_Istream_str_base)f.sstr}; 217 219 _Istream_Rstr f2 = {f.s.inner, (_Istream_str_base)f}; 218 220 return is | f2; 219 221 } // ?|? 220 221 void ?|?( ifstream & in, _Istream_Sstr f ) {222 (ifstream &)(in | f);223 }224 222 225 223 //////////////////////////////////////////////////////// -
libcfa/src/collections/string.hfa
ra22d148 r211def2 10 10 // Created On : Fri Sep 03 11:00:00 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Jan 14 12:03:46202413 // Update Count : 8112 // Last Modified On : Tue Feb 6 20:59:18 2024 13 // Update Count : 118 14 14 // 15 15 … … 80 80 void ?|?(ofstream & out, const string & s); 81 81 ifstream & ?|?(ifstream & in, string & s); 82 void ?|?( ifstream & in, string & s );83 82 84 83 static inline { … … 96 95 void ?|?( ofstream & os, _Ostream_Manip(string) ); 97 96 97 struct _Istream_Swidth { 98 string & s; 99 inline _Istream_str_base; 100 }; // _Istream_Swidth 101 102 struct _Istream_Squoted { 103 _Istream_Swidth sstr; 104 }; // _Istream_Squoted 105 98 106 struct _Istream_Sstr { 99 107 string & s; 100 108 inline _Istream_str_base; 109 // _Istream_Swidth sstr; 101 110 }; // _Istream_Sstr 102 111 103 112 static inline { 104 113 // read width does not include null terminator 105 _Istream_S str wdi( unsigned int rwd, string & s ) { return (_Istream_Sstr)@{ s, {{0p}, rwd, {.flags.rwd : true}} }; }114 _Istream_Swidth wdi( unsigned int rwd, string & s ) { return (_Istream_Swidth)@{ .s : s, { {.scanset : 0p}, .wd : rwd, {.flags.rwd : true} } }; } 106 115 _Istream_Sstr getline( string & s, const char delimiter = '\n' ) { 107 return (_Istream_Sstr)@{ s, {{.delimiters : { delimiter, '\0' } }, -1, {.flags.delimiter : true, .flags.inex : true}} }; 108 } 109 _Istream_Sstr & getline( _Istream_Sstr & fmt, const char delimiter = '\n' ) { 110 fmt.delimiters[0] = delimiter; fmt.delimiters[1] = '\0'; fmt.flags.delimiter = true; fmt.flags.inex = true; return fmt; 111 } 112 _Istream_Sstr incl( const char scanset[], string & s ) { return (_Istream_Sstr)@{ s, {{scanset}, -1, {.flags.inex : false}} }; } 113 _Istream_Sstr & incl( const char scanset[], _Istream_Sstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = false; return fmt; } 114 _Istream_Sstr excl( const char scanset[], string & s ) { return (_Istream_Sstr)@{ s, {{scanset}, -1, {.flags.inex : true}} }; } 115 _Istream_Sstr & excl( const char scanset[], _Istream_Sstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = true; return fmt; } 116 _Istream_Sstr ignore( string & s ) { return (_Istream_Sstr)@{ s, {{0p}, -1, {.flags.ignore : true}} }; } 117 _Istream_Sstr & ignore( _Istream_Sstr & fmt ) { fmt.flags.ignore = true; return fmt; } 116 // return (_Istream_Sstr)@{ { .s : s, { {.delimiters : { delimiter, '\0' } }, .wd : -1, {.flags.delimiter : true} } } }; 117 return (_Istream_Sstr)@{ .s : s, { {.delimiters : { delimiter, '\0' } }, .wd : -1, {.flags.delimiter : true} } }; 118 } 119 _Istream_Sstr & getline( _Istream_Swidth & f, const char delimiter = '\n' ) { 120 f.delimiters[0] = delimiter; f.delimiters[1] = '\0'; f.flags.delimiter = true; return (_Istream_Sstr &)f; 121 } 122 _Istream_Squoted quoted( string & s, const char Ldelimiter = '\"', const char Rdelimiter = '\0' ) { 123 return (_Istream_Squoted)@{ { .s : s, { {.delimiters : { Ldelimiter, Rdelimiter, '\0' }}, .wd : -1, {.flags.rwd : true} } } }; 124 } 125 _Istream_Squoted & quoted( _Istream_Swidth & f, const char Ldelimiter = '"', const char Rdelimiter = '\0' ) { 126 f.delimiters[0] = Ldelimiter; f.delimiters[1] = Rdelimiter; f.delimiters[2] = '\0'; 127 return (_Istream_Squoted &)f; 128 } 129 // _Istream_Sstr incl( const char scanset[], string & s ) { return (_Istream_Sstr)@{ { .s : s, { {.scanset : scanset}, .wd : -1, {.flags.inex : false} } } }; } 130 _Istream_Sstr incl( const char scanset[], string & s ) { return (_Istream_Sstr)@{ .s : s, { {.scanset : scanset}, .wd : -1, {.flags.inex : false} } }; } 131 _Istream_Sstr & incl( const char scanset[], _Istream_Swidth & f ) { f.scanset = scanset; f.flags.inex = false; return (_Istream_Sstr &)f; } 132 // _Istream_Sstr excl( const char scanset[], string & s ) { return (_Istream_Sstr)@{ { .s : s, { {.scanset : scanset}, .wd : -1, {.flags.inex : true} } } }; } 133 _Istream_Sstr excl( const char scanset[], string & s ) { return (_Istream_Sstr)@{ .s : s, { {.scanset : scanset}, .wd : -1, {.flags.inex : true} } }; } 134 _Istream_Sstr & excl( const char scanset[], _Istream_Swidth & f ) { f.scanset = scanset; f.flags.inex = true; return (_Istream_Sstr &)f; } 135 // _Istream_Sstr ignore( string & s ) { return (_Istream_Sstr)@{ { .s : s, { {.scanset : 0p}, .wd : -1, {.flags.ignore : true} } } }; } 136 _Istream_Sstr ignore( string & s ) { return (_Istream_Sstr)@{ .s : s, { {.scanset : 0p}, .wd : -1, {.flags.ignore : true} } }; } 137 _Istream_Sstr & ignore( _Istream_Swidth & f ) { f.flags.ignore = true; return (_Istream_Sstr &)f; } 138 _Istream_Squoted & ignore( _Istream_Squoted & f ) { f.sstr.flags.ignore = true; return (_Istream_Squoted &)f; } 139 // _Istream_Sstr & ignore( _Istream_Sstr & f ) { f.sstr.flags.ignore = true; return (_Istream_Sstr &)f; } 140 _Istream_Sstr & ignore( _Istream_Sstr & f ) { f.flags.ignore = true; return (_Istream_Sstr &)f; } 118 141 } // distribution 142 ifstream & ?|?( ifstream & is, _Istream_Squoted f ); 119 143 ifstream & ?|?( ifstream & is, _Istream_Sstr f ); 120 void ?|?( ifstream & is, _Istream_Sstr t ); 144 static inline ifstream & ?|?( ifstream & is, _Istream_Swidth f ) { return is | *(_Istream_Sstr *)&f; } 121 145 122 146 // Concatenation -
libcfa/src/collections/string_res.cfa
ra22d148 r211def2 10 10 // Created On : Fri Sep 03 11:00:00 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Jan 22 23:12:42202413 // Update Count : 4312 // Last Modified On : Wed Feb 7 22:21:33 2024 13 // Update Count : 81 14 14 // 15 15 … … 25 25 26 26 #include <assert.h> 27 #include <complex.h> 27 #include <complex.h> // creal, cimag 28 28 29 29 //######################### VbyteHeap "header" ######################### … … 34 34 35 35 struct VbyteHeap { 36 int NoOfCompactions;// number of compactions of the byte area37 int NoOfExtensions;// number of extensions in the size of the byte area38 int NoOfReductions;// number of reductions in the size of the byte area39 40 int InitSize;// initial number of bytes in the byte-string area41 int CurrSize;// current number of bytes in the byte-string area42 char *StartVbyte;// pointer to the `st byte of the start of the byte-string area43 char *EndVbyte;// pointer to the next byte after the end of the currently used portion of byte-string area44 void *ExtVbyte;// pointer to the next byte after the end of the byte-string area45 46 HandleNode Header;// header node for handle list36 int NoOfCompactions; // number of compactions of the byte area 37 int NoOfExtensions; // number of extensions in the size of the byte area 38 int NoOfReductions; // number of reductions in the size of the byte area 39 40 int InitSize; // initial number of bytes in the byte-string area 41 int CurrSize; // current number of bytes in the byte-string area 42 char *StartVbyte; // pointer to the `st byte of the start of the byte-string area 43 char *EndVbyte; // pointer to the next byte after the end of the currently used portion of byte-string area 44 void *ExtVbyte; // pointer to the next byte after the end of the byte-string area 45 46 HandleNode Header; // header node for handle list 47 47 }; // VbyteHeap 48 48 49 50 static void compaction( VbyteHeap & ); // compaction of the byte area51 static void garbage( VbyteHeap &, int ); // garbage collect the byte area52 static void extend( VbyteHeap &, int ); // extend the size of the byte area53 static void reduce( VbyteHeap &, int ); // reduce the size of the byte area49 50 static void compaction( VbyteHeap & ); // compaction of the byte area 51 static void garbage( VbyteHeap &, int ); // garbage collect the byte area 52 static void extend( VbyteHeap &, int ); // extend the size of the byte area 53 static void reduce( VbyteHeap &, int ); // reduce the size of the byte area 54 54 55 55 static void ?{}( VbyteHeap &, size_t = 1000 ); 56 56 static void ^?{}( VbyteHeap & ); 57 57 58 static int ByteCmp( char *, int, int, char *, int, int ); 58 static int ByteCmp( char *, int, int, char *, int, int ); // compare 2 blocks of bytes 59 59 static char *VbyteAlloc( VbyteHeap &, int ); // allocate a block bytes in the heap 60 60 static char *VbyteTryAdjustLast( VbyteHeap &, int ); … … 62 62 static void AddThisAfter( HandleNode &, HandleNode & ); 63 63 static void DeleteNode( HandleNode & ); 64 static void MoveThisAfter( HandleNode &, const HandleNode & ); 64 static void MoveThisAfter( HandleNode &, const HandleNode & ); // move current handle after parameter handle 65 65 66 66 … … 69 69 static void ?{}( VbyteHeap & s, size_t Size ) with(s) { 70 70 #ifdef VbyteDebug 71 72 #endif // VbyteDebug 73 74 75 76 77 78 79 #ifdef VbyteDebug 80 81 71 serr | "enter:VbyteHeap::VbyteHeap, s:" | &s | " Size:" | Size; 72 #endif // VbyteDebug 73 NoOfCompactions = NoOfExtensions = NoOfReductions = 0; 74 InitSize = CurrSize = Size; 75 StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize); 76 ExtVbyte = (void *)( StartVbyte + CurrSize ); 77 Header.flink = Header.blink = &Header; 78 Header.ulink = &s; 79 #ifdef VbyteDebug 80 HeaderPtr = &Header; 81 serr | "exit:VbyteHeap::VbyteHeap, s:" | &s; 82 82 #endif // VbyteDebug 83 83 } // VbyteHeap … … 87 87 88 88 static void ^?{}( VbyteHeap & s ) with(s) { 89 89 free( StartVbyte ); 90 90 } // ~VbyteHeap 91 91 … … 99 99 static void ?{}( HandleNode & s ) with(s) { 100 100 #ifdef VbyteDebug 101 102 #endif // VbyteDebug 103 104 105 #ifdef VbyteDebug 106 101 serr | "enter:HandleNode::HandleNode, s:" | &s; 102 #endif // VbyteDebug 103 s = 0; 104 lnth = 0; 105 #ifdef VbyteDebug 106 serr | "exit:HandleNode::HandleNode, s:" | &s; 107 107 #endif // VbyteDebug 108 108 } // HandleNode … … 114 114 static void ?{}( HandleNode & s, VbyteHeap & vh ) with(s) { 115 115 #ifdef VbyteDebug 116 117 #endif // VbyteDebug 118 119 120 121 122 #ifdef VbyteDebug 123 116 serr | "enter:HandleNode::HandleNode, s:" | &s; 117 #endif // VbyteDebug 118 s = 0; 119 lnth = 0; 120 ulink = &vh; 121 AddThisAfter( s, *vh.Header.blink ); 122 #ifdef VbyteDebug 123 serr | "exit:HandleNode::HandleNode, s:" | &s; 124 124 #endif // VbyteDebug 125 125 } // HandleNode … … 131 131 static void ^?{}( HandleNode & s ) with(s) { 132 132 #ifdef VbyteDebug 133 134 135 serr | nlOff;136 serr | " lnth:" | lnth | " s:" | (void *)s | ",\"";137 for ( i; lnth ) {138 139 } // for140 serr | "\" flink:" | flink | " blink:" | blink | nl;141 serr | nlOn;142 143 #endif // VbyteDebug 144 133 serr | "enter:HandleNode::~HandleNode, s:" | & s; 134 { 135 serr | nlOff; 136 serr | " lnth:" | lnth | " s:" | (void *)s | ",\""; 137 for ( i; lnth ) { 138 serr | s[i]; 139 } // for 140 serr | "\" flink:" | flink | " blink:" | blink | nl; 141 serr | nlOn; 142 } 143 #endif // VbyteDebug 144 DeleteNode( s ); 145 145 } // ~HandleNode 146 146 … … 148 148 //######################### String Sharing Context ######################### 149 149 150 static string_sharectx * ambient_string_sharectx; 150 static string_sharectx * ambient_string_sharectx; // fickle top of stack 151 151 static string_sharectx default_string_sharectx = {NEW_SHARING}; // stable bottom of stack 152 152 153 153 void ?{}( string_sharectx & s, StringSharectx_Mode mode ) with( s ) { 154 155 156 157 158 159 160 161 154 (older){ ambient_string_sharectx }; 155 if ( mode == NEW_SHARING ) { 156 (activeHeap){ new( (size_t) 1000 ) }; 157 } else { 158 verify( mode == NO_SHARING ); 159 (activeHeap){ 0p }; 160 } 161 ambient_string_sharectx = & s; 162 162 } 163 163 164 164 void ^?{}( string_sharectx & s ) with( s ) { 165 166 167 168 169 170 while ( c != &s ) &c = &c->older;// find s171 c = s.older;// unlink165 if ( activeHeap ) delete( activeHeap ); 166 167 // unlink s from older-list starting from ambient_string_sharectx 168 // usually, s==ambient_string_sharectx and the loop runs zero times 169 string_sharectx *& c = ambient_string_sharectx; 170 while ( c != &s ) &c = &c->older; // find s 171 c = s.older; // unlink 172 172 } 173 173 … … 176 176 177 177 VbyteHeap * DEBUG_string_heap() { 178 179 178 assert( ambient_string_sharectx->activeHeap && "No sharing context is active" ); 179 return ambient_string_sharectx->activeHeap; 180 180 } 181 181 182 182 size_t DEBUG_string_bytes_avail_until_gc( VbyteHeap * heap ) { 183 183 return ((char *)heap->ExtVbyte) - heap->EndVbyte; 184 184 } 185 185 186 186 size_t DEBUG_string_bytes_in_heap( VbyteHeap * heap ) { 187 187 return heap->CurrSize; 188 188 } 189 189 190 190 const char * DEBUG_string_heap_start( VbyteHeap * heap ) { 191 191 return heap->StartVbyte; 192 192 } 193 193 194 194 // Returns the size of the string in bytes 195 195 size_t size(const string_res & s) with(s) { 196 196 return Handle.lnth; 197 197 } 198 198 … … 201 201 // CFA string is NOT null terminated, so print exactly lnth characters in a minimum width of 0. 202 202 out | wd( 0, s.Handle.lnth, s.Handle.s ) | nonl; 203 203 return out; 204 204 } 205 205 … … 210 210 // Input operator 211 211 ifstream & ?|?(ifstream & in, string_res & s) { 212 213 214 215 216 217 218 219 220 221 222 223 224 225 assert( temp.Handle.ulink->EndVbyte == temp.Handle.s + temp.Handle.lnth );// last in heap226 227 228 229 230 231 232 233 234 235 236 212 // Reading into a temp before assigning to s is near zero overhead in typical cases because of sharing. 213 // If s is a substring of something larger, simple assignment takes care of that case correctly. 214 // But directly reading a variable amount of text into the middle of a larger context is not practical. 215 string_res temp; 216 217 // Read in chunks. Often, one chunk is enough. Keep the string that accumulates chunks last in the heap, 218 // so available room is rest of heap. When a chunk fills the heap, force growth then take the next chunk. 219 for (bool cont = true; cont; ) { 220 cont = false; 221 222 // Append dummy content to temp, forcing expansion when applicable (occurs always on subsequent loops) 223 // length 2 ensures room for at least one real char, plus scanf/pipe-cstr's null terminator 224 temp += "--"; 225 assert( temp.Handle.ulink->EndVbyte == temp.Handle.s + temp.Handle.lnth ); // last in heap 226 227 // reset, to overwrite the appended "--" 228 temp.Handle.lnth -= 2; 229 temp.Handle.ulink->EndVbyte -= 2; 230 231 // rest of heap is available to read into 232 int lenReadable = (char *)temp.Handle.ulink->ExtVbyte - temp.Handle.ulink->EndVbyte; 233 assert (lenReadable >= 2); 234 235 // get bytes 236 try { 237 237 *(temp.Handle.ulink->EndVbyte) = '\0'; // pre-assign empty cstring 238 239 240 241 242 243 244 245 246 247 238 in | wdi( lenReadable, temp.Handle.ulink->EndVbyte ); 239 } catch (cstring_length *) { 240 cont = true; 241 } 242 int lenWasRead = strlen(temp.Handle.ulink->EndVbyte); 243 244 // update metadata 245 temp.Handle.lnth += lenWasRead; 246 temp.Handle.ulink->EndVbyte += lenWasRead; 247 } 248 248 249 249 if ( temp.Handle.lnth > 0 ) s = temp; 250 return in; 251 } 252 253 void ?|?( ifstream & in, string_res & s ) { 254 (ifstream &)(in | s); 250 return in; 251 } 252 253 ifstream & ?|?( ifstream & is, _Istream_Rquoted f ) with( f.rstr ) { 254 int args; 255 fini: { 256 args = fmt( is, "%*[ \f\n\r\t\v]" ); // remove leading whitespace 257 if ( eof( is ) ) break fini; 258 char rfmt[4] = { delimiters[0], '%', 'n', '\0' }; 259 int len = 0; // may not be set in fmt 260 args = fmt( is, rfmt, &len ); // remove leading quote 261 if ( len == 0 || eof( is ) ) break fini; 262 263 // Change the remainder of the read into a getline by reseting the closing delimiter. 264 if ( delimiters[1] != '\0' ) { 265 delimiters[0] = delimiters[1]; 266 delimiters[1] = '\0'; 267 } // if 268 flags.delimiter = true; 269 return is | *(_Istream_Rstr *)&f; 270 } // fini 271 // read failed => no pattern match => set string to null 272 if ( ! flags.ignore && s != 0p && args == 0 ) s[0] = '\0'; 273 if ( args == 1 && eof( is ) ) { // data but scan ended at EOF 274 clear( is ); // => reset EOF => detect again on next read 275 } // if 276 return is; 255 277 } 256 278 … … 295 317 } // ?|? 296 318 297 void ?|?( ifstream & in, _Istream_Rstr f ) {298 (ifstream &)(in | f);299 }300 301 302 319 // Empty constructor 303 320 void ?{}(string_res & s) with(s) { 304 305 306 307 308 309 310 311 312 313 314 315 316 }321 if( ambient_string_sharectx->activeHeap ) { 322 (Handle){ * ambient_string_sharectx->activeHeap }; 323 (shareEditSet_owns_ulink){ false }; 324 verify( Handle.s == 0p && Handle.lnth == 0 ); 325 } else { 326 (Handle){ * new( (size_t) 10 ) }; // TODO: can I lazily avoid allocating for empty string 327 (shareEditSet_owns_ulink){ true }; 328 Handle.s = Handle.ulink->StartVbyte; 329 verify( Handle.lnth == 0 ); 330 } 331 s.shareEditSet_prev = &s; 332 s.shareEditSet_next = &s; 333 } 317 334 318 335 static void eagerCopyCtorHelper(string_res & s, const char * rhs, size_t rhslnth) with(s) { 319 320 321 322 323 324 325 326 327 328 329 330 336 if( ambient_string_sharectx->activeHeap ) { 337 (Handle){ * ambient_string_sharectx->activeHeap }; 338 (shareEditSet_owns_ulink){ false }; 339 } else { 340 (Handle){ * new( rhslnth ) }; 341 (shareEditSet_owns_ulink){ true }; 342 } 343 Handle.s = VbyteAlloc(*Handle.ulink, rhslnth); 344 Handle.lnth = rhslnth; 345 memmove( Handle.s, rhs, rhslnth ); 346 s.shareEditSet_prev = &s; 347 s.shareEditSet_next = &s; 331 348 } 332 349 333 350 // Constructor from a raw buffer and size 334 351 void ?{}(string_res & s, const char * rhs, size_t rhslnth) with(s) { 335 352 eagerCopyCtorHelper(s, rhs, rhslnth); 336 353 } 337 354 338 355 void ?{}( string_res & s, ssize_t rhs ) { 339 340 341 342 356 char buf[64]; 357 int len; 358 snprintf( buf, sizeof(buf)-1, "%zd%n", rhs, &len ); 359 ( s ){ buf, len }; 343 360 } 344 361 void ?{}( string_res & s, size_t rhs ) { 345 346 347 348 362 char buf[64]; 363 int len; 364 snprintf( buf, sizeof(buf)-1, "%zu%n", rhs, &len ); 365 ( s ){ buf, len }; 349 366 } 350 367 void ?{}( string_res & s, double rhs ) { 351 352 353 354 368 char buf[64]; 369 int len; 370 snprintf( buf, sizeof(buf)-1, "%g%n", rhs, &len ); 371 ( s ){ buf, len }; 355 372 } 356 373 void ?{}( string_res & s, long double rhs ) { 357 358 359 360 374 char buf[64]; 375 int len; 376 snprintf( buf, sizeof(buf)-1, "%Lg%n", rhs, &len ); 377 ( s ){ buf, len }; 361 378 } 362 379 void ?{}( string_res & s, double _Complex rhs ) { 363 364 365 366 380 char buf[64]; 381 int len; 382 snprintf( buf, sizeof(buf)-1, "%g+%gi%n", creal( rhs ), cimag( rhs ), &len ); 383 ( s ){ buf, len }; 367 384 } 368 385 void ?{}( string_res & s, long double _Complex rhs ) { 369 370 371 372 386 char buf[64]; 387 int len; 388 snprintf( buf, sizeof(buf)-1, "%Lg+%Lgi%n", creall( rhs ), cimagl( rhs ), &len ); 389 ( s ){ buf, len }; 373 390 } 374 391 375 392 // private ctor (not in header): use specified heap (ignore ambient) and copy chars in 376 393 void ?{}( string_res & s, VbyteHeap & heap, const char * rhs, size_t rhslnth ) with(s) { 377 378 379 380 381 382 383 394 (Handle){ heap }; 395 Handle.s = VbyteAlloc(*Handle.ulink, rhslnth); 396 Handle.lnth = rhslnth; 397 (s.shareEditSet_owns_ulink){ false }; 398 memmove( Handle.s, rhs, rhslnth ); 399 s.shareEditSet_prev = &s; 400 s.shareEditSet_next = &s; 384 401 } 385 402 … … 387 404 // General copy constructor 388 405 void ?{}(string_res & s, const string_res & s2, StrResInitMode mode, size_t start, size_t len ) { 389 390 size_t end = start + len; 391 verify( start <= end && end <= s2.Handle.lnth ); 392 393 if (s2.Handle.ulink != ambient_string_sharectx->activeHeap && mode == COPY_VALUE) { 394 // crossing heaps (including private): copy eagerly 395 eagerCopyCtorHelper(s, s2.Handle.s + start, end - start); 396 verify(s.shareEditSet_prev == &s); 397 verify(s.shareEditSet_next == &s); 398 } else { 399 (s.Handle){}; 400 s.Handle.s = s2.Handle.s + start; 401 s.Handle.lnth = end - start; 402 s.Handle.ulink = s2.Handle.ulink; 403 404 AddThisAfter(s.Handle, s2.Handle ); // insert this handle after rhs handle 405 // ^ bug? skip others at early point in string 406 407 if (mode == COPY_VALUE) { 408 verify(s2.Handle.ulink == ambient_string_sharectx->activeHeap); 409 // requested logical copy in same heap: defer copy until write 410 411 (s.shareEditSet_owns_ulink){ false }; 412 413 // make s alone in its shareEditSet 414 s.shareEditSet_prev = &s; 415 s.shareEditSet_next = &s; 416 } else { 417 verify( mode == SHARE_EDITS ); 418 // sharing edits with source forces same heap as source (ignore context) 419 420 (s.shareEditSet_owns_ulink){ s2.shareEditSet_owns_ulink }; 421 422 // s2 is logically const but not implementation const 423 string_res & s2mod = (string_res &) s2; 424 425 // insert s after s2 on shareEditSet 426 s.shareEditSet_next = s2mod.shareEditSet_next; 427 s.shareEditSet_prev = &s2mod; 428 s.shareEditSet_next->shareEditSet_prev = &s; 429 s.shareEditSet_prev->shareEditSet_next = &s; 430 } 431 } 406 size_t end = start + len; 407 verify( start <= end && end <= s2.Handle.lnth ); 408 409 if (s2.Handle.ulink != ambient_string_sharectx->activeHeap && mode == COPY_VALUE) { 410 // crossing heaps (including private): copy eagerly 411 eagerCopyCtorHelper(s, s2.Handle.s + start, end - start); 412 verify(s.shareEditSet_prev == &s); 413 verify(s.shareEditSet_next == &s); 414 } else { 415 (s.Handle){}; 416 s.Handle.s = s2.Handle.s + start; 417 s.Handle.lnth = end - start; 418 s.Handle.ulink = s2.Handle.ulink; 419 420 AddThisAfter(s.Handle, s2.Handle ); // insert this handle after rhs handle 421 // ^ bug? skip others at early point in string 422 423 if (mode == COPY_VALUE) { 424 verify(s2.Handle.ulink == ambient_string_sharectx->activeHeap); 425 // requested logical copy in same heap: defer copy until write 426 427 (s.shareEditSet_owns_ulink){ false }; 428 429 // make s alone in its shareEditSet 430 s.shareEditSet_prev = &s; 431 s.shareEditSet_next = &s; 432 } else { 433 verify( mode == SHARE_EDITS ); 434 // sharing edits with source forces same heap as source (ignore context) 435 436 (s.shareEditSet_owns_ulink){ s2.shareEditSet_owns_ulink }; 437 438 // s2 is logically const but not implementation const 439 string_res & s2mod = (string_res &) s2; 440 441 // insert s after s2 on shareEditSet 442 s.shareEditSet_next = s2mod.shareEditSet_next; 443 s.shareEditSet_prev = &s2mod; 444 s.shareEditSet_next->shareEditSet_prev = &s; 445 s.shareEditSet_prev->shareEditSet_next = &s; 446 } 447 } 432 448 } 433 449 434 450 static void assignEditSet(string_res & s, string_res * shareEditSetStartPeer, string_res * shareEditSetEndPeer, 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 451 char * resultSesStart, 452 size_t resultSesLnth, 453 HandleNode * resultPadPosition, size_t bsize ) { 454 455 char * beforeBegin = shareEditSetStartPeer->Handle.s; 456 size_t beforeLen = s.Handle.s - beforeBegin; 457 458 char * afterBegin = s.Handle.s + s.Handle.lnth; 459 size_t afterLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - afterBegin; 460 461 size_t oldLnth = s.Handle.lnth; 462 463 s.Handle.s = resultSesStart + beforeLen; 464 s.Handle.lnth = bsize; 465 if (resultPadPosition) 466 MoveThisAfter( s.Handle, *resultPadPosition ); 467 468 // adjust all substring string and handle locations, and check if any substring strings are outside the new base string 469 char *limit = resultSesStart + resultSesLnth; 470 for ( string_res * p = s.shareEditSet_next; p != &s; p = p->shareEditSet_next ) { 471 verify (p->Handle.s >= beforeBegin); 472 if ( p->Handle.s >= afterBegin ) { 473 verify ( p->Handle.s <= afterBegin + afterLen ); 474 verify ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen ); 475 // p starts after the edit 476 // take start and end as end-anchored 477 size_t startOffsetFromEnd = afterBegin + afterLen - p->Handle.s; 478 p->Handle.s = limit - startOffsetFromEnd; 479 // p->Handle.lnth unaffected 480 } else if ( p->Handle.s <= beforeBegin + beforeLen ) { 481 // p starts before, or at the start of, the edit 482 if ( p->Handle.s + p->Handle.lnth <= beforeBegin + beforeLen ) { 483 // p ends before the edit 484 // take end as start-anchored too 485 // p->Handle.lnth unaffected 486 } else if ( p->Handle.s + p->Handle.lnth < afterBegin ) { 487 // p ends during the edit; p does not include the last character replaced 488 // clip end of p to end at start of edit 489 p->Handle.lnth = beforeLen - ( p->Handle.s - beforeBegin ); 490 } else { 491 // p ends after the edit 492 verify ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen ); 493 // take end as end-anchored 494 // stretch-shrink p according to the edit 495 p->Handle.lnth += s.Handle.lnth; 496 p->Handle.lnth -= oldLnth; 497 } 498 // take start as start-anchored 499 size_t startOffsetFromStart = p->Handle.s - beforeBegin; 500 p->Handle.s = resultSesStart + startOffsetFromStart; 501 } else { 502 verify ( p->Handle.s < afterBegin ); 503 // p starts during the edit 504 verify( p->Handle.s + p->Handle.lnth >= beforeBegin + beforeLen ); 505 if ( p->Handle.s + p->Handle.lnth < afterBegin ) { 506 // p ends during the edit; p does not include the last character replaced 507 // set p to empty string at start of edit 508 p->Handle.s = s.Handle.s; 509 p->Handle.lnth = 0; 510 } else { 511 // p includes the end of the edit 512 // clip start of p to start at end of edit 513 int charsToClip = afterBegin - p->Handle.s; 514 p->Handle.s = s.Handle.s + s.Handle.lnth; 515 p->Handle.lnth -= charsToClip; 516 } 517 } 518 if (resultPadPosition) 519 MoveThisAfter( p->Handle, *resultPadPosition ); // move substring handle to maintain sorted order by string position 520 } 505 521 } 506 522 507 523 // traverse the share-edit set (SES) to recover the range of a base string to which `s` belongs 508 524 static void locateInShareEditSet( string_res & s, string_res *& shareEditSetStartPeer, string_res *& shareEditSetEndPeer ) { 509 510 511 512 513 514 515 516 517 518 525 shareEditSetStartPeer = & s; 526 shareEditSetEndPeer = & s; 527 for (string_res * editPeer = s.shareEditSet_next; editPeer != &s; editPeer = editPeer->shareEditSet_next) { 528 if ( editPeer->Handle.s < shareEditSetStartPeer->Handle.s ) { 529 shareEditSetStartPeer = editPeer; 530 } 531 if ( shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth < editPeer->Handle.s + editPeer->Handle.lnth) { 532 shareEditSetEndPeer = editPeer; 533 } 534 } 519 535 } 520 536 521 537 static string_res & assign_(string_res & s, const char * buffer, size_t bsize, const string_res & valSrc) { 522 523 string_res * shareEditSetStartPeer; 524 string_res * shareEditSetEndPeer; 525 locateInShareEditSet( s, shareEditSetStartPeer, shareEditSetEndPeer ); 526 527 verify( shareEditSetEndPeer->Handle.s >= shareEditSetStartPeer->Handle.s ); 528 size_t origEditSetLength = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - shareEditSetStartPeer->Handle.s; 529 verify( origEditSetLength >= s.Handle.lnth ); 530 531 if ( s.shareEditSet_owns_ulink ) { // assigning to private context 532 // ok to overwrite old value within LHS 533 char * prefixStartOrig = shareEditSetStartPeer->Handle.s; 534 int prefixLen = s.Handle.s - prefixStartOrig; 535 char * suffixStartOrig = s.Handle.s + s.Handle.lnth; 536 int suffixLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - suffixStartOrig; 537 538 int delta = bsize - s.Handle.lnth; 539 if ( char * oldBytes = VbyteTryAdjustLast( *s.Handle.ulink, delta ) ) { 540 // growing: copy from old to new 541 char * dest = VbyteAlloc( *s.Handle.ulink, origEditSetLength + delta ); 542 char *destCursor = dest; memcpy(destCursor, prefixStartOrig, prefixLen); 543 destCursor += prefixLen; memcpy(destCursor, buffer , bsize ); 544 destCursor += bsize; memcpy(destCursor, suffixStartOrig, suffixLen); 545 assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 546 dest, 547 origEditSetLength + delta, 548 0p, bsize); 549 free( oldBytes ); 550 } else { 551 // room is already allocated in-place: bubble suffix and overwite middle 552 memmove( suffixStartOrig + delta, suffixStartOrig, suffixLen ); 553 memcpy( s.Handle.s, buffer, bsize ); 554 555 assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 556 shareEditSetStartPeer->Handle.s, 557 origEditSetLength + delta, 558 0p, bsize); 559 } 560 561 } else if ( // assigning to shared context 562 s.Handle.lnth == origEditSetLength && // overwriting entire run of SES 563 & valSrc && // sourcing from a managed string 564 valSrc.Handle.ulink == s.Handle.ulink ) { // sourcing from same heap 565 566 // SES's result will only use characters from the source string => reuse source 567 assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 568 valSrc.Handle.s, 569 valSrc.Handle.lnth, 570 &((string_res&)valSrc).Handle, bsize); 571 572 } else { 573 // overwriting a proper substring of some string: mash characters from old and new together (copy on write) 574 // OR we are importing characters: need to copy eagerly (can't refer to source) 575 576 // full string is from start of shareEditSetStartPeer thru end of shareEditSetEndPeer 577 // `s` occurs in the middle of it, to be replaced 578 // build up the new text in `pasting` 579 580 string_res pasting = { 581 * s.Handle.ulink, // maintain same heap, regardless of context 582 shareEditSetStartPeer->Handle.s, // start of SES 583 s.Handle.s - shareEditSetStartPeer->Handle.s }; // length of SES, before s 584 append( pasting, 585 buffer, // start of replacement for s 586 bsize ); // length of replacement for s 587 append( pasting, 588 s.Handle.s + s.Handle.lnth, // start of SES after s 589 shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - 590 (s.Handle.s + s.Handle.lnth) ); // length of SES, after s 591 592 // The above string building can trigger compaction. 593 // The reference points (that are arguments of the string building) may move during that building. 594 // From s point on, they are stable. 595 596 assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 597 pasting.Handle.s, 598 pasting.Handle.lnth, 599 &pasting.Handle, bsize); 600 } 601 602 return s; 538 string_res * shareEditSetStartPeer; 539 string_res * shareEditSetEndPeer; 540 locateInShareEditSet( s, shareEditSetStartPeer, shareEditSetEndPeer ); 541 542 verify( shareEditSetEndPeer->Handle.s >= shareEditSetStartPeer->Handle.s ); 543 size_t origEditSetLength = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - shareEditSetStartPeer->Handle.s; 544 verify( origEditSetLength >= s.Handle.lnth ); 545 546 if ( s.shareEditSet_owns_ulink ) { // assigning to private context 547 // ok to overwrite old value within LHS 548 char * prefixStartOrig = shareEditSetStartPeer->Handle.s; 549 int prefixLen = s.Handle.s - prefixStartOrig; 550 char * suffixStartOrig = s.Handle.s + s.Handle.lnth; 551 int suffixLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - suffixStartOrig; 552 553 int delta = bsize - s.Handle.lnth; 554 if ( char * oldBytes = VbyteTryAdjustLast( *s.Handle.ulink, delta ) ) { 555 // growing: copy from old to new 556 char * dest = VbyteAlloc( *s.Handle.ulink, origEditSetLength + delta ); 557 char *destCursor = dest; memcpy(destCursor, prefixStartOrig, prefixLen); 558 destCursor += prefixLen; memcpy(destCursor, buffer , bsize ); 559 destCursor += bsize; memcpy(destCursor, suffixStartOrig, suffixLen); 560 assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 561 dest, 562 origEditSetLength + delta, 563 0p, bsize); 564 free( oldBytes ); 565 } else { 566 // room is already allocated in-place: bubble suffix and overwite middle 567 memmove( suffixStartOrig + delta, suffixStartOrig, suffixLen ); 568 memcpy( s.Handle.s, buffer, bsize ); 569 570 assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 571 shareEditSetStartPeer->Handle.s, 572 origEditSetLength + delta, 573 0p, bsize); 574 } 575 576 } else if ( // assigning to shared context 577 s.Handle.lnth == origEditSetLength && // overwriting entire run of SES 578 & valSrc && // sourcing from a managed string 579 valSrc.Handle.ulink == s.Handle.ulink ) { // sourcing from same heap 580 581 // SES's result will only use characters from the source string => reuse source 582 assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 583 valSrc.Handle.s, 584 valSrc.Handle.lnth, 585 &((string_res&)valSrc).Handle, bsize); 586 587 } else { 588 // overwriting a proper substring of some string: mash characters from old and new together (copy on write) 589 // OR we are importing characters: need to copy eagerly (can't refer to source) 590 591 // full string is from start of shareEditSetStartPeer thru end of shareEditSetEndPeer 592 // `s` occurs in the middle of it, to be replaced 593 // build up the new text in `pasting` 594 595 string_res pasting = { 596 * s.Handle.ulink, // maintain same heap, regardless of context 597 shareEditSetStartPeer->Handle.s, // start of SES 598 s.Handle.s - shareEditSetStartPeer->Handle.s }; // length of SES, before s 599 append( pasting, 600 buffer, // start of replacement for s 601 bsize ); // length of replacement for s 602 append( pasting, 603 s.Handle.s + s.Handle.lnth, // start of SES after s 604 shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - 605 (s.Handle.s + s.Handle.lnth) ); // length of SES, after s 606 607 // The above string building can trigger compaction. 608 // The reference points (that are arguments of the string building) may move during that building. 609 // From s point on, they are stable. 610 611 assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 612 pasting.Handle.s, 613 pasting.Handle.lnth, 614 &pasting.Handle, bsize); 615 } 616 617 return s; 603 618 } 604 619 605 620 string_res & assign(string_res & s, const string_res & src, size_t maxlen) { 606 621 return assign_(s, src.Handle.s, min(src.Handle.lnth, maxlen), *0p); 607 622 } 608 623 609 624 string_res & assign(string_res & s, const char * buffer, size_t bsize) { 610 625 return assign_(s, buffer, bsize, *0p); 611 626 } 612 627 613 628 string_res & ?=?(string_res & s, char c) { 614 629 return assign(s, &c, 1); 615 630 } 616 631 617 632 string_res & ?=?( string_res & s, ssize_t rhs ) { 618 619 620 633 string_res rhs2 = rhs; 634 s = rhs2; 635 return s; 621 636 } 622 637 string_res & ?=?( string_res & s, size_t rhs ) { 623 624 625 638 string_res rhs2 = rhs; 639 s = rhs2; 640 return s; 626 641 } 627 642 string_res & ?=?( string_res & s, double rhs ) { 628 629 630 643 string_res rhs2 = rhs; 644 s = rhs2; 645 return s; 631 646 } 632 647 string_res & ?=?( string_res & s, long double rhs ) { 633 634 635 648 string_res rhs2 = rhs; 649 s = rhs2; 650 return s; 636 651 } 637 652 string_res & ?=?( string_res & s, double _Complex rhs ) { 638 639 640 653 string_res rhs2 = rhs; 654 s = rhs2; 655 return s; 641 656 } 642 657 string_res & ?=?( string_res & s, long double _Complex rhs ) { 643 644 645 658 string_res rhs2 = rhs; 659 s = rhs2; 660 return s; 646 661 } 647 662 648 663 // Copy assignment operator 649 664 string_res & ?=?(string_res & s, const string_res & rhs) with( s ) { 650 665 return assign_(s, rhs.Handle.s, rhs.Handle.lnth, rhs); 651 666 } 652 667 653 668 string_res & ?=?(string_res & s, string_res & rhs) with( s ) { 654 655 669 const string_res & rhs2 = rhs; 670 return s = rhs2; 656 671 } 657 672 … … 659 674 // Destructor 660 675 void ^?{}(string_res & s) with(s) { 661 662 663 664 665 666 667 668 669 670 671 676 // much delegated to implied ^VbyteSM 677 678 // sever s from its share-edit peers, if any (four no-ops when already solo) 679 s.shareEditSet_prev->shareEditSet_next = s.shareEditSet_next; 680 s.shareEditSet_next->shareEditSet_prev = s.shareEditSet_prev; 681 // s.shareEditSet_next = &s; 682 // s.shareEditSet_prev = &s; 683 684 if (shareEditSet_owns_ulink && s.shareEditSet_next == &s) { // last one out 685 delete( s.Handle.ulink ); 686 } 672 687 } 673 688 … … 677 692 // offset from the start of the string. 678 693 char ?[?](const string_res & s, size_t index) with(s) { 679 680 694 //TODO: Check if index is valid (no exceptions yet) 695 return Handle.s[index]; 681 696 } 682 697 683 698 void assignAt(const string_res & s, size_t index, char val) { 684 685 686 687 688 699 // caution: not tested (not reachable by string-api-coverage interface) 700 // equivalent form at string level is `s[index] = val`, 701 // which uses the overload that returns a length-1 string 702 string_res editZone = { s, SHARE_EDITS, index, 1 }; 703 assign(editZone, &val, 1); 689 704 } 690 705 … … 694 709 695 710 void append(string_res & str1, const char * buffer, size_t bsize) { 696 697 698 699 } else {// must copy some text700 701 VbyteAlloc( *str1.Handle.ulink, bsize );// create room for 2nd part at the end of string area702 } else {// copy the two parts703 704 char * str1oldBuf = str1.Handle.s;// must read after VbyteAlloc call in case it gs's705 706 707 708 709 710 711 size_t clnth = str1.Handle.lnth + bsize; 712 if ( str1.Handle.s + str1.Handle.lnth == buffer ) { // already juxtapose ? 713 // no-op 714 } else { // must copy some text 715 if ( str1.Handle.s + str1.Handle.lnth == VbyteAlloc(*str1.Handle.ulink, 0) ) { // str1 at end of string area ? 716 VbyteAlloc( *str1.Handle.ulink, bsize ); // create room for 2nd part at the end of string area 717 } else { // copy the two parts 718 char * str1newBuf = VbyteAlloc( *str1.Handle.ulink, clnth ); 719 char * str1oldBuf = str1.Handle.s; // must read after VbyteAlloc call in case it gs's 720 str1.Handle.s = str1newBuf; 721 memcpy( str1.Handle.s, str1oldBuf, str1.Handle.lnth ); 722 } // if 723 memcpy( str1.Handle.s + str1.Handle.lnth, buffer, bsize ); 724 } // if 725 str1.Handle.lnth = clnth; 711 726 } 712 727 713 728 void ?+=?(string_res & str1, const string_res & str2) { 714 729 append( str1, str2.Handle.s, str2.Handle.lnth ); 715 730 } 716 731 717 732 void append(string_res & str1, const string_res & str2, size_t maxlen) { 718 733 append( str1, str2.Handle.s, min(str2.Handle.lnth, maxlen) ); 719 734 } 720 735 721 736 void ?+=?(string_res & s, char c) { 722 737 append( s, & c, 1 ); 723 738 } 724 739 void ?+=?(string_res & s, const char * c) { 725 740 append( s, c, strlen(c) ); 726 741 } 727 742 … … 730 745 731 746 void ?*=?(string_res & s, size_t factor) { 732 733 734 747 string_res s2 = { s, COPY_VALUE }; 748 s = ""; 749 for (factor) s += s2; 735 750 } 736 751 … … 739 754 740 755 int strcmp(const string_res & s1, const string_res & s2) { 741 742 743 744 756 // return 0; 757 int ans1 = memcmp(s1.Handle.s, s2.Handle.s, min(s1.Handle.lnth, s2.Handle.lnth)); 758 if (ans1 != 0) return ans1; 759 return s1.Handle.lnth - s2.Handle.lnth; 745 760 } 746 761 … … 753 768 754 769 int strcmp (const string_res & s1, const char * s2) { 755 756 770 string_res s2x = s2; 771 return strcmp(s1, s2x); 757 772 } 758 773 … … 765 780 766 781 int strcmp (const char * s1, const string_res & s2) { 767 768 782 string_res s1x = s1; 783 return strcmp(s1x, s2); 769 784 } 770 785 … … 777 792 778 793 779 780 794 ////////////////////////////////////////////////////////// 781 795 // Search 782 796 783 797 bool contains(const string_res & s, char ch) { 784 785 786 787 798 for ( i; size(s) ) { 799 if (s[i] == ch) return true; 800 } 801 return false; 788 802 } 789 803 790 804 int find(const string_res & s, char search) { 791 805 return findFrom(s, 0, search); 792 806 } 793 807 794 808 int findFrom(const string_res & s, size_t fromPos, char search) { 795 796 797 798 799 800 801 802 809 // FIXME: This paricular overload (find of single char) is optimized to use memchr. 810 // The general overload (find of string, memchr applying to its first character) and `contains` should be adjusted to match. 811 char * searchFrom = s.Handle.s + fromPos; 812 size_t searchLnth = s.Handle.lnth - fromPos; 813 int searchVal = search; 814 char * foundAt = (char *) memchr(searchFrom, searchVal, searchLnth); 815 if (foundAt == 0p) return s.Handle.lnth; 816 else return foundAt - s.Handle.s; 803 817 } 804 818 805 819 int find(const string_res & s, const string_res & search) { 806 820 return findFrom(s, 0, search); 807 821 } 808 822 809 823 int findFrom(const string_res & s, size_t fromPos, const string_res & search) { 810 824 return findFrom(s, fromPos, search.Handle.s, search.Handle.lnth); 811 825 } 812 826 813 827 int find(const string_res & s, const char * search) { 814 828 return findFrom(s, 0, search); 815 829 } 816 830 int findFrom(const string_res & s, size_t fromPos, const char * search) { 817 831 return findFrom(s, fromPos, search, strlen(search)); 818 832 } 819 833 820 834 int find(const string_res & s, const char * search, size_t searchsize) { 821 835 return findFrom(s, 0, search, searchsize); 822 836 } 823 837 824 838 int findFrom(const string_res & s, size_t fromPos, const char * search, size_t searchsize) { 825 826 /* Remaining implementations essentially ported from Sunjay's work */ 827 828 829 // FIXME: This is a naive algorithm. We probably want to switch to someting 830 // like Boyer-Moore in the future. 831 // https://en.wikipedia.org/wiki/String_searching_algorithm 832 833 // Always find the empty string 834 if (searchsize == 0) { 835 return 0; 836 } 837 838 for ( i; fromPos ~ s.Handle.lnth ) { 839 size_t remaining = s.Handle.lnth - i; 840 // Never going to find the search string if the remaining string is 841 // smaller than search 842 if (remaining < searchsize) { 843 break; 844 } 845 846 bool matched = true; 847 for ( j; searchsize ) { 848 if (search[j] != s.Handle.s[i + j]) { 849 matched = false; 850 break; 851 } 852 } 853 if (matched) { 854 return i; 855 } 856 } 857 858 return s.Handle.lnth; 839 /* Remaining implementations essentially ported from Sunjay's work */ 840 841 // FIXME: This is a naive algorithm. We probably want to switch to someting 842 // like Boyer-Moore in the future. 843 // https://en.wikipedia.org/wiki/String_searching_algorithm 844 845 // Always find the empty string 846 if (searchsize == 0) { 847 return 0; 848 } 849 850 for ( i; fromPos ~ s.Handle.lnth ) { 851 size_t remaining = s.Handle.lnth - i; 852 // Never going to find the search string if the remaining string is 853 // smaller than search 854 if (remaining < searchsize) { 855 break; 856 } 857 858 bool matched = true; 859 for ( j; searchsize ) { 860 if (search[j] != s.Handle.s[i + j]) { 861 matched = false; 862 break; 863 } 864 } 865 if (matched) { 866 return i; 867 } 868 } 869 return s.Handle.lnth; 859 870 } 860 871 861 872 bool includes(const string_res & s, const string_res & search) { 862 873 return includes(s, search.Handle.s, search.Handle.lnth); 863 874 } 864 875 865 876 bool includes(const string_res & s, const char * search) { 866 877 return includes(s, search, strlen(search)); 867 878 } 868 879 869 880 bool includes(const string_res & s, const char * search, size_t searchsize) { 870 881 return find(s, search, searchsize) < s.Handle.lnth; 871 882 } 872 883 873 884 bool startsWith(const string_res & s, const string_res & prefix) { 874 885 return startsWith(s, prefix.Handle.s, prefix.Handle.lnth); 875 886 } 876 887 877 888 bool startsWith(const string_res & s, const char * prefix) { 878 889 return startsWith(s, prefix, strlen(prefix)); 879 890 } 880 891 881 892 bool startsWith(const string_res & s, const char * prefix, size_t prefixsize) { 882 883 884 885 893 if (s.Handle.lnth < prefixsize) { 894 return false; 895 } 896 return memcmp(s.Handle.s, prefix, prefixsize) == 0; 886 897 } 887 898 888 899 bool endsWith(const string_res & s, const string_res & suffix) { 889 900 return endsWith(s, suffix.Handle.s, suffix.Handle.lnth); 890 901 } 891 902 892 903 bool endsWith(const string_res & s, const char * suffix) { 893 904 return endsWith(s, suffix, strlen(suffix)); 894 905 } 895 906 896 907 bool endsWith(const string_res & s, const char * suffix, size_t suffixsize) { 897 if (s.Handle.lnth < suffixsize) { 898 return false; 899 } 900 // Amount to offset the bytes pointer so that we are comparing the end of s 901 // to suffix. s.bytes + offset should be the first byte to compare against suffix 902 size_t offset = s.Handle.lnth - suffixsize; 903 return memcmp(s.Handle.s + offset, suffix, suffixsize) == 0; 904 } 905 906 /* Back to Mike's work */ 907 908 if (s.Handle.lnth < suffixsize) { 909 return false; 910 } 911 // Amount to offset the bytes pointer so that we are comparing the end of s 912 // to suffix. s.bytes + offset should be the first byte to compare against suffix 913 size_t offset = s.Handle.lnth - suffixsize; 914 return memcmp(s.Handle.s + offset, suffix, suffixsize) == 0; 915 } 916 917 /* Back to Mike's work */ 908 918 909 919 /////////////////////////////////////////////////////////////////////////// … … 911 921 912 922 void ?{}( charclass_res & s, const string_res & chars) { 913 923 (s){ chars.Handle.s, chars.Handle.lnth }; 914 924 } 915 925 916 926 void ?{}( charclass_res & s, const char * chars ) { 917 927 (s){ chars, strlen(chars) }; 918 928 } 919 929 920 930 void ?{}( charclass_res & s, const char * chars, size_t charssize ) { 921 922 931 (s.chars){ chars, charssize }; 932 // now sort it ? 923 933 } 924 934 925 935 void ^?{}( charclass_res & s ) { 926 936 ^(s.chars){}; 927 937 } 928 938 929 939 static bool test( const charclass_res & mask, char c ) { 930 931 940 // instead, use sorted char list? 941 return contains( mask.chars, c ); 932 942 } 933 943 934 944 int exclude(const string_res & s, const charclass_res & mask) { 935 936 937 938 945 for ( i; size(s) ) { 946 if ( test(mask, s[i]) ) return i; 947 } 948 return size(s); 939 949 } 940 950 941 951 int include(const string_res & s, const charclass_res & mask) { 942 943 944 945 952 for ( i; size(s) ) { 953 if ( ! test(mask, s[i]) ) return i; 954 } 955 return size(s); 946 956 } 947 957 … … 953 963 static void AddThisAfter( HandleNode & s, HandleNode & n ) with(s) { 954 964 #ifdef VbyteDebug 955 956 #endif // VbyteDebug 957 958 959 960 961 962 963 964 #ifdef VbyteDebug 965 965 serr | "enter:AddThisAfter, s:" | &s | " n:" | &n; 966 #endif // VbyteDebug 967 // Performance note: we are on the critical path here. MB has ensured that the verifies don't contribute to runtime (are compiled away, like they're supposed to be). 968 verify( n.ulink != 0p ); 969 verify( s.ulink == n.ulink ); 970 flink = n.flink; 971 blink = &n; 972 n.flink->blink = &s; 973 n.flink = &s; 974 #ifdef VbyteDebug 975 { 966 976 serr | "HandleList:"; 967 977 serr | nlOff; … … 974 984 } // for 975 985 serr | nlOn; 976 977 986 } 987 serr | "exit:AddThisAfter"; 978 988 #endif // VbyteDebug 979 989 } // AddThisAfter … … 984 994 static void DeleteNode( HandleNode & s ) with(s) { 985 995 #ifdef VbyteDebug 986 987 #endif // VbyteDebug 988 989 990 #ifdef VbyteDebug 991 996 serr | "enter:DeleteNode, s:" | &s; 997 #endif // VbyteDebug 998 flink->blink = blink; 999 blink->flink = flink; 1000 #ifdef VbyteDebug 1001 serr | "exit:DeleteNode"; 992 1002 #endif // VbyteDebug 993 1003 } // DeleteNode … … 999 1009 static char * VbyteAlloc( VbyteHeap & s, int size ) with(s) { 1000 1010 #ifdef VbyteDebug 1001 1002 #endif // VbyteDebug 1003 1004 1005 1006 1007 1011 serr | "enter:VbyteAlloc, size:" | size; 1012 #endif // VbyteDebug 1013 uintptr_t NoBytes; 1014 char *r; 1015 1016 NoBytes = ( uintptr_t )EndVbyte + size; 1017 if ( NoBytes > ( uintptr_t )ExtVbyte ) { // enough room for new byte-string ? 1008 1018 garbage( s, size ); // firer up the garbage collector 1009 1019 verify( (( uintptr_t )EndVbyte + size) <= ( uintptr_t )ExtVbyte && "garbage run did not free up required space" ); 1010 1011 1012 1013 #ifdef VbyteDebug 1014 1015 #endif // VbyteDebug 1016 1020 } // if 1021 r = EndVbyte; 1022 EndVbyte += size; 1023 #ifdef VbyteDebug 1024 serr | "exit:VbyteAlloc, r:" | (void *)r | " EndVbyte:" | (void *)EndVbyte | " ExtVbyte:" | ExtVbyte; 1025 #endif // VbyteDebug 1026 return r; 1017 1027 } // VbyteAlloc 1018 1028 … … 1027 1037 1028 1038 static char * VbyteTryAdjustLast( VbyteHeap & s, int delta ) with(s) { 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1039 if ( ( uintptr_t )EndVbyte + delta <= ( uintptr_t )ExtVbyte ) { 1040 // room available 1041 EndVbyte += delta; 1042 return 0p; 1043 } 1044 1045 char *oldBytes = StartVbyte; 1046 1047 NoOfExtensions += 1; 1048 CurrSize *= 2; 1049 StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize); 1050 ExtVbyte = StartVbyte + CurrSize; 1051 1052 return oldBytes; 1043 1053 } 1044 1054 … … 1049 1059 static void MoveThisAfter( HandleNode & s, const HandleNode & h ) with(s) { 1050 1060 #ifdef VbyteDebug 1051 1052 #endif // VbyteDebug 1053 1054 1055 1061 serr | "enter:MoveThisAfter, s:" | & s | " h:" | & h; 1062 #endif // VbyteDebug 1063 verify( h.ulink != 0p ); 1064 verify( s.ulink == h.ulink ); 1065 if ( s < h.s ) { // check argument values 1056 1066 // serr | "VbyteSM: Error - Cannot move byte string starting at:" | s | " after byte string starting at:" 1057 // 1067 // | ( h->s ) | " and keep handles in ascending order"; 1058 1068 // exit(-1 ); 1059 1069 verify( 0 && "VbyteSM: Error - Cannot move byte strings as requested and keep handles in ascending order"); 1060 1061 1062 1063 1064 1070 } // if 1071 1072 HandleNode *i; 1073 for ( i = h.flink; i->s != 0 && s > ( i->s ); i = i->flink ); // find the position for this node after h 1074 if ( & s != i->blink ) { 1065 1075 DeleteNode( s ); 1066 1076 AddThisAfter( s, *i->blink ); 1067 1068 #ifdef VbyteDebug 1069 1070 serr | "HandleList:";1071 serr | nlOff;1072 for ( HandleNode *n = HeaderPtr->flink; n != HeaderPtr; n = n->flink ) {1073 1074 1075 serr | n->s[i];1076 1077 1078 } // for1079 serr | nlOn;1080 1081 1077 } // if 1078 #ifdef VbyteDebug 1079 { 1080 serr | "HandleList:"; 1081 serr | nlOff; 1082 for ( HandleNode *n = HeaderPtr->flink; n != HeaderPtr; n = n->flink ) { 1083 serr | "\tnode:" | n | " lnth:" | n->lnth | " s:" | (void *)n->s | ",\""; 1084 for ( i; n->lnth ) { 1085 serr | n->s[i]; 1086 } // for 1087 serr | "\" flink:" | n->flink | " blink:" | n->blink | nl; 1088 } // for 1089 serr | nlOn; 1090 } 1091 serr | "exit:MoveThisAfter"; 1082 1092 #endif // VbyteDebug 1083 1093 } // MoveThisAfter 1084 1085 1086 1087 1094 1088 1095 … … 1097 1104 int ByteCmp( char *Src1, int Src1Start, int Src1Lnth, char *Src2, int Src2Start, int Src2Lnth ) { 1098 1105 #ifdef VbyteDebug 1099 serr | "enter:ByteCmp, Src1Start:" | Src1Start | " Src1Lnth:" | Src1Lnth | " Src2Start:" | Src2Start | " Src2Lnth:" | Src2Lnth; 1100 #endif // VbyteDebug 1101 int cmp; 1102 1103 CharZip: for ( int i = 0; ; i += 1 ) { 1104 if ( i == Src2Lnth - 1 ) { 1105 for ( ; ; i += 1 ) { 1106 serr | "enter:ByteCmp, Src1Start:" | Src1Start | " Src1Lnth:" | Src1Lnth | " Src2Start:" | Src2Start | " Src2Lnth:" | Src2Lnth; 1107 #endif // VbyteDebug 1108 int cmp; 1109 1110 CharZip: for ( int i = 0; ; i += 1 ) { 1111 if ( i == Src2Lnth - 1 ) { 1112 for ( ; ; i += 1 ) { 1113 if ( i == Src1Lnth - 1 ) { 1114 cmp = 0; 1115 break CharZip; 1116 } // exit 1117 if ( Src1[Src1Start + i] != ' ') { 1118 // SUSPECTED BUG: this could be be why Peter got the bug report about == " " (why is this case here at all?) 1119 cmp = 1; 1120 break CharZip; 1121 } // exit 1122 } // for 1123 } // exit 1106 1124 if ( i == Src1Lnth - 1 ) { 1107 cmp = 0; 1108 break CharZip; 1125 for ( ; ; i += 1 ) { 1126 if ( i == Src2Lnth - 1 ) { 1127 cmp = 0; 1128 break CharZip; 1129 } // exit 1130 if ( Src2[Src2Start + i] != ' ') { 1131 cmp = -1; 1132 break CharZip; 1133 } // exit 1134 } // for 1109 1135 } // exit 1110 if ( Src1[Src1Start + i] != ' ') { 1111 // SUSPECTED BUG: this could be be why Peter got the bug report about == " " (why is this case here at all?) 1112 cmp = 1; 1113 break CharZip; 1136 if ( Src2[Src2Start + i] != Src1[Src1Start+ i]) { 1137 cmp = Src1[Src1Start + i] > Src2[Src2Start + i] ? 1 : -1; 1138 break CharZip; 1114 1139 } // exit 1115 } // for 1116 } // exit 1117 if ( i == Src1Lnth - 1 ) { 1118 for ( ; ; i += 1 ) { 1119 if ( i == Src2Lnth - 1 ) { 1120 cmp = 0; 1121 break CharZip; 1122 } // exit 1123 if ( Src2[Src2Start + i] != ' ') { 1124 cmp = -1; 1125 break CharZip; 1126 } // exit 1127 } // for 1128 } // exit 1129 if ( Src2[Src2Start + i] != Src1[Src1Start+ i]) { 1130 cmp = Src1[Src1Start + i] > Src2[Src2Start + i] ? 1 : -1; 1131 break CharZip; 1132 } // exit 1133 } // for 1134 #ifdef VbyteDebug 1135 serr | "exit:ByteCmp, cmp:" | cmp; 1136 #endif // VbyteDebug 1137 return cmp; 1140 } // for 1141 #ifdef VbyteDebug 1142 serr | "exit:ByteCmp, cmp:" | cmp; 1143 #endif // VbyteDebug 1144 return cmp; 1138 1145 } // ByteCmp 1139 1146 … … 1145 1152 1146 1153 void compaction(VbyteHeap & s) with(s) { 1147 1148 1149 1150 1151 1152 1153 1154 HandleNode *h; 1155 char *obase, *nbase, *limit; 1156 1157 NoOfCompactions += 1; 1158 EndVbyte = StartVbyte; 1159 h = Header.flink; // ignore header node 1160 for () { 1154 1161 memmove( EndVbyte, h->s, h->lnth ); 1155 1162 obase = h->s; … … 1169 1176 } // for 1170 1177 if ( h == &Header ) break; // end of header list ? 1171 1178 } // for 1172 1179 } // compaction 1173 1180 1174 1181 1175 1182 static double heap_expansion_freespace_threshold = 0.1; // default inherited from prior work: expand heap when less than 10% "free" (i.e. garbage) 1176 1183 // probably an unreasonable default, but need to assess early-round tests on changing it 1177 1184 1178 1185 void TUNING_set_string_heap_liveness_threshold( double val ) { 1179 1186 heap_expansion_freespace_threshold = 1.0 - val; 1180 1187 } 1181 1188 … … 1186 1193 void garbage(VbyteHeap & s, int minreq ) with(s) { 1187 1194 #ifdef VbyteDebug 1188 1189 1195 serr | "enter:garbage"; 1196 { 1190 1197 serr | "HandleList:"; 1191 1198 for ( HandleNode *n = Header.flink; n != &Header; n = n->flink ) { … … 1198 1205 serr | "\" flink:" | n->flink | " blink:" | n->blink; 1199 1206 } // for 1200 1201 #endif // VbyteDebug 1202 1203 1204 1205 1207 } 1208 #endif // VbyteDebug 1209 int AmountUsed, AmountFree; 1210 1211 AmountUsed = 0; 1212 for ( HandleNode *i = Header.flink; i != &Header; i = i->flink ) { // calculate amount of byte area used 1206 1213 AmountUsed += i->lnth; 1207 1208 1209 1210 1214 } // for 1215 AmountFree = ( uintptr_t )ExtVbyte - ( uintptr_t )StartVbyte - AmountUsed; 1216 1217 if ( ( double ) AmountFree < ( CurrSize * heap_expansion_freespace_threshold ) || AmountFree < minreq ) { // free space less than threshold or not enough to serve cur request 1211 1218 1212 1219 extend( s, max( CurrSize, minreq ) ); // extend the heap 1213 1220 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 #ifdef VbyteDebug 1224 1221 // Peter says, "This needs work before it should be used." 1222 // } else if ( AmountFree > CurrSize / 2 ) { // free space greater than 3 times the initial allocation ? 1223 // reduce(( AmountFree / CurrSize - 3 ) * CurrSize ); // reduce the memory 1224 1225 // `extend` implies a `compaction` during the copy 1226 1227 } else { 1228 compaction(s); // in-place 1229 }// if 1230 #ifdef VbyteDebug 1231 { 1225 1232 serr | "HandleList:"; 1226 1233 for ( HandleNode *n = Header.flink; n != &Header; n = n->flink ) { … … 1233 1240 serr | "\" flink:" | n->flink | " blink:" | n->blink; 1234 1241 } // for 1235 1236 1242 } 1243 serr | "exit:garbage"; 1237 1244 #endif // VbyteDebug 1238 1245 } // garbage … … 1247 1254 void extend( VbyteHeap & s, int size ) with (s) { 1248 1255 #ifdef VbyteDebug 1249 1250 #endif // VbyteDebug 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 #ifdef VbyteDebug 1262 1256 serr | "enter:extend, size:" | size; 1257 #endif // VbyteDebug 1258 char *OldStartVbyte; 1259 1260 NoOfExtensions += 1; 1261 OldStartVbyte = StartVbyte; // save previous byte area 1262 1263 CurrSize += size > InitSize ? size : InitSize; // minimum extension, initial size 1264 StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize); 1265 ExtVbyte = (void *)( StartVbyte + CurrSize ); 1266 compaction(s); // copy from old heap to new & adjust pointers to new heap 1267 free( OldStartVbyte ); // release old heap 1268 #ifdef VbyteDebug 1269 serr | "exit:extend, CurrSize:" | CurrSize; 1263 1270 #endif // VbyteDebug 1264 1271 } // extend … … 1272 1279 void VbyteHeap::reduce( int size ) { 1273 1280 #ifdef VbyteDebug 1274 1275 #endif // VbyteDebug 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 #ifdef VbyteDebug 1287 1281 serr | "enter:reduce, size:" | size; 1282 #endif // VbyteDebug 1283 char *OldStartVbyte; 1284 1285 NoOfReductions += 1; 1286 OldStartVbyte = StartVbyte; // save previous byte area 1287 1288 CurrSize -= size; 1289 StartVbyte = EndVbyte = new char[CurrSize]; 1290 ExtVbyte = (void *)( StartVbyte + CurrSize ); 1291 compaction(); // copy from old heap to new & adjust pointers to new heap 1292 delete OldStartVbyte; // release old heap 1293 #ifdef VbyteDebug 1294 !serr | "exit:reduce, CurrSize:" | CurrSize; 1288 1295 #endif // VbyteDebug 1289 1296 } // reduce -
libcfa/src/collections/string_res.hfa
ra22d148 r211def2 10 10 // Created On : Fri Sep 03 11:00:00 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jan 4 11:28:06202413 // Update Count : 2712 // Last Modified On : Wed Feb 7 21:24:40 2024 13 // Update Count : 59 14 14 // 15 15 … … 123 123 void ?|?(ofstream & out, const string_res & s); 124 124 ifstream & ?|?(ifstream & in, string_res & s); 125 void ?|?( ifstream & in, string_res & s ); 125 126 struct _Istream_Rwidth { 127 string_res * s; 128 inline _Istream_str_base; 129 }; // _Istream_Rwidth 130 131 struct _Istream_Rquoted { 132 // string_res * s; 133 // inline _Istream_str_base; 134 _Istream_Rwidth rstr; 135 }; // _Istream_Rquoted 126 136 127 137 struct _Istream_Rstr { 128 138 string_res * s; 129 139 inline _Istream_str_base; 140 // _Istream_Rwidth rstr; 130 141 }; // _Istream_Rstr 131 142 132 143 static inline { 133 144 // read width does not include null terminator 134 _Istream_R str wdi( unsigned int rwd, string_res & s ) { return (_Istream_Rstr)@{ &s, {{0p}, rwd, {.flags.rwd : true}} }; }145 _Istream_Rwidth wdi( unsigned int rwd, string_res & s ) { return (_Istream_Rwidth)@{ .s : &s, { {.scanset : 0p}, .wd : rwd, {.flags.rwd : true} } }; } 135 146 _Istream_Rstr getline( string_res & s, const char delimiter = '\n' ) { 136 return (_Istream_Rstr)@{ &s, {{.delimiters : { delimiter, '\0' } }, -1, {.flags.delimiter : true, .flags.inex : true}} }; 137 } 138 _Istream_Rstr & getline( _Istream_Rstr & fmt, const char delimiter = '\n' ) { 139 fmt.delimiters[0] = delimiter; fmt.delimiters[1] = '\0'; fmt.flags.delimiter = true; fmt.flags.inex = true; return fmt; 140 } 141 _Istream_Rstr incl( const char scanset[], string_res & s ) { return (_Istream_Rstr)@{ &s, {{scanset}, -1, {.flags.inex : false}} }; } 142 _Istream_Rstr & incl( const char scanset[], _Istream_Rstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = false; return fmt; } 143 _Istream_Rstr excl( const char scanset[], string_res & s ) { return (_Istream_Rstr)@{ &s, {{scanset}, -1, {.flags.inex : true}} }; } 144 _Istream_Rstr & excl( const char scanset[], _Istream_Rstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = true; return fmt; } 145 _Istream_Rstr ignore( string_res & s ) { return (_Istream_Rstr)@{ &s, {{0p}, -1, {.flags.ignore : true}} }; } 146 _Istream_Rstr & ignore( _Istream_Rstr & fmt ) { fmt.flags.ignore = true; return fmt; } 147 // return (_Istream_Rstr)@{ { .s : &s, { {.delimiters : { delimiter, '\0' } }, .wd : -1, {.flags.delimiter : true} } } }; 148 return (_Istream_Rstr)@{ .s : &s, { {.delimiters : { delimiter, '\0' } }, .wd : -1, {.flags.delimiter : true} } }; 149 } 150 _Istream_Rstr & getline( _Istream_Rwidth & f, const char delimiter = '\n' ) { 151 f.delimiters[0] = delimiter; f.delimiters[1] = '\0'; f.flags.delimiter = true; return (_Istream_Rstr &)f; 152 } 153 _Istream_Rquoted quoted( string_res & s, const char Ldelimiter = '\"', const char Rdelimiter = '\0' ) { 154 return (_Istream_Rquoted)@{ { .s : &s, { {.delimiters : { Ldelimiter, Rdelimiter, '\0' }}, .wd : -1, {.flags.rwd : true} } } }; 155 } 156 _Istream_Rquoted & quoted( _Istream_Rwidth & f, const char Ldelimiter = '"', const char Rdelimiter = '\0' ) { 157 f.delimiters[0] = Ldelimiter; f.delimiters[1] = Rdelimiter; f.delimiters[2] = '\0'; 158 return (_Istream_Rquoted &)f; 159 } 160 _Istream_Rstr incl( const char scanset[], string_res & s ) { return (_Istream_Rstr)@{ .s : &s, { {.scanset : scanset}, .wd : -1, {.flags.inex : false} } }; } 161 _Istream_Rstr & incl( const char scanset[], _Istream_Rwidth & f ) { f.scanset = scanset; f.flags.inex = false; return (_Istream_Rstr &)f; } 162 _Istream_Rstr excl( const char scanset[], string_res & s ) { return (_Istream_Rstr)@{ .s : &s, { {.scanset : scanset}, .wd : -1, {.flags.inex : true} } }; } 163 _Istream_Rstr & excl( const char scanset[], _Istream_Rwidth & f ) { f.scanset = scanset; f.flags.inex = true; return (_Istream_Rstr &)f; } 164 _Istream_Rstr ignore( string_res & s ) { return (_Istream_Rstr)@{ .s : &s, { {.scanset : 0p}, .wd : -1, {.flags.ignore : true} } }; } 165 _Istream_Rstr & ignore( _Istream_Rwidth & f ) { f.flags.ignore = true; return (_Istream_Rstr &)f; } 166 _Istream_Rquoted & ignore( _Istream_Rquoted & f ) { f.rstr.flags.ignore = true; return (_Istream_Rquoted &)f; } 167 _Istream_Rstr & ignore( _Istream_Rstr & f ) { f.flags.ignore = true; return (_Istream_Rstr &)f; } 147 168 } // distribution 169 ifstream & ?|?( ifstream & is, _Istream_Rquoted f ); 148 170 ifstream & ?|?( ifstream & is, _Istream_Rstr f ); 149 void ?|?( ifstream & is, _Istream_Rstr t ); 171 static inline ifstream & ?|?( ifstream & is, _Istream_Rwidth f ) { return is | *(_Istream_Rstr *)&f; } 150 172 151 173 // Concatenation -
libcfa/src/fstream.cfa
ra22d148 r211def2 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Jan 28 09:56:08202413 // Update Count : 5 5412 // Last Modified On : Thu Feb 1 18:32:15 2024 13 // Update Count : 575 14 14 // 15 15 … … 121 121 } // for 122 122 if ( file == 0p ) { 123 throw (open_failure){ os };123 throwResume (open_failure){ os }; 124 124 // abort | IO_MSG "open output file \"" | name | "\"" | nl | strerror( errno ); 125 125 } // if … … 241 241 } // for 242 242 if ( file == 0p ) { 243 throw (open_failure){ is };243 throwResume (open_failure){ is }; 244 244 // abort | IO_MSG "open input file \"" | name | "\"" | nl | strerror( errno ); 245 245 } // if … … 295 295 va_start( args, format ); 296 296 297 int nargs ;297 int nargs, tmperrno; 298 298 for () { // no check for EINTR limit waiting for keyboard input 299 errno = 0;300 299 disable_interrupts(); 300 errno = 0; 301 301 nargs = vfscanf( (FILE *)(is.file$), format, args ); 302 tmperrno = errno; 302 303 enable_interrupts(); 303 304 if ( nargs != EOF || errno != EINTR ) break; // timer interrupt ? … … 308 309 } // if 309 310 } // if 311 if ( tmperrno == ERANGE ) throwResume ExceptionInst( data_range ); 310 312 va_end( args ); 311 313 return nargs; -
libcfa/src/iostream.cfa
ra22d148 r211def2 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Jan 28 11:58:54202413 // Update Count : 191 712 // Last Modified On : Wed Feb 7 22:19:59 2024 13 // Update Count : 1918 14 14 // 15 15 … … 988 988 fini: { 989 989 args = fmt( is, "%*[ \f\n\r\t\v]" ); // remove leading whitespace 990 990 if ( eof( is ) ) break fini; 991 991 char rfmt[4] = { delimiters[0], '%', 'n', '\0' }; 992 992 int len = 0; // may not be set in fmt 993 993 args = fmt( is, rfmt, &len ); // remove leading quote 994 994 if ( len == 0 || eof( is ) ) break fini; 995 995 996 996 // Change the remainder of the read into a getline by reseting the closing delimiter. -
libcfa/src/iostream.hfa
ra22d148 r211def2 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Jan 28 11:56:29202413 // Update Count : 7 3312 // Last Modified On : Tue Feb 6 18:35:54 2024 13 // Update Count : 743 14 14 // 15 15 … … 370 370 // *********************************** exceptions *********************************** 371 371 372 ExceptionDecl( cstring_length ); 373 ExceptionDecl( missing_data ); 372 ExceptionDecl( missing_data ); // read finds no appropriate data 373 ExceptionDecl( cstring_length ); // character string size exceeded 374 ExceptionDecl( data_range ); // value too large for numerical type 374 375 375 376 // *********************************** manipulators *********************************** … … 406 407 char * s; 407 408 inline _Istream_str_base; 408 }; // _Istream_C str409 }; // _Istream_Cwidth 409 410 410 411 // Restrict nesting of input manipulators to those combinations that make sense. 412 413 struct _Istream_Cquoted { 414 _Istream_Cwidth cstr; 415 }; // _Istream_Cquoted 411 416 412 417 struct _Istream_Cstr { … … 414 419 }; // _Istream_Cstr 415 420 416 struct _Istream_Cquoted {417 _Istream_Cwidth cstr;418 }; // _Istream_Cquoted419 420 421 static inline { 421 422 // width must include room for null terminator, (gcc) scanf does not allow a 0 width => wd > 1 (1 char and null) and rd > 0 (1 char); 422 423 _Istream_Cwidth wdi( unsigned int wd, char s[] ) { 423 if ( wd <= 1 ) throw (cstring_length){ &cstring_length_vt }; // minimum 1 character and null terminator424 if ( wd <= 1 ) throwResume ExceptionInst( cstring_length ); // minimum 1 character and null terminator 424 425 return (_Istream_Cwidth)@{ .s : s, { {.scanset : 0p}, .wd : wd, {.all : 0} } }; 425 426 } 426 427 _Istream_Cwidth wdi( unsigned int wd, unsigned int rwd, char s[] ) { 427 if ( wd <= 1 || wd <= rwd ) throw (cstring_length){ &cstring_length_vt }; // minimum 1 character, null terminator, plus subset428 if ( wd <= 1 || wd <= rwd ) throwResume ExceptionInst( cstring_length ); // minimum 1 character, null terminator, plus subset 428 429 return (_Istream_Cwidth)@{ .s : s, { {.scanset : 0p}, .wd : rwd, {.flags.rwd : true} } }; 430 } 431 _Istream_Cstr & getline( _Istream_Cwidth & f, const char delimiter = '\n' ) { 432 f.delimiters[0] = delimiter; f.delimiters[1] = '\0'; f.flags.delimiter = true; return (_Istream_Cstr &)f; 429 433 } 430 434 _Istream_Cquoted quoted( char & ch, const char Ldelimiter = '\'', const char Rdelimiter = '\0' ) { … … 435 439 return (_Istream_Cquoted &)f; 436 440 } 437 _Istream_Cstr & getline( _Istream_Cwidth & f, const char delimiter = '\n' ) {438 f.delimiters[0] = delimiter; f.delimiters[1] = '\0'; f.flags.delimiter = true; return (_Istream_Cstr &)f;439 }440 441 _Istream_Cstr & incl( const char scanset[], _Istream_Cwidth & f ) { f.scanset = scanset; f.flags.inex = false; return (_Istream_Cstr &)f; } 441 442 _Istream_Cstr & excl( const char scanset[], _Istream_Cwidth & f ) { f.scanset = scanset; f.flags.inex = true; return (_Istream_Cstr &)f; } 442 _Istream_Cstr ignore( const char s[] ) { return (_Istream_C width)@{ .s : (char *)s, { {.scanset : 0p}, .wd : -1, {.flags.ignore : true} } }; }443 _Istream_Cstr ignore( const char s[] ) { return (_Istream_Cstr)@{ { .s : (char *)s, { {.scanset : 0p}, .wd : -1, {.flags.ignore : true} } } }; } 443 444 _Istream_Cstr & ignore( _Istream_Cwidth & f ) { f.flags.ignore = true; return (_Istream_Cstr &)f; } 444 445 _Istream_Cquoted & ignore( _Istream_Cquoted & f ) { f.cstr.flags.ignore = true; return (_Istream_Cquoted &)f; } … … 450 451 istype & ?|?( istype & is, _Istream_Cquoted f ); 451 452 istype & ?|?( istype & is, _Istream_Cstr f ); 452 static inline { 453 istype & ?|?( istype & is, _Istream_Cwidth f ) { return is | *(_Istream_Cstr *)&f; } 454 } // distribution 453 static inline istype & ?|?( istype & is, _Istream_Cwidth f ) { return is | *(_Istream_Cstr *)&f; } 455 454 } // distribution 456 455
Note: See TracChangeset
for help on using the changeset viewer.