Hi,
I'm aiming to access the mpz_t (gmp library integer) value that's contained in a Math::BigInt::GMP object, where that object is contained within a Math::BigInt object (as is the norm).
So I've copied pertinent code straight out of Math::BigInt::GMP's GMP.xs, and the below demo script is meeting that aim just fine (on both Windows and Ubuntu).
But ... I've had to make one small (but significant) change to the GMP.xs code that I copied.
In the mpz_from_sv_nofail function, the original code contained the following:
#if GMP_HAS_MAGICEXT
&& mg->mg_virtual == &vtbl_gmp
#endif
but that condition never holds for me, so I've changed it to:
#if GMP_HAS_MAGICEXT
&& mg->mg_virtual != &vtbl_gmp
#endif
though simply commenting out that code also works fine, and might be safer.
Safer still would be to understand why this anomaly exists. The mpz_from_sv_nofail function appears to be called internally by Math::BigInt::GMP - where the original rendition of it must surely be working fine.
Does anyone know why I'm having to alter it ? (I am totally clueless about magic - a link to some explanatory documentation might help me, though I seriously doubt that.)
Anyway - here's the code that I'm running. There's not much point in running it if you don't have Math::BigInt::GMP installed.
This code is copy'n'pasted straight out of GMP.xs except that:
1) the alteration mentioned above has been made;
2) I added the magic_status XSub to see what GMP_HAS_MAGICEXT was set to;
3) The mpz_access XSub is simply GMP.xs' mpz_from_sv() function, rewritten to print out the value of the mpz_t instead of returning it.
use warnings;
use Math::BigInt lib => 'GMP';
use Inline C => Config =>
LIBS => '-lgmp',
USING => 'ParseRegExp',
BUILD_NOISY => 1;
use Inline C => <<'EOC';
#include <gmp.h>
#ifndef PERL_UNUSED_ARG
# define PERL_UNUSED_ARG(x) ((void)x)
#endif
#ifndef gv_stashpvs
# define gv_stashpvs(name, create) gv_stashpvn(name, sizeof(name) - 1
+, create)
#endif
#ifndef PERL_MAGIC_ext
# define PERL_MAGIC_ext '~'
#endif
#if defined(USE_ITHREADS) && defined(MGf_DUP)
# define GMP_THREADSAFE 1
#else
# define GMP_THREADSAFE 0
#endif
#ifdef sv_magicext
# define GMP_HAS_MAGICEXT 1
#else
# define GMP_HAS_MAGICEXT 0
#endif
#define NEW_GMP_MPZ_T RETVAL = malloc (sizeof(mpz_t));
#define NEW_GMP_MPZ_T_INIT RETVAL = malloc (sizeof(mpz_t)); mpz_init(*
+RETVAL);
#define GMP_GET_ARG_0 TEMP = mpz_from_sv(x);
#define GMP_GET_ARG_1 TEMP_1 = mpz_from_sv(y);
#define GMP_GET_ARGS_0_1 GMP_GET_ARG_0; GMP_GET_ARG_1;
#if GMP_THREADSAFE
STATIC int
dup_gmp_mpz (pTHX_ MAGIC *mg, CLONE_PARAMS *params)
{
mpz_t *RETVAL;
PERL_UNUSED_ARG(params);
NEW_GMP_MPZ_T;
mpz_init_set(*RETVAL, *((mpz_t *)mg->mg_ptr));
mg->mg_ptr = (char *)RETVAL;
return 0;
}
#endif
#if GMP_HAS_MAGICEXT
STATIC MGVTBL vtbl_gmp = {
NULL, /* get */
NULL, /* set */
NULL, /* len */
NULL, /* clear */
NULL, /* free */
# ifdef MGf_COPY
NULL, /* copy */
# endif
# ifdef MGf_DUP
# if GMP_THREADSAFE
dup_gmp_mpz,
# else
NULL, /* dup */
# endif
# endif
# ifdef MGf_LOCAL
NULL, /* local */
# endif
};
#endif
void magic_status(void){
printf("GMP_HAS_MAGICEXT: %d\n", GMP_HAS_MAGICEXT);
}
STATIC mpz_t *
(SV *sv)
{
MAGIC *mg;
if (!sv_derived_from(sv, "Math::BigInt::GMP"))
croak("not of type Math::BigInt::GMP");
for (mg = SvMAGIC(SvRV(sv)); mg; mg = mg->mg_moremagic) {
if (mg->mg_type == PERL_MAGIC_ext
#if GMP_HAS_MAGICEXT
&& mg->mg_virtual != &vtbl_gmp
#endif
) {
#if GMP_HAS_MAGICEXT
return (mpz_t *)mg->mg_ptr;
#else
return INT2PTR(mpz_t *, SvIV((SV *)mg->mg_ptr));
#endif
}
}
return (mpz_t *)NULL;
}
void access_mpz(SV * sv) {
mpz_t *mpz;
if (!(mpz = mpz_from_sv_nofail(sv)))
croak("failed to fetch mpz pointer");
mpz_out_str(NULL, 10, mpz);
}
EOC
magic_status();
my $x = Math::BigInt->new('-' . ('9876543210123456789' x 4));
access_mpz($x->{value}); # Ignores $x->{sign}
For me this outputs (after compilation):
GMP_HAS_MAGICEXT: 1
9876543210123456789987654321012345678998765432101234567899876543210123
+456789
If I revert to the original mpz_from_sv_nofail() code I get:
GMP_HAS_MAGICEXT: 1
failed to fetch mpz pointer at try.pl line 125.
Cheers,
Rob
Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
Read Where should I post X? if you're not absolutely sure you're posting in the right place.
Please read these before you post! —
Posts may use any of the Perl Monks Approved HTML tags:
- a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
| |
For: |
|
Use: |
| & | | & |
| < | | < |
| > | | > |
| [ | | [ |
| ] | | ] |
Link using PerlMonks shortcuts! What shortcuts can I use for linking?
See Writeup Formatting Tips and other pages linked from there for more info.