NAME
Class::HPLOO::InlineC - Add a pseudo syntax over C to work easier with SV*, AV*, HV* and RV*.
DESCRIPTION
Who have worked with XS and perlapi knows that to access values from AV* and HV*, and work with references is not very friendly. To work arounf that I have added a pseudo syntax over the C syntax, that helps to work easily with SV*, AV*, HV* and RV*.
USAGE
use Class::HPLOO ;
class Point {
sub Point ($x , $y) {
$this->{x} = $x ;
$this->{y} = $y ;
}
sub move_x( $mv_x ) {
$this->{x} += $mv_x ;
}
sub[C] void move_y( SV* self , int mv_y ) {
int y = self->{y}->int + mv_y ;
self->{y} = int2sv(y) ;
}
sub[C] SV* get_xy_ref( SV* self ) {
AV* ret = newAV() ;
ret->[0] = self->{x} ;
ret->[1] = self->{y} ;
return \{ret} ;
}
}
my $p = Point->new(10,20) ;
$p->move_x(100) ;
$p->move_y(100) ;
my $xy = $p->get_xy_ref() ; ## returns an ARRAY reference.
print "XY> @$xy\n" ; ## XY> 110 120
As you can see, is very easy to access and set an integer value from $Point->{y} (at self). Also is simple to create an ARRAY and return a reference to it.
FETCH:
self->{y}->int
## Rewrited to:
SvIV( *hv_fetch((HV*)SvRV( self ) , "y" , strlen("y") , 0) )
STORE:
self->{y} = int2sv(y) ;
## Rewrited to:
sv_setsv_mg( *hv_fetch((HV*)SvRV( self ) , "y" , strlen("y") , newSViv(y) ) ;
THE PSEUDO SYNTAX
- FETCH HV:
-
void foo(SV* self) { self->{y}->int ; // $this->{y} as int. self->{y}->float ; // $this->{y} as double. self->{list}->av ; // @{$this->{list}} as AV*. self->{hash}->hv ; // %{$this->{hash}} as HV*. self->{y}->sv; // explicity $this->{y} as SV*. self->{hash}->rv ; // New RV: \%{$this->{hash}} { HV* hv1 = %{ self->{hash} } ; // %{$this->{hash}} HV* hv2 = self->{hash}->hv ; // same } }
- FETCH AV:
-
void foo(SV* self) { self->[0]->int ; // $this->[0] as int. self->[1]->float ; // $this->[1] as double. self->[2]->av ; // @{$this->[2]} as AV*. self->[3]->hv ; // %{$this->[3]} as HV*. self->[3]->sv; // explicity $this->[3] as SV*. self->[4]->rv ; // New RV: \%{$this->[4]} { AV* av1 = @{ self->{list} } ; // @{$this->{list}} AV* av2 = self->{list}->av ; // same } }
- FETCH SV:
-
void foo(SV* val) { val->str ; // $val as char* val->pvx ; // return a pointer to the char* buffer inside the SCALAR. val->int ; // $val as int. val->float ; // $val as double. val->av ; // @{$val} as AV*. val->hv ; // %{$val} as HV*. val->sv ; // explicity $val as SV*. val->rv ; // New RV: \%{$val} { SV* sv = val ; // make sv to point to val. SV* sv = val->sv ; // make sv to point to val but explicity declare val as (SV*) SV* sv = ${val} ; // Access the SV that val points if val is a reference (RV) to another SV. } }
- FETCH RV:
-
void foo(SV* val) { SV* sv_ref = \{val} ; // Create a reference to $val SV* sv = ${sv_ref} // de-reference sv_ref: ${$sv_ref} ; AV* array = newAV() ; // Create a new AV. SV* av_ref = \{array} ; // Create a reference to array ; AV* av = @{av_ref} // Get the array that av_ref make reference. HV* hash = newHV() ; // Create a new HV. SV* hv_ref = \{hash} ; // Create a reference to hash ; HV* hv = %{hv_ref} // Get the hash that hv_ref make reference. }
- STORE
-
The STORE syntax is always an access to an SV = a new SV:
self->{y} = int2sv(10) ; self->[0] = int2sv(10) ;
If you have a SV directly in a C variable you can use ->sv to explicity say that it's an SV and enable the syntax:
SV* y = self->{y} ; // ... y->sv = int2sv(10);
- STORE and REFERENCES
-
Basically to store using a reference we just need to access the SV inside the reference:
AV* array = newAV() ; // Create a new AV. SV* av_ref = \{array} ; // Create a reference to array ; AV* av = @{av_ref} // Get the array that av_ref make reference. array->[0] = int2sv(10) ; array->[1] = int2sv(20) ; array->[2] = int2sv(30) ; // and with av will change the same array: av->[0] = int2sv(10) ; av->[1] = int2sv(20) ; av->[2] = int2sv(30) ; // with the reference is: @{av_ref}[0] = int2sv(10) ; @{av_ref}[1] = int2sv(20) ; @{av_ref}[2] = int2sv(30) ;
- FETCH/STORE AV and HV elements
-
As a normal Perl code the pseudo syntax make the fetch and store to elements that doesn't exists yet true. So, if you fetch an ARRAY position that doesn't exists, a new undef SV will be created in the position before you fetch it. The same idea works for HV, so you can fetch a key of a hash even if it wasn't created yet. And since a STORE is done with a previous FETCH, you can store elements in positions/keys that doesn't exists yet:
AV* array = newAV() ; // Create a new AV. array->[0] = int2sv(10) ; // Store 10 in the position 0 without need to FILL the array before.
Note that each FETCH to an array ensure that the array is filled with the element. And each FETCH to a HASH will automatically create the key.
EASILY RETURNING N ELEMENTS
The easier way to return a list of elements (SV*) is to return a reference to an ARRAY. With this approach you don't need to work with the XS STACK:
sub SV* foo() {
AV* ret = newAV() ; // Create a new AV.
ret->[0] = int2sv(10) ; // store 10 at $ret[0].
AV* table = newHV() ; // Create a new HV.
table->{a} = int2sv(1) ; // set the key a => 1.
table->{b} = int2sv(2) ; // set the key b => 2.
ret->[0] = \{table} // Store a reference to the hash table.
return \{ret} ; // Return a reference to the array @ret.
}
SV* CONVERTIONS
Here's the list of convertion functions:
SV* bool2sv( bool b ) ;
SV* int2sv( long n ) ;
SV* long2sv( long n ) ;
SV* float2sv( float n ) ;
SV* double2sv( double n ) ;
SV* str2sv( char* s ) ;
bool sv2bool( SV* s ) ;
int sv2int( SV* s ) ;
long sv2long( SV* s ) ;
float sv2float( SV* s ) ;
double sv2double( SV* s ) ;
char* sv2str( SV* s ) ;
SEE ALSO
AUTHOR
Graciliano M. P. <gmpassos@cpan.org>
I will appreciate any type of feedback (include your opinions and/or suggestions). ;-P
COPYRIGHT
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.