Ignore:
Timestamp:
Oct 19, 2021, 10:31:53 AM (3 years ago)
Author:
Michael Brooks <mlbrooks@…>
Branches:
ADT, ast-experimental, enum, master, pthread-emulation, qualifiedEnum
Children:
fe18b46
Parents:
7b0e8b7
Message:

String hybrid assignment to unshared now optimizes to overwrite instead of copy.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/containers/string_res.cfa

    r7b0e8b7 r6f7aff3  
    5353static inline int ByteCmp( char *, int, int, char *, int, int );        // compare 2 blocks of bytes
    5454static inline char *VbyteAlloc( VbyteHeap &, int );                     // allocate a block bytes in the heap
    55 
     55static inline char *VbyteTryAdjustLast( VbyteHeap &, int );
    5656
    5757static inline void AddThisAfter( HandleNode &, HandleNode & );
     
    313313    this.Handle.s = resultSesStart + beforeLen;
    314314    this.Handle.lnth = bsize;
    315     MoveThisAfter( this.Handle, *resultPadPosition );
     315    if (resultPadPosition)
     316        MoveThisAfter( this.Handle, *resultPadPosition );
    316317
    317318    // adjust all substring string and handle locations, and check if any substring strings are outside the new base string
     
    365366            }
    366367        }
    367         MoveThisAfter( p->Handle, *resultPadPosition ); // move substring handle to maintain sorted order by string position
     368        if (resultPadPosition)
     369            MoveThisAfter( p->Handle, *resultPadPosition );     // move substring handle to maintain sorted order by string position
    368370    }
    369371}
     
    387389    verify( editSetLength >= this.Handle.lnth );
    388390
    389 
    390     if ( this.Handle.lnth == editSetLength                // the entire run of the share-edit set is being overwritten: SES's result will only use characters from the source string
    391         && & valSrc                                       // sourcing from a managed string
    392         && valSrc.Handle.ulink == this.Handle.ulink  ) {  // sourcing from same heap
    393 
     391    if ( this.shareEditSet_owns_ulink ) {                 // assigning to private context
     392        // ok to overwrite old value within LHS
     393        char * prefixStartOrig = shareEditSetStartPeer->Handle.s;
     394        int prefixLen = this.Handle.s - prefixStartOrig;
     395        char * suffixStartOrig = this.Handle.s + this.Handle.lnth;
     396        int suffixLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - suffixStartOrig;
     397
     398        int delta = bsize - this.Handle.lnth;
     399        if ( char * oldBytes = VbyteTryAdjustLast( *this.Handle.ulink, delta ) ) {
     400            // growing: copy from old to new
     401            char * dest = VbyteAlloc( *this.Handle.ulink, editSetLength );
     402            char *destCursor = dest;        memcpy(destCursor, prefixStartOrig, prefixLen);
     403            destCursor += prefixLen;        memcpy(destCursor, buffer         , bsize    );
     404            destCursor += this.Handle.lnth; memcpy(destCursor, suffixStartOrig, suffixLen);
     405            assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer,
     406                dest,
     407                editSetLength,
     408                0p, bsize);
     409            free( oldBytes );
     410        } else {
     411            // room is already allocated in-place: bubble suffix and overwite middle
     412            memmove( suffixStartOrig + delta, suffixStartOrig, suffixLen );
     413            memcpy( this.Handle.s, buffer, bsize );
     414
     415            assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer,
     416                shareEditSetStartPeer->Handle.s,
     417                editSetLength,
     418                0p, bsize);
     419        }
     420
     421    } else if (                                           // assigning to shared context
     422        this.Handle.lnth == editSetLength &&              // overwriting entire run of SES
     423        & valSrc &&                                       // sourcing from a managed string
     424        valSrc.Handle.ulink == this.Handle.ulink  ) {     // sourcing from same heap
     425
     426        // SES's result will only use characters from the source string => reuse source
    394427        assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer,
    395428            valSrc.Handle.s,
     
    398431       
    399432    } else {
     433        // overwriting a proper substring of some string: mash characters from old and new together (copy on write)
     434        // OR we are importing characters: need to copy eagerly (can't refer to source)
    400435
    401436        // full string is from start of shareEditSetStartPeer thru end of shareEditSetEndPeer
     
    416451        }
    417452
    418         // we are only overwriting a proper substring of some string: need to mash characters from old and new together
    419         // OR we are importing characters: need to copy eagerly
    420453        string_res pasting = {
    421454            * this.Handle.ulink,                               // maintain same heap, regardless of context
     
    439472            &pasting.Handle, bsize);
    440473    }
    441 
    442     // So now, capture their values for use in the overlap cases, below.
    443     // Do not factor these definitions with the arguments used in string building above.
    444 
    445474}
    446475
     
    750779
    751780// Allocates specified storage for a string from byte-string area. If not enough space remains to perform the
    752 // allocation, the garbage collection routine is called and a second attempt is made to allocate the space. If the
    753 // second attempt fails, a further attempt is made to create a new, larger byte-string area.
     781// allocation, the garbage collection routine is called.
    754782
    755783static inline char * VbyteAlloc( VbyteHeap & this, int size ) with(this) {
     
    775803    return r;
    776804} // VbyteAlloc
     805
     806
     807// Adjusts the last allocation in this heap by delta bytes, or resets this heap to be able to offer
     808// new allocations of its original size + delta bytes. Positive delta means bigger;
     809// negative means smaller.  A null return indicates that the original heap location has room for
     810// the requested growth.  A non-null return indicates that copying to a new location is required
     811// but has not been done; the returned value is the old heap storage location; `this` heap is
     812// modified to reference the new location.  In the copy-requred case, the caller should use
     813// VbyteAlloc to claim the new space, while doing optimal copying from old to new, then free old.
     814
     815static inline char * VbyteTryAdjustLast( VbyteHeap & this, int delta ) with(this) {
     816
     817    if ( ( uintptr_t )EndVbyte + delta <= ( uintptr_t )ExtVbyte ) {
     818        // room available
     819        EndVbyte += delta;
     820        return 0p;
     821    }
     822
     823    char *oldBytes = StartVbyte;
     824
     825    NoOfExtensions += 1;
     826    CurrSize *= 2;
     827    StartVbyte = EndVbyte = alloc(CurrSize);
     828    ExtVbyte = StartVbyte + CurrSize;
     829
     830    return oldBytes;
     831}
    777832
    778833
Note: See TracChangeset for help on using the changeset viewer.