in reply to Re^11: XS: SvPVLV examples?
in thread XS: SvPVLV examples?

Actually, the more I think about this, I think you may have been half right back there when you talked about lvalue subs. What I want is both. An lvalue sub that returns a PVLV that I can take a reference to if I need to.

What I'm seeking is the lowest cost way to provide direct access to memory (mapped to a file) from Perl code.

Starting from the beginning. When I map a view of a file, I get given an address. If I set that address into the PV of a scalar and return the scalar to perl, I can directly read from and write to an theoretical 128GB of disk as if it were a simple string in memory. Obviously, if you write sequentially to the whole address space, it will be little quicker than using normal IO because of swapping. But if you are randomly accessing sparsely, letting the OS & hardware take care of the loading the required pages on demand, and remembering to flush back any that you change, makes for very efficient access.

So, to increment a 32-bit integer somewhere in that address space, you might do something like:

my $addr = mapFile( ); substr( $addr, 32, 4 ) = pack 'V', 1+ unpack( 'V', substr $addr, 32, 4 + );

which works as is. But besides being rather unwieldy, it falls foul of the substr limitations you helped identify earlier in the week which means that you cannot use offsets >2GB.

So, my goal is to write a sub (or series of subs) that address both the integer limitations of substr and the unwieldiness of the expression above. Further inspiration comes from some code I used a while ago that incremented substrings in place:

$s = '0123456789';; ++substr( $s, $_, 1) for 0 .. length $s;; print $s;; 12345678911

Which looks okay until you look closely. And gets positively bizarre (though completely logical!):

$s = '999999999';; ++substr( $s, $_, 1) for 0 .. length $s;; print $s;; 11111111119999

And in any case, incrementing bytes isn't particularly useful. However, looking into this PVLV business led me to look at and think about vec in new ways:

$s = chr(0) x 40;; vec( $s, $_, 32 ) = $_ for 0 .. 9;; print unpack 'N*', $s;; 0 1 2 3 4 5 6 7 8 9 $s = pack 'N*', 0 .. 9;; print vec( $s, $_, 32 ) for 0 .. 9;; 0 1 2 3 4 5 6 7 8 9 { no warnings 'portable'; print vec( $s, $_, 64 ) for 0 .. 5 };; 1 8589934595 17179869189 25769803783 34359738377 0

The requirement for persistent lvalueness arises because whilst a sub that takes an offset and size is (reasonably) convenient when dealing with arrays of data or when the offsets are otherwise programmically generated:

++u32at( $_ ) for $start .. $end; u64at( int rand 2**37 ) *= 3 for 1 .. 1e6;

For regularly accessed fields at fixed offsets, it would be far more convenient to be able to use named variables:

my $totalX = u64ref( $headerSize + 3 * 8 ); ... $totalNet = $subTotalA + $subTotalB - $subTotalC;

But I guess that dereference syntax wouldn't be so inconvenient:

$$totalNet = $$subTotalA + $$subTotalB - $$subTotalC;

Anyway, that's where I think I'm headed. And I think your snippet will be usable with the addition of the lvalue attribute on the sub:

#! perl -slw use strict; use warnings; use Inline C => <<'__EOI__'; SV* f(SV* sv, I32 pos, I32 len) { SV* targ = newSV_type(SVt_PVLV); sv_magic(targ, NULL, PERL_MAGIC_substr, NULL, 0); LvTYPE(targ) = 'x'; LvTARG(targ) = SvREFCNT_inc_simple(sv); LvTARGOFF(targ) = pos; LvTARGLEN(targ) = len; return targ; } __EOI__ use Devel::Peek qw( Dump ); sub f :lvalue; my $x = "abcde"; my $r = ++f($x,2,1); Dump $r; print $x; __END__ C:\test>ike2-lv.pl SV = PVNV(0x3da9db8) at 0x277920 REFCNT = 1 FLAGS = (PADMY,POK,pPOK) IV = 0 NV = 0 PV = 0x3f044c8 "d"\0 CUR = 1 LEN = 8 abdde

and some custom set/get magic methods which will essentially be a combination of simplified versions of the existing substr and vec ones. To a) restrict sets to like for like rather than allowing the lvalue to be shrunk or grown through the assignments; b) to only address multiples of bytes/words/dwords/quads, signed and unsigned. And maybe reals; c) do native endianess.


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
RIP PCW It is as I've been saying!(Audio until 20090817)

Replies are listed 'Best First'.
Re^13: XS: SvPVLV examples?
by ikegami (Patriarch) on Sep 25, 2009 at 14:42 UTC

    Update: Ignore this post. I am/was rushed, and I falsely thought it would help when I composed my real reply.

    Quick question first: Are you amiable to changing

    my $addr = mapFile( ... ); substr( $addr, 32, 4 ) = pack 'V', 1+ unpack( 'V', substr $addr, 32, 4 );
    to
    mapFile( my $addr, ... ); substr( $addr, 32, 4 ) = pack 'V', 1+ unpack( 'V', substr $addr, 32, 4 );
    That's how tie gets around the problem.