Changes in / [cc7bbe6:3a038fa]
- Files:
-
- 19 deleted
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/Makefile.am
rcc7bbe6 r3a038fa 63 63 containers/queueLockFree.hfa \ 64 64 containers/stackLockFree.hfa \ 65 containers/string_sharectx.hfa \66 65 containers/vector2.hfa \ 67 66 vec/vec.hfa \ -
libcfa/src/containers/string.cfa
rcc7bbe6 r3a038fa 92 92 } 93 93 94 string & ?=?(string & this, string & other) { //// <---- straw man change94 string ?=?(string & this, string other) { 95 95 (*this.inner) = (*other.inner); 96 96 return this; -
libcfa/src/containers/string.hfa
rcc7bbe6 r3a038fa 41 41 void ?=?(string &s, const string &other); 42 42 void ?=?(string &s, char other); 43 string & ?=?(string &s, string &other); // surprising ret seems to help avoid calls to autogen44 //string ?=?( string &, string ) = void; 43 string ?=?(string &s, string other); // string tolerates memcpys; still saw calls to autogen 44 45 45 void ^?{}(string &s); 46 46 -
libcfa/src/containers/string_res.cfa
rcc7bbe6 r3a038fa 15 15 16 16 #include "string_res.hfa" 17 #include "string_sharectx.hfa"18 19 17 #include <stdlib.hfa> // e.g. malloc 20 #include < assert.h>18 #include <string.h> // e.g. strlen 21 19 22 20 //######################### VbyteHeap "header" ######################### 21 22 23 24 25 26 27 28 29 // DON'T COMMIT: 30 // #define VbyteDebug 31 32 33 34 23 35 24 36 #ifdef VbyteDebug … … 42 54 43 55 44 static void compaction( VbyteHeap & ); // compaction of the byte area45 static void garbage( VbyteHeap &, int); // garbage collect the byte area46 static void extend( VbyteHeap &, int ); // extend the size of the byte area47 static void reduce( VbyteHeap &, int ); // reduce the size of the byte area48 49 static void ?{}( VbyteHeap &, size_t = 1000 );50 static void ^?{}( VbyteHeap & );51 52 static in t ByteCmp(char *, int, int, char *, int, int ); // compare 2 blocks of bytes53 static char *VbyteAlloc( VbyteHeap &, int ); // allocate a block bytes in the heap54 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 handle56 static inline void compaction( VbyteHeap & ); // compaction of the byte area 57 static inline void garbage( VbyteHeap & ); // garbage collect the byte area 58 static inline void extend( VbyteHeap &, int ); // extend the size of the byte area 59 static inline void reduce( VbyteHeap &, int ); // reduce the size of the byte area 60 61 static inline void ?{}( VbyteHeap &, int = 1000 ); 62 static inline void ^?{}( 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 inline int ByteCmp( VbyteHeap &, char *, int, int, char *, int, int ); // compare 2 blocks of bytes 65 static inline char *VbyteAlloc( VbyteHeap &, int ); // allocate a block bytes in the heap 66 67 68 static inline void AddThisAfter( HandleNode &, HandleNode & ); 69 static inline void DeleteNode( HandleNode & ); 70 static inline void MoveThisAfter( HandleNode &, const HandleNode & ); // move current handle after parameter handle 59 71 60 72 61 73 // Allocate the storage for the variable sized area and intialize the heap variables. 62 74 63 static void ?{}( VbyteHeap & this, size_t Size ) with(this) {75 static inline void ?{}( VbyteHeap & this, int Size ) with(this) { 64 76 #ifdef VbyteDebug 65 77 serr | "enter:VbyteHeap::VbyteHeap, this:" | &this | " Size:" | Size; … … 70 82 ExtVbyte = (void *)( StartVbyte + CurrSize ); 71 83 Header.flink = Header.blink = &Header; 72 Header.ulink = & this;73 84 #ifdef VbyteDebug 74 85 HeaderPtr = &Header; … … 80 91 // Release the dynamically allocated storage for the byte area. 81 92 82 static void ^?{}( VbyteHeap & this ) with(this) {93 static inline void ^?{}( VbyteHeap & this ) with(this) { 83 94 free( StartVbyte ); 84 95 } // ~VbyteHeap … … 91 102 // creator. 92 103 93 staticvoid ?{}( HandleNode & this ) with(this) {104 void ?{}( HandleNode & this ) with(this) { 94 105 #ifdef VbyteDebug 95 106 serr | "enter:HandleNode::HandleNode, this:" | &this; … … 106 117 // collection. 107 118 108 staticvoid ?{}( HandleNode & this, VbyteHeap & vh ) with(this) {119 void ?{}( HandleNode & this, VbyteHeap & vh ) with(this) { 109 120 #ifdef VbyteDebug 110 121 serr | "enter:HandleNode::HandleNode, this:" | &this; … … 112 123 s = 0; 113 124 lnth = 0; 114 ulink = &vh;115 125 AddThisAfter( this, *vh.Header.blink ); 116 126 #ifdef VbyteDebug … … 123 133 // is the responsibility of the creator to destroy it. 124 134 125 staticvoid ^?{}( HandleNode & this ) with(this) {135 void ^?{}( HandleNode & this ) with(this) { 126 136 #ifdef VbyteDebug 127 137 serr | "enter:HandleNode::~HandleNode, this:" | & this; … … 139 149 } // ~HandleNode 140 150 141 142 //######################### String Sharing Context #########################143 144 static string_sharectx * ambient_string_sharectx; // fickle top of stack145 static string_sharectx default_string_sharectx = {NEW_SHARING}; // stable bottom of stack146 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_sharectx162 // usually, this==ambient_string_sharectx and the loop runs zero times163 string_sharectx *& c = ambient_string_sharectx;164 while ( c != &this ) &c = &c->older; // find this165 c = this.older; // unlink166 }167 168 151 //######################### String Resource ######################### 169 152 170 153 171 VbyteHeap * DEBUG_string_heap() { 172 assert( ambient_string_sharectx->activeHeap && "No sharing context is active" ); 173 return ambient_string_sharectx->activeHeap; 174 } 154 VbyteHeap HeapArea; 155 156 VbyteHeap * DEBUG_string_heap = & HeapArea; 175 157 176 158 size_t DEBUG_string_bytes_avail_until_gc( VbyteHeap * heap ) { … … 178 160 } 179 161 180 size_t DEBUG_string_bytes_in_heap( VbyteHeap * heap ) {181 return heap->CurrSize;182 }183 184 162 const char * DEBUG_string_heap_start( VbyteHeap * heap ) { 185 163 return heap->StartVbyte; 186 164 } 165 187 166 188 167 // Returns the size of the string in bytes … … 208 187 // Store auto-newline state so it can be restored 209 188 bool anl = getANL$(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 } 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; 220 196 } 221 197 222 198 // Empty constructor 223 199 void ?{}(string_res &s) with(s) { 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 } 200 (Handle){ HeapArea }; 234 201 s.shareEditSet_prev = &s; 235 202 s.shareEditSet_next = &s; 236 203 } 237 204 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); 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); 247 209 Handle.lnth = rhslnth; 248 210 for ( int i = 0; i < rhslnth; i += 1 ) { // copy characters … … 253 215 } 254 216 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; 217 // String literal constructor 218 void ?{}(string_res &s, const char* rhs) { 219 (s){ rhs, strlen(rhs) }; 271 220 } 272 221 … … 274 223 void ?{}(string_res &s, const string_res & s2, StrResInitMode mode, size_t start, size_t end ) { 275 224 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); 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; 283 235 } else { 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; 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; 315 257 } 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 ) { 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. 323 283 324 284 char * beforeBegin = shareEditSetStartPeer->Handle.s; … … 330 290 size_t oldLnth = this.Handle.lnth; 331 291 332 this.Handle.s = resultSesStart+ beforeLen;292 this.Handle.s = pasting.Handle.s + beforeLen; 333 293 this.Handle.lnth = bsize; 334 if (resultPadPosition) 335 MoveThisAfter( this.Handle, *resultPadPosition ); 294 MoveThisAfter( this.Handle, pasting.Handle ); 336 295 337 296 // adjust all substring string and handle locations, and check if any substring strings are outside the new base string 338 char *limit = resultSesStart + resultSesLnth;297 char *limit = pasting.Handle.s + pasting.Handle.lnth; 339 298 for (string_res * p = this.shareEditSet_next; p != &this; p = p->shareEditSet_next) { 340 verify(p->Handle.s >= beforeBegin);299 assert (p->Handle.s >= beforeBegin); 341 300 if ( p->Handle.s >= afterBegin ) { 342 verify( p->Handle.s <= afterBegin + afterLen );343 verify( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );301 assert ( p->Handle.s <= afterBegin + afterLen ); 302 assert ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen ); 344 303 // p starts after the edit 345 304 // take start and end as end-anchored … … 359 318 } else { 360 319 // p ends after the edit 361 verify( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );320 assert ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen ); 362 321 // take end as end-anchored 363 322 // stretch-shrink p according to the edit … … 367 326 // take start as start-anchored 368 327 size_t startOffsetFromStart = p->Handle.s - beforeBegin; 369 p->Handle.s = resultSesStart+ startOffsetFromStart;328 p->Handle.s = pasting.Handle.s + startOffsetFromStart; 370 329 } else { 371 verify( p->Handle.s < afterBegin );330 assert ( p->Handle.s < afterBegin ); 372 331 // p starts during the edit 373 verify( p->Handle.s + p->Handle.lnth >= beforeBegin + beforeLen );332 assert( p->Handle.s + p->Handle.lnth >= beforeBegin + beforeLen ); 374 333 if ( p->Handle.s + p->Handle.lnth < afterBegin ) { 375 334 // p ends during the edit; p does not include the last character replaced … … 385 344 } 386 345 } 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); 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); 490 356 } 491 357 492 358 // Copy assignment operator 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 ) {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 ) { 498 364 const string_res & rhs2 = rhs; 499 returnthis = rhs2;365 this = rhs2; 500 366 } 501 367 … … 508 374 s.shareEditSet_prev->shareEditSet_next = s.shareEditSet_next; 509 375 s.shareEditSet_next->shareEditSet_prev = s.shareEditSet_prev; 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 } 376 s.shareEditSet_next = &s; 377 s.shareEditSet_prev = &s; 516 378 } 517 379 … … 525 387 } 526 388 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 532 389 533 390 /////////////////////////////////////////////////////////////////// … … 535 392 536 393 void append(string_res &str1, const char * buffer, size_t bsize) { 537 size_t clnth = s tr1.Handle.lnth+ bsize;538 if ( str1.Handle.s + s tr1.Handle.lnth== buffer ) { // already juxtapose ?394 size_t clnth = size(str1) + bsize; 395 if ( str1.Handle.s + size(str1) == buffer ) { // already juxtapose ? 539 396 // no-op 540 397 } else { // must copy some text 541 if ( str1.Handle.s + s tr1.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 area398 if ( str1.Handle.s + size(str1) == VbyteAlloc(HeapArea, 0) ) { // str1 at end of string area ? 399 VbyteAlloc(HeapArea, bsize); // create room for 2nd part at the end of string area 543 400 } else { // copy the two parts 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 ); 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); 548 404 } // if 549 memcpy( str1.Handle.s + str1.Handle.lnth, buffer, bsize ); 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 550 407 } // if 551 408 str1.Handle.lnth = clnth; … … 560 417 } 561 418 419 void ?+=?(string_res &s, const char* other) { 420 append( s, other, strlen(other) ); 421 } 562 422 563 423 … … 569 429 570 430 bool ?==?(const string_res &s1, const string_res &s2) { 571 return ByteCmp( s1.Handle.s, 0, s1.Handle.lnth, s2.Handle.s, 0, s2.Handle.lnth) == 0;431 return ByteCmp( HeapArea, s1.Handle.s, 0, s1.Handle.lnth, s2.Handle.s, 0, s2.Handle.lnth) == 0; 572 432 } 573 433 … … 736 596 // Add a new HandleNode node n after the current HandleNode node. 737 597 738 static void AddThisAfter( HandleNode & this, HandleNode & n ) with(this) {598 static inline void AddThisAfter( HandleNode & this, HandleNode & n ) with(this) { 739 599 #ifdef VbyteDebug 740 600 serr | "enter:AddThisAfter, this:" | &this | " n:" | &n; 741 601 #endif // VbyteDebug 742 verify( n.ulink != 0p );743 verify( this.ulink == n.ulink );744 602 flink = n.flink; 745 603 blink = &n; … … 766 624 // Delete the current HandleNode node. 767 625 768 static void DeleteNode( HandleNode & this ) with(this) {626 static inline void DeleteNode( HandleNode & this ) with(this) { 769 627 #ifdef VbyteDebug 770 628 serr | "enter:DeleteNode, this:" | &this; … … 780 638 781 639 // Allocates specified storage for a string from byte-string area. If not enough space remains to perform the 782 // allocation, the garbage collection routine is called. 783 784 static char * VbyteAlloc( VbyteHeap & this, int size ) with(this) { 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) { 785 644 #ifdef VbyteDebug 786 645 serr | "enter:VbyteAlloc, size:" | size; … … 791 650 NoBytes = ( uintptr_t )EndVbyte + size; 792 651 if ( NoBytes > ( uintptr_t )ExtVbyte ) { // enough room for new byte-string ? 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" ); 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 795 658 } // if 796 659 r = EndVbyte; … … 803 666 804 667 805 // Adjusts the last allocation in this heap by delta bytes, or resets this heap to be able to offer806 // 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 for808 // the requested growth. A non-null return indicates that copying to a new location is required809 // but has not been done; the returned value is the old heap storage location; `this` heap is810 // modified to reference the new location. In the copy-requred case, the caller should use811 // 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 available817 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 832 668 // Move an existing HandleNode node h somewhere after the current HandleNode node so that it is in ascending order by 833 669 // the address in the byte string area. 834 670 835 static void MoveThisAfter( HandleNode & this, const HandleNode & h ) with(this) {671 static inline void MoveThisAfter( HandleNode & this, const HandleNode & h ) with(this) { 836 672 #ifdef VbyteDebug 837 673 serr | "enter:MoveThisAfter, this:" | & this | " h:" | & h; 838 674 #endif // VbyteDebug 839 verify( h.ulink != 0p );840 verify( this.ulink == h.ulink );841 675 if ( s < h.s ) { // check argument values 842 676 // serr | "VbyteSM: Error - Cannot move byte string starting at:" | s | " after byte string starting at:" 843 677 // | ( h->s ) | " and keep handles in ascending order"; 844 678 // exit(-1 ); 845 verify( 0 && "VbyteSM: Error - Cannot move byte strings as requested and keep handles in ascending order");679 assert( 0 && "VbyteSM: Error - Cannot move byte strings as requested and keep handles in ascending order"); 846 680 } // if 847 681 … … 875 709 //######################### VbyteHeap ######################### 876 710 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| => truncate 714 // if the |Dst| > |Src| => pad Dst with blanks 715 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 blanks 720 Dst[DstStart + i] = ' '; 721 } // for 722 break; 723 } // exit 724 Dst[DstStart + i] = Src[SrcStart + i]; 725 } // for 726 } // ByteCopy 727 877 728 // Compare two byte strings in the byte-string area. The routine returns the following values: 878 729 // … … 881 732 // -1 => Src1-byte-string < Src2-byte-string 882 733 883 int ByteCmp( char *Src1, int Src1Start, int Src1Lnth, char *Src2, int Src2Start, int Src2Lnth ){734 int ByteCmp( VbyteHeap & this, char *Src1, int Src1Start, int Src1Lnth, char *Src2, int Src2Start, int Src2Lnth ) with(this) { 884 735 #ifdef VbyteDebug 885 736 serr | "enter:ByteCmp, Src1Start:" | Src1Start | " Src1Lnth:" | Src1Lnth | " Src2Start:" | Src2Start | " Src2Lnth:" | Src2Lnth; … … 938 789 h = Header.flink; // ignore header node 939 790 for (;;) { 940 memmove( EndVbyte, h->s, h->lnth );791 ByteCopy( this, EndVbyte, 0, h->lnth, h->s, 0, h->lnth ); 941 792 obase = h->s; 942 793 h->s = EndVbyte; … … 962 813 // the heap. The heap is then compacted in the existing heap or into the newly allocated heap. 963 814 964 void garbage(VbyteHeap & this , int minreq) with(this) {815 void garbage(VbyteHeap & this ) with(this) { 965 816 #ifdef VbyteDebug 966 817 serr | "enter:garbage"; … … 986 837 AmountFree = ( uintptr_t )ExtVbyte - ( uintptr_t )StartVbyte - AmountUsed; 987 838 988 if ( ( double ) AmountFree < ( CurrSize * 0.1 ) || AmountFree < minreq ) { // free space less than 10% or not enough to serve cur request 989 990 extend( this, max( CurrSize, minreq ) ); // extend the heap 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 991 843 992 844 // Peter says, "This needs work before it should be used." … … 994 846 // reduce(( AmountFree / CurrSize - 3 ) * CurrSize ); // reduce the memory 995 847 996 // `extend` implies a `compaction` during the copy 997 998 } else { 999 compaction(this); // in-place 1000 }// if 848 } // if 849 compaction(this); // compact the byte area, in the same or new heap area 1001 850 #ifdef VbyteDebug 1002 851 { … … 1018 867 #undef VbyteDebug 1019 868 869 //WIP 870 #if 0 1020 871 1021 872 … … 1023 874 // area is deleted. 1024 875 1025 void extend( VbyteHeap & this, int size ) with (this) {876 void VbyteHeap::extend( int size ) { 1026 877 #ifdef VbyteDebug 1027 878 serr | "enter:extend, size:" | size; … … 1033 884 1034 885 CurrSize += size > InitSize ? size : InitSize; // minimum extension, initial size 1035 StartVbyte = EndVbyte = alloc(CurrSize);886 StartVbyte = EndVbyte = new char[CurrSize]; 1036 887 ExtVbyte = (void *)( StartVbyte + CurrSize ); 1037 compaction( this); // copy from old heap to new & adjust pointers to new heap1038 free( OldStartVbyte ); // release old heap888 compaction(); // copy from old heap to new & adjust pointers to new heap 889 delete OldStartVbyte; // release old heap 1039 890 #ifdef VbyteDebug 1040 891 serr | "exit:extend, CurrSize:" | CurrSize; … … 1042 893 } // extend 1043 894 1044 //WIP1045 #if 01046 895 1047 896 // 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
rcc7bbe6 r3a038fa 17 17 18 18 #include <fstream.hfa> 19 #include <string.h> // e.g. strlen20 19 21 20 … … 28 27 HandleNode *flink; // forward link 29 28 HandleNode *blink; // backward link 30 VbyteHeap *ulink; // upward link31 29 32 30 char *s; // pointer to byte string … … 34 32 }; // HandleNode 35 33 36 VbyteHeap * DEBUG_string_heap(); 37 size_t DEBUG_string_bytes_in_heap( VbyteHeap * heap ); 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; 38 40 size_t DEBUG_string_bytes_avail_until_gc( VbyteHeap * heap ); 39 41 const char * DEBUG_string_heap_start( VbyteHeap * heap ); … … 45 47 struct string_res { 46 48 HandleNode Handle; // chars, start, end, global neighbours 47 bool shareEditSet_owns_ulink;48 49 string_res * shareEditSet_prev; 49 50 string_res * shareEditSet_next; … … 73 74 // Constructors, Assignment Operators, Destructor 74 75 void ?{}(string_res &s); // empty string 76 void ?{}(string_res &s, const char* initial); // copy from string literal (NULL-terminated) 75 77 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 }79 78 80 79 void ?{}(string_res &s, const string_res & s2) = void; … … 87 86 } 88 87 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); 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); 96 93 97 94 void ^?{}(string_res &s); … … 102 99 103 100 // Concatenation 104 void append(string_res &s, const char* buffer, size_t bsize);105 101 void ?+=?(string_res &s, char other); // append a character 106 102 void ?+=?(string_res &s, const string_res &s2); // append-concatenate to first string 107 static inline void ?+=?(string_res &s, const char* other) { 108 append( s, other, strlen(other) ); 109 } 103 void ?+=?(string_res &s, const char* other); 104 void append(string_res &s, const char* buffer, size_t bsize); 110 105 111 106 // Character access 112 void assignAt(const string_res &s, size_t index, char val);113 107 char ?[?](const string_res &s, size_t index); // Mike changed to ret by val from Sunjay's ref, to match Peter's 114 108 //char codePointAt(const string_res &s, size_t index); // revisit under Unicode -
tests/collections/.expect/string-api-coverage.txt
rcc7bbe6 r3a038fa 1 1 hello hello hello 2 3 hello4 2 true false 5 3 true false -
tests/collections/.expect/string-gc.txt
rcc7bbe6 r3a038fa 38 38 x from 5 to 15 39 39 y from 5 to 15 40 ======================== fillNoCompact41 about to expand, a = aaa42 expanded, a = aaa43 about to expand, a = aaa44 expanded, a = aaa45 about to expand, a = aaa46 expanded, a = aaa47 about to expand, a = aaa48 expanded, a = aaa49 about to expand, a = aaa50 expanded, a = aaa -
tests/collections/string-api-coverage.cfa
rcc7bbe6 r3a038fa 1 1 #include <containers/string.hfa> 2 #include <string_sharectx.hfa>3 2 4 3 void assertWellFormedHandleList( int maxLen ) { // with(HeapArea) … … 26 25 27 26 int main () { 28 29 #ifdef STRING_SHARING_OFF30 string_sharectx c = { NO_SHARING };31 #endif32 33 27 string s = "hello"; 34 28 string s2 = "hello"; … … 37 31 38 32 // IO operator, x2 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 33 sout | s | s | s; 46 34 47 35 // Comparisons -
tests/collections/string-gc.cfa
rcc7bbe6 r3a038fa 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 growth124 125 sout | "======================== fillNoCompact";126 127 size_t lastTimeBytesAvail = bytesRemaining();128 assert( lastTimeBytesAvail >= 200 ); // starting this test with nontrivial room129 130 // mostly fill the pad131 string_res a = "aaa"; // will have to be moved132 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 last144 assert( bytesRemaining() > lastTimeBytesAvail );145 lastTimeBytesAvail = bytesRemaining();146 }147 }148 149 122 int main() { 150 123 basicFillCompact(); 151 124 fillCompact_withSharedEdits(); 152 fillNoCompact();153 125 } -
tests/collections/string-overwrite.cfa
rcc7bbe6 r3a038fa 1 1 #include <containers/string.hfa> 2 #include <string_sharectx.hfa>3 2 4 3 /* … … 12 11 WE = witness end 13 12 14 The test does:13 The dest does: 15 14 starts with the entire string being, initially, the alphabet; prints this entire alphabet 16 15 sets up modifier and witness as ranges within it, and prints a visualization of those ranges … … 25 24 This API's convention has Start positions being inclusive and end positions being exclusive. 26 25 27 v Case number in output28 26 With 1 equivalence class: 29 27 MS = ME = WS = WE 1 … … 120 118 struct { int ms; int me; int ws; int we; char *replaceWith; char *label; } cases[] = { 121 119 { 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) 122 121 { 10, 10, 10, 10, "=====", "1" }, 123 122 { 10, 10, 10, 10, "==" , "" }, … … 224 223 { 12, 14, 10, 16, "=" , "" }, 225 224 { 12, 14, 10, 16, "" , "" }, 225 /* 226 { , , , , "=====", "NN" }, 227 { "==" , "" }, 228 { "=" , "" }, 229 { "" , "" }, 230 */ 226 231 }; 227 232 for ( i; sizeof(cases)/sizeof(cases[0]) ) { … … 233 238 234 239 240 // void f( string & s, string & toEdit ) { 241 242 // sout | s | "|" | toEdit | "|"; 243 244 // s(14, 16) = "-"; 245 // sout | s | "|" | toEdit | "|"; 246 // } 247 235 248 int main() { 236 237 #ifdef STRING_SHARING_OFF238 string_sharectx c = { NO_SHARING };239 #endif240 241 242 249 // 0 1 2 243 250 // 01234567890123456789012345
Note:
See TracChangeset
for help on using the changeset viewer.