Changeset d32679d5


Ignore:
Timestamp:
Aug 12, 2023, 10:26:52 PM (14 months ago)
Author:
Michael Brooks <mlbrooks@…>
Branches:
master
Children:
8d96dee
Parents:
9ca5e56
Message:

String input operator with chunked memory management.

Files:
3 added
4 edited

Legend:

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

    r9ca5e56 rd32679d5  
    100100
    101101////////////////////////////////////////////////////////
    102 // Output
     102// Input-Output
    103103
    104104ofstream & ?|?( ofstream & out, const string & this ) {
     
    109109    (ofstream &)(out | (*this.inner)); ends( out );
    110110}
     111
     112ifstream & ?|?(ifstream &in, string &this) {
     113    return in | (*this.inner); // read to internal string_res
     114}
     115
    111116
    112117////////////////////////////////////////////////////////
  • libcfa/src/containers/string.hfa

    r9ca5e56 rd32679d5  
    5555ofstream & ?|?(ofstream &out, const string &s);
    5656void ?|?(ofstream &out, const string &s);
     57ifstream & ?|?(ifstream &in, string &s);
    5758
    5859// Concatenation
  • libcfa/src/containers/string_res.cfa

    r9ca5e56 rd32679d5  
    1717#include "string_sharectx.hfa"
    1818#include "stdlib.hfa"
     19#include <ctype.h>
    1920
    2021// Workaround for observed performance penalty from calling CFA's alloc.
     
    206207        (ofstream &)(out | s); ends( out );
    207208}
     209
     210// Input operator
     211ifstream & ?|?(ifstream &in, string_res &s) {
     212
     213    // Reading into a temp before assigning to s is near zero overhead in typical cases because of sharing.
     214    // If s is a substring of something larger, simple assignment takes care of that case correctly.
     215    // But directly reading a variable amount of text into the middle of a larger context is not practical.
     216    string_res temp;
     217
     218    // Read in chunks.  Often, one chunk is enough.  Keep the string that accumulates chunks last in the heap,
     219    // so available room is rest of heap.  When a chunk fills the heap, force growth then take the next chunk.
     220    for (;;) {
     221        // Append dummy content to temp, forcing expansion when applicable (occurs always on subsequent loops)
     222        // length 2 ensures room for at least one real char, plus scanf/pipe-cstr's null terminator
     223        temp += "--";
     224        assert( temp.Handle.ulink->EndVbyte == temp.Handle.s + temp.Handle.lnth );    // last in heap
     225
     226        // reset, to overwrite the appended "--"
     227        temp.Handle.lnth -= 2;
     228        temp.Handle.ulink->EndVbyte -= 2;
     229
     230        // rest of heap, less 1 byte for null terminator, is available to read into
     231        int lenReadable = (char*)temp.Handle.ulink->ExtVbyte - temp.Handle.ulink->EndVbyte - 1;
     232        assert (lenReadable >= 1);
     233
     234        // get bytes
     235        in | wdi( lenReadable, temp.Handle.ulink->EndVbyte );
     236        int lenWasRead = strlen(temp.Handle.ulink->EndVbyte);
     237
     238        // update metadata
     239        temp.Handle.lnth += lenWasRead;
     240        temp.Handle.ulink->EndVbyte += lenWasRead;
     241
     242      if (lenWasRead < lenReadable) break;
     243    }
     244
     245    s = temp;
     246    return in;
     247}
     248
    208249
    209250// Empty constructor
     
    373414}
    374415
    375 static string_res & assign_(string_res &this, const char* buffer, size_t bsize, const string_res & valSrc) {
    376 
    377     // traverse the incumbent share-edit set (SES) to recover the range of a base string to which `this` belongs
    378     string_res * shareEditSetStartPeer = & this;
    379     string_res * shareEditSetEndPeer = & this;
    380     for ( string_res * editPeer = this.shareEditSet_next; editPeer != &this; editPeer = editPeer->shareEditSet_next ) {
     416// traverse the share-edit set (SES) to recover the range of a base string to which `this` belongs
     417static void locateInShareEditSet( string_res &this, string_res *&shareEditSetStartPeer, string_res *&shareEditSetEndPeer ) {
     418    shareEditSetStartPeer = & this;
     419    shareEditSetEndPeer = & this;
     420    for (string_res * editPeer = this.shareEditSet_next; editPeer != &this; editPeer = editPeer->shareEditSet_next) {
    381421        if ( editPeer->Handle.s < shareEditSetStartPeer->Handle.s ) {
    382422            shareEditSetStartPeer = editPeer;
     
    386426        }
    387427    }
     428}
     429
     430static string_res & assign_(string_res &this, const char* buffer, size_t bsize, const string_res & valSrc) {
     431
     432    string_res * shareEditSetStartPeer;
     433    string_res * shareEditSetEndPeer;
     434    locateInShareEditSet( this, shareEditSetStartPeer, shareEditSetEndPeer );
    388435
    389436    verify( shareEditSetEndPeer->Handle.s >= shareEditSetStartPeer->Handle.s );
  • libcfa/src/containers/string_res.hfa

    r9ca5e56 rd32679d5  
    101101ofstream & ?|?(ofstream &out, const string_res &s);
    102102void ?|?(ofstream &out, const string_res &s);
     103ifstream & ?|?(ifstream &in, string_res &s);
    103104
    104105// Concatenation
Note: See TracChangeset for help on using the changeset viewer.