- File:
-
- 1 edited
-
libcfa/src/containers/string_res.cfa (modified) (38 diffs)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/containers/string_res.cfa
r08ed947 r6cc87c0 15 15 16 16 #include "string_res.hfa" 17 #include "string_sharectx.hfa" 18 #include "stdlib.hfa" 19 20 // Workaround for observed performance penalty from calling CFA's alloc. 21 // Workaround is: EndVbyte = TEMP_ALLOC(char, CurrSize) 22 // Should be: EndVbyte = alloc(CurrSize) 23 #define TEMP_ALLOC(T, n) (( T* ) malloc( n * sizeof( T ) )) 24 25 #include <assert.h> 17 #include <stdlib.hfa> // e.g. malloc 18 #include <string.h> // e.g. strlen 26 19 27 20 //######################### VbyteHeap "header" ######################### 21 22 23 24 25 26 27 28 29 // DON'T COMMIT: 30 // #define VbyteDebug 31 32 33 34 28 35 29 36 #ifdef VbyteDebug … … 47 54 48 55 49 static void compaction( VbyteHeap & ); // compaction of the byte area50 static void garbage( VbyteHeap &, int); // garbage collect the byte area51 static void extend( VbyteHeap &, int ); // extend the size of the byte area52 static void reduce( VbyteHeap &, int ); // reduce the size of the byte area53 54 static void ?{}( VbyteHeap &, size_t = 1000 );55 static void ^?{}( VbyteHeap & );56 57 static in t ByteCmp(char *, int, int, char *, int, int ); // compare 2 blocks of bytes58 static char *VbyteAlloc( VbyteHeap &, int ); // allocate a block bytes in the heap59 static char *VbyteTryAdjustLast( VbyteHeap &, int ); 60 61 static void AddThisAfter( HandleNode &, HandleNode & );62 static void DeleteNode( HandleNode & );63 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 64 71 65 72 66 73 // Allocate the storage for the variable sized area and intialize the heap variables. 67 74 68 static void ?{}( VbyteHeap & this, size_t Size ) with(this) {75 static inline void ?{}( VbyteHeap & this, int Size ) with(this) { 69 76 #ifdef VbyteDebug 70 77 serr | "enter:VbyteHeap::VbyteHeap, this:" | &this | " Size:" | Size; … … 72 79 NoOfCompactions = NoOfExtensions = NoOfReductions = 0; 73 80 InitSize = CurrSize = Size; 74 StartVbyte = EndVbyte = TEMP_ALLOC(char,CurrSize);81 StartVbyte = EndVbyte = alloc(CurrSize); 75 82 ExtVbyte = (void *)( StartVbyte + CurrSize ); 76 83 Header.flink = Header.blink = &Header; 77 Header.ulink = & this;78 84 #ifdef VbyteDebug 79 85 HeaderPtr = &Header; … … 85 91 // Release the dynamically allocated storage for the byte area. 86 92 87 static void ^?{}( VbyteHeap & this ) with(this) {93 static inline void ^?{}( VbyteHeap & this ) with(this) { 88 94 free( StartVbyte ); 89 95 } // ~VbyteHeap … … 96 102 // creator. 97 103 98 staticvoid ?{}( HandleNode & this ) with(this) {104 void ?{}( HandleNode & this ) with(this) { 99 105 #ifdef VbyteDebug 100 106 serr | "enter:HandleNode::HandleNode, this:" | &this; … … 111 117 // collection. 112 118 113 staticvoid ?{}( HandleNode & this, VbyteHeap & vh ) with(this) {119 void ?{}( HandleNode & this, VbyteHeap & vh ) with(this) { 114 120 #ifdef VbyteDebug 115 121 serr | "enter:HandleNode::HandleNode, this:" | &this; … … 117 123 s = 0; 118 124 lnth = 0; 119 ulink = &vh;120 125 AddThisAfter( this, *vh.Header.blink ); 121 126 #ifdef VbyteDebug … … 128 133 // is the responsibility of the creator to destroy it. 129 134 130 staticvoid ^?{}( HandleNode & this ) with(this) {135 void ^?{}( HandleNode & this ) with(this) { 131 136 #ifdef VbyteDebug 132 137 serr | "enter:HandleNode::~HandleNode, this:" | & this; … … 144 149 } // ~HandleNode 145 150 146 147 //######################### String Sharing Context #########################148 149 static string_sharectx * ambient_string_sharectx; // fickle top of stack150 static string_sharectx default_string_sharectx = {NEW_SHARING}; // stable bottom of stack151 152 void ?{}( string_sharectx & this, StringSharectx_Mode mode ) with( this ) {153 (older){ ambient_string_sharectx };154 if ( mode == NEW_SHARING ) {155 (activeHeap){ new( (size_t) 1000 ) };156 } else {157 verify( mode == NO_SHARING );158 (activeHeap){ 0p };159 }160 ambient_string_sharectx = & this;161 }162 163 void ^?{}( string_sharectx & this ) with( this ) {164 if ( activeHeap ) delete( activeHeap );165 166 // unlink this from older-list starting from ambient_string_sharectx167 // usually, this==ambient_string_sharectx and the loop runs zero times168 string_sharectx *& c = ambient_string_sharectx;169 while ( c != &this ) &c = &c->older; // find this170 c = this.older; // unlink171 }172 173 151 //######################### String Resource ######################### 174 152 175 153 176 VbyteHeap * DEBUG_string_heap() { 177 assert( ambient_string_sharectx->activeHeap && "No sharing context is active" ); 178 return ambient_string_sharectx->activeHeap; 179 } 154 VbyteHeap HeapArea; 155 156 VbyteHeap * DEBUG_string_heap = & HeapArea; 180 157 181 158 size_t DEBUG_string_bytes_avail_until_gc( VbyteHeap * heap ) { … … 183 160 } 184 161 185 size_t DEBUG_string_bytes_in_heap( VbyteHeap * heap ) {186 return heap->CurrSize;187 }188 189 162 const char * DEBUG_string_heap_start( VbyteHeap * heap ) { 190 163 return heap->StartVbyte; 191 164 } 165 192 166 193 167 // Returns the size of the string in bytes … … 213 187 // Store auto-newline state so it can be restored 214 188 bool anl = getANL$(out); 215 if( s.Handle.lnth == 0 ) { 216 sout | ""; 217 } else { 218 nlOff(out); 219 for (size_t i = 0; i < s.Handle.lnth; i++) { 220 // Need to re-apply on the last output operator, for whole-statement version 221 if (anl && i == s.Handle.lnth-1) nlOn(out); 222 out | s[i]; 223 } 224 } 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; 225 196 } 226 197 227 198 // Empty constructor 228 199 void ?{}(string_res &s) with(s) { 229 if( ambient_string_sharectx->activeHeap ) { 230 (Handle){ * ambient_string_sharectx->activeHeap }; 231 (shareEditSet_owns_ulink){ false }; 232 verify( Handle.s == 0p && Handle.lnth == 0 ); 233 } else { 234 (Handle){ * new( (size_t) 10 ) }; // TODO: can I lazily avoid allocating for empty string 235 (shareEditSet_owns_ulink){ true }; 236 Handle.s = Handle.ulink->StartVbyte; 237 verify( Handle.lnth == 0 ); 238 } 200 (Handle){ HeapArea }; 239 201 s.shareEditSet_prev = &s; 240 202 s.shareEditSet_next = &s; 241 203 } 242 204 243 static void eagerCopyCtorHelper(string_res &s, const char* rhs, size_t rhslnth) with(s) { 244 if( ambient_string_sharectx->activeHeap ) { 245 (Handle){ * ambient_string_sharectx->activeHeap }; 246 (shareEditSet_owns_ulink){ false }; 247 } else { 248 (Handle){ * new( rhslnth ) }; 249 (shareEditSet_owns_ulink){ true }; 250 } 251 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); 252 209 Handle.lnth = rhslnth; 253 memmove( Handle.s, rhs, rhslnth ); 210 for ( int i = 0; i < rhslnth; i += 1 ) { // copy characters 211 Handle.s[i] = rhs[i]; 212 } // for 254 213 s.shareEditSet_prev = &s; 255 214 s.shareEditSet_next = &s; 256 215 } 257 216 258 // Constructor from a raw buffer and size 259 void ?{}(string_res &s, const char* rhs, size_t rhslnth) with(s) { 260 eagerCopyCtorHelper(s, rhs, rhslnth); 261 } 262 263 // private ctor (not in header): use specified heap (ignore ambient) and copy chars in 264 void ?{}( string_res &s, VbyteHeap & heap, const char* rhs, size_t rhslnth ) with(s) { 265 (Handle){ heap }; 266 Handle.s = VbyteAlloc(*Handle.ulink, rhslnth); 267 Handle.lnth = rhslnth; 268 (s.shareEditSet_owns_ulink){ false }; 269 memmove( Handle.s, rhs, rhslnth ); 270 s.shareEditSet_prev = &s; 271 s.shareEditSet_next = &s; 217 // String literal constructor 218 void ?{}(string_res &s, const char* rhs) { 219 (s){ rhs, strlen(rhs) }; 272 220 } 273 221 … … 275 223 void ?{}(string_res &s, const string_res & s2, StrResInitMode mode, size_t start, size_t end ) { 276 224 277 verify( start <= end && end <= s2.Handle.lnth ); 278 279 if (s2.Handle.ulink != ambient_string_sharectx->activeHeap && mode == COPY_VALUE) { 280 // crossing heaps (including private): copy eagerly 281 eagerCopyCtorHelper(s, s2.Handle.s + start, end - start); 282 verify(s.shareEditSet_prev == &s); 283 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; 284 235 } else { 285 (s.Handle){}; 286 s.Handle.s = s2.Handle.s + start; 287 s.Handle.lnth = end - start; 288 s.Handle.ulink = s2.Handle.ulink; 289 290 AddThisAfter(s.Handle, s2.Handle ); // insert this handle after rhs handle 291 // ^ bug? skip others at early point in string 292 293 if (mode == COPY_VALUE) { 294 verify(s2.Handle.ulink == ambient_string_sharectx->activeHeap); 295 // requested logical copy in same heap: defer copy until write 296 297 (s.shareEditSet_owns_ulink){ false }; 298 299 // make s alone in its shareEditSet 300 s.shareEditSet_prev = &s; 301 s.shareEditSet_next = &s; 302 } else { 303 verify( mode == SHARE_EDITS ); 304 // sharing edits with source forces same heap as source (ignore context) 305 306 (s.shareEditSet_owns_ulink){ s2.shareEditSet_owns_ulink }; 307 308 // s2 is logically const but not implementation const 309 string_res & s2mod = (string_res &) s2; 310 311 // insert s after s2 on shareEditSet 312 s.shareEditSet_next = s2mod.shareEditSet_next; 313 s.shareEditSet_prev = &s2mod; 314 s.shareEditSet_next->shareEditSet_prev = &s; 315 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; 316 257 } 317 } 318 } 319 320 static void assignEditSet(string_res & this, string_res * shareEditSetStartPeer, string_res * shareEditSetEndPeer, 321 char * resultSesStart, 322 size_t resultSesLnth, 323 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. 324 283 325 284 char * beforeBegin = shareEditSetStartPeer->Handle.s; … … 331 290 size_t oldLnth = this.Handle.lnth; 332 291 333 this.Handle.s = resultSesStart+ beforeLen;292 this.Handle.s = pasting.Handle.s + beforeLen; 334 293 this.Handle.lnth = bsize; 335 if (resultPadPosition) 336 MoveThisAfter( this.Handle, *resultPadPosition ); 294 MoveThisAfter( this.Handle, pasting.Handle ); 337 295 338 296 // adjust all substring string and handle locations, and check if any substring strings are outside the new base string 339 char *limit = resultSesStart + resultSesLnth;297 char *limit = pasting.Handle.s + pasting.Handle.lnth; 340 298 for (string_res * p = this.shareEditSet_next; p != &this; p = p->shareEditSet_next) { 341 verify(p->Handle.s >= beforeBegin);299 assert (p->Handle.s >= beforeBegin); 342 300 if ( p->Handle.s >= afterBegin ) { 343 verify( p->Handle.s <= afterBegin + afterLen );344 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 ); 345 303 // p starts after the edit 346 304 // take start and end as end-anchored … … 360 318 } else { 361 319 // p ends after the edit 362 verify( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );320 assert ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen ); 363 321 // take end as end-anchored 364 322 // stretch-shrink p according to the edit … … 368 326 // take start as start-anchored 369 327 size_t startOffsetFromStart = p->Handle.s - beforeBegin; 370 p->Handle.s = resultSesStart+ startOffsetFromStart;328 p->Handle.s = pasting.Handle.s + startOffsetFromStart; 371 329 } else { 372 verify( p->Handle.s < afterBegin );330 assert ( p->Handle.s < afterBegin ); 373 331 // p starts during the edit 374 verify( p->Handle.s + p->Handle.lnth >= beforeBegin + beforeLen );332 assert( p->Handle.s + p->Handle.lnth >= beforeBegin + beforeLen ); 375 333 if ( p->Handle.s + p->Handle.lnth < afterBegin ) { 376 334 // p ends during the edit; p does not include the last character replaced … … 386 344 } 387 345 } 388 if (resultPadPosition) 389 MoveThisAfter( p->Handle, *resultPadPosition ); // move substring handle to maintain sorted order by string position 390 } 391 } 392 393 static string_res & assign_(string_res &this, const char* buffer, size_t bsize, const string_res & valSrc) { 394 395 // traverse the incumbent share-edit set (SES) to recover the range of a base string to which `this` belongs 396 string_res * shareEditSetStartPeer = & this; 397 string_res * shareEditSetEndPeer = & this; 398 for (string_res * editPeer = this.shareEditSet_next; editPeer != &this; editPeer = editPeer->shareEditSet_next) { 399 if ( editPeer->Handle.s < shareEditSetStartPeer->Handle.s ) { 400 shareEditSetStartPeer = editPeer; 401 } 402 if ( shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth < editPeer->Handle.s + editPeer->Handle.lnth) { 403 shareEditSetEndPeer = editPeer; 404 } 405 } 406 407 verify( shareEditSetEndPeer->Handle.s >= shareEditSetStartPeer->Handle.s ); 408 size_t origEditSetLength = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - shareEditSetStartPeer->Handle.s; 409 verify( origEditSetLength >= this.Handle.lnth ); 410 411 if ( this.shareEditSet_owns_ulink ) { // assigning to private context 412 // ok to overwrite old value within LHS 413 char * prefixStartOrig = shareEditSetStartPeer->Handle.s; 414 int prefixLen = this.Handle.s - prefixStartOrig; 415 char * suffixStartOrig = this.Handle.s + this.Handle.lnth; 416 int suffixLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - suffixStartOrig; 417 418 int delta = bsize - this.Handle.lnth; 419 if ( char * oldBytes = VbyteTryAdjustLast( *this.Handle.ulink, delta ) ) { 420 // growing: copy from old to new 421 char * dest = VbyteAlloc( *this.Handle.ulink, origEditSetLength + delta ); 422 char *destCursor = dest; memcpy(destCursor, prefixStartOrig, prefixLen); 423 destCursor += prefixLen; memcpy(destCursor, buffer , bsize ); 424 destCursor += bsize; memcpy(destCursor, suffixStartOrig, suffixLen); 425 assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer, 426 dest, 427 origEditSetLength + delta, 428 0p, bsize); 429 free( oldBytes ); 430 } else { 431 // room is already allocated in-place: bubble suffix and overwite middle 432 memmove( suffixStartOrig + delta, suffixStartOrig, suffixLen ); 433 memcpy( this.Handle.s, buffer, bsize ); 434 435 assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer, 436 shareEditSetStartPeer->Handle.s, 437 origEditSetLength + delta, 438 0p, bsize); 439 } 440 441 } else if ( // assigning to shared context 442 this.Handle.lnth == origEditSetLength && // overwriting entire run of SES 443 & valSrc && // sourcing from a managed string 444 valSrc.Handle.ulink == this.Handle.ulink ) { // sourcing from same heap 445 446 // SES's result will only use characters from the source string => reuse source 447 assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer, 448 valSrc.Handle.s, 449 valSrc.Handle.lnth, 450 &((string_res&)valSrc).Handle, bsize); 451 452 } else { 453 // overwriting a proper substring of some string: mash characters from old and new together (copy on write) 454 // OR we are importing characters: need to copy eagerly (can't refer to source) 455 456 // full string is from start of shareEditSetStartPeer thru end of shareEditSetEndPeer 457 // `this` occurs in the middle of it, to be replaced 458 // build up the new text in `pasting` 459 460 string_res pasting = { 461 * this.Handle.ulink, // maintain same heap, regardless of context 462 shareEditSetStartPeer->Handle.s, // start of SES 463 this.Handle.s - shareEditSetStartPeer->Handle.s }; // length of SES, before this 464 append( pasting, 465 buffer, // start of replacement for this 466 bsize ); // length of replacement for this 467 append( pasting, 468 this.Handle.s + this.Handle.lnth, // start of SES after this 469 shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - 470 (this.Handle.s + this.Handle.lnth) ); // length of SES, after this 471 472 // The above string building can trigger compaction. 473 // The reference points (that are arguments of the string building) may move during that building. 474 // From this point on, they are stable. 475 476 assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer, 477 pasting.Handle.s, 478 pasting.Handle.lnth, 479 &pasting.Handle, bsize); 480 } 481 482 return this; 483 } 484 485 string_res & assign(string_res &this, const char* buffer, size_t bsize) { 486 return assign_(this, buffer, bsize, *0p); 487 } 488 489 string_res & ?=?(string_res &s, char other) { 490 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); 491 356 } 492 357 493 358 // Copy assignment operator 494 string_res &?=?(string_res & this, const string_res & rhs) with( this ) {495 return assign_(this, rhs.Handle.s, rhs.Handle.lnth, rhs);496 } 497 498 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 ) { 499 364 const string_res & rhs2 = rhs; 500 returnthis = rhs2;365 this = rhs2; 501 366 } 502 367 … … 509 374 s.shareEditSet_prev->shareEditSet_next = s.shareEditSet_next; 510 375 s.shareEditSet_next->shareEditSet_prev = s.shareEditSet_prev; 511 // s.shareEditSet_next = &s; 512 // s.shareEditSet_prev = &s; 513 514 if (shareEditSet_owns_ulink && s.shareEditSet_next == &s) { // last one out 515 delete( s.Handle.ulink ); 516 } 376 s.shareEditSet_next = &s; 377 s.shareEditSet_prev = &s; 517 378 } 518 379 … … 526 387 } 527 388 528 void assignAt(const string_res &s, size_t index, char val) {529 string_res editZone = { s, SHARE_EDITS, index, index+1 };530 assign(editZone, &val, 1);531 }532 533 389 534 390 /////////////////////////////////////////////////////////////////// … … 536 392 537 393 void append(string_res &str1, const char * buffer, size_t bsize) { 538 size_t clnth = s tr1.Handle.lnth+ bsize;539 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 ? 540 396 // no-op 541 397 } else { // must copy some text 542 if ( str1.Handle.s + s tr1.Handle.lnth == VbyteAlloc(*str1.Handle.ulink, 0) ) { // str1 at end of string area ?543 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 544 400 } else { // copy the two parts 545 char * str1newBuf = VbyteAlloc( *str1.Handle.ulink, clnth ); 546 char * str1oldBuf = str1.Handle.s; // must read after VbyteAlloc call in case it gs's 547 str1.Handle.s = str1newBuf; 548 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); 549 404 } // if 550 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 551 407 } // if 552 408 str1.Handle.lnth = clnth; … … 561 417 } 562 418 419 void ?+=?(string_res &s, const char* other) { 420 append( s, other, strlen(other) ); 421 } 563 422 564 423 … … 570 429 571 430 bool ?==?(const string_res &s1, const string_res &s2) { 572 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; 573 432 } 574 433 … … 596 455 597 456 int find(const string_res &s, char search) { 598 return findFrom(s, 0, search); 599 } 600 601 int findFrom(const string_res &s, size_t fromPos, char search) { 602 // FIXME: This paricular overload (find of single char) is optimized to use memchr. 603 // The general overload (find of string, memchr applying to its first character) and `contains` should be adjusted to match. 604 char * searchFrom = s.Handle.s + fromPos; 605 size_t searchLnth = s.Handle.lnth - fromPos; 606 int searchVal = search; 607 char * foundAt = (char *) memchr(searchFrom, searchVal, searchLnth); 608 if (foundAt == 0p) return s.Handle.lnth; 609 else return foundAt - s.Handle.s; 610 } 457 for (i; size(s)) { 458 if (s[i] == search) return i; 459 } 460 return size(s); 461 } 462 463 /* Remaining implementations essentially ported from Sunjay's work */ 611 464 612 465 int find(const string_res &s, const string_res &search) { 613 return findFrom(s, 0, search); 614 } 615 616 int findFrom(const string_res &s, size_t fromPos, const string_res &search) { 617 return findFrom(s, fromPos, search.Handle.s, search.Handle.lnth); 466 return find(s, search.Handle.s, search.Handle.lnth); 618 467 } 619 468 620 469 int find(const string_res &s, const char* search) { 621 return findFrom(s, 0, search); 622 } 623 int findFrom(const string_res &s, size_t fromPos, const char* search) { 624 return findFrom(s, fromPos, search, strlen(search)); 470 return find(s, search, strlen(search)); 625 471 } 626 472 627 473 int find(const string_res &s, const char* search, size_t searchsize) { 628 return findFrom(s, 0, search, searchsize);629 }630 631 int findFrom(const string_res &s, size_t fromPos, const char* search, size_t searchsize) {632 633 /* Remaining implementations essentially ported from Sunjay's work */634 635 636 474 // FIXME: This is a naive algorithm. We probably want to switch to someting 637 475 // like Boyer-Moore in the future. … … 643 481 } 644 482 645 for (size_t i = fromPos; i < s.Handle.lnth; i++) {483 for (size_t i = 0; i < s.Handle.lnth; i++) { 646 484 size_t remaining = s.Handle.lnth - i; 647 485 // Never going to find the search string if the remaining string is … … 758 596 // Add a new HandleNode node n after the current HandleNode node. 759 597 760 static void AddThisAfter( HandleNode & this, HandleNode & n ) with(this) {598 static inline void AddThisAfter( HandleNode & this, HandleNode & n ) with(this) { 761 599 #ifdef VbyteDebug 762 600 serr | "enter:AddThisAfter, this:" | &this | " n:" | &n; 763 601 #endif // VbyteDebug 764 // 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).765 verify( n.ulink != 0p );766 verify( this.ulink == n.ulink );767 602 flink = n.flink; 768 603 blink = &n; … … 789 624 // Delete the current HandleNode node. 790 625 791 static void DeleteNode( HandleNode & this ) with(this) {626 static inline void DeleteNode( HandleNode & this ) with(this) { 792 627 #ifdef VbyteDebug 793 628 serr | "enter:DeleteNode, this:" | &this; … … 803 638 804 639 // Allocates specified storage for a string from byte-string area. If not enough space remains to perform the 805 // allocation, the garbage collection routine is called. 806 807 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) { 808 644 #ifdef VbyteDebug 809 645 serr | "enter:VbyteAlloc, size:" | size; … … 814 650 NoBytes = ( uintptr_t )EndVbyte + size; 815 651 if ( NoBytes > ( uintptr_t )ExtVbyte ) { // enough room for new byte-string ? 816 garbage( this, size ); // firer up the garbage collector 817 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 818 658 } // if 819 659 r = EndVbyte; … … 826 666 827 667 828 // Adjusts the last allocation in this heap by delta bytes, or resets this heap to be able to offer829 // new allocations of its original size + delta bytes. Positive delta means bigger;830 // negative means smaller. A null return indicates that the original heap location has room for831 // the requested growth. A non-null return indicates that copying to a new location is required832 // but has not been done; the returned value is the old heap storage location; `this` heap is833 // modified to reference the new location. In the copy-requred case, the caller should use834 // VbyteAlloc to claim the new space, while doing optimal copying from old to new, then free old.835 836 static char * VbyteTryAdjustLast( VbyteHeap & this, int delta ) with(this) {837 838 if ( ( uintptr_t )EndVbyte + delta <= ( uintptr_t )ExtVbyte ) {839 // room available840 EndVbyte += delta;841 return 0p;842 }843 844 char *oldBytes = StartVbyte;845 846 NoOfExtensions += 1;847 CurrSize *= 2;848 StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize);849 ExtVbyte = StartVbyte + CurrSize;850 851 return oldBytes;852 }853 854 855 668 // Move an existing HandleNode node h somewhere after the current HandleNode node so that it is in ascending order by 856 669 // the address in the byte string area. 857 670 858 static void MoveThisAfter( HandleNode & this, const HandleNode & h ) with(this) {671 static inline void MoveThisAfter( HandleNode & this, const HandleNode & h ) with(this) { 859 672 #ifdef VbyteDebug 860 673 serr | "enter:MoveThisAfter, this:" | & this | " h:" | & h; 861 674 #endif // VbyteDebug 862 verify( h.ulink != 0p );863 verify( this.ulink == h.ulink );864 675 if ( s < h.s ) { // check argument values 865 676 // serr | "VbyteSM: Error - Cannot move byte string starting at:" | s | " after byte string starting at:" 866 677 // | ( h->s ) | " and keep handles in ascending order"; 867 678 // exit(-1 ); 868 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"); 869 680 } // if 870 681 … … 898 709 //######################### VbyteHeap ######################### 899 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 900 728 // Compare two byte strings in the byte-string area. The routine returns the following values: 901 729 // … … 904 732 // -1 => Src1-byte-string < Src2-byte-string 905 733 906 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) { 907 735 #ifdef VbyteDebug 908 736 serr | "enter:ByteCmp, Src1Start:" | Src1Start | " Src1Lnth:" | Src1Lnth | " Src2Start:" | Src2Start | " Src2Lnth:" | Src2Lnth; … … 961 789 h = Header.flink; // ignore header node 962 790 for (;;) { 963 memmove( EndVbyte, h->s, h->lnth );791 ByteCopy( this, EndVbyte, 0, h->lnth, h->s, 0, h->lnth ); 964 792 obase = h->s; 965 793 h->s = EndVbyte; … … 982 810 983 811 984 static double heap_expansion_freespace_threshold = 0.1; // default inherited from prior work: expand heap when less than 10% "free" (i.e. garbage)985 // probably an unreasonable default, but need to assess early-round tests on changing it986 987 void TUNING_set_string_heap_liveness_threshold( double val ) {988 heap_expansion_freespace_threshold = 1.0 - val;989 }990 991 992 812 // Garbage determines the amount of free space left in the heap and then reduces, leave the same, or extends the size of 993 813 // the heap. The heap is then compacted in the existing heap or into the newly allocated heap. 994 814 995 void garbage(VbyteHeap & this , int minreq) with(this) {815 void garbage(VbyteHeap & this ) with(this) { 996 816 #ifdef VbyteDebug 997 817 serr | "enter:garbage"; … … 1017 837 AmountFree = ( uintptr_t )ExtVbyte - ( uintptr_t )StartVbyte - AmountUsed; 1018 838 1019 if ( ( double ) AmountFree < ( CurrSize * heap_expansion_freespace_threshold ) || AmountFree < minreq ) { // free space less than threshold or not enough to serve cur request 1020 1021 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 1022 843 1023 844 // Peter says, "This needs work before it should be used." … … 1025 846 // reduce(( AmountFree / CurrSize - 3 ) * CurrSize ); // reduce the memory 1026 847 1027 // `extend` implies a `compaction` during the copy 1028 1029 } else { 1030 compaction(this); // in-place 1031 }// if 848 } // if 849 compaction(this); // compact the byte area, in the same or new heap area 1032 850 #ifdef VbyteDebug 1033 851 { … … 1049 867 #undef VbyteDebug 1050 868 869 //WIP 870 #if 0 1051 871 1052 872 … … 1054 874 // area is deleted. 1055 875 1056 void extend( VbyteHeap & this, int size ) with (this) {876 void VbyteHeap::extend( int size ) { 1057 877 #ifdef VbyteDebug 1058 878 serr | "enter:extend, size:" | size; … … 1064 884 1065 885 CurrSize += size > InitSize ? size : InitSize; // minimum extension, initial size 1066 StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize);886 StartVbyte = EndVbyte = new char[CurrSize]; 1067 887 ExtVbyte = (void *)( StartVbyte + CurrSize ); 1068 compaction( this); // copy from old heap to new & adjust pointers to new heap1069 free( OldStartVbyte ); // release old heap888 compaction(); // copy from old heap to new & adjust pointers to new heap 889 delete OldStartVbyte; // release old heap 1070 890 #ifdef VbyteDebug 1071 891 serr | "exit:extend, CurrSize:" | CurrSize; … … 1073 893 } // extend 1074 894 1075 //WIP1076 #if 01077 895 1078 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
Note:
See TracChangeset
for help on using the changeset viewer.