APISection: User Contributed Perl Documentation (1)Updated: 2003-05-21 |
APISection: User Contributed Perl Documentation (1)Updated: 2003-05-21 |
use PDL;
sub mkmypiddle {
...
}
use Carp;
sub mkmypiddle {
my $class = shift;
my $pdl = $class->new;
$pdl->set_datatype($PDL_B);
my @dims = (1,3,4);
my $size = 1;
for (@dims) { $size *= $_ }
$pdl->setdims([@dims]);
my $dref = $pdl->get_dataref();
# read data directly from file
open my $file, '<data.dat' or die "couldn't open data.dat";
my $len = $size*PDL::Core::howbig($pdl->get_datatype);
croak "couldn't read enough data" if
read( $file, $$dref, $len) != $len;
close $file;
$pdl->upd_data();
return $pdl;
}
use PDL::LiteF; use PDL::Core::Dev;
$a = myfloatseq(); # exercise our C piddle constructor
print $a->info,"\n";
# the reason for this config call is explained below
use Inline C => Config =>
INC => &PDL_INCLUDE, # make sure we find pdlcore.h etc
TYPEMAPS => &PDL_TYPEMAP, # use the PDL typemap
AUTO_INCLUDE => &PDL_AUTO_INCLUDE, # global declarations and includes
BOOT => &PDL_BOOT; # boot code to load the Core struct
use Inline C; Inline->init; # useful if you want to be able to 'do'-load this script
__DATA__
__C__
static pdl* new_pdl(int datatype, PDL_Long dims[], int ndims)
{
pdl *p = PDL->pdlnew();
PDL->setdims (p, dims, ndims); /* set dims */
p->datatype = datatype; /* and data type */
PDL->allocdata (p); /* allocate the data chunk */
return p;
}
pdl* myfloatseq()
{
PDL_Long dims[] = {5,5,5};
pdl *p = new_pdl(PDL_F,dims,3);
PDL_Float *dataf = (PDL_Float *) p->data;
int i;
for (i=0;i<5*5*5;i++)
dataf[i] = i; /* the data must be initialized ! */
return p;
}
use PDL::LiteF; use PDL::Core::Dev; use PDL::Graphics::PGPLOT;
$b = mkpiddle();
print $b->info,"\n";
imag1 $b;
use Inline C => Config =>
INC => &PDL_INCLUDE,
TYPEMAPS => &PDL_TYPEMAP,
AUTO_INCLUDE => &PDL_AUTO_INCLUDE,
BOOT => &PDL_BOOT;
use Inline C; Inline->init;
__DATA__
__C__
/* wrap a user supplied chunk of data into a piddle
* You must specify the dimensions (dims,ndims) and
* the datatype (constants for the datatypes are declared
* in pdl.h; e.g. PDL_B for byte type, etc)
*
* when the created piddle 'npdl' is destroyed on the
* Perl side the function passed as the 'delete_magic'
* parameter will be called with the pointer to the pdl structure
* and the 'delparam' argument.
* This gives you an opportunity to perform any clean up
* that is necessary. For example, you might have to
* explicitly call a function to free the resources
* associated with your data pointer.
* At the very least 'delete_magic' should zero the piddle's data pointer:
*
* void delete_mydata(pdl* pdl, int param)
* {
* pdl->data = 0;
* }
* pdl *p = pdl_wrap(mydata, PDL_B, dims, ndims, delete_mydata,0);
*
* pdl_wrap returns the pointer to the pdl
* that was created.
*/
typedef void (*DelMagic)(pdl *, int param);
static void default_magic(pdl *p, int pa) { p->data = 0; }
static pdl* pdl_wrap(void *data, int datatype, PDL_Long dims[],
int ndims, DelMagic delete_magic, int delparam)
{
pdl* npdl = PDL->pdlnew(); /* get the empty container */
PDL->setdims(npdl,dims,ndims); /* set dims */
npdl->datatype = datatype; /* and data type */
npdl->data = data; /* point it to your data */
/* make sure the core doesn't meddle with your data */
npdl->state |= PDL_DONTTOUCHDATA | PDL_ALLOCATED;
if (delete_magic != NULL)
PDL->add_deletedata_magic(npdl, delete_magic, delparam);
else
PDL->add_deletedata_magic(npdl, default_magic, 0);
return npdl;
}
#define SZ 256
/* a really silly function that makes a ramp image
* in reality this could be an opaque function
* in some library that you are using
*/
static PDL_Byte* mkramp(void)
{
PDL_Byte *data;
int i;
if ((data = malloc(SZ*SZ*sizeof(PDL_Byte))) == NULL)
croak("mkramp: Couldn't allocate memory");
for (i=0;i<SZ*SZ;i++)
data[i] = i % SZ;
return data;
}
/* this function takes care of the required clean-up */
static void delete_myramp(pdl* p, int param)
{
if (p->data)
free(p->data);
p->data = 0;
}
pdl* mkpiddle()
{
PDL_Long dims[] = {SZ,SZ};
pdl *p;
p = pdl_wrap((void *) mkramp(), PDL_B, dims, 2,
delete_myramp,0); /* the delparam is abitrarily set to 0 */
return p;
}
use Inline C => Config =>
INC => &PDL_INCLUDE,
TYPEMAPS => &PDL_TYPEMAP,
AUTO_INCLUDE => &PDL_AUTO_INCLUDE, # declarations
BOOT => &PDL_BOOT; # code for the XS boot section
The code returned by "PDL_AUTO_INCLUDE" makes sure that pdlcore.h is included and declares the static variables to hold the pointer to the "Core" struct. It looks something like this:
print PDL_AUTO_INCLUDE;
#include <pdlcore.h> static Core* PDL; /* Structure holds core C functions */ static SV* CoreSV; /* Gets pointer to perl var holding core structure */
The code returned by "PDL_BOOT" retrieves the $PDL::SHARE variable and initializes the pointer to the "Core" struct. For those who know their way around the Perl API here is the code:
print PDL_BOOT;
perl_require_pv ("PDL::Core"); /* make sure PDL::Core is loaded */
CoreSV = perl_get_sv("PDL::SHARE",FALSE); /* SV* value */
#ifndef aTHX_
#define aTHX_
#endif
if (CoreSV==NULL)
Perl_croak(aTHX_ "We require the PDL::Core module, which was not found");
PDL = INT2PTR(Core*,SvIV( CoreSV )); /* Core* value */
if (PDL->Version != PDL_CORE_VERSION)
Perl_croak(aTHX_ "The code needs to be recompiled against the newly installed PDL");
The "Core" struct contains version info to ensure that the structure defined in pdlcore.h really corresponds to the one obtained at runtime. The code above tests for this
if (PDL->Version != PDL_CORE_VERSION)
....
For more information on the Core struct see PDL::Internals.
With these preparations your code can now access the core routines as already shown in some of the examples above, e.g.
pdl *p = PDL->pdlnew();
By default the C variable named "PDL" is used to hold the pointer to the "Core" struct. If that is (for whichever reason) a problem you can explicitly specify a name for the variable with the "PDL_AUTO_INCLUDE" and the "PDL_BOOT" routines:
use Inline C => Config =>
INC => &PDL_INCLUDE,
TYPEMAPS => &PDL_TYPEMAP,
AUTO_INCLUDE => &PDL_AUTO_INCLUDE 'PDL_Corep',
BOOT => &PDL_BOOT 'PDL_Corep';
Make sure you use the same identifier with "PDL_AUTO_INCLUDE" and "PDL_BOOT" and use that same identifier in your own code. E.g., continuning from the example above:
pdl *p = PDL_Corep->pdlnew();
"pdlnew" returns an empty pdl object that needs further initialization to turn it into a proper piddle. Example:
pdl *p = PDL->pdlnew(); PDL->setdims(p,dims,ndims); p->datatype = PDL_B;
where X is one of B,S,U,L,F,D and Xtype is one of Byte, Short, Ushort, Long, Float or Double.