Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl SV value from pointer without copy

Tags:

perl

xs

How I could create SV value from null terminated string without copy? Like newSVpv(const char*, STRLEN) but without copy and with moving ownership to Perl (so Perl must release that string memory). I need this to avoid huge memory allocation and copy.

I found following example:

SV *r = sv_newmortal();
SvPOK_on(r);
sv_usepvn_mg(r, string, strlen(string) + 1);

But I don't have deep knowledge of XS internals and have some doubts.

like image 352
John Tracid Avatar asked Jun 10 '15 17:06

John Tracid


1 Answers

If you want Perl to manage the memory block, it needs to know how to reallocate it and deallocate it. The only memory it knows how to reallocate and deallocate is memory allocated using its allocator, Newx. (Otherwise, it would have to associate a reallocator and deallocator with each memory block.)

If you can't allocate the memory block using Newx, then your best option might be to create a read-only SV with SvLEN set to zero. That tells Perl that it doesn't own the memory. That SV could be blessed into a class that has a destructor that will deallocate the memory using the appropriate deallocator.

If you can allocate the memory block using Newx, then you can use the following:

SV* newSVpvn_steal_flags(pTHX_ const char* ptr, STRLEN len, const U32 flags) {
#define newSVpvn_steal_flags(a,b,c) newSVpvn_steal_flags(aTHX_ a,b,c)
    SV* sv;

    assert(!(flags & ~(SVf_UTF8|SVs_TEMP|SV_HAS_TRAILING_NUL)));

    sv = newSV(0);
    sv_usepvn_flags(sv, ptr, len, flags & SV_HAS_TRAILING_NUL);
    if ((flags & SVf_UTF8) && SvOK(sv)) {
        SvUTF8_on(sv);
    }

    SvTAINT(sv);

    if (flags & SVs_TEMP) {
        sv_2mortal(sv);
    }

    return sv;
}

Note: ptr should point to memory that was allocated by Newx, and it must point to the start of the block returned by Newx.

Note: Accepts flags SVf_UTF8 (to specify that ptr is the UTF-8 encoding of the string to be seen in Perl), SVs_TEMP (to have sv_2mortal called on the SV) and SV_HAS_TRAILING_NUL (see below).

Note: Some code expects the string buffer of scalars to have a trailing NUL (even though the length of the buffer is known and even though the buffer can contain NULs). If the memory block you allocated has a trailing NUL beyond the end of the data (e.g. a C-style NUL-terminated string), then pass the SV_HAS_TRAILING_NUL flag. If not, the function will attempt to extend the buffer and add a NUL.

like image 165
ikegami Avatar answered Oct 14 '22 10:10

ikegami