Changes in / [cc7bbe6:3a038fa]


Ignore:
Files:
19 deleted
10 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/Makefile.am

    rcc7bbe6 r3a038fa  
    6363        containers/queueLockFree.hfa \
    6464        containers/stackLockFree.hfa \
    65         containers/string_sharectx.hfa \
    6665        containers/vector2.hfa \
    6766        vec/vec.hfa \
  • libcfa/src/containers/string.cfa

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

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

    rcc7bbe6 r3a038fa  
    1515
    1616#include "string_res.hfa"
    17 #include "string_sharectx.hfa"
    18 
    1917#include <stdlib.hfa>  // e.g. malloc
    20 #include <assert.h>
     18#include <string.h>    // e.g. strlen
    2119
    2220//######################### VbyteHeap "header" #########################
     21
     22
     23
     24
     25
     26
     27
     28
     29// DON'T COMMIT:
     30// #define VbyteDebug
     31
     32
     33
     34
    2335
    2436#ifdef VbyteDebug
     
    4254
    4355   
    44 static void compaction( VbyteHeap & );                          // compaction of the byte area
    45 static void garbage( VbyteHeap &, int );                                // garbage collect the byte area
    46 static void extend( VbyteHeap &, int );                 // extend the size of the byte area
    47 static void reduce( VbyteHeap &, int );                 // reduce the size of the byte area
    48 
    49 static void ?{}( VbyteHeap &, size_t = 1000 );
    50 static void ^?{}( VbyteHeap & );
    51 
    52 static int ByteCmp( char *, int, int, char *, int, int );       // compare 2 blocks of bytes
    53 static char *VbyteAlloc( VbyteHeap &, int );                    // allocate a block bytes in the heap
    54 static char *VbyteTryAdjustLast( VbyteHeap &, int );
    55 
    56 static void AddThisAfter( HandleNode &, HandleNode & );
    57 static void DeleteNode( HandleNode & );
    58 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
    5971
    6072
    6173// Allocate the storage for the variable sized area and intialize the heap variables.
    6274
    63 static void ?{}( VbyteHeap & this, size_t Size ) with(this) {
     75static inline void ?{}( VbyteHeap & this, int Size ) with(this) {
    6476#ifdef VbyteDebug
    6577    serr | "enter:VbyteHeap::VbyteHeap, this:" | &this | " Size:" | Size;
     
    7082    ExtVbyte = (void *)( StartVbyte + CurrSize );
    7183    Header.flink = Header.blink = &Header;
    72     Header.ulink = & this;
    7384#ifdef VbyteDebug
    7485    HeaderPtr = &Header;
     
    8091// Release the dynamically allocated storage for the byte area.
    8192
    82 static void ^?{}( VbyteHeap & this ) with(this) {
     93static inline void ^?{}( VbyteHeap & this ) with(this) {
    8394    free( StartVbyte );
    8495} // ~VbyteHeap
     
    91102// creator.
    92103
    93 static void ?{}( HandleNode & this ) with(this) {
     104void ?{}( HandleNode & this ) with(this) {
    94105#ifdef VbyteDebug
    95106    serr | "enter:HandleNode::HandleNode, this:" | &this;
     
    106117// collection.
    107118
    108 static void ?{}( HandleNode & this, VbyteHeap & vh ) with(this) {
     119void ?{}( HandleNode & this, VbyteHeap & vh ) with(this) {
    109120#ifdef VbyteDebug
    110121    serr | "enter:HandleNode::HandleNode, this:" | &this;
     
    112123    s = 0;
    113124    lnth = 0;
    114     ulink = &vh;
    115125    AddThisAfter( this, *vh.Header.blink );
    116126#ifdef VbyteDebug
     
    123133// is the responsibility of the creator to destroy it.
    124134
    125 static void ^?{}( HandleNode & this ) with(this) {
     135void ^?{}( HandleNode & this ) with(this) {
    126136#ifdef VbyteDebug
    127137    serr | "enter:HandleNode::~HandleNode, this:" | & this;
     
    139149} // ~HandleNode
    140150
    141 
    142 //######################### String Sharing Context #########################
    143 
    144 static string_sharectx * ambient_string_sharectx;               // fickle top of stack
    145 static string_sharectx default_string_sharectx = {NEW_SHARING}; // stable bottom of stack
    146 
    147 void ?{}( string_sharectx & this, StringSharectx_Mode mode ) with( this ) {
    148     (older){ ambient_string_sharectx };
    149     if ( mode == NEW_SHARING ) {
    150         (activeHeap){ new( (size_t) 1000 ) };
    151     } else {
    152         verify( mode == NO_SHARING );
    153         (activeHeap){ 0p };
    154     }
    155     ambient_string_sharectx = & this;
    156 }
    157 
    158 void ^?{}( string_sharectx & this ) with( this ) {
    159     if ( activeHeap ) delete( activeHeap );
    160 
    161     // unlink this from older-list starting from ambient_string_sharectx
    162     // usually, this==ambient_string_sharectx and the loop runs zero times
    163     string_sharectx *& c = ambient_string_sharectx;
    164     while ( c != &this ) &c = &c->older;              // find this
    165     c = this.older;                                   // unlink
    166 }
    167 
    168151//######################### String Resource #########################
    169152
    170153
    171 VbyteHeap * DEBUG_string_heap() {
    172     assert( ambient_string_sharectx->activeHeap && "No sharing context is active" );
    173     return ambient_string_sharectx->activeHeap;
    174 }
     154VbyteHeap HeapArea;
     155
     156VbyteHeap * DEBUG_string_heap = & HeapArea;
    175157
    176158size_t DEBUG_string_bytes_avail_until_gc( VbyteHeap * heap ) {
     
    178160}
    179161
    180 size_t DEBUG_string_bytes_in_heap( VbyteHeap * heap ) {
    181     return heap->CurrSize;
    182 }
    183 
    184162const char * DEBUG_string_heap_start( VbyteHeap * heap ) {
    185163    return heap->StartVbyte;
    186164}
     165
    187166
    188167// Returns the size of the string in bytes
     
    208187    // Store auto-newline state so it can be restored
    209188    bool anl = getANL$(out);
    210     if( s.Handle.lnth == 0 ) {
    211         sout | "";
    212     } else {
    213         nlOff(out);
    214         for (size_t i = 0; i < s.Handle.lnth; i++) {
    215             // Need to re-apply on the last output operator, for whole-statement version
    216             if (anl && i == s.Handle.lnth-1) nlOn(out);
    217             out | s[i];
    218         }
    219     }
     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;
    220196}
    221197
    222198// Empty constructor
    223199void ?{}(string_res &s) with(s) {
    224     if( ambient_string_sharectx->activeHeap ) {
    225         (Handle){ * ambient_string_sharectx->activeHeap };
    226         (shareEditSet_owns_ulink){ false };
    227         verify( Handle.s == 0p && Handle.lnth == 0 );
    228     } else {
    229         (Handle){ * new( (size_t) 10 ) };  // TODO: can I lazily avoid allocating for empty string
    230         (shareEditSet_owns_ulink){ true };
    231         Handle.s = Handle.ulink->StartVbyte;
    232         verify( Handle.lnth == 0 );
    233     }
     200    (Handle){ HeapArea };
    234201    s.shareEditSet_prev = &s;
    235202    s.shareEditSet_next = &s;
    236203}
    237204
    238 static void eagerCopyCtorHelper(string_res &s, const char* rhs, size_t rhslnth) with(s) {
    239     if( ambient_string_sharectx->activeHeap ) {
    240         (Handle){ * ambient_string_sharectx->activeHeap };
    241         (shareEditSet_owns_ulink){ false };
    242     } else {
    243         (Handle){ * new( rhslnth ) };
    244         (shareEditSet_owns_ulink){ true };
    245     }
    246     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);
    247209    Handle.lnth = rhslnth;
    248210    for ( int i = 0; i < rhslnth; i += 1 ) {            // copy characters
     
    253215}
    254216
    255 // Constructor from a raw buffer and size
    256 void ?{}(string_res &s, const char* rhs, size_t rhslnth) with(s) {
    257     eagerCopyCtorHelper(s, rhs, rhslnth);
    258 }
    259 
    260 // private ctor (not in header): use specified heap (ignore ambient) and copy chars in
    261 void ?{}( string_res &s, VbyteHeap & heap, const char* rhs, size_t rhslnth ) with(s) {
    262     (Handle){ heap };
    263     Handle.s = VbyteAlloc(*Handle.ulink, rhslnth);
    264     Handle.lnth = rhslnth;
    265     (s.shareEditSet_owns_ulink){ false };
    266     for ( int i = 0; i < rhslnth; i += 1 ) {            // copy characters
    267         Handle.s[i] = rhs[i];
    268     } // for
    269     s.shareEditSet_prev = &s;
    270     s.shareEditSet_next = &s;
     217// String literal constructor
     218void ?{}(string_res &s, const char* rhs) {
     219    (s){ rhs, strlen(rhs) };
    271220}
    272221
     
    274223void ?{}(string_res &s, const string_res & s2, StrResInitMode mode, size_t start, size_t end ) {
    275224
    276     verify( start <= end && end <= s2.Handle.lnth );
    277 
    278     if (s2.Handle.ulink != ambient_string_sharectx->activeHeap && mode == COPY_VALUE) {
    279         // crossing heaps (including private): copy eagerly
    280         eagerCopyCtorHelper(s, s2.Handle.s + start, end - start);
    281         verify(s.shareEditSet_prev == &s);
    282         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;
    283235    } else {
    284         (s.Handle){};
    285         s.Handle.s = s2.Handle.s + start;
    286         s.Handle.lnth = end - start;
    287         s.Handle.ulink = s2.Handle.ulink;
    288 
    289         AddThisAfter(s.Handle, s2.Handle );                     // insert this handle after rhs handle
    290         // ^ bug?  skip others at early point in string
    291 
    292         if (mode == COPY_VALUE) {
    293             verify(s2.Handle.ulink == ambient_string_sharectx->activeHeap);
    294             // requested logical copy in same heap: defer copy until write
    295 
    296             (s.shareEditSet_owns_ulink){ false };
    297 
    298             // make s alone in its shareEditSet
    299             s.shareEditSet_prev = &s;
    300             s.shareEditSet_next = &s;
    301         } else {
    302             verify( mode == SHARE_EDITS );
    303             // sharing edits with source forces same heap as source (ignore context)
    304 
    305             (s.shareEditSet_owns_ulink){ s2.shareEditSet_owns_ulink };
    306 
    307             // s2 is logically const but not implementation const
    308             string_res & s2mod = (string_res &) s2;
    309 
    310             // insert s after s2 on shareEditSet
    311             s.shareEditSet_next = s2mod.shareEditSet_next;
    312             s.shareEditSet_prev = &s2mod;
    313             s.shareEditSet_next->shareEditSet_prev = &s;
    314             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;
    315257        }
    316     }
    317 }
    318 
    319 static void assignEditSet(string_res & this, string_res * shareEditSetStartPeer, string_res * shareEditSetEndPeer,
    320     char * resultSesStart,
    321     size_t resultSesLnth,
    322     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.
    323283
    324284    char * beforeBegin = shareEditSetStartPeer->Handle.s;
     
    330290    size_t oldLnth = this.Handle.lnth;
    331291
    332     this.Handle.s = resultSesStart + beforeLen;
     292    this.Handle.s = pasting.Handle.s + beforeLen;
    333293    this.Handle.lnth = bsize;
    334     if (resultPadPosition)
    335         MoveThisAfter( this.Handle, *resultPadPosition );
     294    MoveThisAfter( this.Handle, pasting.Handle );
    336295
    337296    // adjust all substring string and handle locations, and check if any substring strings are outside the new base string
    338     char *limit = resultSesStart + resultSesLnth;
     297    char *limit = pasting.Handle.s + pasting.Handle.lnth;
    339298    for (string_res * p = this.shareEditSet_next; p != &this; p = p->shareEditSet_next) {
    340         verify (p->Handle.s >= beforeBegin);
     299        assert (p->Handle.s >= beforeBegin);
    341300        if ( p->Handle.s >= afterBegin ) {
    342             verify ( p->Handle.s <= afterBegin + afterLen );
    343             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 );
    344303            // p starts after the edit
    345304            // take start and end as end-anchored
     
    359318            } else {
    360319                // p ends after the edit
    361                 verify ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );
     320                assert ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );
    362321                // take end as end-anchored
    363322                // stretch-shrink p according to the edit
     
    367326            // take start as start-anchored
    368327            size_t startOffsetFromStart = p->Handle.s - beforeBegin;
    369             p->Handle.s = resultSesStart + startOffsetFromStart;
     328            p->Handle.s = pasting.Handle.s + startOffsetFromStart;
    370329        } else {
    371             verify ( p->Handle.s < afterBegin );
     330            assert ( p->Handle.s < afterBegin );
    372331            // p starts during the edit
    373             verify( p->Handle.s + p->Handle.lnth >= beforeBegin + beforeLen );
     332            assert( p->Handle.s + p->Handle.lnth >= beforeBegin + beforeLen );
    374333            if ( p->Handle.s + p->Handle.lnth < afterBegin ) {
    375334                // p ends during the edit; p does not include the last character replaced
     
    385344            }
    386345        }
    387         if (resultPadPosition)
    388             MoveThisAfter( p->Handle, *resultPadPosition );     // move substring handle to maintain sorted order by string position
    389     }
    390 }
    391 
    392 static string_res & assign_(string_res &this, const char* buffer, size_t bsize, const string_res & valSrc) {
    393 
    394     // traverse the incumbent share-edit set (SES) to recover the range of a base string to which `this` belongs
    395     string_res * shareEditSetStartPeer = & this;
    396     string_res * shareEditSetEndPeer = & this;
    397     for (string_res * editPeer = this.shareEditSet_next; editPeer != &this; editPeer = editPeer->shareEditSet_next) {
    398         if ( editPeer->Handle.s < shareEditSetStartPeer->Handle.s ) {
    399             shareEditSetStartPeer = editPeer;
    400         }
    401         if ( shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth < editPeer->Handle.s + editPeer->Handle.lnth) {
    402             shareEditSetEndPeer = editPeer;
    403         }
    404     }
    405 
    406     verify( shareEditSetEndPeer->Handle.s >= shareEditSetStartPeer->Handle.s );
    407     size_t origEditSetLength = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - shareEditSetStartPeer->Handle.s;
    408     verify( origEditSetLength >= this.Handle.lnth );
    409 
    410     if ( this.shareEditSet_owns_ulink ) {                 // assigning to private context
    411         // ok to overwrite old value within LHS
    412         char * prefixStartOrig = shareEditSetStartPeer->Handle.s;
    413         int prefixLen = this.Handle.s - prefixStartOrig;
    414         char * suffixStartOrig = this.Handle.s + this.Handle.lnth;
    415         int suffixLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - suffixStartOrig;
    416 
    417         int delta = bsize - this.Handle.lnth;
    418         if ( char * oldBytes = VbyteTryAdjustLast( *this.Handle.ulink, delta ) ) {
    419             // growing: copy from old to new
    420             char * dest = VbyteAlloc( *this.Handle.ulink, origEditSetLength + delta );
    421             char *destCursor = dest;  memcpy(destCursor, prefixStartOrig, prefixLen);
    422             destCursor += prefixLen;  memcpy(destCursor, buffer         , bsize    );
    423             destCursor += bsize;      memcpy(destCursor, suffixStartOrig, suffixLen);
    424             assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer,
    425                 dest,
    426                 origEditSetLength + delta,
    427                 0p, bsize);
    428             free( oldBytes );
    429         } else {
    430             // room is already allocated in-place: bubble suffix and overwite middle
    431             memmove( suffixStartOrig + delta, suffixStartOrig, suffixLen );
    432             memcpy( this.Handle.s, buffer, bsize );
    433 
    434             assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer,
    435                 shareEditSetStartPeer->Handle.s,
    436                 origEditSetLength + delta,
    437                 0p, bsize);
    438         }
    439 
    440     } else if (                                           // assigning to shared context
    441         this.Handle.lnth == origEditSetLength &&          // overwriting entire run of SES
    442         & valSrc &&                                       // sourcing from a managed string
    443         valSrc.Handle.ulink == this.Handle.ulink  ) {     // sourcing from same heap
    444 
    445         // SES's result will only use characters from the source string => reuse source
    446         assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer,
    447             valSrc.Handle.s,
    448             valSrc.Handle.lnth,
    449             &((string_res&)valSrc).Handle, bsize);
    450        
    451     } else {
    452         // overwriting a proper substring of some string: mash characters from old and new together (copy on write)
    453         // OR we are importing characters: need to copy eagerly (can't refer to source)
    454 
    455         // full string is from start of shareEditSetStartPeer thru end of shareEditSetEndPeer
    456         // `this` occurs in the middle of it, to be replaced
    457         // build up the new text in `pasting`
    458 
    459         string_res pasting = {
    460             * this.Handle.ulink,                               // maintain same heap, regardless of context
    461             shareEditSetStartPeer->Handle.s,                   // start of SES
    462             this.Handle.s - shareEditSetStartPeer->Handle.s }; // length of SES, before this
    463         append( pasting,
    464             buffer,                                            // start of replacement for this
    465             bsize );                                           // length of replacement for this
    466         append( pasting,
    467             this.Handle.s + this.Handle.lnth,                  // start of SES after this
    468             shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth -
    469             (this.Handle.s + this.Handle.lnth) );              // length of SES, after this
    470 
    471         // The above string building can trigger compaction.
    472         // The reference points (that are arguments of the string building) may move during that building.
    473         // From this point on, they are stable.
    474 
    475         assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer,
    476             pasting.Handle.s,
    477             pasting.Handle.lnth,
    478             &pasting.Handle, bsize);
    479     }
    480 
    481     return this;
    482 }
    483 
    484 string_res & assign(string_res &this, const char* buffer, size_t bsize) {
    485     return assign_(this, buffer, bsize, *0p);
    486 }
    487 
    488 string_res & ?=?(string_res &s, char other) {
    489     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);
    490356}
    491357
    492358// Copy assignment operator
    493 string_res & ?=?(string_res & this, const string_res & rhs) with( this ) {
    494     return assign_(this, rhs.Handle.s, rhs.Handle.lnth, rhs);
    495 }
    496 
    497 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 ) {
    498364    const string_res & rhs2 = rhs;
    499     return this = rhs2;
     365    this = rhs2;
    500366}
    501367
     
    508374    s.shareEditSet_prev->shareEditSet_next = s.shareEditSet_next;
    509375    s.shareEditSet_next->shareEditSet_prev = s.shareEditSet_prev;
    510     // s.shareEditSet_next = &s;
    511     // s.shareEditSet_prev = &s;
    512 
    513     if (shareEditSet_owns_ulink && s.shareEditSet_next == &s) { // last one out
    514         delete( s.Handle.ulink );
    515     }
     376    s.shareEditSet_next = &s;
     377    s.shareEditSet_prev = &s;
    516378}
    517379
     
    525387}
    526388
    527 void assignAt(const string_res &s, size_t index, char val) {
    528     string_res editZone = { s, SHARE_EDITS, index, index+1 };
    529     assign(editZone, &val, 1);
    530 }
    531 
    532389
    533390///////////////////////////////////////////////////////////////////
     
    535392
    536393void append(string_res &str1, const char * buffer, size_t bsize) {
    537     size_t clnth = str1.Handle.lnth + bsize;
    538     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 ?
    539396        // no-op
    540397    } else {                                            // must copy some text
    541         if ( str1.Handle.s + str1.Handle.lnth == VbyteAlloc(*str1.Handle.ulink, 0) ) { // str1 at end of string area ?
    542             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
    543400        } else {                                        // copy the two parts
    544             char * str1newBuf = VbyteAlloc( *str1.Handle.ulink, clnth );
    545             char * str1oldBuf = str1.Handle.s;  // must read after VbyteAlloc call in case it gs's
    546             str1.Handle.s = str1newBuf;
    547             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);
    548404        } // if
    549         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
    550407    } // if
    551408    str1.Handle.lnth = clnth;
     
    560417}
    561418
     419void ?+=?(string_res &s, const char* other) {
     420    append( s, other, strlen(other) );
     421}
    562422
    563423
     
    569429
    570430bool ?==?(const string_res &s1, const string_res &s2) {
    571     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;
    572432}
    573433
     
    736596// Add a new HandleNode node n after the current HandleNode node.
    737597
    738 static void AddThisAfter( HandleNode & this, HandleNode & n ) with(this) {
     598static inline void AddThisAfter( HandleNode & this, HandleNode & n ) with(this) {
    739599#ifdef VbyteDebug
    740600    serr | "enter:AddThisAfter, this:" | &this | " n:" | &n;
    741601#endif // VbyteDebug
    742     verify( n.ulink != 0p );
    743     verify( this.ulink == n.ulink );
    744602    flink = n.flink;
    745603    blink = &n;
     
    766624// Delete the current HandleNode node.
    767625
    768 static void DeleteNode( HandleNode & this ) with(this) {
     626static inline void DeleteNode( HandleNode & this ) with(this) {
    769627#ifdef VbyteDebug
    770628    serr | "enter:DeleteNode, this:" | &this;
     
    780638
    781639// Allocates specified storage for a string from byte-string area. If not enough space remains to perform the
    782 // allocation, the garbage collection routine is called.
    783 
    784 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) {
    785644#ifdef VbyteDebug
    786645    serr | "enter:VbyteAlloc, size:" | size;
     
    791650    NoBytes = ( uintptr_t )EndVbyte + size;
    792651    if ( NoBytes > ( uintptr_t )ExtVbyte ) {            // enough room for new byte-string ?
    793                 garbage( this, size );                                  // firer up the garbage collector
    794                 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
    795658    } // if
    796659    r = EndVbyte;
     
    803666
    804667
    805 // Adjusts the last allocation in this heap by delta bytes, or resets this heap to be able to offer
    806 // new allocations of its original size + delta bytes. Positive delta means bigger;
    807 // negative means smaller.  A null return indicates that the original heap location has room for
    808 // the requested growth.  A non-null return indicates that copying to a new location is required
    809 // but has not been done; the returned value is the old heap storage location; `this` heap is
    810 // modified to reference the new location.  In the copy-requred case, the caller should use
    811 // VbyteAlloc to claim the new space, while doing optimal copying from old to new, then free old.
    812 
    813 static char * VbyteTryAdjustLast( VbyteHeap & this, int delta ) with(this) {
    814 
    815     if ( ( uintptr_t )EndVbyte + delta <= ( uintptr_t )ExtVbyte ) {
    816         // room available
    817         EndVbyte += delta;
    818         return 0p;
    819     }
    820 
    821     char *oldBytes = StartVbyte;
    822 
    823     NoOfExtensions += 1;
    824     CurrSize *= 2;
    825     StartVbyte = EndVbyte = alloc(CurrSize);
    826     ExtVbyte = StartVbyte + CurrSize;
    827 
    828     return oldBytes;
    829 }
    830 
    831 
    832668// Move an existing HandleNode node h somewhere after the current HandleNode node so that it is in ascending order by
    833669// the address in the byte string area.
    834670
    835 static void MoveThisAfter( HandleNode & this, const HandleNode  & h ) with(this) {
     671static inline void MoveThisAfter( HandleNode & this, const HandleNode  & h ) with(this) {
    836672#ifdef VbyteDebug
    837673    serr | "enter:MoveThisAfter, this:" | & this | " h:" | & h;
    838674#endif // VbyteDebug
    839     verify( h.ulink != 0p );
    840     verify( this.ulink == h.ulink );
    841675    if ( s < h.s ) {                                    // check argument values
    842676                // serr | "VbyteSM: Error - Cannot move byte string starting at:" | s | " after byte string starting at:"
    843677                //      | ( h->s ) | " and keep handles in ascending order";
    844678                // exit(-1 );
    845                 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");
    846680    } // if
    847681
     
    875709//######################### VbyteHeap #########################
    876710
     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
    877728// Compare two byte strings in the byte-string area. The routine returns the following values:
    878729//
     
    881732// -1 => Src1-byte-string < Src2-byte-string
    882733
    883 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) {
    884735#ifdef VbyteDebug
    885736    serr | "enter:ByteCmp, Src1Start:" | Src1Start | " Src1Lnth:" | Src1Lnth | " Src2Start:" | Src2Start | " Src2Lnth:" | Src2Lnth;
     
    938789    h = Header.flink;                                   // ignore header node
    939790    for (;;) {
    940                 memmove( EndVbyte, h->s, h->lnth );
     791                ByteCopy( this, EndVbyte, 0, h->lnth, h->s, 0, h->lnth );
    941792                obase = h->s;
    942793                h->s = EndVbyte;
     
    962813// the heap.  The heap is then compacted in the existing heap or into the newly allocated heap.
    963814
    964 void garbage(VbyteHeap & this, int minreq ) with(this) {
     815void garbage(VbyteHeap & this ) with(this) {
    965816#ifdef VbyteDebug
    966817    serr | "enter:garbage";
     
    986837    AmountFree = ( uintptr_t )ExtVbyte - ( uintptr_t )StartVbyte - AmountUsed;
    987838   
    988     if ( ( double ) AmountFree < ( CurrSize * 0.1 ) || AmountFree < minreq ) {  // free space less than 10%  or not enough to serve cur request
    989 
    990                 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
    991843
    992844                        //  Peter says, "This needs work before it should be used."
     
    994846                        //              reduce(( AmountFree / CurrSize - 3 ) * CurrSize ); // reduce the memory
    995847
    996         // `extend` implies a `compaction` during the copy
    997 
    998     } else {
    999         compaction(this);                                       // in-place
    1000     }// if
     848    } // if
     849    compaction(this);                                   // compact the byte area, in the same or new heap area
    1001850#ifdef VbyteDebug
    1002851    {
     
    1018867#undef VbyteDebug
    1019868
     869//WIP
     870#if 0
    1020871
    1021872
     
    1023874// area is deleted.
    1024875
    1025 void extend( VbyteHeap & this, int size ) with (this) {
     876void VbyteHeap::extend( int size ) {
    1026877#ifdef VbyteDebug
    1027878    serr | "enter:extend, size:" | size;
     
    1033884   
    1034885    CurrSize += size > InitSize ? size : InitSize;      // minimum extension, initial size
    1035     StartVbyte = EndVbyte = alloc(CurrSize);
     886    StartVbyte = EndVbyte = new char[CurrSize];
    1036887    ExtVbyte = (void *)( StartVbyte + CurrSize );
    1037     compaction(this);                                   // copy from old heap to new & adjust pointers to new heap
    1038     free( OldStartVbyte );                              // release old heap
     888    compaction();                                       // copy from old heap to new & adjust pointers to new heap
     889    delete OldStartVbyte;                               // release old heap
    1039890#ifdef VbyteDebug
    1040891    serr | "exit:extend, CurrSize:" | CurrSize;
     
    1042893} // extend
    1043894
    1044 //WIP
    1045 #if 0
    1046895
    1047896// Extend the size of the byte-string area by creating a new area and copying the old area into it. The old byte-string
  • libcfa/src/containers/string_res.hfa

    rcc7bbe6 r3a038fa  
    1717
    1818#include <fstream.hfa>
    19 #include <string.h>    // e.g. strlen
    2019
    2120   
     
    2827    HandleNode *flink;                                  // forward link
    2928    HandleNode *blink;                                  // backward link
    30     VbyteHeap *ulink;                   // upward link
    3129
    3230    char *s;                                            // pointer to byte string
     
    3432}; // HandleNode
    3533
    36 VbyteHeap * DEBUG_string_heap();
    37 size_t DEBUG_string_bytes_in_heap( VbyteHeap * heap );
     34void ?{}( HandleNode & );                       // constructor for header node
     35
     36void ?{}( HandleNode &, VbyteHeap & );          // constructor for nodes in the handle list
     37void ^?{}( HandleNode & );                      // destructor for handle nodes
     38
     39extern VbyteHeap * DEBUG_string_heap;
    3840size_t DEBUG_string_bytes_avail_until_gc( VbyteHeap * heap );
    3941const char * DEBUG_string_heap_start( VbyteHeap * heap );
     
    4547struct string_res {
    4648    HandleNode Handle; // chars, start, end, global neighbours
    47     bool shareEditSet_owns_ulink;
    4849    string_res * shareEditSet_prev;
    4950    string_res * shareEditSet_next;
     
    7374// Constructors, Assignment Operators, Destructor
    7475void ?{}(string_res &s); // empty string
     76void ?{}(string_res &s, const char* initial); // copy from string literal (NULL-terminated)
    7577void ?{}(string_res &s, const char* buffer, size_t bsize); // copy specific length from buffer
    76 static inline void ?{}(string_res &s, const char* rhs) { // copy from string literal (NULL-terminated)
    77     (s){ rhs, strlen(rhs) };
    78 }
    7978
    8079void ?{}(string_res &s, const string_res & s2) = void;
     
    8786}
    8887
    89 string_res & assign(string_res &s, const char* buffer, size_t bsize); // copy specific length from buffer
    90 static inline string_res & ?=?(string_res &s, const char* other) {  // copy from string literal (NULL-terminated)
    91     return assign(s, other, strlen(other));
    92 }
    93 string_res & ?=?(string_res &s, const string_res &other);
    94 string_res & ?=?(string_res &s, string_res &other);
    95 string_res & ?=?(string_res &s, char other);
     88void assign(string_res &s, const char* buffer, size_t bsize); // copy specific length from buffer
     89void ?=?(string_res &s, const char* other); // copy from string literal (NULL-terminated)
     90void ?=?(string_res &s, const string_res &other);
     91void ?=?(string_res &s, string_res &other);
     92void ?=?(string_res &s, char other);
    9693
    9794void ^?{}(string_res &s);
     
    10299
    103100// Concatenation
    104 void append(string_res &s, const char* buffer, size_t bsize);
    105101void ?+=?(string_res &s, char other); // append a character
    106102void ?+=?(string_res &s, const string_res &s2); // append-concatenate to first string
    107 static inline void ?+=?(string_res &s, const char* other) {
    108     append( s, other, strlen(other) );
    109 }
     103void ?+=?(string_res &s, const char* other);
     104void append(string_res &s, const char* buffer, size_t bsize);
    110105
    111106// Character access
    112 void assignAt(const string_res &s, size_t index, char val);
    113107char ?[?](const string_res &s, size_t index); // Mike changed to ret by val from Sunjay's ref, to match Peter's
    114108//char codePointAt(const string_res &s, size_t index); // revisit under Unicode
  • tests/collections/.expect/string-api-coverage.txt

    rcc7bbe6 r3a038fa  
    11hello hello hello
    2 
    3 hello
    42true false
    53true false
  • tests/collections/.expect/string-gc.txt

    rcc7bbe6 r3a038fa  
    3838x from 5 to 15
    3939y from 5 to 15
    40 ======================== fillNoCompact
    41 about to expand, a = aaa
    42 expanded, a = aaa
    43 about to expand, a = aaa
    44 expanded, a = aaa
    45 about to expand, a = aaa
    46 expanded, a = aaa
    47 about to expand, a = aaa
    48 expanded, a = aaa
    49 about to expand, a = aaa
    50 expanded, a = aaa
  • tests/collections/string-api-coverage.cfa

    rcc7bbe6 r3a038fa  
    11#include <containers/string.hfa>
    2 #include <string_sharectx.hfa>
    32
    43void assertWellFormedHandleList( int maxLen ) { // with(HeapArea)
     
    2625
    2726int main () {
    28 
    29     #ifdef STRING_SHARING_OFF
    30     string_sharectx c = { NO_SHARING };
    31     #endif
    32 
    3327    string s = "hello";
    3428    string s2 = "hello";
     
    3731
    3832    // IO operator, x2
    39     sout | s | s | s;  // hello hello hello
    40 
    41     // empty ctor then assign
    42     string sxx;
    43     sout | sxx;  // (blank line)
    44     sxx = s;
    45     sout | sxx;  // hello
     33    sout | s | s | s;
    4634
    4735    // Comparisons
  • tests/collections/string-gc.cfa

    rcc7bbe6 r3a038fa  
    22
    33size_t bytesRemaining() {
    4     return DEBUG_string_bytes_avail_until_gc( DEBUG_string_heap() );
     4    return DEBUG_string_bytes_avail_until_gc( DEBUG_string_heap );
    55}
    66
    77size_t heapOffsetStart( string_res & s ) {
    8     const char * startByte = DEBUG_string_heap_start( DEBUG_string_heap() );
     8    const char * startByte = DEBUG_string_heap_start( DEBUG_string_heap );
    99    assert( s.Handle.s >= startByte );
    1010    return s.Handle.s - startByte;
     
    120120}
    121121
    122 void fillNoCompact() {
    123     // show that allocating in a heap filled with mostly live strings (no collectable garbage) causes heap growth
    124 
    125     sout | "======================== fillNoCompact";
    126 
    127     size_t lastTimeBytesAvail = bytesRemaining();
    128     assert( lastTimeBytesAvail >= 200 ); // starting this test with nontrivial room
    129 
    130     // mostly fill the pad
    131     string_res a = "aaa";  // will have to be moved
    132     string_res z = "zzz";
    133     for (i; 5) {
    134         while ( bytesRemaining() > 10 ) {
    135             z += ".";
    136         }
    137         sout | "about to expand, a = " | a;
    138         while ( bytesRemaining() <= 10 ) {
    139             z += ".";
    140         }
    141         sout | "expanded, a = " | a;
    142 
    143         // each growth gives more usable space than the last
    144         assert( bytesRemaining() > lastTimeBytesAvail );
    145         lastTimeBytesAvail = bytesRemaining();
    146     }
    147 }
    148 
    149122int main() {
    150123    basicFillCompact();
    151124    fillCompact_withSharedEdits();
    152     fillNoCompact();
    153125}
  • tests/collections/string-overwrite.cfa

    rcc7bbe6 r3a038fa  
    11#include <containers/string.hfa>
    2 #include <string_sharectx.hfa>
    32
    43/*
     
    1211WE = witness end
    1312
    14 The test does:
     13The dest does:
    1514  starts with the entire string being, initially, the alphabet; prints this entire alphabet
    1615  sets up modifier and witness as ranges within it, and prints a visualization of those ranges
     
    2524This API's convention has Start positions being inclusive and end positions being exclusive.
    2625
    27                                 v Case number in output
    2826With 1 equivalence class:
    2927MS = ME = WS = WE               1
     
    120118    struct { int ms; int me; int ws; int we; char *replaceWith; char *label; } cases[] = {
    121119        { 12, 14, 10, 20, "xxxxx", "warmup" },
     120//        { 12, 14, 12, 14, "xxxxx", ""       },  // the bug that got me into this test (should be a dup with case 6)
    122121        { 10, 10, 10, 10, "=====", "1"      },
    123122        { 10, 10, 10, 10, "=="   , ""       },
     
    224223        { 12, 14, 10, 16, "="    , ""       },
    225224        { 12, 14, 10, 16, ""     , ""       },
     225/*
     226        { , , , , "=====", "NN"     },
     227        {  "=="   , ""       },
     228        {  "="    , ""       },
     229        {  ""     , ""       },
     230*/
    226231    };
    227232    for ( i; sizeof(cases)/sizeof(cases[0]) ) {
     
    233238
    234239
     240// void f( string & s, string & toEdit ) {
     241
     242//     sout | s | "|" | toEdit | "|";
     243
     244//     s(14, 16) = "-";
     245//     sout | s | "|" | toEdit | "|";
     246// }
     247
    235248int main() {
    236 
    237     #ifdef STRING_SHARING_OFF
    238     string_sharectx c = { NO_SHARING };
    239     #endif
    240 
    241 
    242249    //          0         1         2
    243250    //          01234567890123456789012345
Note: See TracChangeset for help on using the changeset viewer.