Perl SV value from pointer without copy

How can I create an SV value from a zero-terminated string without a copy? Like newSVpv(const char*, STRLEN) , but without copying and transferring ownership of Perl (so Perl should free up this string memory). I need this to avoid huge memory allocation and copying.

I found the following example:

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

But I do not have deep knowledge about the insides of XS and there are some doubts.

+6
source share
1 answer

If you want Perl to manage a block of memory, it needs to know how to reallocate it and free it. The only memory he knows how to redistribute and free is the memory allocated with his allocator, Newx . (Otherwise, he would have to associate the redistributor and deactivator with each memory block.)

If you cannot allocate a memory block using Newx , then the best option would be to create an SV for reading only with SvLEN set to zero. This tells Perl that it does not own memory. This SV can be blessed into a class that has a destructor that will free memory using the appropriate deallocator.

If you can allocate a block of memory using Newx , 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 must point to memory allocated by Newx , and it must point to the beginning of the block returned by Newx .

Note. Accepts the flags SVf_UTF8 (to indicate that ptr is the UTF-8 encoding of the string that will be visible in Perl), SVs_TEMP (for invoking sv_2mortal on SV) and SV_HAS_TRAILING_NUL (see below).

Note. In some code, it is expected that the scalar string buffer should have a trailing NUL (although the length of the buffer is known and even though the buffer may contain NUL). If the memory block you selected has a trailing NUL outside the data (for example, a string with a null C-style character), pass the flag SV_HAS_TRAILING_NUL . If not, the function will try to expand the buffer and add NUL.

+6
source

Source: https://habr.com/ru/post/988862/


All Articles