Discussion:
array slices
(too old to reply)
Xavier Noria
2005-11-01 18:57:36 UTC
Permalink
I founded nothing about slices in perlguts, perlxs*, or perlapi
(where are they documented?), so I wrote this little utility to take
a slice from AV* data using the indices in AV* indices (integers),
and put the result in AV* out (indices and out are guaranteed to have
the same length):

void __slice(AV* indices, AV* data, AV* out) {
int i;
I32 last_index;
I32 index;
SV* val;

last_index = av_len(indices);
for (i = 0; i <= last_index; ++i) {
index = SvIVX(*av_fetch(indices, i, 0));
val = *av_fetch(data, index, 0);
av_store(out, i, newSVsv(val));
}
}

I am just starting to play around with the C API. Is this code right
as far as XS is concerned? Is there a better idiom?

-- fxn
Reinhard Pagitsch
2005-11-03 08:05:36 UTC
Permalink
Hello,
I founded nothing about slices in perlguts, perlxs*, or perlapi (where
are they documented?), so I wrote this little utility to take a slice
from AV* data using the indices in AV* indices (integers), and put the
result in AV* out (indices and out are guaranteed to have the same
void __slice(AV* indices, AV* data, AV* out) {
int i;
I32 last_index;
I32 index;
SV* val;
last_index = av_len(indices);
for (i = 0; i <= last_index; ++i) {
index = SvIVX(*av_fetch(indices, i, 0));
val = *av_fetch(data, index, 0);
av_store(out, i, newSVsv(val));
}
}
I am just starting to play around with the C API. Is this code right as
far as XS is concerned? Is there a better idiom?
-- fxn
I do not understand what you mean. The code you posted here is only to
make a copy of the array data and put it into the array out.

I think simpler would be (not tested):
void __slice(AV* data, AV* out) {
int i;
I32 max;

max = av_len(data);
for (i = 0; i <= max; ++i) {
av_store(out, i, newSVsv(*av_fetch(data, i, 0)));
}
}

But on the other way a memcpy() coud be do the same, I think.

In the book "Extending and Embedding Perl" from TIM JENNESS and SIMON
COZENS I found something about slices, but I do not know if it is what
you want.

As I understand a slice it is a "part" of the array, isn't it?

regards
Reinhard
Xavier Noria
2005-11-03 09:15:17 UTC
Permalink
Post by Reinhard Pagitsch
Post by Xavier Noria
I founded nothing about slices in perlguts, perlxs*, or perlapi
(where are they documented?), so I wrote this little utility to
take a slice from AV* data using the indices in AV* indices
(integers), and put the result in AV* out (indices and out are
void __slice(AV* indices, AV* data, AV* out) {
int i;
I32 last_index;
I32 index;
SV* val;
last_index = av_len(indices);
for (i = 0; i <= last_index; ++i) {
index = SvIVX(*av_fetch(indices, i, 0));
val = *av_fetch(data, index, 0);
av_store(out, i, newSVsv(val));
}
}
I am just starting to play around with the C API. Is this code
right as far as XS is concerned? Is there a better idiom?
I do not understand what you mean. The code you posted here is only
to make a copy of the array data and put it into the array out.
Yes, the subroutine has a bad name, it should be called
__slice_and_copy.
Post by Reinhard Pagitsch
void __slice(AV* data, AV* out) {
int i;
I32 max;
max = av_len(data);
for (i = 0; i <= max; ++i) {
av_store(out, i, newSVsv(*av_fetch(data, i, 0)));
}
}
The difference is that you're copying the entire data into out,
whereas in the code I sent only the slice indicated by indices is
copied. My code is (wants to be) the C equivalent of

@out = @data[@indices];
Post by Reinhard Pagitsch
In the book "Extending and Embedding Perl" from TIM JENNESS and
SIMON COZENS I found something about slices, but I do not know if
it is what you want.
I have yet to buy it, would you please summarise what they say about
array slices?

-- fxn
Reinhard Pagitsch
2005-11-04 07:40:12 UTC
Permalink
Hello Xavier,

Did you got my private mal?
Xavier Noria
2005-11-04 10:01:37 UTC
Permalink
Post by Reinhard Pagitsch
Hello Xavier,
Did you got my private mal?
Yep!

The text was actually about extending arrays, but it was helpful in
the sense that they applied the concepts to implement by hand array
slicing, so that suggests there's no built-in support.

Thank you!

-- fxn
Tassilo von Parseval
2005-11-03 10:15:41 UTC
Permalink
Post by Reinhard Pagitsch
I founded nothing about slices in perlguts, perlxs*, or perlapi (where
are they documented?), so I wrote this little utility to take a slice
from AV* data using the indices in AV* indices (integers), and put the
result in AV* out (indices and out are guaranteed to have the same
void __slice(AV* indices, AV* data, AV* out) {
int i;
I32 last_index;
I32 index;
SV* val;
last_index = av_len(indices);
for (i = 0; i <= last_index; ++i) {
index = SvIVX(*av_fetch(indices, i, 0));
val = *av_fetch(data, index, 0);
av_store(out, i, newSVsv(val));
}
}
I am just starting to play around with the C API. Is this code right as
far as XS is concerned? Is there a better idiom?
-- fxn
I do not understand what you mean. The code you posted here is only to
make a copy of the array data and put it into the array out.
No, his code copies only those elements whose indices are in the array
passed as first argument to __slice.
Post by Reinhard Pagitsch
void __slice(AV* data, AV* out) {
int i;
I32 max;
max = av_len(data);
for (i = 0; i <= max; ++i) {
av_store(out, i, newSVsv(*av_fetch(data, i, 0)));
}
}
But on the other way a memcpy() coud be do the same, I think.
That wouldn't work, unless you'd intend to make a deep memcpy. And that
is more or less what newSVsv does.

With a simple memcpy of the SV* array of an AV you'd sort of create
aliases, but you'd mess up the ref-counts. They'd need to be adjusted
as well (and I am not even sure that this is all it takes).

Tassilo
--
use bigint;
$n=71423350343770280161397026330337371139054411854220053437565440;
$m=-8,;;$_=$n&(0xff)<<$m,,$_>>=$m,,print+chr,,while(($m+=8)<=200);
Salvador Fandino
2005-11-16 12:30:10 UTC
Permalink
I founded nothing about slices in perlguts, perlxs*, or perlapi (where
are they documented?), so I wrote this little utility to take a slice
from AV* data using the indices in AV* indices (integers), and put the
result in AV* out (indices and out are guaranteed to have the same
void __slice(AV* indices, AV* data, AV* out) {
int i;
I32 last_index;
I32 index;
SV* val;
last_index = av_len(indices);
for (i = 0; i <= last_index; ++i) {
index = SvIVX(*av_fetch(indices, i, 0));
val = *av_fetch(data, index, 0);
av_store(out, i, newSVsv(val));
}
}
Hi Xavier, how are you doing?

to make a real splice, instead of cloning the SV with newSVsv(), just
increment the reference count of the original one and store it on the
target AV.

For instance:

void __slice(AV* indices, AV* data, AV* out) {
int i;
I32 last_index;
I32 index;
SV* val;

last_index = av_len(indices);
for (i = 0; i <= last_index; ++i) {
index = SvIVX(*av_fetch(indices, i, 0));

val = *av_fetch(data, index, 1); // <-- note the 1 here,
// to create a new SV if it
// doesn't exists yet on the
// original AV!

SvREFCNT_inc(val);

av_store(out, i, val);

// well, if out can be a tied array (and in the general
// case, it can), then you should replace the last line with
// this one:
// if (!av_store(out, i, val)) SvREFCNT_dec(val);

}
}

BTW, I can lend you my copy of "Extending and Embedding Perl" if you want.

Cheers,

- Salva

Loading...