Changes in / [db1ebed:5235d49]
- Files:
-
- 19 added
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/Makefile.am
rdb1ebed r5235d49 63 63 containers/queueLockFree.hfa \ 64 64 containers/stackLockFree.hfa \ 65 containers/string_sharectx.hfa \ 65 66 containers/vector2.hfa \ 66 67 vec/vec.hfa \ -
libcfa/src/containers/string.cfa
rdb1ebed r5235d49 92 92 } 93 93 94 string ?=?(string & this, string other) {94 string & ?=?(string & this, string & other) { //// <---- straw man change 95 95 (*this.inner) = (*other.inner); 96 96 return this; -
libcfa/src/containers/string.hfa
rdb1ebed r5235d49 41 41 void ?=?(string &s, const string &other); 42 42 void ?=?(string &s, char other); 43 string ?=?(string &s, string other); // string tolerates memcpys; still saw calls to autogen44 43 string & ?=?(string &s, string &other); // surprising ret seems to help avoid calls to autogen 44 //string ?=?( string &, string ) = void; 45 45 void ^?{}(string &s); 46 46 -
libcfa/src/containers/string_res.cfa
rdb1ebed r5235d49 15 15 16 16 #include "string_res.hfa" 17 #include "string_sharectx.hfa" 18 17 19 #include <stdlib.hfa> // e.g. malloc 18 #include < string.h> // e.g. strlen20 #include <assert.h> 19 21 20 22 //######################### VbyteHeap "header" ######################### 21 22 23 24 25 26 27 28 29 // DON'T COMMIT:30 // #define VbyteDebug31 32 33 34 35 23 36 24 #ifdef VbyteDebug … … 54 42 55 43 56 static inlinevoid compaction( VbyteHeap & ); // compaction of the byte area57 static inline void garbage( VbyteHeap &); // garbage collect the byte area58 static inlinevoid extend( VbyteHeap &, int ); // extend the size of the byte area59 static inlinevoid reduce( VbyteHeap &, int ); // reduce the size of the byte area60 61 static inline void ?{}( VbyteHeap &, int = 1000 );62 static inlinevoid ^?{}( VbyteHeap & );63 static inline void ByteCopy( VbyteHeap &, char *, int, int, char *, int, int ); // copy a block of bytes from one location in the heap to another 64 static in line int ByteCmp( VbyteHeap &,char *, int, int, char *, int, int ); // compare 2 blocks of bytes65 static inlinechar *VbyteAlloc( VbyteHeap &, int ); // allocate a block bytes in the heap66 67 68 static inlinevoid AddThisAfter( HandleNode &, HandleNode & );69 static inlinevoid DeleteNode( HandleNode & );70 static inlinevoid MoveThisAfter( HandleNode &, const HandleNode & ); // move current handle after parameter handle44 static void compaction( VbyteHeap & ); // compaction of the byte area 45 static void garbage( VbyteHeap &, int ); // garbage collect the byte area 46 static void extend( VbyteHeap &, int ); // extend the size of the byte area 47 static void reduce( VbyteHeap &, int ); // reduce the size of the byte area 48 49 static void ?{}( VbyteHeap &, size_t = 1000 ); 50 static void ^?{}( VbyteHeap & ); 51 52 static int ByteCmp( char *, int, int, char *, int, int ); // compare 2 blocks of bytes 53 static char *VbyteAlloc( VbyteHeap &, int ); // allocate a block bytes in the heap 54 static char *VbyteTryAdjustLast( VbyteHeap &, int ); 55 56 static void AddThisAfter( HandleNode &, HandleNode & ); 57 static void DeleteNode( HandleNode & ); 58 static void MoveThisAfter( HandleNode &, const HandleNode & ); // move current handle after parameter handle 71 59 72 60 73 61 // Allocate the storage for the variable sized area and intialize the heap variables. 74 62 75 static inline void ?{}( VbyteHeap & this, int Size ) with(this) {63 static void ?{}( VbyteHeap & this, size_t Size ) with(this) { 76 64 #ifdef VbyteDebug 77 65 serr | "enter:VbyteHeap::VbyteHeap, this:" | &this | " Size:" | Size; … … 82 70 ExtVbyte = (void *)( StartVbyte + CurrSize ); 83 71 Header.flink = Header.blink = &Header; 72 Header.ulink = & this; 84 73 #ifdef VbyteDebug 85 74 HeaderPtr = &Header; … … 91 80 // Release the dynamically allocated storage for the byte area. 92 81 93 static inlinevoid ^?{}( VbyteHeap & this ) with(this) {82 static void ^?{}( VbyteHeap & this ) with(this) { 94 83 free( StartVbyte ); 95 84 } // ~VbyteHeap … … 102 91 // creator. 103 92 104 void ?{}( HandleNode & this ) with(this) {93 static void ?{}( HandleNode & this ) with(this) { 105 94 #ifdef VbyteDebug 106 95 serr | "enter:HandleNode::HandleNode, this:" | &this; … … 117 106 // collection. 118 107 119 void ?{}( HandleNode & this, VbyteHeap & vh ) with(this) {108 static void ?{}( HandleNode & this, VbyteHeap & vh ) with(this) { 120 109 #ifdef VbyteDebug 121 110 serr | "enter:HandleNode::HandleNode, this:" | &this; … … 123 112 s = 0; 124 113 lnth = 0; 114 ulink = &vh; 125 115 AddThisAfter( this, *vh.Header.blink ); 126 116 #ifdef VbyteDebug … … 133 123 // is the responsibility of the creator to destroy it. 134 124 135 void ^?{}( HandleNode & this ) with(this) {125 static void ^?{}( HandleNode & this ) with(this) { 136 126 #ifdef VbyteDebug 137 127 serr | "enter:HandleNode::~HandleNode, this:" | & this; … … 149 139 } // ~HandleNode 150 140 141 142 //######################### String Sharing Context ######################### 143 144 static string_sharectx * ambient_string_sharectx; // fickle top of stack 145 static string_sharectx default_string_sharectx = {NEW_SHARING}; // stable bottom of stack 146 147 void ?{}( string_sharectx & this, StringSharectx_Mode mode ) with( this ) { 148 (older){ ambient_string_sharectx }; 149 if ( mode == NEW_SHARING ) { 150 (activeHeap){ new( (size_t) 1000 ) }; 151 } else { 152 verify( mode == NO_SHARING ); 153 (activeHeap){ 0p }; 154 } 155 ambient_string_sharectx = & this; 156 } 157 158 void ^?{}( string_sharectx & this ) with( this ) { 159 if ( activeHeap ) delete( activeHeap ); 160 161 // unlink this from older-list starting from ambient_string_sharectx 162 // usually, this==ambient_string_sharectx and the loop runs zero times 163 string_sharectx *& c = ambient_string_sharectx; 164 while ( c != &this ) &c = &c->older; // find this 165 c = this.older; // unlink 166 } 167 151 168 //######################### String Resource ######################### 152 169 153 170 154 VbyteHeap HeapArea; 155 156 VbyteHeap * DEBUG_string_heap = & HeapArea; 171 VbyteHeap * DEBUG_string_heap() { 172 assert( ambient_string_sharectx->activeHeap && "No sharing context is active" ); 173 return ambient_string_sharectx->activeHeap; 174 } 157 175 158 176 size_t DEBUG_string_bytes_avail_until_gc( VbyteHeap * heap ) { … … 160 178 } 161 179 180 size_t DEBUG_string_bytes_in_heap( VbyteHeap * heap ) { 181 return heap->CurrSize; 182 } 183 162 184 const char * DEBUG_string_heap_start( VbyteHeap * heap ) { 163 185 return heap->StartVbyte; 164 186 } 165 166 187 167 188 // Returns the size of the string in bytes … … 187 208 // Store auto-newline state so it can be restored 188 209 bool anl = getANL$(out); 189 nlOff(out); 190 for (size_t i = 0; i < s.Handle.lnth; i++) { 191 // Need to re-apply on the last output operator, for whole-statement version 192 if (anl && i == s.Handle.lnth-1) nlOn(out); 193 out | s[i]; 194 } 195 return out; 210 if( s.Handle.lnth == 0 ) { 211 sout | ""; 212 } else { 213 nlOff(out); 214 for (size_t i = 0; i < s.Handle.lnth; i++) { 215 // Need to re-apply on the last output operator, for whole-statement version 216 if (anl && i == s.Handle.lnth-1) nlOn(out); 217 out | s[i]; 218 } 219 } 196 220 } 197 221 198 222 // Empty constructor 199 223 void ?{}(string_res &s) with(s) { 200 (Handle){ HeapArea }; 224 if( ambient_string_sharectx->activeHeap ) { 225 (Handle){ * ambient_string_sharectx->activeHeap }; 226 (shareEditSet_owns_ulink){ false }; 227 verify( Handle.s == 0p && Handle.lnth == 0 ); 228 } else { 229 (Handle){ * new( (size_t) 10 ) }; // TODO: can I lazily avoid allocating for empty string 230 (shareEditSet_owns_ulink){ true }; 231 Handle.s = Handle.ulink->StartVbyte; 232 verify( Handle.lnth == 0 ); 233 } 201 234 s.shareEditSet_prev = &s; 202 235 s.shareEditSet_next = &s; 203 236 } 204 237 205 // Constructor from a raw buffer and size 206 void ?{}(string_res &s, const char* rhs, size_t rhslnth) with(s) { 207 (Handle){ HeapArea }; 208 Handle.s = VbyteAlloc(HeapArea, rhslnth); 238 static void eagerCopyCtorHelper(string_res &s, const char* rhs, size_t rhslnth) with(s) { 239 if( ambient_string_sharectx->activeHeap ) { 240 (Handle){ * ambient_string_sharectx->activeHeap }; 241 (shareEditSet_owns_ulink){ false }; 242 } else { 243 (Handle){ * new( rhslnth ) }; 244 (shareEditSet_owns_ulink){ true }; 245 } 246 Handle.s = VbyteAlloc(*Handle.ulink, rhslnth); 209 247 Handle.lnth = rhslnth; 210 248 for ( int i = 0; i < rhslnth; i += 1 ) { // copy characters … … 215 253 } 216 254 217 // String literal constructor 218 void ?{}(string_res &s, const char* rhs) { 219 (s){ rhs, strlen(rhs) }; 255 // Constructor from a raw buffer and size 256 void ?{}(string_res &s, const char* rhs, size_t rhslnth) with(s) { 257 eagerCopyCtorHelper(s, rhs, rhslnth); 258 } 259 260 // private ctor (not in header): use specified heap (ignore ambient) and copy chars in 261 void ?{}( string_res &s, VbyteHeap & heap, const char* rhs, size_t rhslnth ) with(s) { 262 (Handle){ heap }; 263 Handle.s = VbyteAlloc(*Handle.ulink, rhslnth); 264 Handle.lnth = rhslnth; 265 (s.shareEditSet_owns_ulink){ false }; 266 for ( int i = 0; i < rhslnth; i += 1 ) { // copy characters 267 Handle.s[i] = rhs[i]; 268 } // for 269 s.shareEditSet_prev = &s; 270 s.shareEditSet_next = &s; 220 271 } 221 272 … … 223 274 void ?{}(string_res &s, const string_res & s2, StrResInitMode mode, size_t start, size_t end ) { 224 275 225 (s.Handle){ HeapArea }; 226 s.Handle.s = s2.Handle.s + start; 227 s.Handle.lnth = end - start; 228 MoveThisAfter(s.Handle, s2.Handle ); // insert this handle after rhs handle 229 // ^ bug? skip others at early point in string 230 231 if (mode == COPY_VALUE) { 232 // make s alone in its shareEditSet 233 s.shareEditSet_prev = &s; 234 s.shareEditSet_next = &s; 276 verify( start <= end && end <= s2.Handle.lnth ); 277 278 if (s2.Handle.ulink != ambient_string_sharectx->activeHeap && mode == COPY_VALUE) { 279 // crossing heaps (including private): copy eagerly 280 eagerCopyCtorHelper(s, s2.Handle.s + start, end - start); 281 verify(s.shareEditSet_prev == &s); 282 verify(s.shareEditSet_next == &s); 235 283 } else { 236 assert( mode == SHARE_EDITS ); 237 238 // s2 is logically const but not implementation const 239 string_res & s2mod = (string_res &) s2; 240 241 // insert s after s2 on shareEditSet 242 s.shareEditSet_next = s2mod.shareEditSet_next; 243 s.shareEditSet_prev = &s2mod; 244 s.shareEditSet_next->shareEditSet_prev = &s; 245 s.shareEditSet_prev->shareEditSet_next = &s; 246 } 247 } 248 249 void assign(string_res &this, const char* buffer, size_t bsize) { 250 251 // traverse the incumbent share-edit set (SES) to recover the range of a base string to which `this` belongs 252 string_res * shareEditSetStartPeer = & this; 253 string_res * shareEditSetEndPeer = & this; 254 for (string_res * editPeer = this.shareEditSet_next; editPeer != &this; editPeer = editPeer->shareEditSet_next) { 255 if ( editPeer->Handle.s < shareEditSetStartPeer->Handle.s ) { 256 shareEditSetStartPeer = editPeer; 284 (s.Handle){}; 285 s.Handle.s = s2.Handle.s + start; 286 s.Handle.lnth = end - start; 287 s.Handle.ulink = s2.Handle.ulink; 288 289 AddThisAfter(s.Handle, s2.Handle ); // insert this handle after rhs handle 290 // ^ bug? skip others at early point in string 291 292 if (mode == COPY_VALUE) { 293 verify(s2.Handle.ulink == ambient_string_sharectx->activeHeap); 294 // requested logical copy in same heap: defer copy until write 295 296 (s.shareEditSet_owns_ulink){ false }; 297 298 // make s alone in its shareEditSet 299 s.shareEditSet_prev = &s; 300 s.shareEditSet_next = &s; 301 } else { 302 verify( mode == SHARE_EDITS ); 303 // sharing edits with source forces same heap as source (ignore context) 304 305 (s.shareEditSet_owns_ulink){ s2.shareEditSet_owns_ulink }; 306 307 // s2 is logically const but not implementation const 308 string_res & s2mod = (string_res &) s2; 309 310 // insert s after s2 on shareEditSet 311 s.shareEditSet_next = s2mod.shareEditSet_next; 312 s.shareEditSet_prev = &s2mod; 313 s.shareEditSet_next->shareEditSet_prev = &s; 314 s.shareEditSet_prev->shareEditSet_next = &s; 257 315 } 258 if ( shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth < editPeer->Handle.s + editPeer->Handle.lnth) { 259 shareEditSetEndPeer = editPeer; 260 } 261 } 262 263 // full string is from start of shareEditSetStartPeer thru end of shareEditSetEndPeer 264 // `this` occurs in the middle of it, to be replaced 265 // build up the new text in `pasting` 266 267 string_res pasting = { 268 shareEditSetStartPeer->Handle.s, // start of SES 269 this.Handle.s - shareEditSetStartPeer->Handle.s }; // length of SES, before this 270 append( pasting, 271 buffer, // start of replacement for this 272 bsize ); // length of replacement for this 273 append( pasting, 274 this.Handle.s + this.Handle.lnth, // start of SES after this 275 shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - 276 (this.Handle.s + this.Handle.lnth) ); // length of SES, after this 277 278 // The above string building can trigger compaction. 279 // The reference points (that are arguments of the string building) may move during that building. 280 // From this point on, they are stable. 281 // So now, capture their values for use in the overlap cases, below. 282 // Do not factor these definitions with the arguments used above. 316 } 317 } 318 319 static void assignEditSet(string_res & this, string_res * shareEditSetStartPeer, string_res * shareEditSetEndPeer, 320 char * resultSesStart, 321 size_t resultSesLnth, 322 HandleNode * resultPadPosition, size_t bsize ) { 283 323 284 324 char * beforeBegin = shareEditSetStartPeer->Handle.s; … … 290 330 size_t oldLnth = this.Handle.lnth; 291 331 292 this.Handle.s = pasting.Handle.s+ beforeLen;332 this.Handle.s = resultSesStart + beforeLen; 293 333 this.Handle.lnth = bsize; 294 MoveThisAfter( this.Handle, pasting.Handle ); 334 if (resultPadPosition) 335 MoveThisAfter( this.Handle, *resultPadPosition ); 295 336 296 337 // adjust all substring string and handle locations, and check if any substring strings are outside the new base string 297 char *limit = pasting.Handle.s + pasting.Handle.lnth;338 char *limit = resultSesStart + resultSesLnth; 298 339 for (string_res * p = this.shareEditSet_next; p != &this; p = p->shareEditSet_next) { 299 assert(p->Handle.s >= beforeBegin);340 verify (p->Handle.s >= beforeBegin); 300 341 if ( p->Handle.s >= afterBegin ) { 301 assert( p->Handle.s <= afterBegin + afterLen );302 assert( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );342 verify ( p->Handle.s <= afterBegin + afterLen ); 343 verify ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen ); 303 344 // p starts after the edit 304 345 // take start and end as end-anchored … … 318 359 } else { 319 360 // p ends after the edit 320 assert( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );361 verify ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen ); 321 362 // take end as end-anchored 322 363 // stretch-shrink p according to the edit … … 326 367 // take start as start-anchored 327 368 size_t startOffsetFromStart = p->Handle.s - beforeBegin; 328 p->Handle.s = pasting.Handle.s+ startOffsetFromStart;369 p->Handle.s = resultSesStart + startOffsetFromStart; 329 370 } else { 330 assert( p->Handle.s < afterBegin );371 verify ( p->Handle.s < afterBegin ); 331 372 // p starts during the edit 332 assert( p->Handle.s + p->Handle.lnth >= beforeBegin + beforeLen );373 verify( p->Handle.s + p->Handle.lnth >= beforeBegin + beforeLen ); 333 374 if ( p->Handle.s + p->Handle.lnth < afterBegin ) { 334 375 // p ends during the edit; p does not include the last character replaced … … 344 385 } 345 386 } 346 MoveThisAfter( p->Handle, pasting.Handle ); // move substring handle to maintain sorted order by string position 347 } 348 } 349 350 void ?=?(string_res &s, const char* other) { 351 assign(s, other, strlen(other)); 352 } 353 354 void ?=?(string_res &s, char other) { 355 assign(s, &other, 1); 387 if (resultPadPosition) 388 MoveThisAfter( p->Handle, *resultPadPosition ); // move substring handle to maintain sorted order by string position 389 } 390 } 391 392 static string_res & assign_(string_res &this, const char* buffer, size_t bsize, const string_res & valSrc) { 393 394 // traverse the incumbent share-edit set (SES) to recover the range of a base string to which `this` belongs 395 string_res * shareEditSetStartPeer = & this; 396 string_res * shareEditSetEndPeer = & this; 397 for (string_res * editPeer = this.shareEditSet_next; editPeer != &this; editPeer = editPeer->shareEditSet_next) { 398 if ( editPeer->Handle.s < shareEditSetStartPeer->Handle.s ) { 399 shareEditSetStartPeer = editPeer; 400 } 401 if ( shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth < editPeer->Handle.s + editPeer->Handle.lnth) { 402 shareEditSetEndPeer = editPeer; 403 } 404 } 405 406 verify( shareEditSetEndPeer->Handle.s >= shareEditSetStartPeer->Handle.s ); 407 size_t origEditSetLength = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - shareEditSetStartPeer->Handle.s; 408 verify( origEditSetLength >= this.Handle.lnth ); 409 410 if ( this.shareEditSet_owns_ulink ) { // assigning to private context 411 // ok to overwrite old value within LHS 412 char * prefixStartOrig = shareEditSetStartPeer->Handle.s; 413 int prefixLen = this.Handle.s - prefixStartOrig; 414 char * suffixStartOrig = this.Handle.s + this.Handle.lnth; 415 int suffixLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - suffixStartOrig; 416 417 int delta = bsize - this.Handle.lnth; 418 if ( char * oldBytes = VbyteTryAdjustLast( *this.Handle.ulink, delta ) ) { 419 // growing: copy from old to new 420 char * dest = VbyteAlloc( *this.Handle.ulink, origEditSetLength + delta ); 421 char *destCursor = dest; memcpy(destCursor, prefixStartOrig, prefixLen); 422 destCursor += prefixLen; memcpy(destCursor, buffer , bsize ); 423 destCursor += bsize; memcpy(destCursor, suffixStartOrig, suffixLen); 424 assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer, 425 dest, 426 origEditSetLength + delta, 427 0p, bsize); 428 free( oldBytes ); 429 } else { 430 // room is already allocated in-place: bubble suffix and overwite middle 431 memmove( suffixStartOrig + delta, suffixStartOrig, suffixLen ); 432 memcpy( this.Handle.s, buffer, bsize ); 433 434 assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer, 435 shareEditSetStartPeer->Handle.s, 436 origEditSetLength + delta, 437 0p, bsize); 438 } 439 440 } else if ( // assigning to shared context 441 this.Handle.lnth == origEditSetLength && // overwriting entire run of SES 442 & valSrc && // sourcing from a managed string 443 valSrc.Handle.ulink == this.Handle.ulink ) { // sourcing from same heap 444 445 // SES's result will only use characters from the source string => reuse source 446 assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer, 447 valSrc.Handle.s, 448 valSrc.Handle.lnth, 449 &((string_res&)valSrc).Handle, bsize); 450 451 } else { 452 // overwriting a proper substring of some string: mash characters from old and new together (copy on write) 453 // OR we are importing characters: need to copy eagerly (can't refer to source) 454 455 // full string is from start of shareEditSetStartPeer thru end of shareEditSetEndPeer 456 // `this` occurs in the middle of it, to be replaced 457 // build up the new text in `pasting` 458 459 string_res pasting = { 460 * this.Handle.ulink, // maintain same heap, regardless of context 461 shareEditSetStartPeer->Handle.s, // start of SES 462 this.Handle.s - shareEditSetStartPeer->Handle.s }; // length of SES, before this 463 append( pasting, 464 buffer, // start of replacement for this 465 bsize ); // length of replacement for this 466 append( pasting, 467 this.Handle.s + this.Handle.lnth, // start of SES after this 468 shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - 469 (this.Handle.s + this.Handle.lnth) ); // length of SES, after this 470 471 // The above string building can trigger compaction. 472 // The reference points (that are arguments of the string building) may move during that building. 473 // From this point on, they are stable. 474 475 assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer, 476 pasting.Handle.s, 477 pasting.Handle.lnth, 478 &pasting.Handle, bsize); 479 } 480 481 return this; 482 } 483 484 string_res & assign(string_res &this, const char* buffer, size_t bsize) { 485 return assign_(this, buffer, bsize, *0p); 486 } 487 488 string_res & ?=?(string_res &s, char other) { 489 return assign(s, &other, 1); 356 490 } 357 491 358 492 // Copy assignment operator 359 void?=?(string_res & this, const string_res & rhs) with( this ) {360 assign(this, rhs.Handle.s, rhs.Handle.lnth);361 } 362 363 void?=?(string_res & this, string_res & rhs) with( this ) {493 string_res & ?=?(string_res & this, const string_res & rhs) with( this ) { 494 return assign_(this, rhs.Handle.s, rhs.Handle.lnth, rhs); 495 } 496 497 string_res & ?=?(string_res & this, string_res & rhs) with( this ) { 364 498 const string_res & rhs2 = rhs; 365 this = rhs2;499 return this = rhs2; 366 500 } 367 501 … … 374 508 s.shareEditSet_prev->shareEditSet_next = s.shareEditSet_next; 375 509 s.shareEditSet_next->shareEditSet_prev = s.shareEditSet_prev; 376 s.shareEditSet_next = &s; 377 s.shareEditSet_prev = &s; 510 // s.shareEditSet_next = &s; 511 // s.shareEditSet_prev = &s; 512 513 if (shareEditSet_owns_ulink && s.shareEditSet_next == &s) { // last one out 514 delete( s.Handle.ulink ); 515 } 378 516 } 379 517 … … 387 525 } 388 526 527 void assignAt(const string_res &s, size_t index, char val) { 528 string_res editZone = { s, SHARE_EDITS, index, index+1 }; 529 assign(editZone, &val, 1); 530 } 531 389 532 390 533 /////////////////////////////////////////////////////////////////// … … 392 535 393 536 void append(string_res &str1, const char * buffer, size_t bsize) { 394 size_t clnth = s ize(str1)+ bsize;395 if ( str1.Handle.s + s ize(str1)== buffer ) { // already juxtapose ?537 size_t clnth = str1.Handle.lnth + bsize; 538 if ( str1.Handle.s + str1.Handle.lnth == buffer ) { // already juxtapose ? 396 539 // no-op 397 540 } else { // must copy some text 398 if ( str1.Handle.s + s ize(str1) == VbyteAlloc(HeapArea, 0) ) { // str1 at end of string area ?399 VbyteAlloc( HeapArea, bsize); // create room for 2nd part at the end of string area541 if ( str1.Handle.s + str1.Handle.lnth == VbyteAlloc(*str1.Handle.ulink, 0) ) { // str1 at end of string area ? 542 VbyteAlloc( *str1.Handle.ulink, bsize ); // create room for 2nd part at the end of string area 400 543 } else { // copy the two parts 401 char * str1oldBuf = str1.Handle.s; 402 str1.Handle.s = VbyteAlloc( HeapArea, clnth ); 403 ByteCopy( HeapArea, str1.Handle.s, 0, str1.Handle.lnth, str1oldBuf, 0, str1.Handle.lnth); 544 char * str1newBuf = VbyteAlloc( *str1.Handle.ulink, clnth ); 545 char * str1oldBuf = str1.Handle.s; // must read after VbyteAlloc call in case it gs's 546 str1.Handle.s = str1newBuf; 547 memcpy( str1.Handle.s, str1oldBuf, str1.Handle.lnth ); 404 548 } // if 405 ByteCopy( HeapArea, str1.Handle.s, str1.Handle.lnth, bsize, (char*)buffer, 0, (int)bsize); 406 // VbyteHeap & this, char *Dst, int DstStart, int DstLnth, char *Src, int SrcStart, int SrcLnth 549 memcpy( str1.Handle.s + str1.Handle.lnth, buffer, bsize ); 407 550 } // if 408 551 str1.Handle.lnth = clnth; … … 417 560 } 418 561 419 void ?+=?(string_res &s, const char* other) {420 append( s, other, strlen(other) );421 }422 562 423 563 … … 429 569 430 570 bool ?==?(const string_res &s1, const string_res &s2) { 431 return ByteCmp( HeapArea,s1.Handle.s, 0, s1.Handle.lnth, s2.Handle.s, 0, s2.Handle.lnth) == 0;571 return ByteCmp( s1.Handle.s, 0, s1.Handle.lnth, s2.Handle.s, 0, s2.Handle.lnth) == 0; 432 572 } 433 573 … … 596 736 // Add a new HandleNode node n after the current HandleNode node. 597 737 598 static inlinevoid AddThisAfter( HandleNode & this, HandleNode & n ) with(this) {738 static void AddThisAfter( HandleNode & this, HandleNode & n ) with(this) { 599 739 #ifdef VbyteDebug 600 740 serr | "enter:AddThisAfter, this:" | &this | " n:" | &n; 601 741 #endif // VbyteDebug 742 verify( n.ulink != 0p ); 743 verify( this.ulink == n.ulink ); 602 744 flink = n.flink; 603 745 blink = &n; … … 624 766 // Delete the current HandleNode node. 625 767 626 static inlinevoid DeleteNode( HandleNode & this ) with(this) {768 static void DeleteNode( HandleNode & this ) with(this) { 627 769 #ifdef VbyteDebug 628 770 serr | "enter:DeleteNode, this:" | &this; … … 638 780 639 781 // Allocates specified storage for a string from byte-string area. If not enough space remains to perform the 640 // allocation, the garbage collection routine is called and a second attempt is made to allocate the space. If the 641 // second attempt fails, a further attempt is made to create a new, larger byte-string area. 642 643 static inline char * VbyteAlloc( VbyteHeap & this, int size ) with(this) { 782 // allocation, the garbage collection routine is called. 783 784 static char * VbyteAlloc( VbyteHeap & this, int size ) with(this) { 644 785 #ifdef VbyteDebug 645 786 serr | "enter:VbyteAlloc, size:" | size; … … 650 791 NoBytes = ( uintptr_t )EndVbyte + size; 651 792 if ( NoBytes > ( uintptr_t )ExtVbyte ) { // enough room for new byte-string ? 652 garbage( this ); // firer up the garbage collector 653 NoBytes = ( uintptr_t )EndVbyte + size; // try again 654 if ( NoBytes > ( uintptr_t )ExtVbyte ) { // enough room for new byte-string ? 655 assert( 0 && "need to implement actual growth" ); 656 // extend( size ); // extend the byte-string area 657 } // if 793 garbage( this, size ); // firer up the garbage collector 794 verify( (( uintptr_t )EndVbyte + size) <= ( uintptr_t )ExtVbyte && "garbage run did not free up required space" ); 658 795 } // if 659 796 r = EndVbyte; … … 666 803 667 804 805 // Adjusts the last allocation in this heap by delta bytes, or resets this heap to be able to offer 806 // new allocations of its original size + delta bytes. Positive delta means bigger; 807 // negative means smaller. A null return indicates that the original heap location has room for 808 // the requested growth. A non-null return indicates that copying to a new location is required 809 // but has not been done; the returned value is the old heap storage location; `this` heap is 810 // modified to reference the new location. In the copy-requred case, the caller should use 811 // VbyteAlloc to claim the new space, while doing optimal copying from old to new, then free old. 812 813 static char * VbyteTryAdjustLast( VbyteHeap & this, int delta ) with(this) { 814 815 if ( ( uintptr_t )EndVbyte + delta <= ( uintptr_t )ExtVbyte ) { 816 // room available 817 EndVbyte += delta; 818 return 0p; 819 } 820 821 char *oldBytes = StartVbyte; 822 823 NoOfExtensions += 1; 824 CurrSize *= 2; 825 StartVbyte = EndVbyte = alloc(CurrSize); 826 ExtVbyte = StartVbyte + CurrSize; 827 828 return oldBytes; 829 } 830 831 668 832 // Move an existing HandleNode node h somewhere after the current HandleNode node so that it is in ascending order by 669 833 // the address in the byte string area. 670 834 671 static inlinevoid MoveThisAfter( HandleNode & this, const HandleNode & h ) with(this) {835 static void MoveThisAfter( HandleNode & this, const HandleNode & h ) with(this) { 672 836 #ifdef VbyteDebug 673 837 serr | "enter:MoveThisAfter, this:" | & this | " h:" | & h; 674 838 #endif // VbyteDebug 839 verify( h.ulink != 0p ); 840 verify( this.ulink == h.ulink ); 675 841 if ( s < h.s ) { // check argument values 676 842 // serr | "VbyteSM: Error - Cannot move byte string starting at:" | s | " after byte string starting at:" 677 843 // | ( h->s ) | " and keep handles in ascending order"; 678 844 // exit(-1 ); 679 assert( 0 && "VbyteSM: Error - Cannot move byte strings as requested and keep handles in ascending order");845 verify( 0 && "VbyteSM: Error - Cannot move byte strings as requested and keep handles in ascending order"); 680 846 } // if 681 847 … … 709 875 //######################### VbyteHeap ######################### 710 876 711 // Move characters from one location in the byte-string area to another. The routine handles the following situations:712 //713 // if the |Src| > |Dst| => truncate714 // if the |Dst| > |Src| => pad Dst with blanks715 716 void ByteCopy( VbyteHeap & this, char *Dst, int DstStart, int DstLnth, char *Src, int SrcStart, int SrcLnth ) {717 for ( int i = 0; i < DstLnth; i += 1 ) {718 if ( i == SrcLnth ) { // |Dst| > |Src|719 for ( ; i < DstLnth; i += 1 ) { // pad Dst with blanks720 Dst[DstStart + i] = ' ';721 } // for722 break;723 } // exit724 Dst[DstStart + i] = Src[SrcStart + i];725 } // for726 } // ByteCopy727 728 877 // Compare two byte strings in the byte-string area. The routine returns the following values: 729 878 // … … 732 881 // -1 => Src1-byte-string < Src2-byte-string 733 882 734 int ByteCmp( VbyteHeap & this, char *Src1, int Src1Start, int Src1Lnth, char *Src2, int Src2Start, int Src2Lnth ) with(this){883 int ByteCmp( char *Src1, int Src1Start, int Src1Lnth, char *Src2, int Src2Start, int Src2Lnth ) { 735 884 #ifdef VbyteDebug 736 885 serr | "enter:ByteCmp, Src1Start:" | Src1Start | " Src1Lnth:" | Src1Lnth | " Src2Start:" | Src2Start | " Src2Lnth:" | Src2Lnth; … … 789 938 h = Header.flink; // ignore header node 790 939 for (;;) { 791 ByteCopy( this, EndVbyte, 0, h->lnth, h->s, 0, h->lnth );940 memmove( EndVbyte, h->s, h->lnth ); 792 941 obase = h->s; 793 942 h->s = EndVbyte; … … 813 962 // the heap. The heap is then compacted in the existing heap or into the newly allocated heap. 814 963 815 void garbage(VbyteHeap & this ) with(this) {964 void garbage(VbyteHeap & this, int minreq ) with(this) { 816 965 #ifdef VbyteDebug 817 966 serr | "enter:garbage"; … … 831 980 int AmountUsed, AmountFree; 832 981 982 // assert( false ); 983 833 984 AmountUsed = 0; 834 985 for ( HandleNode *i = Header.flink; i != &Header; i = i->flink ) { // calculate amount of byte area used … … 837 988 AmountFree = ( uintptr_t )ExtVbyte - ( uintptr_t )StartVbyte - AmountUsed; 838 989 839 if ( AmountFree < ( int )( CurrSize * 0.1 )) { // free space less than 10% ? 840 841 assert( 0 && "need to implement actual growth" ); 842 // extend( CurrSize ); // extend the heap 990 if ( ( double ) AmountFree < ( CurrSize * 0.1 ) || AmountFree < minreq ) { // free space less than 10% or not enough to serve cur request 991 992 extend( this, max( CurrSize, minreq ) ); // extend the heap 843 993 844 994 // Peter says, "This needs work before it should be used." … … 867 1017 #undef VbyteDebug 868 1018 869 //WIP870 #if 0871 1019 872 1020 … … 874 1022 // area is deleted. 875 1023 876 void VbyteHeap::extend( int size) {1024 void extend( VbyteHeap & this, int size ) with (this) { 877 1025 #ifdef VbyteDebug 878 1026 serr | "enter:extend, size:" | size; … … 884 1032 885 1033 CurrSize += size > InitSize ? size : InitSize; // minimum extension, initial size 886 StartVbyte = EndVbyte = new char[CurrSize];1034 StartVbyte = EndVbyte = alloc(CurrSize); 887 1035 ExtVbyte = (void *)( StartVbyte + CurrSize ); 888 compaction( ); // copy from old heap to new & adjust pointers to new heap889 delete OldStartVbyte; // release old heap1036 compaction(this); // copy from old heap to new & adjust pointers to new heap 1037 free( OldStartVbyte ); // release old heap 890 1038 #ifdef VbyteDebug 891 1039 serr | "exit:extend, CurrSize:" | CurrSize; … … 893 1041 } // extend 894 1042 1043 //WIP 1044 #if 0 895 1045 896 1046 // Extend the size of the byte-string area by creating a new area and copying the old area into it. The old byte-string -
libcfa/src/containers/string_res.hfa
rdb1ebed r5235d49 17 17 18 18 #include <fstream.hfa> 19 #include <string.h> // e.g. strlen 19 20 20 21 … … 27 28 HandleNode *flink; // forward link 28 29 HandleNode *blink; // backward link 30 VbyteHeap *ulink; // upward link 29 31 30 32 char *s; // pointer to byte string … … 32 34 }; // HandleNode 33 35 34 void ?{}( HandleNode & ); // constructor for header node 35 36 void ?{}( HandleNode &, VbyteHeap & ); // constructor for nodes in the handle list 37 void ^?{}( HandleNode & ); // destructor for handle nodes 38 39 extern VbyteHeap * DEBUG_string_heap; 36 VbyteHeap * DEBUG_string_heap(); 37 size_t DEBUG_string_bytes_in_heap( VbyteHeap * heap ); 40 38 size_t DEBUG_string_bytes_avail_until_gc( VbyteHeap * heap ); 41 39 const char * DEBUG_string_heap_start( VbyteHeap * heap ); … … 47 45 struct string_res { 48 46 HandleNode Handle; // chars, start, end, global neighbours 47 bool shareEditSet_owns_ulink; 49 48 string_res * shareEditSet_prev; 50 49 string_res * shareEditSet_next; … … 74 73 // Constructors, Assignment Operators, Destructor 75 74 void ?{}(string_res &s); // empty string 76 void ?{}(string_res &s, const char* initial); // copy from string literal (NULL-terminated)77 75 void ?{}(string_res &s, const char* buffer, size_t bsize); // copy specific length from buffer 76 static inline void ?{}(string_res &s, const char* rhs) { // copy from string literal (NULL-terminated) 77 (s){ rhs, strlen(rhs) }; 78 } 78 79 79 80 void ?{}(string_res &s, const string_res & s2) = void; … … 86 87 } 87 88 88 void assign(string_res &s, const char* buffer, size_t bsize); // copy specific length from buffer 89 void ?=?(string_res &s, const char* other); // copy from string literal (NULL-terminated) 90 void ?=?(string_res &s, const string_res &other); 91 void ?=?(string_res &s, string_res &other); 92 void ?=?(string_res &s, char other); 89 string_res & assign(string_res &s, const char* buffer, size_t bsize); // copy specific length from buffer 90 static inline string_res & ?=?(string_res &s, const char* other) { // copy from string literal (NULL-terminated) 91 return assign(s, other, strlen(other)); 92 } 93 string_res & ?=?(string_res &s, const string_res &other); 94 string_res & ?=?(string_res &s, string_res &other); 95 string_res & ?=?(string_res &s, char other); 93 96 94 97 void ^?{}(string_res &s); … … 99 102 100 103 // Concatenation 104 void append(string_res &s, const char* buffer, size_t bsize); 101 105 void ?+=?(string_res &s, char other); // append a character 102 106 void ?+=?(string_res &s, const string_res &s2); // append-concatenate to first string 103 void ?+=?(string_res &s, const char* other); 104 void append(string_res &s, const char* buffer, size_t bsize); 107 static inline void ?+=?(string_res &s, const char* other) { 108 append( s, other, strlen(other) ); 109 } 105 110 106 111 // Character access 112 void assignAt(const string_res &s, size_t index, char val); 107 113 char ?[?](const string_res &s, size_t index); // Mike changed to ret by val from Sunjay's ref, to match Peter's 108 114 //char codePointAt(const string_res &s, size_t index); // revisit under Unicode -
tests/collections/.expect/string-api-coverage.txt
rdb1ebed r5235d49 1 1 hello hello hello 2 3 hello 2 4 true false 3 5 true false -
tests/collections/.expect/string-gc.txt
rdb1ebed r5235d49 38 38 x from 5 to 15 39 39 y from 5 to 15 40 ======================== fillNoCompact 41 about to expand, a = aaa 42 expanded, a = aaa 43 about to expand, a = aaa 44 expanded, a = aaa 45 about to expand, a = aaa 46 expanded, a = aaa 47 about to expand, a = aaa 48 expanded, a = aaa 49 about to expand, a = aaa 50 expanded, a = aaa -
tests/collections/string-api-coverage.cfa
rdb1ebed r5235d49 1 1 #include <containers/string.hfa> 2 #include <string_sharectx.hfa> 2 3 3 4 void assertWellFormedHandleList( int maxLen ) { // with(HeapArea) … … 25 26 26 27 int main () { 28 29 #ifdef STRING_SHARING_OFF 30 string_sharectx c = { NO_SHARING }; 31 #endif 32 27 33 string s = "hello"; 28 34 string s2 = "hello"; … … 31 37 32 38 // IO operator, x2 33 sout | s | s | s; 39 sout | s | s | s; // hello hello hello 40 41 // empty ctor then assign 42 string sxx; 43 sout | sxx; // (blank line) 44 sxx = s; 45 sout | sxx; // hello 34 46 35 47 // Comparisons -
tests/collections/string-gc.cfa
rdb1ebed r5235d49 2 2 3 3 size_t bytesRemaining() { 4 return DEBUG_string_bytes_avail_until_gc( DEBUG_string_heap );4 return DEBUG_string_bytes_avail_until_gc( DEBUG_string_heap() ); 5 5 } 6 6 7 7 size_t heapOffsetStart( string_res & s ) { 8 const char * startByte = DEBUG_string_heap_start( DEBUG_string_heap );8 const char * startByte = DEBUG_string_heap_start( DEBUG_string_heap() ); 9 9 assert( s.Handle.s >= startByte ); 10 10 return s.Handle.s - startByte; … … 120 120 } 121 121 122 void fillNoCompact() { 123 // show that allocating in a heap filled with mostly live strings (no collectable garbage) causes heap growth 124 125 sout | "======================== fillNoCompact"; 126 127 size_t lastTimeBytesAvail = bytesRemaining(); 128 assert( lastTimeBytesAvail >= 200 ); // starting this test with nontrivial room 129 130 // mostly fill the pad 131 string_res a = "aaa"; // will have to be moved 132 string_res z = "zzz"; 133 for (i; 5) { 134 while ( bytesRemaining() > 10 ) { 135 z += "."; 136 } 137 sout | "about to expand, a = " | a; 138 while ( bytesRemaining() <= 10 ) { 139 z += "."; 140 } 141 sout | "expanded, a = " | a; 142 143 // each growth gives more usable space than the last 144 assert( bytesRemaining() > lastTimeBytesAvail ); 145 lastTimeBytesAvail = bytesRemaining(); 146 } 147 } 148 122 149 int main() { 123 150 basicFillCompact(); 124 151 fillCompact_withSharedEdits(); 152 fillNoCompact(); 125 153 } -
tests/collections/string-overwrite.cfa
rdb1ebed r5235d49 1 1 #include <containers/string.hfa> 2 #include <string_sharectx.hfa> 2 3 3 4 /* … … 11 12 WE = witness end 12 13 13 The dest does:14 The test does: 14 15 starts with the entire string being, initially, the alphabet; prints this entire alphabet 15 16 sets up modifier and witness as ranges within it, and prints a visualization of those ranges … … 24 25 This API's convention has Start positions being inclusive and end positions being exclusive. 25 26 27 v Case number in output 26 28 With 1 equivalence class: 27 29 MS = ME = WS = WE 1 … … 118 120 struct { int ms; int me; int ws; int we; char *replaceWith; char *label; } cases[] = { 119 121 { 12, 14, 10, 20, "xxxxx", "warmup" }, 120 // { 12, 14, 12, 14, "xxxxx", "" }, // the bug that got me into this test (should be a dup with case 6)121 122 { 10, 10, 10, 10, "=====", "1" }, 122 123 { 10, 10, 10, 10, "==" , "" }, … … 223 224 { 12, 14, 10, 16, "=" , "" }, 224 225 { 12, 14, 10, 16, "" , "" }, 225 /*226 { , , , , "=====", "NN" },227 { "==" , "" },228 { "=" , "" },229 { "" , "" },230 */231 226 }; 232 227 for ( i; sizeof(cases)/sizeof(cases[0]) ) { … … 238 233 239 234 240 // void f( string & s, string & toEdit ) {241 242 // sout | s | "|" | toEdit | "|";243 244 // s(14, 16) = "-";245 // sout | s | "|" | toEdit | "|";246 // }247 248 235 int main() { 236 237 #ifdef STRING_SHARING_OFF 238 string_sharectx c = { NO_SHARING }; 239 #endif 240 241 249 242 // 0 1 2 250 243 // 01234567890123456789012345
Note: See TracChangeset
for help on using the changeset viewer.