in reply to Re: XS Prepending space to an SVs PV
in thread XS Prepending space to an SVs PV

modified to accept an additional argument that indicates how much extra space should be allocated when reallocation of the string memory is required:
static char * my_sv_unchop(pTHX_ SV *sv, STRLEN size, STRLEN reserve) { STRLEN len; char *pv = SvPV(sv, len); IV off = SvOOK(sv) ? SvIVX(sv) : 0; if (!size) return pv; if (off >= size) { SvLEN_set(sv, SvLEN(sv) + size); SvCUR_set(sv, len + size); SvPV_set(sv, pv - size); if (off == size) SvFLAGS(sv) &= ~SVf_OOK; else SvIV_set(sv, off - size); } else { size += reserve; if ((size < reserve) || (len + size < size)) Perl_croak(aTHX_ "panic: memory wrap"); if (len + size <= off + SvLEN(sv)) { SvCUR_set(sv, len + size); SvPV_set(sv, pv - off); Move(pv, pv + size - off, len, char); if (off) { SvLEN_set(sv, SvLEN(sv) + off ); SvFLAGS(sv) &= ~SVf_OOK; } } else { SV *tmp = sv_2mortal(newSV(len + size)); char *tmp_pv; SvPOK_on(tmp); tmp_pv = SvPV_nolen(tmp); Move(pv, tmp_pv + size, len, char); SvCUR_set(tmp, len + size); sv_setsv(sv, tmp); } if (reserve) sv_chop(sv, SvPVX(sv) + reserve); } return SvPVX(sv); }

Replies are listed 'Best First'.
Re^3: XS Prepending space to an SVs PV
by BrowserUk (Patriarch) on Apr 27, 2006 at 01:58 UTC

    Many thanks (again) for this code, it is very generous of you and so much easier to learn from than the pure reference material of the 'guts and 'api docs.

    I set about adapting the above sub to my needs which are slightly less demanding that yours. The naming of sv_chop is (historical; set in stone; not of your making), slightly confusing with respect to Perl's chop as they operate on different ends of the string. That makes sv_unchop even more confusing :)

    Anyway, whilst reading the docs on sv_chop, I noticed sv_insert and relating that back to creamygoodness' explanation and demonstration that used substr to prepend to a string, I thought I'd see if I could use that to simplify things a little. What I came up with is this:

    if( *a == 9 ) { ## Time to prepend another byte if( SvOOK( n ) ) { ## If we've some reserve left use it SvLEN_set( n, SvLEN( n ) +1 ); SvCUR_set( n, ++l ); SvPV_set( n, --a ); } else { ## else insert 100 more bytes and use sv_chop ## to reserve 99 of them for later char pad[100] = { 0, }; ## Initialise the reserve to all z +eros sv_insert( n, 0, 0, pad, 100 ); sv_chop( n, SvPVX( n ) + 99 ); a = SvPVX( n ); ++l; } } ...

    Whether that could be useful to you I don't know, but if you have the time to cast an eye over it and tell me if you see any obvious fopars... thanks again.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      You have to check that there is still space free when the OOK flag is true and update the IV also:
      ... if (SvOOK( n ) && (SvIV(sv) > 0)) { /* If we've some reserve left use +it */ SvLEN_set( n, SvLEN( n ) +1 ); SvCUR_set( n, ++l ); SvPV_set( n, --a ); SvIVX(sv)--; } ...