Ignore:
Timestamp:
Feb 26, 2024, 3:53:42 AM (23 months ago)
Author:
JiadaL <j82liang@…>
Branches:
master
Children:
3f9a8d0
Parents:
0522ebe (diff), 022bce0 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Resolve conflict

File:
1 edited

Legend:

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

    r0522ebe ra4da45e  
    1010// Created On       : Fri Sep 03 11:00:00 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jan 22 23:12:42 2024
    13 // Update Count     : 43
     12// Last Modified On : Sat Feb 10 17:47:22 2024
     13// Update Count     : 83
    1414//
    1515
     
    2525
    2626#include <assert.h>
    27 #include <complex.h>                           // creal, cimag
     27#include <complex.h>                                               // creal, cimag
    2828
    2929//######################### VbyteHeap "header" #########################
     
    3434
    3535struct VbyteHeap {
    36     int NoOfCompactions;                                                // number of compactions of the byte area
    37     int NoOfExtensions;                                                 // number of extensions in the size of the byte area
    38     int NoOfReductions;                                                 // number of reductions in the size of the byte area
    39    
    40     int InitSize;                                                               // initial number of bytes in the byte-string area
    41     int CurrSize;                                                               // current number of bytes in the byte-string area
    42     char *StartVbyte;                                                   // pointer to the `st byte of the start of the byte-string area
    43     char *EndVbyte;                                                             // pointer to the next byte after the end of the currently used portion of byte-string area
    44     void *ExtVbyte;                                                             // pointer to the next byte after the end of the byte-string area
    45 
    46     HandleNode Header;                                                  // header node for handle list
     36        int NoOfCompactions;                                                            // number of compactions of the byte area
     37        int NoOfExtensions;                                                                     // number of extensions in the size of the byte area
     38        int NoOfReductions;                                                                     // number of reductions in the size of the byte area
     39       
     40        int InitSize;                                                                           // initial number of bytes in the byte-string area
     41        int CurrSize;                                                                           // current number of bytes in the byte-string area
     42        char *StartVbyte;                                                                       // pointer to the `st byte of the start of the byte-string area
     43        char *EndVbyte;                                                                         // pointer to the next byte after the end of the currently used portion of byte-string area
     44        void *ExtVbyte;                                                                         // pointer to the next byte after the end of the byte-string area
     45
     46        HandleNode Header;                                                                      // header node for handle list
    4747}; // VbyteHeap
    4848
    49    
    50 static void compaction( VbyteHeap & );                  // compaction of the byte area
    51 static void garbage( VbyteHeap &, int );                // garbage collect the byte area
    52 static void extend( VbyteHeap &, int );                 // extend the size of the byte area
    53 static void reduce( VbyteHeap &, int );                 // reduce the size of the byte area
     49
     50static void compaction( VbyteHeap & );                                  // compaction of the byte area
     51static void garbage( VbyteHeap &, int );                                // garbage collect the byte area
     52static void extend( VbyteHeap &, int );                                 // extend the size of the byte area
     53static void reduce( VbyteHeap &, int );                                 // reduce the size of the byte area
    5454
    5555static void ?{}( VbyteHeap &, size_t = 1000 );
    5656static void ^?{}( VbyteHeap & );
    5757
    58 static int ByteCmp( char *, int, int, char *, int, int );       // compare 2 blocks of bytes
     58static int ByteCmp( char *, int, int, char *, int, int ); // compare 2 blocks of bytes
    5959static char *VbyteAlloc( VbyteHeap &, int );                    // allocate a block bytes in the heap
    6060static char *VbyteTryAdjustLast( VbyteHeap &, int );
     
    6262static void AddThisAfter( HandleNode &, HandleNode & );
    6363static void DeleteNode( HandleNode & );
    64 static void MoveThisAfter( HandleNode &, const HandleNode & );          // move current handle after parameter handle
     64static void MoveThisAfter( HandleNode &, const HandleNode & ); // move current handle after parameter handle
    6565
    6666
     
    6969static void ?{}( VbyteHeap & s, size_t Size ) with(s) {
    7070#ifdef VbyteDebug
    71     serr | "enter:VbyteHeap::VbyteHeap, s:" | &s | " Size:" | Size;
    72 #endif // VbyteDebug
    73     NoOfCompactions = NoOfExtensions = NoOfReductions = 0;
    74     InitSize = CurrSize = Size;
    75     StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize);
    76     ExtVbyte = (void *)( StartVbyte + CurrSize );
    77     Header.flink = Header.blink = &Header;
    78     Header.ulink = &s;
    79 #ifdef VbyteDebug
    80     HeaderPtr = &Header;
    81     serr | "exit:VbyteHeap::VbyteHeap, s:" | &s;
     71        serr | "enter:VbyteHeap::VbyteHeap, s:" | &s | " Size:" | Size;
     72#endif // VbyteDebug
     73        NoOfCompactions = NoOfExtensions = NoOfReductions = 0;
     74        InitSize = CurrSize = Size;
     75        StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize);
     76        ExtVbyte = (void *)( StartVbyte + CurrSize );
     77        Header.flink = Header.blink = &Header;
     78        Header.ulink = &s;
     79#ifdef VbyteDebug
     80        HeaderPtr = &Header;
     81        serr | "exit:VbyteHeap::VbyteHeap, s:" | &s;
    8282#endif // VbyteDebug
    8383} // VbyteHeap
     
    8787
    8888static void ^?{}( VbyteHeap & s ) with(s) {
    89     free( StartVbyte );
     89        free( StartVbyte );
    9090} // ~VbyteHeap
    9191
     
    9999static void ?{}( HandleNode & s ) with(s) {
    100100#ifdef VbyteDebug
    101     serr | "enter:HandleNode::HandleNode, s:" | &s;
    102 #endif // VbyteDebug
    103     s = 0;
    104     lnth = 0;
    105 #ifdef VbyteDebug
    106     serr | "exit:HandleNode::HandleNode, s:" | &s;
     101        serr | "enter:HandleNode::HandleNode, s:" | &s;
     102#endif // VbyteDebug
     103        s = 0;
     104        lnth = 0;
     105#ifdef VbyteDebug
     106        serr | "exit:HandleNode::HandleNode, s:" | &s;
    107107#endif // VbyteDebug
    108108} // HandleNode
     
    114114static void ?{}( HandleNode & s, VbyteHeap & vh ) with(s) {
    115115#ifdef VbyteDebug
    116     serr | "enter:HandleNode::HandleNode, s:" | &s;
    117 #endif // VbyteDebug
    118     s = 0;
    119     lnth = 0;
    120     ulink = &vh;
    121     AddThisAfter( s, *vh.Header.blink );
    122 #ifdef VbyteDebug
    123     serr | "exit:HandleNode::HandleNode, s:" | &s;
     116        serr | "enter:HandleNode::HandleNode, s:" | &s;
     117#endif // VbyteDebug
     118        s = 0;
     119        lnth = 0;
     120        ulink = &vh;
     121        AddThisAfter( s, *vh.Header.blink );
     122#ifdef VbyteDebug
     123        serr | "exit:HandleNode::HandleNode, s:" | &s;
    124124#endif // VbyteDebug
    125125} // HandleNode
     
    131131static void ^?{}( HandleNode & s ) with(s) {
    132132#ifdef VbyteDebug
    133     serr | "enter:HandleNode::~HandleNode, s:" | & s;
    134     {
    135         serr | nlOff;
    136         serr | " lnth:" | lnth | " s:" | (void *)s | ",\"";
    137         for ( i; lnth ) {
    138             serr | s[i];
    139         } // for
    140         serr | "\" flink:" | flink | " blink:" | blink | nl;
    141         serr | nlOn;
    142     }
    143 #endif // VbyteDebug
    144     DeleteNode( s );
     133        serr | "enter:HandleNode::~HandleNode, s:" | & s;
     134        {
     135                serr | nlOff;
     136                serr | " lnth:" | lnth | " s:" | (void *)s | ",\"";
     137                for ( i; lnth ) {
     138                        serr | s[i];
     139                } // for
     140                serr | "\" flink:" | flink | " blink:" | blink | nl;
     141                serr | nlOn;
     142        }
     143#endif // VbyteDebug
     144        DeleteNode( s );
    145145} // ~HandleNode
    146146
     
    148148//######################### String Sharing Context #########################
    149149
    150 static string_sharectx * ambient_string_sharectx;               // fickle top of stack
     150static string_sharectx * ambient_string_sharectx;               // fickle top of stack
    151151static string_sharectx default_string_sharectx = {NEW_SHARING}; // stable bottom of stack
    152152
    153153void ?{}( string_sharectx & s, StringSharectx_Mode mode ) with( s ) {
    154     (older){ ambient_string_sharectx };
    155     if ( mode == NEW_SHARING ) {
    156         (activeHeap){ new( (size_t) 1000 ) };
    157     } else {
    158         verify( mode == NO_SHARING );
    159         (activeHeap){ 0p };
    160     }
    161     ambient_string_sharectx = & s;
     154        (older){ ambient_string_sharectx };
     155        if ( mode == NEW_SHARING ) {
     156                (activeHeap){ new( (size_t) 1000 ) };
     157        } else {
     158                verify( mode == NO_SHARING );
     159                (activeHeap){ 0p };
     160        }
     161        ambient_string_sharectx = & s;
    162162}
    163163
    164164void ^?{}( string_sharectx & s ) with( s ) {
    165     if ( activeHeap ) delete( activeHeap );
    166 
    167     // unlink s from older-list starting from ambient_string_sharectx
    168     // usually, s==ambient_string_sharectx and the loop runs zero times
    169     string_sharectx *& c = ambient_string_sharectx;
    170     while ( c != &s ) &c = &c->older;              // find s
    171     c = s.older;                                   // unlink
     165        if ( activeHeap ) delete( activeHeap );
     166
     167        // unlink s from older-list starting from ambient_string_sharectx
     168        // usually, s==ambient_string_sharectx and the loop runs zero times
     169        string_sharectx *& c = ambient_string_sharectx;
     170        while ( c != &s ) &c = &c->older;                                       // find s
     171        c = s.older;                                                                            // unlink
    172172}
    173173
     
    176176
    177177VbyteHeap * DEBUG_string_heap() {
    178     assert( ambient_string_sharectx->activeHeap && "No sharing context is active" );
    179     return ambient_string_sharectx->activeHeap;
     178        assert( ambient_string_sharectx->activeHeap && "No sharing context is active" );
     179        return ambient_string_sharectx->activeHeap;
    180180}
    181181
    182182size_t DEBUG_string_bytes_avail_until_gc( VbyteHeap * heap ) {
    183     return ((char *)heap->ExtVbyte) - heap->EndVbyte;
     183        return ((char *)heap->ExtVbyte) - heap->EndVbyte;
    184184}
    185185
    186186size_t DEBUG_string_bytes_in_heap( VbyteHeap * heap ) {
    187     return heap->CurrSize;
     187        return heap->CurrSize;
    188188}
    189189
    190190const char * DEBUG_string_heap_start( VbyteHeap * heap ) {
    191     return heap->StartVbyte;
     191        return heap->StartVbyte;
    192192}
    193193
    194194// Returns the size of the string in bytes
    195195size_t size(const string_res & s) with(s) {
    196     return Handle.lnth;
     196        return Handle.lnth;
    197197}
    198198
     
    201201        // CFA string is NOT null terminated, so print exactly lnth characters in a minimum width of 0.
    202202        out | wd( 0, s.Handle.lnth, s.Handle.s ) | nonl;
    203     return out;
     203        return out;
    204204}
    205205
     
    210210// Input operator
    211211ifstream & ?|?(ifstream & in, string_res & s) {
    212     // Reading into a temp before assigning to s is near zero overhead in typical cases because of sharing.
    213     // If s is a substring of something larger, simple assignment takes care of that case correctly.
    214     // But directly reading a variable amount of text into the middle of a larger context is not practical.
    215     string_res temp;
    216 
    217     // Read in chunks.  Often, one chunk is enough.  Keep the string that accumulates chunks last in the heap,
    218     // so available room is rest of heap.  When a chunk fills the heap, force growth then take the next chunk.
    219     for (bool cont = true; cont; ) {
    220         cont = false;
    221 
    222         // Append dummy content to temp, forcing expansion when applicable (occurs always on subsequent loops)
    223         // length 2 ensures room for at least one real char, plus scanf/pipe-cstr's null terminator
    224         temp += "--";
    225         assert( temp.Handle.ulink->EndVbyte == temp.Handle.s + temp.Handle.lnth );    // last in heap
    226 
    227         // reset, to overwrite the appended "--"
    228         temp.Handle.lnth -= 2;
    229         temp.Handle.ulink->EndVbyte -= 2;
    230 
    231         // rest of heap is available to read into
    232         int lenReadable = (char *)temp.Handle.ulink->ExtVbyte - temp.Handle.ulink->EndVbyte;
    233         assert (lenReadable >= 2);
    234 
    235         // get bytes
    236         try {
     212        // Reading into a temp before assigning to s is near zero overhead in typical cases because of sharing.
     213        // If s is a substring of something larger, simple assignment takes care of that case correctly.
     214        // But directly reading a variable amount of text into the middle of a larger context is not practical.
     215        string_res temp;
     216
     217        // Read in chunks.  Often, one chunk is enough.  Keep the string that accumulates chunks last in the heap,
     218        // so available room is rest of heap.  When a chunk fills the heap, force growth then take the next chunk.
     219        for (bool cont = true; cont; ) {
     220                cont = false;
     221
     222                // Append dummy content to temp, forcing expansion when applicable (occurs always on subsequent loops)
     223                // length 2 ensures room for at least one real char, plus scanf/pipe-cstr's null terminator
     224                temp += "--";
     225                assert( temp.Handle.ulink->EndVbyte == temp.Handle.s + temp.Handle.lnth );      // last in heap
     226
     227                // reset, to overwrite the appended "--"
     228                temp.Handle.lnth -= 2;
     229                temp.Handle.ulink->EndVbyte -= 2;
     230
     231                // rest of heap is available to read into
     232                int lenReadable = (char *)temp.Handle.ulink->ExtVbyte - temp.Handle.ulink->EndVbyte;
     233                assert (lenReadable >= 2);
     234
     235                // get bytes
     236                try {
    237237                        *(temp.Handle.ulink->EndVbyte) = '\0';   // pre-assign empty cstring
    238             in | wdi( lenReadable, temp.Handle.ulink->EndVbyte );
    239         } catch (cstring_length *) {
    240             cont = true;
    241         }
    242         int lenWasRead = strlen(temp.Handle.ulink->EndVbyte);
    243 
    244         // update metadata
    245         temp.Handle.lnth += lenWasRead;
    246         temp.Handle.ulink->EndVbyte += lenWasRead;
    247     }
     238                        in | wdi( lenReadable, temp.Handle.ulink->EndVbyte );
     239                } catch (cstring_length *) {
     240                        cont = true;
     241                }
     242                int lenWasRead = strlen(temp.Handle.ulink->EndVbyte);
     243
     244                // update metadata
     245                temp.Handle.lnth += lenWasRead;
     246                temp.Handle.ulink->EndVbyte += lenWasRead;
     247        }
    248248
    249249        if ( temp.Handle.lnth > 0 ) s = temp;
    250     return in;
    251 }
    252 
    253 void ?|?( ifstream & in, string_res & s ) {
    254     (ifstream &)(in | s);
     250        return in;
     251}
     252
     253ifstream & ?|?( ifstream & is, _Istream_Rquoted f ) with( f.rstr ) {
     254        if ( eof( is ) ) throwResume ExceptionInst( missing_data );
     255        int args;
     256  fini: {
     257                char rfmt[5] = { ' ', delimiters[0], '%', 'n', '\0' };
     258                int len = -1;                                                                   // may not be set in fmt
     259                args = fmt( is, rfmt, &len );                                   // remove leading whitespace and quote
     260          if ( eof( is ) || len == -1 ) break fini;
     261
     262                // Change the remainder of the read into a getline by reseting the closing delimiter.
     263                if ( delimiters[1] != '\0' ) {
     264                        delimiters[0] = delimiters[1];
     265                        delimiters[1] = '\0';
     266                } // if
     267                flags.delimiter = true;
     268                return is | *(_Istream_Rstr *)&f;
     269        } // fini
     270        // read failed => no pattern match => set string to null
     271        if ( ! flags.ignore && s != 0p && args == 0 ) s[0] = '\0';
     272        if ( args == 1 && eof( is ) ) {                                         // data but scan ended at EOF
     273                clear( is );                                                                    // => reset EOF => detect again on next read
     274        } // if
     275        return is;
    255276}
    256277
     
    295316} // ?|?
    296317
    297 void ?|?( ifstream & in, _Istream_Rstr f ) {
    298     (ifstream &)(in | f);
    299 }
    300 
    301 
    302318// Empty constructor
    303319void ?{}(string_res & s) with(s) {
    304     if( ambient_string_sharectx->activeHeap ) {
    305         (Handle){ * ambient_string_sharectx->activeHeap };
    306         (shareEditSet_owns_ulink){ false };
    307         verify( Handle.s == 0p && Handle.lnth == 0 );
    308     } else {
    309         (Handle){ * new( (size_t) 10 ) };  // TODO: can I lazily avoid allocating for empty string
    310         (shareEditSet_owns_ulink){ true };
    311         Handle.s = Handle.ulink->StartVbyte;
    312         verify( Handle.lnth == 0 );
    313     }
    314     s.shareEditSet_prev = &s;
    315     s.shareEditSet_next = &s;
    316 }
     320        if( ambient_string_sharectx->activeHeap ) {
     321                (Handle){ * ambient_string_sharectx->activeHeap };
     322                (shareEditSet_owns_ulink){ false };
     323                verify( Handle.s == 0p && Handle.lnth == 0 );
     324        } else {
     325                (Handle){ * new( (size_t) 10 ) };  // TODO: can I lazily avoid allocating for empty string
     326                (shareEditSet_owns_ulink){ true };
     327                Handle.s = Handle.ulink->StartVbyte;
     328                verify( Handle.lnth == 0 );
     329        }
     330        s.shareEditSet_prev = &s;
     331        s.shareEditSet_next = &s;
     332                }
    317333
    318334static void eagerCopyCtorHelper(string_res & s, const char * rhs, size_t rhslnth) with(s) {
    319     if( ambient_string_sharectx->activeHeap ) {
    320         (Handle){ * ambient_string_sharectx->activeHeap };
    321         (shareEditSet_owns_ulink){ false };
    322     } else {
    323         (Handle){ * new( rhslnth ) };
    324         (shareEditSet_owns_ulink){ true };
    325     }
    326     Handle.s = VbyteAlloc(*Handle.ulink, rhslnth);
    327     Handle.lnth = rhslnth;
    328     memmove( Handle.s, rhs, rhslnth );
    329     s.shareEditSet_prev = &s;
    330     s.shareEditSet_next = &s;
     335        if( ambient_string_sharectx->activeHeap ) {
     336                (Handle){ * ambient_string_sharectx->activeHeap };
     337                (shareEditSet_owns_ulink){ false };
     338        } else {
     339                (Handle){ * new( rhslnth ) };
     340                (shareEditSet_owns_ulink){ true };
     341        }
     342        Handle.s = VbyteAlloc(*Handle.ulink, rhslnth);
     343        Handle.lnth = rhslnth;
     344        memmove( Handle.s, rhs, rhslnth );
     345        s.shareEditSet_prev = &s;
     346        s.shareEditSet_next = &s;
    331347}
    332348
    333349// Constructor from a raw buffer and size
    334350void ?{}(string_res & s, const char * rhs, size_t rhslnth) with(s) {
    335     eagerCopyCtorHelper(s, rhs, rhslnth);
     351        eagerCopyCtorHelper(s, rhs, rhslnth);
    336352}
    337353
    338354void ?{}( string_res & s, ssize_t rhs ) {
    339     char buf[64];
    340     int len;
    341     snprintf( buf, sizeof(buf)-1, "%zd%n", rhs, &len );
    342     ( s ){ buf, len };
     355        char buf[64];
     356        int len;
     357        snprintf( buf, sizeof(buf)-1, "%zd%n", rhs, &len );
     358        ( s ){ buf, len };
    343359}
    344360void ?{}( string_res & s, size_t rhs ) {
    345     char buf[64];
    346     int len;
    347     snprintf( buf, sizeof(buf)-1, "%zu%n", rhs, &len );
    348     ( s ){ buf, len };
     361        char buf[64];
     362        int len;
     363        snprintf( buf, sizeof(buf)-1, "%zu%n", rhs, &len );
     364        ( s ){ buf, len };
    349365}
    350366void ?{}( string_res & s, double rhs ) {
    351     char buf[64];
    352     int len;
    353     snprintf( buf, sizeof(buf)-1, "%g%n", rhs, &len );
    354     ( s ){ buf, len };
     367        char buf[64];
     368        int len;
     369        snprintf( buf, sizeof(buf)-1, "%g%n", rhs, &len );
     370        ( s ){ buf, len };
    355371}
    356372void ?{}( string_res & s, long double rhs ) {
    357     char buf[64];
    358     int len;
    359     snprintf( buf, sizeof(buf)-1, "%Lg%n", rhs, &len );
    360     ( s ){ buf, len };
     373        char buf[64];
     374        int len;
     375        snprintf( buf, sizeof(buf)-1, "%Lg%n", rhs, &len );
     376        ( s ){ buf, len };
    361377}
    362378void ?{}( string_res & s, double _Complex rhs ) {
    363     char buf[64];
    364     int len;
    365     snprintf( buf, sizeof(buf)-1, "%g+%gi%n", creal( rhs ), cimag( rhs ), &len );
    366     ( s ){ buf, len };
     379        char buf[64];
     380        int len;
     381        snprintf( buf, sizeof(buf)-1, "%g+%gi%n", creal( rhs ), cimag( rhs ), &len );
     382        ( s ){ buf, len };
    367383}
    368384void ?{}( string_res & s, long double _Complex rhs ) {
    369     char buf[64];
    370     int len;
    371     snprintf( buf, sizeof(buf)-1, "%Lg+%Lgi%n", creall( rhs ), cimagl( rhs ), &len );
    372     ( s ){ buf, len };
     385        char buf[64];
     386        int len;
     387        snprintf( buf, sizeof(buf)-1, "%Lg+%Lgi%n", creall( rhs ), cimagl( rhs ), &len );
     388        ( s ){ buf, len };
    373389}
    374390
    375391// private ctor (not in header): use specified heap (ignore ambient) and copy chars in
    376392void ?{}( string_res & s, VbyteHeap & heap, const char * rhs, size_t rhslnth ) with(s) {
    377     (Handle){ heap };
    378     Handle.s = VbyteAlloc(*Handle.ulink, rhslnth);
    379     Handle.lnth = rhslnth;
    380     (s.shareEditSet_owns_ulink){ false };
    381     memmove( Handle.s, rhs, rhslnth );
    382     s.shareEditSet_prev = &s;
    383     s.shareEditSet_next = &s;
     393        (Handle){ heap };
     394        Handle.s = VbyteAlloc(*Handle.ulink, rhslnth);
     395        Handle.lnth = rhslnth;
     396        (s.shareEditSet_owns_ulink){ false };
     397        memmove( Handle.s, rhs, rhslnth );
     398        s.shareEditSet_prev = &s;
     399        s.shareEditSet_next = &s;
    384400}
    385401
     
    387403// General copy constructor
    388404void ?{}(string_res & s, const string_res & s2, StrResInitMode mode, size_t start, size_t len ) {
    389 
    390     size_t end = start + len;
    391     verify( start <= end && end <= s2.Handle.lnth );
    392 
    393     if (s2.Handle.ulink != ambient_string_sharectx->activeHeap && mode == COPY_VALUE) {
    394         // crossing heaps (including private): copy eagerly
    395         eagerCopyCtorHelper(s, s2.Handle.s + start, end - start);
    396         verify(s.shareEditSet_prev == &s);
    397         verify(s.shareEditSet_next == &s);
    398     } else {
    399         (s.Handle){};
    400         s.Handle.s = s2.Handle.s + start;
    401         s.Handle.lnth = end - start;
    402         s.Handle.ulink = s2.Handle.ulink;
    403 
    404         AddThisAfter(s.Handle, s2.Handle );                     // insert this handle after rhs handle
    405         // ^ bug?  skip others at early point in string
    406 
    407         if (mode == COPY_VALUE) {
    408             verify(s2.Handle.ulink == ambient_string_sharectx->activeHeap);
    409             // requested logical copy in same heap: defer copy until write
    410 
    411             (s.shareEditSet_owns_ulink){ false };
    412 
    413             // make s alone in its shareEditSet
    414             s.shareEditSet_prev = &s;
    415             s.shareEditSet_next = &s;
    416         } else {
    417             verify( mode == SHARE_EDITS );
    418             // sharing edits with source forces same heap as source (ignore context)
    419 
    420             (s.shareEditSet_owns_ulink){ s2.shareEditSet_owns_ulink };
    421 
    422             // s2 is logically const but not implementation const
    423             string_res & s2mod = (string_res &) s2;
    424 
    425             // insert s after s2 on shareEditSet
    426             s.shareEditSet_next = s2mod.shareEditSet_next;
    427             s.shareEditSet_prev = &s2mod;
    428             s.shareEditSet_next->shareEditSet_prev = &s;
    429             s.shareEditSet_prev->shareEditSet_next = &s;
    430         }
    431     }
     405        size_t end = start + len;
     406        verify( start <= end && end <= s2.Handle.lnth );
     407
     408        if (s2.Handle.ulink != ambient_string_sharectx->activeHeap && mode == COPY_VALUE) {
     409                // crossing heaps (including private): copy eagerly
     410                eagerCopyCtorHelper(s, s2.Handle.s + start, end - start);
     411                verify(s.shareEditSet_prev == &s);
     412                verify(s.shareEditSet_next == &s);
     413        } else {
     414                (s.Handle){};
     415                s.Handle.s = s2.Handle.s + start;
     416                s.Handle.lnth = end - start;
     417                s.Handle.ulink = s2.Handle.ulink;
     418
     419                AddThisAfter(s.Handle, s2.Handle );                     // insert this handle after rhs handle
     420                // ^ bug?  skip others at early point in string
     421
     422                if (mode == COPY_VALUE) {
     423                        verify(s2.Handle.ulink == ambient_string_sharectx->activeHeap);
     424                        // requested logical copy in same heap: defer copy until write
     425
     426                        (s.shareEditSet_owns_ulink){ false };
     427
     428                        // make s alone in its shareEditSet
     429                        s.shareEditSet_prev = &s;
     430                        s.shareEditSet_next = &s;
     431                } else {
     432                        verify( mode == SHARE_EDITS );
     433                        // sharing edits with source forces same heap as source (ignore context)
     434
     435                        (s.shareEditSet_owns_ulink){ s2.shareEditSet_owns_ulink };
     436
     437                        // s2 is logically const but not implementation const
     438                        string_res & s2mod = (string_res &) s2;
     439
     440                        // insert s after s2 on shareEditSet
     441                        s.shareEditSet_next = s2mod.shareEditSet_next;
     442                        s.shareEditSet_prev = &s2mod;
     443                        s.shareEditSet_next->shareEditSet_prev = &s;
     444                        s.shareEditSet_prev->shareEditSet_next = &s;
     445                }
     446        }
    432447}
    433448
    434449static void assignEditSet(string_res & s, string_res * shareEditSetStartPeer, string_res * shareEditSetEndPeer,
    435     char * resultSesStart,
    436     size_t resultSesLnth,
    437     HandleNode * resultPadPosition, size_t bsize ) {
    438 
    439     char * beforeBegin = shareEditSetStartPeer->Handle.s;
    440     size_t beforeLen = s.Handle.s - beforeBegin;
    441 
    442     char * afterBegin = s.Handle.s + s.Handle.lnth;
    443     size_t afterLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - afterBegin;
    444 
    445     size_t oldLnth = s.Handle.lnth;
    446 
    447     s.Handle.s = resultSesStart + beforeLen;
    448     s.Handle.lnth = bsize;
    449     if (resultPadPosition)
    450         MoveThisAfter( s.Handle, *resultPadPosition );
    451 
    452     // adjust all substring string and handle locations, and check if any substring strings are outside the new base string
    453     char *limit = resultSesStart + resultSesLnth;
    454     for ( string_res * p = s.shareEditSet_next; p != &s; p = p->shareEditSet_next ) {
    455         verify (p->Handle.s >= beforeBegin);
    456         if ( p->Handle.s >= afterBegin ) {
    457             verify ( p->Handle.s <= afterBegin + afterLen );
    458             verify ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );
    459             // p starts after the edit
    460             // take start and end as end-anchored
    461             size_t startOffsetFromEnd = afterBegin + afterLen - p->Handle.s;
    462             p->Handle.s = limit - startOffsetFromEnd;
    463             // p->Handle.lnth unaffected
    464         } else if ( p->Handle.s <= beforeBegin + beforeLen ) {
    465             // p starts before, or at the start of, the edit
    466             if ( p->Handle.s + p->Handle.lnth <= beforeBegin + beforeLen ) {
    467                 // p ends before the edit
    468                 // take end as start-anchored too
    469                 // p->Handle.lnth unaffected
    470             } else if ( p->Handle.s + p->Handle.lnth < afterBegin ) {
    471                 // p ends during the edit; p does not include the last character replaced
    472                 // clip end of p to end at start of edit
    473                 p->Handle.lnth = beforeLen - ( p->Handle.s - beforeBegin );
    474             } else {
    475                 // p ends after the edit
    476                 verify ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );
    477                 // take end as end-anchored
    478                 // stretch-shrink p according to the edit
    479                 p->Handle.lnth += s.Handle.lnth;
    480                 p->Handle.lnth -= oldLnth;
    481             }
    482             // take start as start-anchored
    483             size_t startOffsetFromStart = p->Handle.s - beforeBegin;
    484             p->Handle.s = resultSesStart + startOffsetFromStart;
    485         } else {
    486             verify ( p->Handle.s < afterBegin );
    487             // p starts during the edit
    488             verify( p->Handle.s + p->Handle.lnth >= beforeBegin + beforeLen );
    489             if ( p->Handle.s + p->Handle.lnth < afterBegin ) {
    490                 // p ends during the edit; p does not include the last character replaced
    491                 // set p to empty string at start of edit
    492                 p->Handle.s = s.Handle.s;
    493                 p->Handle.lnth = 0;
    494             } else {
    495                 // p includes the end of the edit
    496                 // clip start of p to start at end of edit
    497                 int charsToClip = afterBegin - p->Handle.s;
    498                 p->Handle.s = s.Handle.s + s.Handle.lnth;
    499                 p->Handle.lnth -= charsToClip;
    500             }
    501         }
    502         if (resultPadPosition)
    503             MoveThisAfter( p->Handle, *resultPadPosition );     // move substring handle to maintain sorted order by string position
    504     }
     450                                                  char * resultSesStart,
     451                                                  size_t resultSesLnth,
     452                                                  HandleNode * resultPadPosition, size_t bsize ) {
     453
     454        char * beforeBegin = shareEditSetStartPeer->Handle.s;
     455        size_t beforeLen = s.Handle.s - beforeBegin;
     456
     457        char * afterBegin = s.Handle.s + s.Handle.lnth;
     458        size_t afterLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - afterBegin;
     459
     460        size_t oldLnth = s.Handle.lnth;
     461
     462        s.Handle.s = resultSesStart + beforeLen;
     463        s.Handle.lnth = bsize;
     464        if (resultPadPosition)
     465                MoveThisAfter( s.Handle, *resultPadPosition );
     466
     467        // adjust all substring string and handle locations, and check if any substring strings are outside the new base string
     468        char *limit = resultSesStart + resultSesLnth;
     469        for ( string_res * p = s.shareEditSet_next; p != &s; p = p->shareEditSet_next ) {
     470                verify (p->Handle.s >= beforeBegin);
     471                if ( p->Handle.s >= afterBegin ) {
     472                        verify ( p->Handle.s <= afterBegin + afterLen );
     473                        verify ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );
     474                        // p starts after the edit
     475                        // take start and end as end-anchored
     476                        size_t startOffsetFromEnd = afterBegin + afterLen - p->Handle.s;
     477                        p->Handle.s = limit - startOffsetFromEnd;
     478                        // p->Handle.lnth unaffected
     479                } else if ( p->Handle.s <= beforeBegin + beforeLen ) {
     480                        // p starts before, or at the start of, the edit
     481                        if ( p->Handle.s + p->Handle.lnth <= beforeBegin + beforeLen ) {
     482                                // p ends before the edit
     483                                // take end as start-anchored too
     484                                // p->Handle.lnth unaffected
     485                        } else if ( p->Handle.s + p->Handle.lnth < afterBegin ) {
     486                                // p ends during the edit; p does not include the last character replaced
     487                                // clip end of p to end at start of edit
     488                                p->Handle.lnth = beforeLen - ( p->Handle.s - beforeBegin );
     489                        } else {
     490                                // p ends after the edit
     491                                verify ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );
     492                                // take end as end-anchored
     493                                // stretch-shrink p according to the edit
     494                                p->Handle.lnth += s.Handle.lnth;
     495                                p->Handle.lnth -= oldLnth;
     496                        }
     497                        // take start as start-anchored
     498                        size_t startOffsetFromStart = p->Handle.s - beforeBegin;
     499                        p->Handle.s = resultSesStart + startOffsetFromStart;
     500                } else {
     501                        verify ( p->Handle.s < afterBegin );
     502                        // p starts during the edit
     503                        verify( p->Handle.s + p->Handle.lnth >= beforeBegin + beforeLen );
     504                        if ( p->Handle.s + p->Handle.lnth < afterBegin ) {
     505                                // p ends during the edit; p does not include the last character replaced
     506                                // set p to empty string at start of edit
     507                                p->Handle.s = s.Handle.s;
     508                                p->Handle.lnth = 0;
     509                        } else {
     510                                // p includes the end of the edit
     511                                // clip start of p to start at end of edit
     512                                int charsToClip = afterBegin - p->Handle.s;
     513                                p->Handle.s = s.Handle.s + s.Handle.lnth;
     514                                p->Handle.lnth -= charsToClip;
     515                        }
     516                }
     517                if (resultPadPosition)
     518                        MoveThisAfter( p->Handle, *resultPadPosition ); // move substring handle to maintain sorted order by string position
     519        }
    505520}
    506521
    507522// traverse the share-edit set (SES) to recover the range of a base string to which `s` belongs
    508523static void locateInShareEditSet( string_res & s, string_res *& shareEditSetStartPeer, string_res *& shareEditSetEndPeer ) {
    509     shareEditSetStartPeer = & s;
    510     shareEditSetEndPeer = & s;
    511     for (string_res * editPeer = s.shareEditSet_next; editPeer != &s; editPeer = editPeer->shareEditSet_next) {
    512         if ( editPeer->Handle.s < shareEditSetStartPeer->Handle.s ) {
    513             shareEditSetStartPeer = editPeer;
    514         }
    515         if ( shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth < editPeer->Handle.s + editPeer->Handle.lnth) {
    516             shareEditSetEndPeer = editPeer;
    517         }
    518     }
     524        shareEditSetStartPeer = & s;
     525        shareEditSetEndPeer = & s;
     526        for (string_res * editPeer = s.shareEditSet_next; editPeer != &s; editPeer = editPeer->shareEditSet_next) {
     527                if ( editPeer->Handle.s < shareEditSetStartPeer->Handle.s ) {
     528                        shareEditSetStartPeer = editPeer;
     529                }
     530                if ( shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth < editPeer->Handle.s + editPeer->Handle.lnth) {
     531                        shareEditSetEndPeer = editPeer;
     532                }
     533        }
    519534}
    520535
    521536static string_res & assign_(string_res & s, const char * buffer, size_t bsize, const string_res & valSrc) {
    522 
    523     string_res * shareEditSetStartPeer;
    524     string_res * shareEditSetEndPeer;
    525     locateInShareEditSet( s, shareEditSetStartPeer, shareEditSetEndPeer );
    526 
    527     verify( shareEditSetEndPeer->Handle.s >= shareEditSetStartPeer->Handle.s );
    528     size_t origEditSetLength = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - shareEditSetStartPeer->Handle.s;
    529     verify( origEditSetLength >= s.Handle.lnth );
    530 
    531     if ( s.shareEditSet_owns_ulink ) {                 // assigning to private context
    532         // ok to overwrite old value within LHS
    533         char * prefixStartOrig = shareEditSetStartPeer->Handle.s;
    534         int prefixLen = s.Handle.s - prefixStartOrig;
    535         char * suffixStartOrig = s.Handle.s + s.Handle.lnth;
    536         int suffixLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - suffixStartOrig;
    537 
    538         int delta = bsize - s.Handle.lnth;
    539         if ( char * oldBytes = VbyteTryAdjustLast( *s.Handle.ulink, delta ) ) {
    540             // growing: copy from old to new
    541             char * dest = VbyteAlloc( *s.Handle.ulink, origEditSetLength + delta );
    542             char *destCursor = dest;  memcpy(destCursor, prefixStartOrig, prefixLen);
    543             destCursor += prefixLen;  memcpy(destCursor, buffer         , bsize    );
    544             destCursor += bsize;      memcpy(destCursor, suffixStartOrig, suffixLen);
    545             assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer,
    546                 dest,
    547                 origEditSetLength + delta,
    548                 0p, bsize);
    549             free( oldBytes );
    550         } else {
    551             // room is already allocated in-place: bubble suffix and overwite middle
    552             memmove( suffixStartOrig + delta, suffixStartOrig, suffixLen );
    553             memcpy( s.Handle.s, buffer, bsize );
    554 
    555             assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer,
    556                 shareEditSetStartPeer->Handle.s,
    557                 origEditSetLength + delta,
    558                 0p, bsize);
    559         }
    560 
    561     } else if (                                           // assigning to shared context
    562         s.Handle.lnth == origEditSetLength &&          // overwriting entire run of SES
    563         & valSrc &&                                       // sourcing from a managed string
    564         valSrc.Handle.ulink == s.Handle.ulink  ) {     // sourcing from same heap
    565 
    566         // SES's result will only use characters from the source string => reuse source
    567         assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer,
    568             valSrc.Handle.s,
    569             valSrc.Handle.lnth,
    570             &((string_res&)valSrc).Handle, bsize);
    571        
    572     } else {
    573         // overwriting a proper substring of some string: mash characters from old and new together (copy on write)
    574         // OR we are importing characters: need to copy eagerly (can't refer to source)
    575 
    576         // full string is from start of shareEditSetStartPeer thru end of shareEditSetEndPeer
    577         // `s` occurs in the middle of it, to be replaced
    578         // build up the new text in `pasting`
    579 
    580         string_res pasting = {
    581             * s.Handle.ulink,                               // maintain same heap, regardless of context
    582             shareEditSetStartPeer->Handle.s,                   // start of SES
    583             s.Handle.s - shareEditSetStartPeer->Handle.s }; // length of SES, before s
    584         append( pasting,
    585             buffer,                                            // start of replacement for s
    586             bsize );                                           // length of replacement for s
    587         append( pasting,
    588             s.Handle.s + s.Handle.lnth,                  // start of SES after s
    589             shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth -
    590             (s.Handle.s + s.Handle.lnth) );              // length of SES, after s
    591 
    592         // The above string building can trigger compaction.
    593         // The reference points (that are arguments of the string building) may move during that building.
    594         // From s point on, they are stable.
    595 
    596         assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer,
    597             pasting.Handle.s,
    598             pasting.Handle.lnth,
    599             &pasting.Handle, bsize);
    600     }
    601 
    602     return s;
     537        string_res * shareEditSetStartPeer;
     538        string_res * shareEditSetEndPeer;
     539        locateInShareEditSet( s, shareEditSetStartPeer, shareEditSetEndPeer );
     540
     541        verify( shareEditSetEndPeer->Handle.s >= shareEditSetStartPeer->Handle.s );
     542        size_t origEditSetLength = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - shareEditSetStartPeer->Handle.s;
     543        verify( origEditSetLength >= s.Handle.lnth );
     544
     545        if ( s.shareEditSet_owns_ulink ) {                               // assigning to private context
     546                // ok to overwrite old value within LHS
     547                char * prefixStartOrig = shareEditSetStartPeer->Handle.s;
     548                int prefixLen = s.Handle.s - prefixStartOrig;
     549                char * suffixStartOrig = s.Handle.s + s.Handle.lnth;
     550                int suffixLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - suffixStartOrig;
     551
     552                int delta = bsize - s.Handle.lnth;
     553                if ( char * oldBytes = VbyteTryAdjustLast( *s.Handle.ulink, delta ) ) {
     554                        // growing: copy from old to new
     555                        char * dest = VbyteAlloc( *s.Handle.ulink, origEditSetLength + delta );
     556                        char *destCursor = dest;  memcpy(destCursor, prefixStartOrig, prefixLen);
     557                        destCursor += prefixLen;  memcpy(destCursor, buffer              , bsize        );
     558                        destCursor += bsize;      memcpy(destCursor, suffixStartOrig, suffixLen);
     559                        assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer,
     560                                                  dest,
     561                                                  origEditSetLength + delta,
     562                                                  0p, bsize);
     563                        free( oldBytes );
     564                } else {
     565                        // room is already allocated in-place: bubble suffix and overwite middle
     566                        memmove( suffixStartOrig + delta, suffixStartOrig, suffixLen );
     567                        memcpy( s.Handle.s, buffer, bsize );
     568
     569                        assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer,
     570                                                  shareEditSetStartPeer->Handle.s,
     571                                                  origEditSetLength + delta,
     572                                                  0p, bsize);
     573                }
     574
     575        } else if (                                                                                // assigning to shared context
     576                s.Handle.lnth == origEditSetLength &&             // overwriting entire run of SES
     577                & valSrc &&                                                                        // sourcing from a managed string
     578                valSrc.Handle.ulink == s.Handle.ulink  ) {       // sourcing from same heap
     579
     580                // SES's result will only use characters from the source string => reuse source
     581                assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer,
     582                                          valSrc.Handle.s,
     583                                          valSrc.Handle.lnth,
     584                                          &((string_res&)valSrc).Handle, bsize);
     585               
     586        } else {
     587                // overwriting a proper substring of some string: mash characters from old and new together (copy on write)
     588                // OR we are importing characters: need to copy eagerly (can't refer to source)
     589
     590                // full string is from start of shareEditSetStartPeer thru end of shareEditSetEndPeer
     591                // `s` occurs in the middle of it, to be replaced
     592                // build up the new text in `pasting`
     593
     594                string_res pasting = {
     595                        * s.Handle.ulink,                                                          // maintain same heap, regardless of context
     596                        shareEditSetStartPeer->Handle.s,                                   // start of SES
     597                        s.Handle.s - shareEditSetStartPeer->Handle.s }; // length of SES, before s
     598                append( pasting,
     599                                buffer,                                                                                 // start of replacement for s
     600                                bsize );                                                                                   // length of replacement for s
     601                append( pasting,
     602                                s.Handle.s + s.Handle.lnth,                               // start of SES after s
     603                                shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth -
     604                                (s.Handle.s + s.Handle.lnth) );                   // length of SES, after s
     605
     606                // The above string building can trigger compaction.
     607                // The reference points (that are arguments of the string building) may move during that building.
     608                // From s point on, they are stable.
     609
     610                assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer,
     611                                          pasting.Handle.s,
     612                                          pasting.Handle.lnth,
     613                                          &pasting.Handle, bsize);
     614        }
     615
     616        return s;
    603617}
    604618
    605619string_res & assign(string_res & s, const string_res & src, size_t maxlen) {
    606     return assign_(s, src.Handle.s, min(src.Handle.lnth, maxlen), *0p);
     620        return assign_(s, src.Handle.s, min(src.Handle.lnth, maxlen), *0p);
    607621}
    608622
    609623string_res & assign(string_res & s, const char * buffer, size_t bsize) {
    610     return assign_(s, buffer, bsize, *0p);
     624        return assign_(s, buffer, bsize, *0p);
    611625}
    612626
    613627string_res & ?=?(string_res & s, char c) {
    614     return assign(s, &c, 1);
     628        return assign(s, &c, 1);
    615629}
    616630
    617631string_res & ?=?( string_res & s, ssize_t rhs ) {
    618     string_res rhs2 = rhs;
    619     s = rhs2;
    620     return s;
     632        string_res rhs2 = rhs;
     633        s = rhs2;
     634        return s;
    621635}
    622636string_res & ?=?( string_res & s, size_t rhs ) {
    623     string_res rhs2 = rhs;
    624     s = rhs2;
    625     return s;
     637        string_res rhs2 = rhs;
     638        s = rhs2;
     639        return s;
    626640}
    627641string_res & ?=?( string_res & s, double rhs ) {
    628     string_res rhs2 = rhs;
    629     s = rhs2;
    630     return s;
     642        string_res rhs2 = rhs;
     643        s = rhs2;
     644        return s;
    631645}
    632646string_res & ?=?( string_res & s, long double rhs ) {
    633     string_res rhs2 = rhs;
    634     s = rhs2;
    635     return s;
     647        string_res rhs2 = rhs;
     648        s = rhs2;
     649        return s;
    636650}
    637651string_res & ?=?( string_res & s, double _Complex rhs ) {
    638     string_res rhs2 = rhs;
    639     s = rhs2;
    640     return s;
     652        string_res rhs2 = rhs;
     653        s = rhs2;
     654        return s;
    641655}
    642656string_res & ?=?( string_res & s, long double _Complex rhs ) {
    643     string_res rhs2 = rhs;
    644     s = rhs2;
    645     return s;
     657        string_res rhs2 = rhs;
     658        s = rhs2;
     659        return s;
    646660}
    647661
    648662// Copy assignment operator
    649663string_res & ?=?(string_res & s, const string_res & rhs) with( s ) {
    650     return assign_(s, rhs.Handle.s, rhs.Handle.lnth, rhs);
     664        return assign_(s, rhs.Handle.s, rhs.Handle.lnth, rhs);
    651665}
    652666
    653667string_res & ?=?(string_res & s, string_res & rhs) with( s ) {
    654     const string_res & rhs2 = rhs;
    655     return s = rhs2;
     668        const string_res & rhs2 = rhs;
     669        return s = rhs2;
    656670}
    657671
     
    659673// Destructor
    660674void ^?{}(string_res & s) with(s) {
    661     // much delegated to implied ^VbyteSM
    662 
    663     // sever s from its share-edit peers, if any (four no-ops when already solo)
    664     s.shareEditSet_prev->shareEditSet_next = s.shareEditSet_next;
    665     s.shareEditSet_next->shareEditSet_prev = s.shareEditSet_prev;
    666     // s.shareEditSet_next = &s;
    667     // s.shareEditSet_prev = &s;
    668 
    669     if (shareEditSet_owns_ulink && s.shareEditSet_next == &s) { // last one out
    670         delete( s.Handle.ulink );
    671     }
     675        // much delegated to implied ^VbyteSM
     676
     677        // sever s from its share-edit peers, if any (four no-ops when already solo)
     678        s.shareEditSet_prev->shareEditSet_next = s.shareEditSet_next;
     679        s.shareEditSet_next->shareEditSet_prev = s.shareEditSet_prev;
     680        // s.shareEditSet_next = &s;
     681        // s.shareEditSet_prev = &s;
     682
     683        if (shareEditSet_owns_ulink && s.shareEditSet_next == &s) { // last one out
     684                delete( s.Handle.ulink );
     685        }
    672686}
    673687
     
    677691// offset from the start of the string.
    678692char ?[?](const string_res & s, size_t index) with(s) {
    679     //TODO: Check if index is valid (no exceptions yet)
    680     return Handle.s[index];
     693        //TODO: Check if index is valid (no exceptions yet)
     694        return Handle.s[index];
    681695}
    682696
    683697void assignAt(const string_res & s, size_t index, char val) {
    684     // caution: not tested (not reachable by string-api-coverage interface)
    685     // equivalent form at string level is `s[index] = val`,
    686     // which uses the overload that returns a length-1 string
    687     string_res editZone = { s, SHARE_EDITS, index, 1 };
    688     assign(editZone, &val, 1);
     698        // caution: not tested (not reachable by string-api-coverage interface)
     699        // equivalent form at string level is `s[index] = val`,
     700        // which uses the overload that returns a length-1 string
     701        string_res editZone = { s, SHARE_EDITS, index, 1 };
     702        assign(editZone, &val, 1);
    689703}
    690704
     
    694708
    695709void append(string_res & str1, const char * buffer, size_t bsize) {
    696     size_t clnth = str1.Handle.lnth + bsize;
    697     if ( str1.Handle.s + str1.Handle.lnth == buffer ) { // already juxtapose ?
    698         // no-op
    699     } else {                                            // must copy some text
    700         if ( str1.Handle.s + str1.Handle.lnth == VbyteAlloc(*str1.Handle.ulink, 0) ) { // str1 at end of string area ?
    701             VbyteAlloc( *str1.Handle.ulink, bsize ); // create room for 2nd part at the end of string area
    702         } else {                                        // copy the two parts
    703             char * str1newBuf = VbyteAlloc( *str1.Handle.ulink, clnth );
    704             char * str1oldBuf = str1.Handle.s;  // must read after VbyteAlloc call in case it gs's
    705             str1.Handle.s = str1newBuf;
    706             memcpy( str1.Handle.s, str1oldBuf,  str1.Handle.lnth );
    707         } // if
    708         memcpy( str1.Handle.s + str1.Handle.lnth, buffer, bsize );
    709     } // if
    710     str1.Handle.lnth = clnth;
     710        size_t clnth = str1.Handle.lnth + bsize;
     711        if ( str1.Handle.s + str1.Handle.lnth == buffer ) { // already juxtapose ?
     712                // no-op
     713        } else {                                                                                        // must copy some text
     714                if ( str1.Handle.s + str1.Handle.lnth == VbyteAlloc(*str1.Handle.ulink, 0) ) { // str1 at end of string area ?
     715                        VbyteAlloc( *str1.Handle.ulink, bsize );        // create room for 2nd part at the end of string area
     716                } else {                                                                                // copy the two parts
     717                        char * str1newBuf = VbyteAlloc( *str1.Handle.ulink, clnth );
     718                        char * str1oldBuf = str1.Handle.s;                      // must read after VbyteAlloc call in case it gs's
     719                        str1.Handle.s = str1newBuf;
     720                        memcpy( str1.Handle.s, str1oldBuf,  str1.Handle.lnth );
     721                } // if
     722                memcpy( str1.Handle.s + str1.Handle.lnth, buffer, bsize );
     723        } // if
     724        str1.Handle.lnth = clnth;
    711725}
    712726
    713727void ?+=?(string_res & str1, const string_res & str2) {
    714     append( str1, str2.Handle.s, str2.Handle.lnth );
     728        append( str1, str2.Handle.s, str2.Handle.lnth );
    715729}
    716730
    717731void append(string_res & str1, const string_res & str2, size_t maxlen) {
    718     append( str1, str2.Handle.s, min(str2.Handle.lnth, maxlen) );
     732        append( str1, str2.Handle.s, min(str2.Handle.lnth, maxlen) );
    719733}
    720734
    721735void ?+=?(string_res & s, char c) {
    722     append( s, & c, 1 );
     736        append( s, & c, 1 );
    723737}
    724738void ?+=?(string_res & s, const char * c) {
    725     append( s, c, strlen(c) );
     739        append( s, c, strlen(c) );
    726740}
    727741
     
    730744
    731745void ?*=?(string_res & s, size_t factor) {
    732     string_res s2 = { s, COPY_VALUE };
    733     s = "";
    734     for (factor) s += s2;
     746        string_res s2 = { s, COPY_VALUE };
     747        s = "";
     748        for (factor) s += s2;
    735749}
    736750
     
    739753
    740754int strcmp(const string_res & s1, const string_res & s2) {
    741     // return 0;
    742     int ans1 = memcmp(s1.Handle.s, s2.Handle.s, min(s1.Handle.lnth, s2.Handle.lnth));
    743     if (ans1 != 0) return ans1;
    744     return s1.Handle.lnth - s2.Handle.lnth;
     755        // return 0;
     756        int ans1 = memcmp(s1.Handle.s, s2.Handle.s, min(s1.Handle.lnth, s2.Handle.lnth));
     757        if (ans1 != 0) return ans1;
     758        return s1.Handle.lnth - s2.Handle.lnth;
    745759}
    746760
     
    753767
    754768int strcmp (const string_res & s1, const char * s2) {
    755     string_res s2x = s2;
    756     return strcmp(s1, s2x);
     769        string_res s2x = s2;
     770        return strcmp(s1, s2x);
    757771}
    758772
     
    765779
    766780int strcmp (const char * s1, const string_res & s2) {
    767     string_res s1x = s1;
    768     return strcmp(s1x, s2);
     781        string_res s1x = s1;
     782        return strcmp(s1x, s2);
    769783}
    770784
     
    777791
    778792
    779 
    780793//////////////////////////////////////////////////////////
    781794// Search
    782795
    783796bool contains(const string_res & s, char ch) {
    784     for ( i; size(s) ) {
    785         if (s[i] == ch) return true;
    786     }
    787     return false;
     797        for ( i; size(s) ) {
     798                if (s[i] == ch) return true;
     799        }
     800        return false;
    788801}
    789802
    790803int find(const string_res & s, char search) {
    791     return findFrom(s, 0, search);
     804        return findFrom(s, 0, search);
    792805}
    793806
    794807int findFrom(const string_res & s, size_t fromPos, char search) {
    795     // FIXME: This paricular overload (find of single char) is optimized to use memchr.
    796     // The general overload (find of string, memchr applying to its first character) and `contains` should be adjusted to match.
    797     char * searchFrom = s.Handle.s + fromPos;
    798     size_t searchLnth = s.Handle.lnth - fromPos;
    799     int searchVal = search;
    800     char * foundAt = (char *) memchr(searchFrom, searchVal, searchLnth);
    801     if (foundAt == 0p) return s.Handle.lnth;
    802     else return foundAt - s.Handle.s;
     808        // FIXME: This paricular overload (find of single char) is optimized to use memchr.
     809        // The general overload (find of string, memchr applying to its first character) and `contains` should be adjusted to match.
     810        char * searchFrom = s.Handle.s + fromPos;
     811        size_t searchLnth = s.Handle.lnth - fromPos;
     812        int searchVal = search;
     813        char * foundAt = (char *) memchr(searchFrom, searchVal, searchLnth);
     814        if (foundAt == 0p) return s.Handle.lnth;
     815        else return foundAt - s.Handle.s;
    803816}
    804817
    805818int find(const string_res & s, const string_res & search) {
    806     return findFrom(s, 0, search);
     819        return findFrom(s, 0, search);
    807820}
    808821
    809822int findFrom(const string_res & s, size_t fromPos, const string_res & search) {
    810     return findFrom(s, fromPos, search.Handle.s, search.Handle.lnth);
     823        return findFrom(s, fromPos, search.Handle.s, search.Handle.lnth);
    811824}
    812825
    813826int find(const string_res & s, const char * search) {
    814     return findFrom(s, 0, search);
     827        return findFrom(s, 0, search);
    815828}
    816829int findFrom(const string_res & s, size_t fromPos, const char * search) {
    817     return findFrom(s, fromPos, search, strlen(search));
     830        return findFrom(s, fromPos, search, strlen(search));
    818831}
    819832
    820833int find(const string_res & s, const char * search, size_t searchsize) {
    821     return findFrom(s, 0, search, searchsize);
     834        return findFrom(s, 0, search, searchsize);
    822835}
    823836
    824837int findFrom(const string_res & s, size_t fromPos, const char * search, size_t searchsize) {
    825 
    826     /* Remaining implementations essentially ported from Sunjay's work */
    827 
    828 
    829     // FIXME: This is a naive algorithm. We probably want to switch to someting
    830     // like Boyer-Moore in the future.
    831     // https://en.wikipedia.org/wiki/String_searching_algorithm
    832 
    833     // Always find the empty string
    834     if (searchsize == 0) {
    835         return 0;
    836     }
    837 
    838     for ( i; fromPos ~ s.Handle.lnth ) {
    839         size_t remaining = s.Handle.lnth - i;
    840         // Never going to find the search string if the remaining string is
    841         // smaller than search
    842         if (remaining < searchsize) {
    843             break;
    844         }
    845 
    846         bool matched = true;
    847         for ( j; searchsize ) {
    848             if (search[j] != s.Handle.s[i + j]) {
    849                 matched = false;
    850                 break;
    851             }
    852         }
    853         if (matched) {
    854             return i;
    855         }
    856     }
    857 
    858     return s.Handle.lnth;
     838        /* Remaining implementations essentially ported from Sunjay's work */
     839
     840        // FIXME: This is a naive algorithm. We probably want to switch to someting
     841        // like Boyer-Moore in the future.
     842        // https://en.wikipedia.org/wiki/String_searching_algorithm
     843
     844        // Always find the empty string
     845        if (searchsize == 0) {
     846                return 0;
     847        }
     848
     849        for ( i; fromPos ~ s.Handle.lnth ) {
     850                size_t remaining = s.Handle.lnth - i;
     851                // Never going to find the search string if the remaining string is
     852                // smaller than search
     853                if (remaining < searchsize) {
     854                        break;
     855                }
     856
     857                bool matched = true;
     858                for ( j; searchsize ) {
     859                        if (search[j] != s.Handle.s[i + j]) {
     860                                matched = false;
     861                                break;
     862                        }
     863                }
     864                if (matched) {
     865                        return i;
     866                }
     867        }
     868        return s.Handle.lnth;
    859869}
    860870
    861871bool includes(const string_res & s, const string_res & search) {
    862     return includes(s, search.Handle.s, search.Handle.lnth);
     872        return includes(s, search.Handle.s, search.Handle.lnth);
    863873}
    864874
    865875bool includes(const string_res & s, const char * search) {
    866     return includes(s, search, strlen(search));
     876        return includes(s, search, strlen(search));
    867877}
    868878
    869879bool includes(const string_res & s, const char * search, size_t searchsize) {
    870     return find(s, search, searchsize) < s.Handle.lnth;
     880        return find(s, search, searchsize) < s.Handle.lnth;
    871881}
    872882
    873883bool startsWith(const string_res & s, const string_res & prefix) {
    874     return startsWith(s, prefix.Handle.s, prefix.Handle.lnth);
     884        return startsWith(s, prefix.Handle.s, prefix.Handle.lnth);
    875885}
    876886
    877887bool startsWith(const string_res & s, const char * prefix) {
    878     return startsWith(s, prefix, strlen(prefix));
     888        return startsWith(s, prefix, strlen(prefix));
    879889}
    880890
    881891bool startsWith(const string_res & s, const char * prefix, size_t prefixsize) {
    882     if (s.Handle.lnth < prefixsize) {
    883         return false;
    884     }
    885     return memcmp(s.Handle.s, prefix, prefixsize) == 0;
     892        if (s.Handle.lnth < prefixsize) {
     893                return false;
     894        }
     895        return memcmp(s.Handle.s, prefix, prefixsize) == 0;
    886896}
    887897
    888898bool endsWith(const string_res & s, const string_res & suffix) {
    889     return endsWith(s, suffix.Handle.s, suffix.Handle.lnth);
     899        return endsWith(s, suffix.Handle.s, suffix.Handle.lnth);
    890900}
    891901
    892902bool endsWith(const string_res & s, const char * suffix) {
    893     return endsWith(s, suffix, strlen(suffix));
     903        return endsWith(s, suffix, strlen(suffix));
    894904}
    895905
    896906bool endsWith(const string_res & s, const char * suffix, size_t suffixsize) {
    897     if (s.Handle.lnth < suffixsize) {
    898         return false;
    899     }
    900     // Amount to offset the bytes pointer so that we are comparing the end of s
    901     // to suffix. s.bytes + offset should be the first byte to compare against suffix
    902     size_t offset = s.Handle.lnth - suffixsize;
    903     return memcmp(s.Handle.s + offset, suffix, suffixsize) == 0;
    904 }
    905 
    906     /* Back to Mike's work */
    907 
     907        if (s.Handle.lnth < suffixsize) {
     908                return false;
     909        }
     910        // Amount to offset the bytes pointer so that we are comparing the end of s
     911        // to suffix. s.bytes + offset should be the first byte to compare against suffix
     912        size_t offset = s.Handle.lnth - suffixsize;
     913        return memcmp(s.Handle.s + offset, suffix, suffixsize) == 0;
     914}
     915
     916/* Back to Mike's work */
    908917
    909918///////////////////////////////////////////////////////////////////////////
     
    911920
    912921void ?{}( charclass_res & s, const string_res & chars) {
    913     (s){ chars.Handle.s, chars.Handle.lnth };
     922        (s){ chars.Handle.s, chars.Handle.lnth };
    914923}
    915924
    916925void ?{}( charclass_res & s, const char * chars ) {
    917     (s){ chars, strlen(chars) };
     926        (s){ chars, strlen(chars) };
    918927}
    919928
    920929void ?{}( charclass_res & s, const char * chars, size_t charssize ) {
    921     (s.chars){ chars, charssize };
    922     // now sort it ?
     930        (s.chars){ chars, charssize };
     931        // now sort it ?
    923932}
    924933
    925934void ^?{}( charclass_res & s ) {
    926     ^(s.chars){};
     935        ^(s.chars){};
    927936}
    928937
    929938static bool test( const charclass_res & mask, char c ) {
    930     // instead, use sorted char list?
    931     return contains( mask.chars, c );
     939        // instead, use sorted char list?
     940        return contains( mask.chars, c );
    932941}
    933942
    934943int exclude(const string_res & s, const charclass_res & mask) {
    935     for ( i; size(s) ) {
    936         if ( test(mask, s[i]) ) return i;
    937     }
    938     return size(s);
     944        for ( i; size(s) ) {
     945                if ( test(mask, s[i]) ) return i;
     946        }
     947        return size(s);
    939948}
    940949
    941950int include(const string_res & s, const charclass_res & mask) {
    942     for ( i; size(s) ) {
    943         if ( ! test(mask, s[i]) ) return i;
    944     }
    945     return size(s);
     951        for ( i; size(s) ) {
     952                if ( ! test(mask, s[i]) ) return i;
     953        }
     954        return size(s);
    946955}
    947956
     
    953962static void AddThisAfter( HandleNode & s, HandleNode & n ) with(s) {
    954963#ifdef VbyteDebug
    955     serr | "enter:AddThisAfter, s:" | &s | " n:" | &n;
    956 #endif // VbyteDebug
    957     // 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).
    958     verify( n.ulink != 0p );
    959     verify( s.ulink == n.ulink );
    960     flink = n.flink;
    961     blink = &n;
    962     n.flink->blink = &s;
    963     n.flink = &s;
    964 #ifdef VbyteDebug
    965     {
     964        serr | "enter:AddThisAfter, s:" | &s | " n:" | &n;
     965#endif // VbyteDebug
     966        // 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).
     967        verify( n.ulink != 0p );
     968        verify( s.ulink == n.ulink );
     969        flink = n.flink;
     970        blink = &n;
     971        n.flink->blink = &s;
     972        n.flink = &s;
     973#ifdef VbyteDebug
     974        {
    966975                serr | "HandleList:";
    967976                serr | nlOff;
     
    974983                } // for
    975984                serr | nlOn;
    976     }
    977     serr | "exit:AddThisAfter";
     985        }
     986        serr | "exit:AddThisAfter";
    978987#endif // VbyteDebug
    979988} // AddThisAfter
     
    984993static void DeleteNode( HandleNode & s ) with(s) {
    985994#ifdef VbyteDebug
    986     serr | "enter:DeleteNode, s:" | &s;
    987 #endif // VbyteDebug
    988     flink->blink = blink;
    989     blink->flink = flink;
    990 #ifdef VbyteDebug
    991     serr | "exit:DeleteNode";
     995        serr | "enter:DeleteNode, s:" | &s;
     996#endif // VbyteDebug
     997        flink->blink = blink;
     998        blink->flink = flink;
     999#ifdef VbyteDebug
     1000        serr | "exit:DeleteNode";
    9921001#endif // VbyteDebug
    9931002} //  DeleteNode
     
    9991008static char * VbyteAlloc( VbyteHeap & s, int size ) with(s) {
    10001009#ifdef VbyteDebug
    1001     serr | "enter:VbyteAlloc, size:" | size;
    1002 #endif // VbyteDebug
    1003     uintptr_t NoBytes;
    1004     char *r;
    1005 
    1006     NoBytes = ( uintptr_t )EndVbyte + size;
    1007     if ( NoBytes > ( uintptr_t )ExtVbyte ) {                    // enough room for new byte-string ?
     1010        serr | "enter:VbyteAlloc, size:" | size;
     1011#endif // VbyteDebug
     1012        uintptr_t NoBytes;
     1013        char *r;
     1014
     1015        NoBytes = ( uintptr_t )EndVbyte + size;
     1016        if ( NoBytes > ( uintptr_t )ExtVbyte ) {                        // enough room for new byte-string ?
    10081017                garbage( s, size );                                                             // firer up the garbage collector
    10091018                verify( (( uintptr_t )EndVbyte + size) <= ( uintptr_t )ExtVbyte  && "garbage run did not free up required space" );
    1010     } // if
    1011     r = EndVbyte;
    1012     EndVbyte += size;
    1013 #ifdef VbyteDebug
    1014     serr | "exit:VbyteAlloc, r:" | (void *)r | " EndVbyte:" | (void *)EndVbyte | " ExtVbyte:" | ExtVbyte;
    1015 #endif // VbyteDebug
    1016     return r;
     1019        } // if
     1020        r = EndVbyte;
     1021        EndVbyte += size;
     1022#ifdef VbyteDebug
     1023        serr | "exit:VbyteAlloc, r:" | (void *)r | " EndVbyte:" | (void *)EndVbyte | " ExtVbyte:" | ExtVbyte;
     1024#endif // VbyteDebug
     1025        return r;
    10171026} // VbyteAlloc
    10181027
     
    10271036
    10281037static char * VbyteTryAdjustLast( VbyteHeap & s, int delta ) with(s) {
    1029     if ( ( uintptr_t )EndVbyte + delta <= ( uintptr_t )ExtVbyte ) {
    1030         // room available
    1031         EndVbyte += delta;
    1032         return 0p;
    1033     }
    1034 
    1035     char *oldBytes = StartVbyte;
    1036 
    1037     NoOfExtensions += 1;
    1038     CurrSize *= 2;
    1039     StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize);
    1040     ExtVbyte = StartVbyte + CurrSize;
    1041 
    1042     return oldBytes;
     1038        if ( ( uintptr_t )EndVbyte + delta <= ( uintptr_t )ExtVbyte ) {
     1039                // room available
     1040                EndVbyte += delta;
     1041                return 0p;
     1042        }
     1043
     1044        char *oldBytes = StartVbyte;
     1045
     1046        NoOfExtensions += 1;
     1047        CurrSize *= 2;
     1048        StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize);
     1049        ExtVbyte = StartVbyte + CurrSize;
     1050
     1051        return oldBytes;
    10431052}
    10441053
     
    10491058static void MoveThisAfter( HandleNode & s, const HandleNode  & h ) with(s) {
    10501059#ifdef VbyteDebug
    1051     serr | "enter:MoveThisAfter, s:" | & s | " h:" | & h;
    1052 #endif // VbyteDebug
    1053     verify( h.ulink != 0p );
    1054     verify( s.ulink == h.ulink );
    1055     if ( s < h.s ) {                                    // check argument values
     1060        serr | "enter:MoveThisAfter, s:" | & s | " h:" | & h;
     1061#endif // VbyteDebug
     1062        verify( h.ulink != 0p );
     1063        verify( s.ulink == h.ulink );
     1064        if ( s < h.s ) {                                        // check argument values
    10561065                // serr | "VbyteSM: Error - Cannot move byte string starting at:" | s | " after byte string starting at:"
    1057                 //      | ( h->s ) | " and keep handles in ascending order";
     1066                //        | ( h->s ) | " and keep handles in ascending order";
    10581067                // exit(-1 );
    10591068                verify( 0 && "VbyteSM: Error - Cannot move byte strings as requested and keep handles in ascending order");
    1060     } // if
    1061 
    1062     HandleNode *i;
    1063     for ( i = h.flink; i->s != 0 && s > ( i->s ); i = i->flink ); // find the position for this node after h
    1064     if ( & s != i->blink ) {
     1069        } // if
     1070
     1071        HandleNode *i;
     1072        for ( i = h.flink; i->s != 0 && s > ( i->s ); i = i->flink ); // find the position for this node after h
     1073        if ( & s != i->blink ) {
    10651074                DeleteNode( s );
    10661075                AddThisAfter( s, *i->blink );
    1067     } // if
    1068 #ifdef VbyteDebug
    1069     {
    1070         serr | "HandleList:";
    1071         serr | nlOff;
    1072         for ( HandleNode *n = HeaderPtr->flink; n != HeaderPtr; n = n->flink ) {
    1073             serr | "\tnode:" | n | " lnth:" | n->lnth | " s:" | (void *)n->s | ",\"";
    1074             for ( i; n->lnth ) {
    1075                         serr | n->s[i];
    1076             } // for
    1077             serr | "\" flink:" | n->flink | " blink:" | n->blink | nl;
    1078         } // for
    1079         serr | nlOn;
    1080     }
    1081     serr | "exit:MoveThisAfter";
     1076        } // if
     1077#ifdef VbyteDebug
     1078        {
     1079                serr | "HandleList:";
     1080                serr | nlOff;
     1081                for ( HandleNode *n = HeaderPtr->flink; n != HeaderPtr; n = n->flink ) {
     1082                        serr | "\tnode:" | n | " lnth:" | n->lnth | " s:" | (void *)n->s | ",\"";
     1083                        for ( i; n->lnth ) {
     1084                                serr | n->s[i];
     1085                        } // for
     1086                        serr | "\" flink:" | n->flink | " blink:" | n->blink | nl;
     1087                } // for
     1088                serr | nlOn;
     1089        }
     1090        serr | "exit:MoveThisAfter";
    10821091#endif // VbyteDebug
    10831092} // MoveThisAfter
    1084 
    1085 
    1086 
    10871093
    10881094
     
    10971103int ByteCmp( char *Src1, int Src1Start, int Src1Lnth, char *Src2, int Src2Start, int Src2Lnth )  {
    10981104#ifdef VbyteDebug
    1099     serr | "enter:ByteCmp, Src1Start:" | Src1Start | " Src1Lnth:" | Src1Lnth | " Src2Start:" | Src2Start | " Src2Lnth:" | Src2Lnth;
    1100 #endif // VbyteDebug
    1101     int cmp;
    1102 
    1103     CharZip: for ( int i = 0; ; i += 1 ) {
    1104         if ( i == Src2Lnth - 1 ) {
    1105             for ( ; ; i += 1 ) {
     1105        serr | "enter:ByteCmp, Src1Start:" | Src1Start | " Src1Lnth:" | Src1Lnth | " Src2Start:" | Src2Start | " Src2Lnth:" | Src2Lnth;
     1106#endif // VbyteDebug
     1107        int cmp;
     1108
     1109  CharZip: for ( int i = 0; ; i += 1 ) {
     1110                if ( i == Src2Lnth - 1 ) {
     1111                        for ( ; ; i += 1 ) {
     1112                                if ( i == Src1Lnth - 1 ) {
     1113                                        cmp = 0;
     1114                                        break CharZip;
     1115                                } // exit
     1116                                if ( Src1[Src1Start + i] != ' ') {
     1117                                        // SUSPECTED BUG:  this could be be why Peter got the bug report about == " "  (why is this case here at all?)
     1118                                        cmp = 1;
     1119                                        break CharZip;
     1120                                } // exit
     1121                        } // for
     1122                } // exit
    11061123                if ( i == Src1Lnth - 1 ) {
    1107                     cmp = 0;
    1108                     break CharZip;
     1124                        for ( ; ; i += 1 ) {
     1125                                if ( i == Src2Lnth - 1 ) {
     1126                                        cmp = 0;
     1127                                        break CharZip;
     1128                                } // exit
     1129                                if ( Src2[Src2Start + i] != ' ') {
     1130                                        cmp = -1;
     1131                                        break CharZip;
     1132                                } // exit
     1133                        } // for
    11091134                } // exit
    1110                 if ( Src1[Src1Start + i] != ' ') {
    1111                         // SUSPECTED BUG:  this could be be why Peter got the bug report about == " "  (why is this case here at all?)
    1112                     cmp = 1;
    1113                     break CharZip;
     1135                if ( Src2[Src2Start + i] != Src1[Src1Start+ i]) {
     1136                        cmp = Src1[Src1Start + i] > Src2[Src2Start + i] ? 1 : -1;
     1137                        break CharZip;
    11141138                } // exit
    1115             } // for
    1116         } // exit
    1117         if ( i == Src1Lnth - 1 ) {
    1118             for ( ; ; i += 1 ) {
    1119                 if ( i == Src2Lnth - 1 ) {
    1120                     cmp = 0;
    1121                     break CharZip;
    1122                 } // exit
    1123                 if ( Src2[Src2Start + i] != ' ') {
    1124                     cmp = -1;
    1125                     break CharZip;
    1126                 } // exit
    1127             } // for
    1128         } // exit
    1129       if ( Src2[Src2Start + i] != Src1[Src1Start+ i]) {
    1130             cmp = Src1[Src1Start + i] > Src2[Src2Start + i] ? 1 : -1;
    1131             break CharZip;
    1132         } // exit
    1133     } // for
    1134 #ifdef VbyteDebug
    1135     serr | "exit:ByteCmp, cmp:" | cmp;
    1136 #endif // VbyteDebug
    1137     return cmp;
     1139        } // for
     1140#ifdef VbyteDebug
     1141        serr | "exit:ByteCmp, cmp:" | cmp;
     1142#endif // VbyteDebug
     1143        return cmp;
    11381144} // ByteCmp
    11391145
     
    11451151
    11461152void compaction(VbyteHeap & s) with(s) {
    1147     HandleNode *h;
    1148     char *obase, *nbase, *limit;
    1149    
    1150     NoOfCompactions += 1;
    1151     EndVbyte = StartVbyte;
    1152     h = Header.flink;                                   // ignore header node
    1153     for () {
     1153        HandleNode *h;
     1154        char *obase, *nbase, *limit;
     1155       
     1156        NoOfCompactions += 1;
     1157        EndVbyte = StartVbyte;
     1158        h = Header.flink;                                       // ignore header node
     1159        for () {
    11541160                memmove( EndVbyte, h->s, h->lnth );
    11551161                obase = h->s;
     
    11691175                } // for
    11701176                if ( h == &Header ) break;                      // end of header list ?
    1171     } // for
     1177        } // for
    11721178} // compaction
    11731179
    11741180
    11751181static double heap_expansion_freespace_threshold = 0.1;  // default inherited from prior work: expand heap when less than 10% "free" (i.e. garbage)
    1176                                                         // probably an unreasonable default, but need to assess early-round tests on changing it
     1182                                                                                                                // probably an unreasonable default, but need to assess early-round tests on changing it
    11771183
    11781184void TUNING_set_string_heap_liveness_threshold( double val ) {
    1179     heap_expansion_freespace_threshold = 1.0 - val;
     1185        heap_expansion_freespace_threshold = 1.0 - val;
    11801186}
    11811187
     
    11861192void garbage(VbyteHeap & s, int minreq ) with(s) {
    11871193#ifdef VbyteDebug
    1188     serr | "enter:garbage";
    1189     {
     1194        serr | "enter:garbage";
     1195        {
    11901196                serr | "HandleList:";
    11911197                for ( HandleNode *n = Header.flink; n != &Header; n = n->flink ) {
     
    11981204                        serr | "\" flink:" | n->flink | " blink:" | n->blink;
    11991205                } // for
    1200     }
    1201 #endif // VbyteDebug
    1202     int AmountUsed, AmountFree;
    1203 
    1204     AmountUsed = 0;
    1205     for ( HandleNode *i = Header.flink; i != &Header; i = i->flink ) { // calculate amount of byte area used
     1206        }
     1207#endif // VbyteDebug
     1208        int AmountUsed, AmountFree;
     1209
     1210        AmountUsed = 0;
     1211        for ( HandleNode *i = Header.flink; i != &Header; i = i->flink ) { // calculate amount of byte area used
    12061212                AmountUsed += i->lnth;
    1207     } // for
    1208     AmountFree = ( uintptr_t )ExtVbyte - ( uintptr_t )StartVbyte - AmountUsed;
    1209    
    1210     if ( ( double ) AmountFree < ( CurrSize * heap_expansion_freespace_threshold ) || AmountFree < minreq ) {   // free space less than threshold or not enough to serve cur request
     1213        } // for
     1214        AmountFree = ( uintptr_t )ExtVbyte - ( uintptr_t )StartVbyte - AmountUsed;
     1215       
     1216        if ( ( double ) AmountFree < ( CurrSize * heap_expansion_freespace_threshold ) || AmountFree < minreq ) {       // free space less than threshold or not enough to serve cur request
    12111217
    12121218                extend( s, max( CurrSize, minreq ) );                           // extend the heap
    12131219
    1214                         //  Peter says, "This needs work before it should be used."
    1215                         //  } else if ( AmountFree > CurrSize / 2 ) {           // free space greater than 3 times the initial allocation ?
    1216                         //              reduce(( AmountFree / CurrSize - 3 ) * CurrSize ); // reduce the memory
    1217 
    1218         // `extend` implies a `compaction` during the copy
    1219 
    1220     } else {
    1221         compaction(s);                                  // in-place
    1222     }// if
    1223 #ifdef VbyteDebug
    1224     {
     1220                //  Peter says, "This needs work before it should be used."
     1221                //  } else if ( AmountFree > CurrSize / 2 ) {           // free space greater than 3 times the initial allocation ?
     1222                //              reduce(( AmountFree / CurrSize - 3 ) * CurrSize ); // reduce the memory
     1223
     1224                // `extend` implies a `compaction` during the copy
     1225
     1226        } else {
     1227                compaction(s);                                  // in-place
     1228        }// if
     1229#ifdef VbyteDebug
     1230        {
    12251231                serr | "HandleList:";
    12261232                for ( HandleNode *n = Header.flink; n != &Header; n = n->flink ) {
     
    12331239                        serr | "\" flink:" | n->flink | " blink:" | n->blink;
    12341240                } // for
    1235     }
    1236     serr | "exit:garbage";
     1241        }
     1242        serr | "exit:garbage";
    12371243#endif // VbyteDebug
    12381244} // garbage
     
    12471253void extend( VbyteHeap & s, int size ) with (s) {
    12481254#ifdef VbyteDebug
    1249     serr | "enter:extend, size:" | size;
    1250 #endif // VbyteDebug
    1251     char *OldStartVbyte;
    1252 
    1253     NoOfExtensions += 1;
    1254     OldStartVbyte = StartVbyte;                         // save previous byte area
    1255    
    1256     CurrSize += size > InitSize ? size : InitSize;      // minimum extension, initial size
    1257     StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize);
    1258     ExtVbyte = (void *)( StartVbyte + CurrSize );
    1259     compaction(s);                                      // copy from old heap to new & adjust pointers to new heap
    1260     free( OldStartVbyte );                              // release old heap
    1261 #ifdef VbyteDebug
    1262     serr | "exit:extend, CurrSize:" | CurrSize;
     1255        serr | "enter:extend, size:" | size;
     1256#endif // VbyteDebug
     1257        char *OldStartVbyte;
     1258
     1259        NoOfExtensions += 1;
     1260        OldStartVbyte = StartVbyte;                             // save previous byte area
     1261       
     1262        CurrSize += size > InitSize ? size : InitSize;  // minimum extension, initial size
     1263        StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize);
     1264        ExtVbyte = (void *)( StartVbyte + CurrSize );
     1265        compaction(s);                                  // copy from old heap to new & adjust pointers to new heap
     1266        free( OldStartVbyte );                          // release old heap
     1267#ifdef VbyteDebug
     1268        serr | "exit:extend, CurrSize:" | CurrSize;
    12631269#endif // VbyteDebug
    12641270} // extend
     
    12721278void VbyteHeap::reduce( int size ) {
    12731279#ifdef VbyteDebug
    1274     serr | "enter:reduce, size:" | size;
    1275 #endif // VbyteDebug
    1276     char *OldStartVbyte;
    1277 
    1278     NoOfReductions += 1;
    1279     OldStartVbyte = StartVbyte;                         // save previous byte area
    1280    
    1281     CurrSize -= size;
    1282     StartVbyte = EndVbyte = new char[CurrSize];
    1283     ExtVbyte = (void *)( StartVbyte + CurrSize );
    1284     compaction();                                       // copy from old heap to new & adjust pointers to new heap
    1285     delete  OldStartVbyte;                              // release old heap
    1286 #ifdef VbyteDebug
    1287     serr | "exit:reduce, CurrSize:" | CurrSize;
     1280        serr | "enter:reduce, size:" | size;
     1281#endif // VbyteDebug
     1282        char *OldStartVbyte;
     1283
     1284        NoOfReductions += 1;
     1285        OldStartVbyte = StartVbyte;                             // save previous byte area
     1286       
     1287        CurrSize -= size;
     1288        StartVbyte = EndVbyte = new char[CurrSize];
     1289        ExtVbyte = (void *)( StartVbyte + CurrSize );
     1290        compaction();                                   // copy from old heap to new & adjust pointers to new heap
     1291        delete  OldStartVbyte;                          // release old heap
     1292#ifdef VbyteDebug
     1293        !serr | "exit:reduce, CurrSize:" | CurrSize;
    12881294#endif // VbyteDebug
    12891295} // reduce
Note: See TracChangeset for help on using the changeset viewer.