Changeset 4b3b352


Ignore:
Timestamp:
Oct 7, 2021, 2:13:46 PM (14 months ago)
Author:
Michael Brooks <mlbrooks@…>
Branches:
enum, master, pthread-emulation, qualifiedEnum
Children:
804bf677
Parents:
0f781fb8
Message:

String hybrid has working separated sharing contexts

Files:
5 edited

Legend:

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

    r0f781fb8 r4b3b352  
    9292}
    9393
    94 string ?=?(string & this, string other) {
     94string & ?=?(string & this, string & other) { //// <---- straw man change
    9595    (*this.inner) = (*other.inner);
    9696    return this;
  • libcfa/src/containers/string.hfa

    r0f781fb8 r4b3b352  
    4141void ?=?(string &s, const string &other);
    4242void ?=?(string &s, char other);
    43 string ?=?(string &s, string other);  // string tolerates memcpys; still saw calls to autogen
    44 
     43string & ?=?(string &s, string &other);  // surprising ret seems to help avoid calls to autogen
     44//string ?=?( string &, string ) = void;
    4545void ^?{}(string &s);
    4646
  • libcfa/src/containers/string_res.cfa

    r0f781fb8 r4b3b352  
    223223}
    224224
    225 // Constructor from a raw buffer and size
    226 void ?{}(string_res &s, const char* rhs, size_t rhslnth) with(s) {
     225static inline void eagerCopyCtorHelper(string_res &s, const char* rhs, size_t rhslnth) with(s) {
    227226    assert( ambient_string_sharectx->activeHeap && "Need to implement private contexts" );
    228227    (Handle){ * ambient_string_sharectx->activeHeap };
     
    236235}
    237236
     237// Constructor from a raw buffer and size
     238void ?{}(string_res &s, const char* rhs, size_t rhslnth) with(s) {
     239    eagerCopyCtorHelper(s, rhs, rhslnth);
     240}
     241
    238242// String literal constructor
    239243void ?{}(string_res &s, const char* rhs) {
     
    245249
    246250    assert( ambient_string_sharectx->activeHeap && "Need to implement private contexts" );
    247     assert( s2.Handle.ulink == ambient_string_sharectx->activeHeap && "need to implement context crossing");
    248251
    249252    verify( start <= end && end <= s2.Handle.lnth );
    250253
    251     (s.Handle){};
    252     s.Handle.s = s2.Handle.s + start;
    253     s.Handle.lnth = end - start;
    254     s.Handle.ulink = ambient_string_sharectx->activeHeap;
    255     AddThisAfter(s.Handle, s2.Handle );                 // insert this handle after rhs handle
    256     // ^ bug?  skip others at early point in string
     254    if (s2.Handle.ulink == ambient_string_sharectx->activeHeap) {
     255        // same heap: allow overlap
     256        (s.Handle){};
     257        s.Handle.s = s2.Handle.s + start;
     258        s.Handle.lnth = end - start;
     259        s.Handle.ulink = ambient_string_sharectx->activeHeap;
     260        AddThisAfter(s.Handle, s2.Handle );                     // insert this handle after rhs handle
     261        // ^ bug?  skip others at early point in string
    257262   
    258     if (mode == COPY_VALUE) {
    259         // make s alone in its shareEditSet
    260         s.shareEditSet_prev = &s;
    261         s.shareEditSet_next = &s;
     263        if (mode == COPY_VALUE) {
     264            // make s alone in its shareEditSet
     265            s.shareEditSet_prev = &s;
     266            s.shareEditSet_next = &s;
     267        } else {
     268            verify( mode == SHARE_EDITS );
     269
     270            // s2 is logically const but not implementation const
     271            string_res & s2mod = (string_res &) s2;
     272
     273            // insert s after s2 on shareEditSet
     274            s.shareEditSet_next = s2mod.shareEditSet_next;
     275            s.shareEditSet_prev = &s2mod;
     276            s.shareEditSet_next->shareEditSet_prev = &s;
     277            s.shareEditSet_prev->shareEditSet_next = &s;
     278        }
    262279    } else {
    263         verify( mode == SHARE_EDITS );
    264 
    265         // s2 is logically const but not implementation const
    266         string_res & s2mod = (string_res &) s2;
    267 
    268         // insert s after s2 on shareEditSet
    269         s.shareEditSet_next = s2mod.shareEditSet_next;
    270         s.shareEditSet_prev = &s2mod;
    271         s.shareEditSet_next->shareEditSet_prev = &s;
    272         s.shareEditSet_prev->shareEditSet_next = &s;
    273     }
    274 }
    275 
    276 void assign(string_res &this, const char* buffer, size_t bsize) {
    277 
    278     // traverse the incumbent share-edit set (SES) to recover the range of a base string to which `this` belongs
    279     string_res * shareEditSetStartPeer = & this;
    280     string_res * shareEditSetEndPeer = & this;
    281     for (string_res * editPeer = this.shareEditSet_next; editPeer != &this; editPeer = editPeer->shareEditSet_next) {
    282         if ( editPeer->Handle.s < shareEditSetStartPeer->Handle.s ) {
    283             shareEditSetStartPeer = editPeer;
    284         }
    285         if ( shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth < editPeer->Handle.s + editPeer->Handle.lnth) {
    286             shareEditSetEndPeer = editPeer;
    287         }
    288     }
    289 
    290     // full string is from start of shareEditSetStartPeer thru end of shareEditSetEndPeer
    291     // `this` occurs in the middle of it, to be replaced
    292     // build up the new text in `pasting`
    293 
    294     string_res pasting = {
    295         shareEditSetStartPeer->Handle.s,                   // start of SES
    296         this.Handle.s - shareEditSetStartPeer->Handle.s }; // length of SES, before this
    297     append( pasting,
    298         buffer,                                            // start of replacement for this
    299         bsize );                                           // length of replacement for this
    300     append( pasting,
    301         this.Handle.s + this.Handle.lnth,                  // start of SES after this
    302         shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth -
    303         (this.Handle.s + this.Handle.lnth) );              // length of SES, after this
    304 
    305     // The above string building can trigger compaction.
    306     // The reference points (that are arguments of the string building) may move during that building.
    307     // From this point on, they are stable.
    308     // So now, capture their values for use in the overlap cases, below.
    309     // Do not factor these definitions with the arguments used above.
     280        // crossing heaps: eager copy
     281        assert( mode == COPY_VALUE && "need to solidify context-crossing rules for requesting shared edits");
     282        eagerCopyCtorHelper(s, s2.Handle.s + start, end - start);
     283        verify(s.shareEditSet_prev == &s);
     284        verify(s.shareEditSet_next == &s);
     285    }
     286}
     287
     288static void assignEditSet(string_res & this, string_res * shareEditSetStartPeer, string_res * shareEditSetEndPeer,
     289    char * resultSesStart,
     290    size_t resultSesLnth,
     291    HandleNode * resultPadPosition, size_t bsize ) {
    310292
    311293    char * beforeBegin = shareEditSetStartPeer->Handle.s;
     
    317299    size_t oldLnth = this.Handle.lnth;
    318300
    319     this.Handle.s = pasting.Handle.s + beforeLen;
     301    this.Handle.s = resultSesStart + beforeLen;
    320302    this.Handle.lnth = bsize;
    321     MoveThisAfter( this.Handle, pasting.Handle );
     303    MoveThisAfter( this.Handle, *resultPadPosition );
    322304
    323305    // adjust all substring string and handle locations, and check if any substring strings are outside the new base string
    324     char *limit = pasting.Handle.s + pasting.Handle.lnth;
     306    char *limit = resultSesStart + resultSesLnth;
    325307    for (string_res * p = this.shareEditSet_next; p != &this; p = p->shareEditSet_next) {
    326308        verify (p->Handle.s >= beforeBegin);
     
    353335            // take start as start-anchored
    354336            size_t startOffsetFromStart = p->Handle.s - beforeBegin;
    355             p->Handle.s = pasting.Handle.s + startOffsetFromStart;
     337            p->Handle.s = resultSesStart + startOffsetFromStart;
    356338        } else {
    357339            verify ( p->Handle.s < afterBegin );
     
    371353            }
    372354        }
    373         MoveThisAfter( p->Handle, pasting.Handle );     // move substring handle to maintain sorted order by string position
    374     }
     355        MoveThisAfter( p->Handle, *resultPadPosition ); // move substring handle to maintain sorted order by string position
     356    }
     357}
     358
     359static void assign_(string_res &this, const char* buffer, size_t bsize, const string_res & valSrc) {
     360
     361    // traverse the incumbent share-edit set (SES) to recover the range of a base string to which `this` belongs
     362    string_res * shareEditSetStartPeer = & this;
     363    string_res * shareEditSetEndPeer = & this;
     364    for (string_res * editPeer = this.shareEditSet_next; editPeer != &this; editPeer = editPeer->shareEditSet_next) {
     365        if ( editPeer->Handle.s < shareEditSetStartPeer->Handle.s ) {
     366            shareEditSetStartPeer = editPeer;
     367        }
     368        if ( shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth < editPeer->Handle.s + editPeer->Handle.lnth) {
     369            shareEditSetEndPeer = editPeer;
     370        }
     371    }
     372
     373    verify( shareEditSetEndPeer->Handle.s >= shareEditSetStartPeer->Handle.s );
     374    size_t editSetLength = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - shareEditSetStartPeer->Handle.s;
     375    verify( editSetLength >= this.Handle.lnth );
     376
     377
     378    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
     379        && & valSrc                                       // sourcing from a managed string
     380        && valSrc.Handle.ulink == this.Handle.ulink  ) {  // sourcing from same heap
     381
     382        assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer,
     383            valSrc.Handle.s,
     384            valSrc.Handle.lnth,
     385            &((string_res&)valSrc).Handle, bsize);
     386       
     387    } else {
     388
     389        // full string is from start of shareEditSetStartPeer thru end of shareEditSetEndPeer
     390        // `this` occurs in the middle of it, to be replaced
     391        // build up the new text in `pasting`
     392
     393        // super private string ctor: ignore ambient context
     394        void ?{}( string_res &s, VbyteHeap & heap, const char* rhs, size_t rhslnth ) with(s) {
     395            (Handle){ heap };
     396            Handle.s = VbyteAlloc(*Handle.ulink, rhslnth);
     397            Handle.lnth = rhslnth;
     398            for ( int i = 0; i < rhslnth; i += 1 ) {            // copy characters
     399                Handle.s[i] = rhs[i];
     400            } // for
     401            s.shareEditSet_prev = &s;
     402            s.shareEditSet_next = &s;
     403        }
     404
     405        // we are only overwriting a proper substring of some string: need to mash characters from old and new together
     406        // OR we are importing characters: need to copy eagerly
     407        string_res pasting = {
     408            * this.Handle.ulink,                               // maintain same heap, regardless of context
     409            shareEditSetStartPeer->Handle.s,                   // start of SES
     410            this.Handle.s - shareEditSetStartPeer->Handle.s }; // length of SES, before this
     411        append( pasting,
     412            buffer,                                            // start of replacement for this
     413            bsize );                                           // length of replacement for this
     414        append( pasting,
     415            this.Handle.s + this.Handle.lnth,                  // start of SES after this
     416            shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth -
     417            (this.Handle.s + this.Handle.lnth) );              // length of SES, after this
     418
     419        // The above string building can trigger compaction.
     420        // The reference points (that are arguments of the string building) may move during that building.
     421        // From this point on, they are stable.
     422
     423        assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer,
     424            pasting.Handle.s,
     425            pasting.Handle.lnth,
     426            &pasting.Handle, bsize);
     427    }
     428
     429    // So now, capture their values for use in the overlap cases, below.
     430    // Do not factor these definitions with the arguments used in string building above.
     431
     432}
     433
     434void assign(string_res &this, const char* buffer, size_t bsize) {
     435    assign_(this, buffer, bsize, *0p);
    375436}
    376437
     
    385446// Copy assignment operator
    386447void ?=?(string_res & this, const string_res & rhs) with( this ) {
    387     assign(this, rhs.Handle.s, rhs.Handle.lnth);
     448    assign_(this, rhs.Handle.s, rhs.Handle.lnth, rhs);
    388449}
    389450
  • tests/collections/.expect/string-ctx-manage.txt

    r0f781fb8 r4b3b352  
     1hi
     2bye
     3hi
     4bye
    15done
  • tests/collections/string-ctx-manage.cfa

    r0f781fb8 r4b3b352  
    11#include <string.hfa>
    22#include <string_sharectx.hfa>
     3#include <string_res.hfa>
    34
    4 // The functionality for these tests isn't written yet.
    5 // But its interface compiles and the cases it drives are detected.
     5void baseline() {
     6    string x = "hi";
    67
    7 void failEagerCopy() {
     8    string y = x; // construct y in same context, no write yet => no copy yet
     9    assert( y.inner->Handle.s == x.inner->Handle.s);
     10    sout | y; // hi
     11
     12    x = "bye";
     13    y = x; // y in same context, no write yet => no copy yet
     14    assert( y.inner->Handle.s == x.inner->Handle.s);
     15    sout | y; // bye
     16}
     17
     18void eagerCopy() {
    819    string x = "hi";
    9     string_sharectx c = { NO_SHARING };
     20    string_sharectx c = { NEW_SHARING };
    1021
    11     // want: implied forced eager copy
    12     // got: assertion failure, "need to implement context crossing"
    13     string y = x;
     22    string y = x; // construct y in different context => eager copy
     23    assert( y.inner->Handle.s != x.inner->Handle.s);
     24    sout | y; // hi
     25
     26    x = "bye";                                                     //.... Bookmark 9/30 shallow:  surprisingly this step failed
     27    y = x; // y was already in different context => eager copy
     28    assert( y.inner->Handle.s != x.inner->Handle.s);
     29    sout | y; // bye
    1430}
    1531
     
    2642
    2743int main() {
     44    baseline();
     45    eagerCopy();
    2846    if (showFail) {
    29         failEagerCopy();
    3047        failSoloAlloc();
    3148    }
Note: See TracChangeset for help on using the changeset viewer.