Ignore:
File:
1 edited

Legend:

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

    r08ed947 r6cc87c0  
    1515
    1616#include "string_res.hfa"
    17 #include "string_sharectx.hfa"
    18 #include "stdlib.hfa"
    19 
    20 // Workaround for observed performance penalty from calling CFA's alloc.
    21 // Workaround is:  EndVbyte = TEMP_ALLOC(char, CurrSize)
    22 // Should be:      EndVbyte = alloc(CurrSize)
    23 #define TEMP_ALLOC(T, n) (( T* ) malloc( n * sizeof( T ) ))
    24 
    25 #include <assert.h>
     17#include <stdlib.hfa>  // e.g. malloc
     18#include <string.h>    // e.g. strlen
    2619
    2720//######################### VbyteHeap "header" #########################
     21
     22
     23
     24
     25
     26
     27
     28
     29// DON'T COMMIT:
     30// #define VbyteDebug
     31
     32
     33
     34
    2835
    2936#ifdef VbyteDebug
     
    4754
    4855   
    49 static void compaction( VbyteHeap & );                          // compaction of the byte area
    50 static void garbage( VbyteHeap &, int );                                // garbage collect the byte area
    51 static void extend( VbyteHeap &, int );                 // extend the size of the byte area
    52 static void reduce( VbyteHeap &, int );                 // reduce the size of the byte area
    53 
    54 static void ?{}( VbyteHeap &, size_t = 1000 );
    55 static void ^?{}( VbyteHeap & );
    56 
    57 static int ByteCmp( char *, int, int, char *, int, int );       // compare 2 blocks of bytes
    58 static char *VbyteAlloc( VbyteHeap &, int );                    // allocate a block bytes in the heap
    59 static char *VbyteTryAdjustLast( VbyteHeap &, int );
    60 
    61 static void AddThisAfter( HandleNode &, HandleNode & );
    62 static void DeleteNode( HandleNode & );
    63 static void MoveThisAfter( HandleNode &, const HandleNode & );          // move current handle after parameter handle
     56static inline void compaction( VbyteHeap & );                           // compaction of the byte area
     57static inline void garbage( VbyteHeap & );                              // garbage collect the byte area
     58static inline void extend( VbyteHeap &, int );                  // extend the size of the byte area
     59static inline void reduce( VbyteHeap &, int );                  // reduce the size of the byte area
     60
     61static inline void ?{}( VbyteHeap &, int = 1000 );
     62static inline void ^?{}( VbyteHeap & );
     63static inline void ByteCopy( VbyteHeap &, char *, int, int, char *, int, int ); // copy a block of bytes from one location in the heap to another
     64static inline int ByteCmp( VbyteHeap &, char *, int, int, char *, int, int );   // compare 2 blocks of bytes
     65static inline char *VbyteAlloc( VbyteHeap &, int );                     // allocate a block bytes in the heap
     66
     67
     68static inline void AddThisAfter( HandleNode &, HandleNode & );
     69static inline void DeleteNode( HandleNode & );
     70static inline void MoveThisAfter( HandleNode &, const HandleNode & );           // move current handle after parameter handle
    6471
    6572
    6673// Allocate the storage for the variable sized area and intialize the heap variables.
    6774
    68 static void ?{}( VbyteHeap & this, size_t Size ) with(this) {
     75static inline void ?{}( VbyteHeap & this, int Size ) with(this) {
    6976#ifdef VbyteDebug
    7077    serr | "enter:VbyteHeap::VbyteHeap, this:" | &this | " Size:" | Size;
     
    7279    NoOfCompactions = NoOfExtensions = NoOfReductions = 0;
    7380    InitSize = CurrSize = Size;
    74     StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize);
     81    StartVbyte = EndVbyte = alloc(CurrSize);
    7582    ExtVbyte = (void *)( StartVbyte + CurrSize );
    7683    Header.flink = Header.blink = &Header;
    77     Header.ulink = & this;
    7884#ifdef VbyteDebug
    7985    HeaderPtr = &Header;
     
    8591// Release the dynamically allocated storage for the byte area.
    8692
    87 static void ^?{}( VbyteHeap & this ) with(this) {
     93static inline void ^?{}( VbyteHeap & this ) with(this) {
    8894    free( StartVbyte );
    8995} // ~VbyteHeap
     
    96102// creator.
    97103
    98 static void ?{}( HandleNode & this ) with(this) {
     104void ?{}( HandleNode & this ) with(this) {
    99105#ifdef VbyteDebug
    100106    serr | "enter:HandleNode::HandleNode, this:" | &this;
     
    111117// collection.
    112118
    113 static void ?{}( HandleNode & this, VbyteHeap & vh ) with(this) {
     119void ?{}( HandleNode & this, VbyteHeap & vh ) with(this) {
    114120#ifdef VbyteDebug
    115121    serr | "enter:HandleNode::HandleNode, this:" | &this;
     
    117123    s = 0;
    118124    lnth = 0;
    119     ulink = &vh;
    120125    AddThisAfter( this, *vh.Header.blink );
    121126#ifdef VbyteDebug
     
    128133// is the responsibility of the creator to destroy it.
    129134
    130 static void ^?{}( HandleNode & this ) with(this) {
     135void ^?{}( HandleNode & this ) with(this) {
    131136#ifdef VbyteDebug
    132137    serr | "enter:HandleNode::~HandleNode, this:" | & this;
     
    144149} // ~HandleNode
    145150
    146 
    147 //######################### String Sharing Context #########################
    148 
    149 static string_sharectx * ambient_string_sharectx;               // fickle top of stack
    150 static string_sharectx default_string_sharectx = {NEW_SHARING}; // stable bottom of stack
    151 
    152 void ?{}( string_sharectx & this, StringSharectx_Mode mode ) with( this ) {
    153     (older){ ambient_string_sharectx };
    154     if ( mode == NEW_SHARING ) {
    155         (activeHeap){ new( (size_t) 1000 ) };
    156     } else {
    157         verify( mode == NO_SHARING );
    158         (activeHeap){ 0p };
    159     }
    160     ambient_string_sharectx = & this;
    161 }
    162 
    163 void ^?{}( string_sharectx & this ) with( this ) {
    164     if ( activeHeap ) delete( activeHeap );
    165 
    166     // unlink this from older-list starting from ambient_string_sharectx
    167     // usually, this==ambient_string_sharectx and the loop runs zero times
    168     string_sharectx *& c = ambient_string_sharectx;
    169     while ( c != &this ) &c = &c->older;              // find this
    170     c = this.older;                                   // unlink
    171 }
    172 
    173151//######################### String Resource #########################
    174152
    175153
    176 VbyteHeap * DEBUG_string_heap() {
    177     assert( ambient_string_sharectx->activeHeap && "No sharing context is active" );
    178     return ambient_string_sharectx->activeHeap;
    179 }
     154VbyteHeap HeapArea;
     155
     156VbyteHeap * DEBUG_string_heap = & HeapArea;
    180157
    181158size_t DEBUG_string_bytes_avail_until_gc( VbyteHeap * heap ) {
     
    183160}
    184161
    185 size_t DEBUG_string_bytes_in_heap( VbyteHeap * heap ) {
    186     return heap->CurrSize;
    187 }
    188 
    189162const char * DEBUG_string_heap_start( VbyteHeap * heap ) {
    190163    return heap->StartVbyte;
    191164}
     165
    192166
    193167// Returns the size of the string in bytes
     
    213187    // Store auto-newline state so it can be restored
    214188    bool anl = getANL$(out);
    215     if( s.Handle.lnth == 0 ) {
    216         sout | "";
    217     } else {
    218         nlOff(out);
    219         for (size_t i = 0; i < s.Handle.lnth; i++) {
    220             // Need to re-apply on the last output operator, for whole-statement version
    221             if (anl && i == s.Handle.lnth-1) nlOn(out);
    222             out | s[i];
    223         }
    224     }
     189    nlOff(out);
     190    for (size_t i = 0; i < s.Handle.lnth; i++) {
     191        // Need to re-apply on the last output operator, for whole-statement version
     192        if (anl && i == s.Handle.lnth-1) nlOn(out);
     193        out | s[i];
     194    }
     195    return out;
    225196}
    226197
    227198// Empty constructor
    228199void ?{}(string_res &s) with(s) {
    229     if( ambient_string_sharectx->activeHeap ) {
    230         (Handle){ * ambient_string_sharectx->activeHeap };
    231         (shareEditSet_owns_ulink){ false };
    232         verify( Handle.s == 0p && Handle.lnth == 0 );
    233     } else {
    234         (Handle){ * new( (size_t) 10 ) };  // TODO: can I lazily avoid allocating for empty string
    235         (shareEditSet_owns_ulink){ true };
    236         Handle.s = Handle.ulink->StartVbyte;
    237         verify( Handle.lnth == 0 );
    238     }
     200    (Handle){ HeapArea };
    239201    s.shareEditSet_prev = &s;
    240202    s.shareEditSet_next = &s;
    241203}
    242204
    243 static void eagerCopyCtorHelper(string_res &s, const char* rhs, size_t rhslnth) with(s) {
    244     if( ambient_string_sharectx->activeHeap ) {
    245         (Handle){ * ambient_string_sharectx->activeHeap };
    246         (shareEditSet_owns_ulink){ false };
    247     } else {
    248         (Handle){ * new( rhslnth ) };
    249         (shareEditSet_owns_ulink){ true };
    250     }
    251     Handle.s = VbyteAlloc(*Handle.ulink, rhslnth);
     205// Constructor from a raw buffer and size
     206void ?{}(string_res &s, const char* rhs, size_t rhslnth) with(s) {
     207    (Handle){ HeapArea };
     208    Handle.s = VbyteAlloc(HeapArea, rhslnth);
    252209    Handle.lnth = rhslnth;
    253     memmove( Handle.s, rhs, rhslnth );
     210    for ( int i = 0; i < rhslnth; i += 1 ) {            // copy characters
     211        Handle.s[i] = rhs[i];
     212    } // for
    254213    s.shareEditSet_prev = &s;
    255214    s.shareEditSet_next = &s;
    256215}
    257216
    258 // Constructor from a raw buffer and size
    259 void ?{}(string_res &s, const char* rhs, size_t rhslnth) with(s) {
    260     eagerCopyCtorHelper(s, rhs, rhslnth);
    261 }
    262 
    263 // private ctor (not in header): use specified heap (ignore ambient) and copy chars in
    264 void ?{}( string_res &s, VbyteHeap & heap, const char* rhs, size_t rhslnth ) with(s) {
    265     (Handle){ heap };
    266     Handle.s = VbyteAlloc(*Handle.ulink, rhslnth);
    267     Handle.lnth = rhslnth;
    268     (s.shareEditSet_owns_ulink){ false };
    269     memmove( Handle.s, rhs, rhslnth );
    270     s.shareEditSet_prev = &s;
    271     s.shareEditSet_next = &s;
     217// String literal constructor
     218void ?{}(string_res &s, const char* rhs) {
     219    (s){ rhs, strlen(rhs) };
    272220}
    273221
     
    275223void ?{}(string_res &s, const string_res & s2, StrResInitMode mode, size_t start, size_t end ) {
    276224
    277     verify( start <= end && end <= s2.Handle.lnth );
    278 
    279     if (s2.Handle.ulink != ambient_string_sharectx->activeHeap && mode == COPY_VALUE) {
    280         // crossing heaps (including private): copy eagerly
    281         eagerCopyCtorHelper(s, s2.Handle.s + start, end - start);
    282         verify(s.shareEditSet_prev == &s);
    283         verify(s.shareEditSet_next == &s);
     225    (s.Handle){ HeapArea };
     226    s.Handle.s = s2.Handle.s + start;
     227    s.Handle.lnth = end - start;
     228    MoveThisAfter(s.Handle, s2.Handle );                        // insert this handle after rhs handle
     229    // ^ bug?  skip others at early point in string
     230   
     231    if (mode == COPY_VALUE) {
     232        // make s alone in its shareEditSet
     233        s.shareEditSet_prev = &s;
     234        s.shareEditSet_next = &s;
    284235    } else {
    285         (s.Handle){};
    286         s.Handle.s = s2.Handle.s + start;
    287         s.Handle.lnth = end - start;
    288         s.Handle.ulink = s2.Handle.ulink;
    289 
    290         AddThisAfter(s.Handle, s2.Handle );                     // insert this handle after rhs handle
    291         // ^ bug?  skip others at early point in string
    292 
    293         if (mode == COPY_VALUE) {
    294             verify(s2.Handle.ulink == ambient_string_sharectx->activeHeap);
    295             // requested logical copy in same heap: defer copy until write
    296 
    297             (s.shareEditSet_owns_ulink){ false };
    298 
    299             // make s alone in its shareEditSet
    300             s.shareEditSet_prev = &s;
    301             s.shareEditSet_next = &s;
    302         } else {
    303             verify( mode == SHARE_EDITS );
    304             // sharing edits with source forces same heap as source (ignore context)
    305 
    306             (s.shareEditSet_owns_ulink){ s2.shareEditSet_owns_ulink };
    307 
    308             // s2 is logically const but not implementation const
    309             string_res & s2mod = (string_res &) s2;
    310 
    311             // insert s after s2 on shareEditSet
    312             s.shareEditSet_next = s2mod.shareEditSet_next;
    313             s.shareEditSet_prev = &s2mod;
    314             s.shareEditSet_next->shareEditSet_prev = &s;
    315             s.shareEditSet_prev->shareEditSet_next = &s;
     236        assert( mode == SHARE_EDITS );
     237
     238        // s2 is logically const but not implementation const
     239        string_res & s2mod = (string_res &) s2;
     240
     241        // insert s after s2 on shareEditSet
     242        s.shareEditSet_next = s2mod.shareEditSet_next;
     243        s.shareEditSet_prev = &s2mod;
     244        s.shareEditSet_next->shareEditSet_prev = &s;
     245        s.shareEditSet_prev->shareEditSet_next = &s;
     246    }
     247}
     248
     249void assign(string_res &this, const char* buffer, size_t bsize) {
     250
     251    // traverse the incumbent share-edit set (SES) to recover the range of a base string to which `this` belongs
     252    string_res * shareEditSetStartPeer = & this;
     253    string_res * shareEditSetEndPeer = & this;
     254    for (string_res * editPeer = this.shareEditSet_next; editPeer != &this; editPeer = editPeer->shareEditSet_next) {
     255        if ( editPeer->Handle.s < shareEditSetStartPeer->Handle.s ) {
     256            shareEditSetStartPeer = editPeer;
    316257        }
    317     }
    318 }
    319 
    320 static void assignEditSet(string_res & this, string_res * shareEditSetStartPeer, string_res * shareEditSetEndPeer,
    321     char * resultSesStart,
    322     size_t resultSesLnth,
    323     HandleNode * resultPadPosition, size_t bsize ) {
     258        if ( shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth < editPeer->Handle.s + editPeer->Handle.lnth) {
     259            shareEditSetEndPeer = editPeer;
     260        }
     261    }
     262
     263    // full string is from start of shareEditSetStartPeer thru end of shareEditSetEndPeer
     264    // `this` occurs in the middle of it, to be replaced
     265    // build up the new text in `pasting`
     266
     267    string_res pasting = {
     268        shareEditSetStartPeer->Handle.s,                   // start of SES
     269        this.Handle.s - shareEditSetStartPeer->Handle.s }; // length of SES, before this
     270    append( pasting,
     271        buffer,                                            // start of replacement for this
     272        bsize );                                           // length of replacement for this
     273    append( pasting,
     274        this.Handle.s + this.Handle.lnth,                  // start of SES after this
     275        shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth -
     276        (this.Handle.s + this.Handle.lnth) );              // length of SES, after this
     277
     278    // The above string building can trigger compaction.
     279    // The reference points (that are arguments of the string building) may move during that building.
     280    // From this point on, they are stable.
     281    // So now, capture their values for use in the overlap cases, below.
     282    // Do not factor these definitions with the arguments used above.
    324283
    325284    char * beforeBegin = shareEditSetStartPeer->Handle.s;
     
    331290    size_t oldLnth = this.Handle.lnth;
    332291
    333     this.Handle.s = resultSesStart + beforeLen;
     292    this.Handle.s = pasting.Handle.s + beforeLen;
    334293    this.Handle.lnth = bsize;
    335     if (resultPadPosition)
    336         MoveThisAfter( this.Handle, *resultPadPosition );
     294    MoveThisAfter( this.Handle, pasting.Handle );
    337295
    338296    // adjust all substring string and handle locations, and check if any substring strings are outside the new base string
    339     char *limit = resultSesStart + resultSesLnth;
     297    char *limit = pasting.Handle.s + pasting.Handle.lnth;
    340298    for (string_res * p = this.shareEditSet_next; p != &this; p = p->shareEditSet_next) {
    341         verify (p->Handle.s >= beforeBegin);
     299        assert (p->Handle.s >= beforeBegin);
    342300        if ( p->Handle.s >= afterBegin ) {
    343             verify ( p->Handle.s <= afterBegin + afterLen );
    344             verify ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );
     301            assert ( p->Handle.s <= afterBegin + afterLen );
     302            assert ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );
    345303            // p starts after the edit
    346304            // take start and end as end-anchored
     
    360318            } else {
    361319                // p ends after the edit
    362                 verify ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );
     320                assert ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );
    363321                // take end as end-anchored
    364322                // stretch-shrink p according to the edit
     
    368326            // take start as start-anchored
    369327            size_t startOffsetFromStart = p->Handle.s - beforeBegin;
    370             p->Handle.s = resultSesStart + startOffsetFromStart;
     328            p->Handle.s = pasting.Handle.s + startOffsetFromStart;
    371329        } else {
    372             verify ( p->Handle.s < afterBegin );
     330            assert ( p->Handle.s < afterBegin );
    373331            // p starts during the edit
    374             verify( p->Handle.s + p->Handle.lnth >= beforeBegin + beforeLen );
     332            assert( p->Handle.s + p->Handle.lnth >= beforeBegin + beforeLen );
    375333            if ( p->Handle.s + p->Handle.lnth < afterBegin ) {
    376334                // p ends during the edit; p does not include the last character replaced
     
    386344            }
    387345        }
    388         if (resultPadPosition)
    389             MoveThisAfter( p->Handle, *resultPadPosition );     // move substring handle to maintain sorted order by string position
    390     }
    391 }
    392 
    393 static string_res & assign_(string_res &this, const char* buffer, size_t bsize, const string_res & valSrc) {
    394 
    395     // traverse the incumbent share-edit set (SES) to recover the range of a base string to which `this` belongs
    396     string_res * shareEditSetStartPeer = & this;
    397     string_res * shareEditSetEndPeer = & this;
    398     for (string_res * editPeer = this.shareEditSet_next; editPeer != &this; editPeer = editPeer->shareEditSet_next) {
    399         if ( editPeer->Handle.s < shareEditSetStartPeer->Handle.s ) {
    400             shareEditSetStartPeer = editPeer;
    401         }
    402         if ( shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth < editPeer->Handle.s + editPeer->Handle.lnth) {
    403             shareEditSetEndPeer = editPeer;
    404         }
    405     }
    406 
    407     verify( shareEditSetEndPeer->Handle.s >= shareEditSetStartPeer->Handle.s );
    408     size_t origEditSetLength = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - shareEditSetStartPeer->Handle.s;
    409     verify( origEditSetLength >= this.Handle.lnth );
    410 
    411     if ( this.shareEditSet_owns_ulink ) {                 // assigning to private context
    412         // ok to overwrite old value within LHS
    413         char * prefixStartOrig = shareEditSetStartPeer->Handle.s;
    414         int prefixLen = this.Handle.s - prefixStartOrig;
    415         char * suffixStartOrig = this.Handle.s + this.Handle.lnth;
    416         int suffixLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - suffixStartOrig;
    417 
    418         int delta = bsize - this.Handle.lnth;
    419         if ( char * oldBytes = VbyteTryAdjustLast( *this.Handle.ulink, delta ) ) {
    420             // growing: copy from old to new
    421             char * dest = VbyteAlloc( *this.Handle.ulink, origEditSetLength + delta );
    422             char *destCursor = dest;  memcpy(destCursor, prefixStartOrig, prefixLen);
    423             destCursor += prefixLen;  memcpy(destCursor, buffer         , bsize    );
    424             destCursor += bsize;      memcpy(destCursor, suffixStartOrig, suffixLen);
    425             assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer,
    426                 dest,
    427                 origEditSetLength + delta,
    428                 0p, bsize);
    429             free( oldBytes );
    430         } else {
    431             // room is already allocated in-place: bubble suffix and overwite middle
    432             memmove( suffixStartOrig + delta, suffixStartOrig, suffixLen );
    433             memcpy( this.Handle.s, buffer, bsize );
    434 
    435             assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer,
    436                 shareEditSetStartPeer->Handle.s,
    437                 origEditSetLength + delta,
    438                 0p, bsize);
    439         }
    440 
    441     } else if (                                           // assigning to shared context
    442         this.Handle.lnth == origEditSetLength &&          // overwriting entire run of SES
    443         & valSrc &&                                       // sourcing from a managed string
    444         valSrc.Handle.ulink == this.Handle.ulink  ) {     // sourcing from same heap
    445 
    446         // SES's result will only use characters from the source string => reuse source
    447         assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer,
    448             valSrc.Handle.s,
    449             valSrc.Handle.lnth,
    450             &((string_res&)valSrc).Handle, bsize);
    451        
    452     } else {
    453         // overwriting a proper substring of some string: mash characters from old and new together (copy on write)
    454         // OR we are importing characters: need to copy eagerly (can't refer to source)
    455 
    456         // full string is from start of shareEditSetStartPeer thru end of shareEditSetEndPeer
    457         // `this` occurs in the middle of it, to be replaced
    458         // build up the new text in `pasting`
    459 
    460         string_res pasting = {
    461             * this.Handle.ulink,                               // maintain same heap, regardless of context
    462             shareEditSetStartPeer->Handle.s,                   // start of SES
    463             this.Handle.s - shareEditSetStartPeer->Handle.s }; // length of SES, before this
    464         append( pasting,
    465             buffer,                                            // start of replacement for this
    466             bsize );                                           // length of replacement for this
    467         append( pasting,
    468             this.Handle.s + this.Handle.lnth,                  // start of SES after this
    469             shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth -
    470             (this.Handle.s + this.Handle.lnth) );              // length of SES, after this
    471 
    472         // The above string building can trigger compaction.
    473         // The reference points (that are arguments of the string building) may move during that building.
    474         // From this point on, they are stable.
    475 
    476         assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer,
    477             pasting.Handle.s,
    478             pasting.Handle.lnth,
    479             &pasting.Handle, bsize);
    480     }
    481 
    482     return this;
    483 }
    484 
    485 string_res & assign(string_res &this, const char* buffer, size_t bsize) {
    486     return assign_(this, buffer, bsize, *0p);
    487 }
    488 
    489 string_res & ?=?(string_res &s, char other) {
    490     return assign(s, &other, 1);
     346        MoveThisAfter( p->Handle, pasting.Handle );     // move substring handle to maintain sorted order by string position
     347    }
     348}
     349
     350void ?=?(string_res &s, const char* other) {
     351    assign(s, other, strlen(other));
     352}
     353
     354void ?=?(string_res &s, char other) {
     355    assign(s, &other, 1);
    491356}
    492357
    493358// Copy assignment operator
    494 string_res & ?=?(string_res & this, const string_res & rhs) with( this ) {
    495     return assign_(this, rhs.Handle.s, rhs.Handle.lnth, rhs);
    496 }
    497 
    498 string_res & ?=?(string_res & this, string_res & rhs) with( this ) {
     359void ?=?(string_res & this, const string_res & rhs) with( this ) {
     360    assign(this, rhs.Handle.s, rhs.Handle.lnth);
     361}
     362
     363void ?=?(string_res & this, string_res & rhs) with( this ) {
    499364    const string_res & rhs2 = rhs;
    500     return this = rhs2;
     365    this = rhs2;
    501366}
    502367
     
    509374    s.shareEditSet_prev->shareEditSet_next = s.shareEditSet_next;
    510375    s.shareEditSet_next->shareEditSet_prev = s.shareEditSet_prev;
    511     // s.shareEditSet_next = &s;
    512     // s.shareEditSet_prev = &s;
    513 
    514     if (shareEditSet_owns_ulink && s.shareEditSet_next == &s) { // last one out
    515         delete( s.Handle.ulink );
    516     }
     376    s.shareEditSet_next = &s;
     377    s.shareEditSet_prev = &s;
    517378}
    518379
     
    526387}
    527388
    528 void assignAt(const string_res &s, size_t index, char val) {
    529     string_res editZone = { s, SHARE_EDITS, index, index+1 };
    530     assign(editZone, &val, 1);
    531 }
    532 
    533389
    534390///////////////////////////////////////////////////////////////////
     
    536392
    537393void append(string_res &str1, const char * buffer, size_t bsize) {
    538     size_t clnth = str1.Handle.lnth + bsize;
    539     if ( str1.Handle.s + str1.Handle.lnth == buffer ) { // already juxtapose ?
     394    size_t clnth = size(str1) + bsize;
     395    if ( str1.Handle.s + size(str1) == buffer ) { // already juxtapose ?
    540396        // no-op
    541397    } else {                                            // must copy some text
    542         if ( str1.Handle.s + str1.Handle.lnth == VbyteAlloc(*str1.Handle.ulink, 0) ) { // str1 at end of string area ?
    543             VbyteAlloc( *str1.Handle.ulink, bsize ); // create room for 2nd part at the end of string area
     398        if ( str1.Handle.s + size(str1) == VbyteAlloc(HeapArea, 0) ) { // str1 at end of string area ?
     399            VbyteAlloc(HeapArea, bsize); // create room for 2nd part at the end of string area
    544400        } else {                                        // copy the two parts
    545             char * str1newBuf = VbyteAlloc( *str1.Handle.ulink, clnth );
    546             char * str1oldBuf = str1.Handle.s;  // must read after VbyteAlloc call in case it gs's
    547             str1.Handle.s = str1newBuf;
    548             memcpy( str1.Handle.s, str1oldBuf,  str1.Handle.lnth );
     401            char * str1oldBuf = str1.Handle.s;
     402            str1.Handle.s = VbyteAlloc( HeapArea, clnth );
     403            ByteCopy( HeapArea, str1.Handle.s, 0, str1.Handle.lnth, str1oldBuf, 0, str1.Handle.lnth);
    549404        } // if
    550         memcpy( str1.Handle.s + str1.Handle.lnth, buffer, bsize );
     405        ByteCopy( HeapArea, str1.Handle.s, str1.Handle.lnth, bsize, (char*)buffer, 0, (int)bsize);
     406        //       VbyteHeap & this, char *Dst, int DstStart, int DstLnth, char *Src, int SrcStart, int SrcLnth
    551407    } // if
    552408    str1.Handle.lnth = clnth;
     
    561417}
    562418
     419void ?+=?(string_res &s, const char* other) {
     420    append( s, other, strlen(other) );
     421}
    563422
    564423
     
    570429
    571430bool ?==?(const string_res &s1, const string_res &s2) {
    572     return ByteCmp( s1.Handle.s, 0, s1.Handle.lnth, s2.Handle.s, 0, s2.Handle.lnth) == 0;
     431    return ByteCmp( HeapArea, s1.Handle.s, 0, s1.Handle.lnth, s2.Handle.s, 0, s2.Handle.lnth) == 0;
    573432}
    574433
     
    596455
    597456int find(const string_res &s, char search) {
    598     return findFrom(s, 0, search);
    599 }
    600 
    601 int findFrom(const string_res &s, size_t fromPos, char search) {
    602     // FIXME: This paricular overload (find of single char) is optimized to use memchr.
    603     // The general overload (find of string, memchr applying to its first character) and `contains` should be adjusted to match.
    604     char * searchFrom = s.Handle.s + fromPos;
    605     size_t searchLnth = s.Handle.lnth - fromPos;
    606     int searchVal = search;
    607     char * foundAt = (char *) memchr(searchFrom, searchVal, searchLnth);
    608     if (foundAt == 0p) return s.Handle.lnth;
    609     else return foundAt - s.Handle.s;
    610 }
     457    for (i; size(s)) {
     458        if (s[i] == search) return i;
     459    }
     460    return size(s);
     461}
     462
     463    /* Remaining implementations essentially ported from Sunjay's work */
    611464
    612465int find(const string_res &s, const string_res &search) {
    613     return findFrom(s, 0, search);
    614 }
    615 
    616 int findFrom(const string_res &s, size_t fromPos, const string_res &search) {
    617     return findFrom(s, fromPos, search.Handle.s, search.Handle.lnth);
     466    return find(s, search.Handle.s, search.Handle.lnth);
    618467}
    619468
    620469int find(const string_res &s, const char* search) {
    621     return findFrom(s, 0, search);
    622 }
    623 int findFrom(const string_res &s, size_t fromPos, const char* search) {
    624     return findFrom(s, fromPos, search, strlen(search));
     470    return find(s, search, strlen(search));
    625471}
    626472
    627473int find(const string_res &s, const char* search, size_t searchsize) {
    628     return findFrom(s, 0, search, searchsize);
    629 }
    630 
    631 int findFrom(const string_res &s, size_t fromPos, const char* search, size_t searchsize) {
    632 
    633     /* Remaining implementations essentially ported from Sunjay's work */
    634 
    635 
    636474    // FIXME: This is a naive algorithm. We probably want to switch to someting
    637475    // like Boyer-Moore in the future.
     
    643481    }
    644482
    645     for (size_t i = fromPos; i < s.Handle.lnth; i++) {
     483    for (size_t i = 0; i < s.Handle.lnth; i++) {
    646484        size_t remaining = s.Handle.lnth - i;
    647485        // Never going to find the search string if the remaining string is
     
    758596// Add a new HandleNode node n after the current HandleNode node.
    759597
    760 static void AddThisAfter( HandleNode & this, HandleNode & n ) with(this) {
     598static inline void AddThisAfter( HandleNode & this, HandleNode & n ) with(this) {
    761599#ifdef VbyteDebug
    762600    serr | "enter:AddThisAfter, this:" | &this | " n:" | &n;
    763601#endif // VbyteDebug
    764     // Performance note: we are on the critical path here. MB has ensured that the verifies don't contribute to runtime (are compiled away, like they're supposed to be).
    765     verify( n.ulink != 0p );
    766     verify( this.ulink == n.ulink );
    767602    flink = n.flink;
    768603    blink = &n;
     
    789624// Delete the current HandleNode node.
    790625
    791 static void DeleteNode( HandleNode & this ) with(this) {
     626static inline void DeleteNode( HandleNode & this ) with(this) {
    792627#ifdef VbyteDebug
    793628    serr | "enter:DeleteNode, this:" | &this;
     
    803638
    804639// Allocates specified storage for a string from byte-string area. If not enough space remains to perform the
    805 // allocation, the garbage collection routine is called.
    806 
    807 static char * VbyteAlloc( VbyteHeap & this, int size ) with(this) {
     640// allocation, the garbage collection routine is called and a second attempt is made to allocate the space. If the
     641// second attempt fails, a further attempt is made to create a new, larger byte-string area.
     642
     643static inline char * VbyteAlloc( VbyteHeap & this, int size ) with(this) {
    808644#ifdef VbyteDebug
    809645    serr | "enter:VbyteAlloc, size:" | size;
     
    814650    NoBytes = ( uintptr_t )EndVbyte + size;
    815651    if ( NoBytes > ( uintptr_t )ExtVbyte ) {            // enough room for new byte-string ?
    816                 garbage( this, size );                                  // firer up the garbage collector
    817                 verify( (( uintptr_t )EndVbyte + size) <= ( uintptr_t )ExtVbyte  && "garbage run did not free up required space" );
     652                garbage( this );                                        // firer up the garbage collector
     653                NoBytes = ( uintptr_t )EndVbyte + size;         // try again
     654                if ( NoBytes > ( uintptr_t )ExtVbyte ) {        // enough room for new byte-string ?
     655assert( 0 && "need to implement actual growth" );
     656                        // extend( size );                              // extend the byte-string area
     657                } // if
    818658    } // if
    819659    r = EndVbyte;
     
    826666
    827667
    828 // Adjusts the last allocation in this heap by delta bytes, or resets this heap to be able to offer
    829 // new allocations of its original size + delta bytes. Positive delta means bigger;
    830 // negative means smaller.  A null return indicates that the original heap location has room for
    831 // the requested growth.  A non-null return indicates that copying to a new location is required
    832 // but has not been done; the returned value is the old heap storage location; `this` heap is
    833 // modified to reference the new location.  In the copy-requred case, the caller should use
    834 // VbyteAlloc to claim the new space, while doing optimal copying from old to new, then free old.
    835 
    836 static char * VbyteTryAdjustLast( VbyteHeap & this, int delta ) with(this) {
    837 
    838     if ( ( uintptr_t )EndVbyte + delta <= ( uintptr_t )ExtVbyte ) {
    839         // room available
    840         EndVbyte += delta;
    841         return 0p;
    842     }
    843 
    844     char *oldBytes = StartVbyte;
    845 
    846     NoOfExtensions += 1;
    847     CurrSize *= 2;
    848     StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize);
    849     ExtVbyte = StartVbyte + CurrSize;
    850 
    851     return oldBytes;
    852 }
    853 
    854 
    855668// Move an existing HandleNode node h somewhere after the current HandleNode node so that it is in ascending order by
    856669// the address in the byte string area.
    857670
    858 static void MoveThisAfter( HandleNode & this, const HandleNode  & h ) with(this) {
     671static inline void MoveThisAfter( HandleNode & this, const HandleNode  & h ) with(this) {
    859672#ifdef VbyteDebug
    860673    serr | "enter:MoveThisAfter, this:" | & this | " h:" | & h;
    861674#endif // VbyteDebug
    862     verify( h.ulink != 0p );
    863     verify( this.ulink == h.ulink );
    864675    if ( s < h.s ) {                                    // check argument values
    865676                // serr | "VbyteSM: Error - Cannot move byte string starting at:" | s | " after byte string starting at:"
    866677                //      | ( h->s ) | " and keep handles in ascending order";
    867678                // exit(-1 );
    868                 verify( 0 && "VbyteSM: Error - Cannot move byte strings as requested and keep handles in ascending order");
     679                assert( 0 && "VbyteSM: Error - Cannot move byte strings as requested and keep handles in ascending order");
    869680    } // if
    870681
     
    898709//######################### VbyteHeap #########################
    899710
     711// Move characters from one location in the byte-string area to another. The routine handles the following situations:
     712//
     713// if the |Src| > |Dst| => truncate
     714// if the |Dst| > |Src| => pad Dst with blanks
     715
     716void ByteCopy( VbyteHeap & this, char *Dst, int DstStart, int DstLnth, char *Src, int SrcStart, int SrcLnth ) {
     717    for ( int i = 0; i < DstLnth; i += 1 ) {
     718      if ( i == SrcLnth ) {                             // |Dst| > |Src|
     719            for ( ; i < DstLnth; i += 1 ) {             // pad Dst with blanks
     720                Dst[DstStart + i] = ' ';
     721            } // for
     722            break;
     723        } // exit
     724        Dst[DstStart + i] = Src[SrcStart + i];
     725    } // for
     726} // ByteCopy
     727
    900728// Compare two byte strings in the byte-string area. The routine returns the following values:
    901729//
     
    904732// -1 => Src1-byte-string < Src2-byte-string
    905733
    906 int ByteCmp( char *Src1, int Src1Start, int Src1Lnth, char *Src2, int Src2Start, int Src2Lnth ) {
     734int ByteCmp( VbyteHeap & this, char *Src1, int Src1Start, int Src1Lnth, char *Src2, int Src2Start, int Src2Lnth )  with(this) {
    907735#ifdef VbyteDebug
    908736    serr | "enter:ByteCmp, Src1Start:" | Src1Start | " Src1Lnth:" | Src1Lnth | " Src2Start:" | Src2Start | " Src2Lnth:" | Src2Lnth;
     
    961789    h = Header.flink;                                   // ignore header node
    962790    for (;;) {
    963                 memmove( EndVbyte, h->s, h->lnth );
     791                ByteCopy( this, EndVbyte, 0, h->lnth, h->s, 0, h->lnth );
    964792                obase = h->s;
    965793                h->s = EndVbyte;
     
    982810
    983811
    984 static double heap_expansion_freespace_threshold = 0.1;  // default inherited from prior work: expand heap when less than 10% "free" (i.e. garbage)
    985                                                          // probably an unreasonable default, but need to assess early-round tests on changing it
    986 
    987 void TUNING_set_string_heap_liveness_threshold( double val ) {
    988     heap_expansion_freespace_threshold = 1.0 - val;
    989 }
    990 
    991 
    992812// Garbage determines the amount of free space left in the heap and then reduces, leave the same, or extends the size of
    993813// the heap.  The heap is then compacted in the existing heap or into the newly allocated heap.
    994814
    995 void garbage(VbyteHeap & this, int minreq ) with(this) {
     815void garbage(VbyteHeap & this ) with(this) {
    996816#ifdef VbyteDebug
    997817    serr | "enter:garbage";
     
    1017837    AmountFree = ( uintptr_t )ExtVbyte - ( uintptr_t )StartVbyte - AmountUsed;
    1018838   
    1019     if ( ( double ) AmountFree < ( CurrSize * heap_expansion_freespace_threshold ) || AmountFree < minreq ) {   // free space less than threshold or not enough to serve cur request
    1020 
    1021                 extend( this, max( CurrSize, minreq ) );                                // extend the heap
     839    if ( AmountFree < ( int )( CurrSize * 0.1 )) {      // free space less than 10% ?
     840
     841assert( 0 && "need to implement actual growth" );
     842//              extend( CurrSize );                             // extend the heap
    1022843
    1023844                        //  Peter says, "This needs work before it should be used."
     
    1025846                        //              reduce(( AmountFree / CurrSize - 3 ) * CurrSize ); // reduce the memory
    1026847
    1027         // `extend` implies a `compaction` during the copy
    1028 
    1029     } else {
    1030         compaction(this);                                       // in-place
    1031     }// if
     848    } // if
     849    compaction(this);                                   // compact the byte area, in the same or new heap area
    1032850#ifdef VbyteDebug
    1033851    {
     
    1049867#undef VbyteDebug
    1050868
     869//WIP
     870#if 0
    1051871
    1052872
     
    1054874// area is deleted.
    1055875
    1056 void extend( VbyteHeap & this, int size ) with (this) {
     876void VbyteHeap::extend( int size ) {
    1057877#ifdef VbyteDebug
    1058878    serr | "enter:extend, size:" | size;
     
    1064884   
    1065885    CurrSize += size > InitSize ? size : InitSize;      // minimum extension, initial size
    1066     StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize);
     886    StartVbyte = EndVbyte = new char[CurrSize];
    1067887    ExtVbyte = (void *)( StartVbyte + CurrSize );
    1068     compaction(this);                                   // copy from old heap to new & adjust pointers to new heap
    1069     free( OldStartVbyte );                              // release old heap
     888    compaction();                                       // copy from old heap to new & adjust pointers to new heap
     889    delete OldStartVbyte;                               // release old heap
    1070890#ifdef VbyteDebug
    1071891    serr | "exit:extend, CurrSize:" | CurrSize;
     
    1073893} // extend
    1074894
    1075 //WIP
    1076 #if 0
    1077895
    1078896// Extend the size of the byte-string area by creating a new area and copying the old area into it. The old byte-string
Note: See TracChangeset for help on using the changeset viewer.