-----BEGIN PGP SIGNED MESSAGE-----

Hello,

I am trying to design the XS code for the new BigInt package. I had the 
following idea:

* we return a references to a blessed scalar (that seems to be neccessary, 
e.g. I don't think I can bless the scalar and return it as-is, the RV seems 
to be necc.)
* The referenced scalar should be used to store the stuff I need.

The second point is where it gets murky. I need basically to store:

* flags and a sign. Both can be put together into an int
* A or P (or none, as told by the flags), which can be put into a double
* a ptr to the low-level math object (usually a blessed RV)

Now, instead of malloc() a struct like:

        struct BigInt {
                int flags;
                int sign;
                double P;
                double A;
                SV* CALC;
        };

and then putting a ptr to it into the PV slot, I thought I could:

        put the flags/sign into the IV slot (sign: lower 8 bit, flags the rest)
        put AP into the NV slot (we only have A or P, never both)
        put the ptr into the PV slot

Problems:

* I am not sure this will work. 
* I have problems calling a Perl routine, and storing it's return value, and 
later retrieving it.

Attached is my very first (well, more like round 246, last attempt) at the 
code to create an object. Also attached is a small test.pl test-driving 
this. A more complete module for:

        perl Makefile.PL
        make
        perl -Mblib -Ilib test.pl

can be found at 

        http://bloodgate.com/perl/packages/devel/Math-BigInt-XS-2.00.tar.gz

I read the "Extending and Embedding Perl" book, but it never told exactly 
how to call "normal" Perl subroutines from XS - all it talked about was 
calling them from C (are there differences?) and using them as callbacks 
(which I don't want to, but it seems similiar, but what are the 
differences?). The book is actually quite confusing on these issues...

The test.pl outputs on my system:

SV = RV(0x818d8a4) at 0x8149d3c
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,ROK)
  RV = 0x8149ba4
  SV = PVMG(0x8167040) at 0x8149ba4
    REFCNT = 1
    FLAGS = (OBJECT,POK,pPOK)
    IV = 1
    NV = 2.1
    PV = 0x815a358 ""\0
    CUR = 0
    LEN = 1
    STASH = 0x81bbd5c   "Math::BigInt"
SV = NULL(0x81bc200) at 0x815a358
  REFCNT = 0
  FLAGS = ()

The first dump shows the reference and the SV stuffed with my info. The 
second is the attempt to retrieve the Math::BigInt::Calc object from the PV 
(a reference to a blessed AV actually), judgin from the matching address 
(0x815a358) that went ok, but the contents are not what I expected.

There is also the problem on DESTROY, I am sure I need a special routine to 
handle the freeing of the embedded CALC object and my "stuffed" SV.

Maybe it would be better to create a RV that points to a blessed RV, which 
points to the CALC object _and_ contains an IV and NV?

In any event, all the easy stuff in Perl like:

        $CALC->_new( \$wanted );

is hideous complicated in XS, or so it seems. You need like 20-30 lines of 
very complicated code just to achive this, and even then you haven't taken 
into account inheritance or changable classnames... *sigh*

Thank you for your insight,

Tels

- -- 
 Signed on Sun Jan 18 13:10:52 2004 with key 0x93B84C15.
 Visit my photo gallery at http://bloodgate.com/photos/
 PGP key on http://bloodgate.com/tels.asc or per email.

 "I am soo clumsy today." *crash*

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.2-rc1-SuSE (GNU/Linux)
Comment: When cryptography is outlawed, bayl bhgynjf jvyy unir cevinpl.

iQEVAwUBQAp7nncLPEOTuEwVAQFz/wf9FDUWwHFie61LI4Ioo6LURYrCJr5KoNrw
2/yaj3TZCdu1AWkyld3MsbrC04ThzbLbCktxVRjmhWk7COl7h24HJjTrbhp5Pcd0
P6tVVVMVeXbJM0o76xIJ394Qa7/LZiLoRzMvs7zMUslxbGGCQ8R0fbVB+vLLptDT
wmM5at+i+fo/5mWkJCuL05F98DDDbOfaVp495+6k6kKzNY+UzO7LSZdgMul8RULp
MWjlpypQ9lN1deqkL9697uibMa3rsvCNCTXtsZ1F1qgtCmFOFPok18lIKwVqEwIA
YNuXtvdQXhWDyKrdRm3DM/lhvYvWSLnu12CbHD6oikr7ZlkI28ZE9A==
=OXhy
-----END PGP SIGNATURE-----
#!/usr/bin/perl -w

use Math::BigInt;
use Devel::Size qw/total_size/;
use Devel::Peek;

my $x = Math::BigInt->new(1);

print total_size($x),"\n";
print Dump($x);

Dump( $x->_calc_object() );

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

/* Math::BigInt XS code */

/* we store the BigInt info inside a SV:
  IV & 0xF =		sign:
  0 => 'NaN', 1 => '+', +2 => 'inf', -1 => '-', -2 => '-inf'
  IV 0 0xFFF >> 8 = 	flags:	
  bitmask: bit	set means
		0	undef (otherwise normal object)
		1	use AP to round
		2	 AP is _A or _P (if bit 1 is set)
			 0 => AP is _A
			 1 => AP is _P
		3	_F: if set, never round this object
  PV = ptr to low-level math library object (aka unsigned value)
  NV = A or P, accuracy or precision (see flags)

MODULE = Math::BigInt		PACKAGE = Math::BigInt
PROTOTYPES: ENABLE

##############################################################################
# new()  - create a new Math::BigInt object

SV*
new(class, n)
	SV*	class
	SV*	n
  PREINIT:
	dSP;
	SV*	x;
	SV*	rv;
	SV*	calc;
	int	count;
  PPCODE:
    ENTER;
    SAVETMPS;
    PUSHMARK(SP);
    XPUSHs ( newSViv( 8 ) );	/* class argument does not matter */
    XPUSHs ( n );
    PUTBACK;
    count = call_pv ("Math::BigInt::Calc::_new", G_SCALAR );
    SPAGAIN;
    /* get return arg and make copy of ptr to LIB object */
    calc = POPs;
    SvREFCNT_inc(calc);
    FREETMPS;
    LEAVE;

    rv = sv_newmortal();
    newSVrv( rv, "Math::BigInt");
    /* now we have rv pointing to a new SV, which we fill with our info */
    x = SvRV ( rv );
    sv_setuv (x, 0x0001);		/* flags => 0, sign => 1 ('+') */
    sv_setnv (x, 2.1);			/* AP = 0 (2.1 to test it works) */
    sv_setpvn (x, (const char*) calc, 0);
    PUSHs ( rv );

##############################################################################
# return the embedded CALC object for testing

SV*
_calc_object(x)
	SV*	x
  PREINIT:
	SV*	rt;
	SV*	rv;
  PPCODE:
    /* dereference the RV we get */
    rv = SvRV ( x );
    rt = SvPV_nolen(rv);
    PUSHs(rt);

Reply via email to