Changeset 6cc87c0


Ignore:
Timestamp:
Sep 20, 2021, 10:41:29 PM (4 weeks ago)
Author:
Michael Brooks <mlbrooks@…>
Branches:
master
Children:
3bf3b6b
Parents:
6aa84e0
Message:

String bug fixes and new tests.

Enabled white-box visibility (DEBUG_ functions) into the string representation for heap-oriented tests.

string-gc/basicFillCompact

  • newly testable, now with the DEBUG_ visibility, but was basically already working

string-gc/fillCompact_withSharedEdits

  • new check for bug fixed here, where an append that triggers a compaction left substrings with dangling pointers

to the old text-pad range; fix is how string_res/assign now sequences growth-pushing operations before grabbing
pointers into the ranges of the old-version

string-overwrite

  • new broad check a few of whose cases are fixed here; fixes are the adjustments to the case priorities and

edge-case classifications in string_res/assign "adjust all substring string and handle locations" section

Files:
4 added
2 edited

Legend:

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

    r6aa84e0 r6cc87c0  
    2121
    2222
    23 #ifdef VbyteDebug
    24 extern HandleNode *HeaderPtr;
     23
     24
     25
     26
     27
     28
     29// DON'T COMMIT:
     30// #define VbyteDebug
     31
     32
     33
     34
     35
     36#ifdef VbyteDebug
     37HandleNode *HeaderPtr;
    2538#endif // VbyteDebug
    2639
     
    140153
    141154VbyteHeap HeapArea;
     155
     156VbyteHeap * DEBUG_string_heap = & HeapArea;
     157
     158size_t DEBUG_string_bytes_avail_until_gc( VbyteHeap * heap ) {
     159    return ((char*)heap->ExtVbyte) - heap->EndVbyte;
     160}
     161
     162const char * DEBUG_string_heap_start( VbyteHeap * heap ) {
     163    return heap->StartVbyte;
     164}
     165
    142166
    143167// Returns the size of the string in bytes
     
    225249void assign(string_res &this, const char* buffer, size_t bsize) {
    226250
     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;
     257        }
     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.
     283
     284    char * beforeBegin = shareEditSetStartPeer->Handle.s;
     285    size_t beforeLen = this.Handle.s - beforeBegin;
     286
    227287    char * afterBegin = this.Handle.s + this.Handle.lnth;
    228 
    229     char * shareEditSetStart = this.Handle.s;
    230     char * shareEditSetEnd = afterBegin;
    231     for (string_res * editPeer = this.shareEditSet_next; editPeer != &this; editPeer = editPeer->shareEditSet_next) {
    232         shareEditSetStart = min( shareEditSetStart, editPeer->Handle.s );
    233         shareEditSetEnd = max( shareEditSetStart, editPeer->Handle.s + editPeer->Handle.lnth);
    234     }
    235 
    236     char * beforeBegin = shareEditSetStart;
    237     size_t beforeLen = this.Handle.s - shareEditSetStart;
    238     size_t afterLen = shareEditSetEnd - afterBegin;
    239 
    240     string_res pasting = { beforeBegin, beforeLen };
    241     append(pasting, buffer, bsize);
    242     string_res after = { afterBegin, afterLen }; // juxtaposed with in-progress pasting
    243     pasting += after;                        // optimized case
     288    size_t afterLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - afterBegin;
    244289
    245290    size_t oldLnth = this.Handle.lnth;
     
    253298    for (string_res * p = this.shareEditSet_next; p != &this; p = p->shareEditSet_next) {
    254299        assert (p->Handle.s >= beforeBegin);
    255         if ( p->Handle.s < beforeBegin + beforeLen ) {
    256             // p starts before the edit
    257             if ( p->Handle.s + p->Handle.lnth < beforeBegin + beforeLen ) {
     300        if ( p->Handle.s >= afterBegin ) {
     301            assert ( p->Handle.s <= afterBegin + afterLen );
     302            assert ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );
     303            // p starts after the edit
     304            // take start and end as end-anchored
     305            size_t startOffsetFromEnd = afterBegin + afterLen - p->Handle.s;
     306            p->Handle.s = limit - startOffsetFromEnd;
     307            // p->Handle.lnth unaffected
     308        } else if ( p->Handle.s <= beforeBegin + beforeLen ) {
     309            // p starts before, or at the start of, the edit
     310            if ( p->Handle.s + p->Handle.lnth <= beforeBegin + beforeLen ) {
    258311                // p ends before the edit
    259312                // take end as start-anchored too
    260313                // p->Handle.lnth unaffected
    261314            } else if ( p->Handle.s + p->Handle.lnth < afterBegin ) {
    262                 // p ends during the edit
     315                // p ends during the edit; p does not include the last character replaced
    263316                // clip end of p to end at start of edit
    264317                p->Handle.lnth = beforeLen - ( p->Handle.s - beforeBegin );
     
    274327            size_t startOffsetFromStart = p->Handle.s - beforeBegin;
    275328            p->Handle.s = pasting.Handle.s + startOffsetFromStart;
    276         } else if ( p->Handle.s < afterBegin ) {
     329        } else {
     330            assert ( p->Handle.s < afterBegin );
    277331            // p starts during the edit
    278332            assert( p->Handle.s + p->Handle.lnth >= beforeBegin + beforeLen );
    279333            if ( p->Handle.s + p->Handle.lnth < afterBegin ) {
    280                 // p ends during the edit
     334                // p ends during the edit; p does not include the last character replaced
    281335                // set p to empty string at start of edit
    282336                p->Handle.s = this.Handle.s;
    283337                p->Handle.lnth = 0;
    284338            } else {
    285                 // p ends after the edit
     339                // p includes the end of the edit
    286340                // clip start of p to start at end of edit
     341                int charsToClip = afterBegin - p->Handle.s;
    287342                p->Handle.s = this.Handle.s + this.Handle.lnth;
    288                 p->Handle.lnth += this.Handle.lnth;
    289                 p->Handle.lnth -= oldLnth;
     343                p->Handle.lnth -= charsToClip;
    290344            }
    291         } else {
    292             assert ( p->Handle.s <= afterBegin + afterLen );
    293             assert ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );
    294             // p starts after the edit
    295             // take start and end as end-anchored
    296             size_t startOffsetFromEnd = afterBegin + afterLen - p->Handle.s;
    297             p->Handle.s = limit - startOffsetFromEnd;
    298             // p->Handle.lnth unaffected
    299345        }
    300346        MoveThisAfter( p->Handle, pasting.Handle );     // move substring handle to maintain sorted order by string position
     
    641687    } // if
    642688#ifdef VbyteDebug
    643     serr | "exit:MoveThisAfter";
    644689    {
    645690        serr | "HandleList:";
     
    650695                serr | n->s[i];
    651696            } // for
    652             serr | "\" flink:" | n->flink | " blink:" | n->blink;
     697            serr | "\" flink:" | n->flink | " blink:" | n->blink | nl;
    653698        } // for
    654699        serr | nlOn;
    655700    }
     701    serr | "exit:MoveThisAfter";
    656702#endif // VbyteDebug
    657703} // MoveThisAfter
     
    662708
    663709//######################### VbyteHeap #########################
    664 
    665 #ifdef VbyteDebug
    666 HandleNode *HeaderPtr = 0p;
    667 #endif // VbyteDebug
    668710
    669711// Move characters from one location in the byte-string area to another. The routine handles the following situations:
  • libcfa/src/containers/string_res.hfa

    r6aa84e0 r6cc87c0  
    3636void ?{}( HandleNode &, VbyteHeap & );          // constructor for nodes in the handle list
    3737void ^?{}( HandleNode & );                      // destructor for handle nodes
     38
     39extern VbyteHeap * DEBUG_string_heap;
     40size_t DEBUG_string_bytes_avail_until_gc( VbyteHeap * heap );
     41const char * DEBUG_string_heap_start( VbyteHeap * heap );
    3842
    3943
Note: See TracChangeset for help on using the changeset viewer.