.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .ie \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .el \{\ . de IX .. .\} .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "API 1p" .TH API 1p "2012-01-02" "perl v5.14.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" PDL::API \- making piddles from Perl and C/XS code .SH "DESCRIPTION" .IX Header "DESCRIPTION" A simple cookbook how to create piddles manually. It covers both the Perl and the C/XS level. Additionally, it describes the \s-1PDL\s0 core routines that can be accessed from other modules. These routines basically define the \s-1PDL\s0 \s-1API\s0. If you need to access piddles from C/XS you probably need to know about these functions. .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 4 \& use PDL; \& sub mkmypiddle { \& ... \& } .Ve .SH "Creating a piddle manually from Perl" .IX Header "Creating a piddle manually from Perl" Sometimes you want to create a piddle \fImanually\fR from binary data. You can do that at the Perl level. Examples in the distribution include some of the \&\s-1IO\s0 routines. The code snippet below illustrates the required steps. .PP .Vb 10 \& 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, \*(Aqget_datatype); \& croak "couldn\*(Aqt read enough data" if \& read( $file, $$dref, $len) != $len; \& close $file; \& $pdl\->upd_data(); \& \& return $pdl; \& } .Ve .SH "Creating a piddle in C" .IX Header "Creating a piddle in C" The following example creates a piddle at the C level. We use the \f(CW\*(C`Inline\*(C'\fR module which is really the way to interface Perl and C these days. Note the use of the \f(CW\*(C`PDL_INCLUDE\*(C'\fR, \f(CW\*(C`PDL_TYPEMAP\*(C'\fR, \&\f(CW\*(C`PDL_AUTO_INCLUDE\*(C'\fR and \f(CW\*(C`PDL_BOOT\*(C'\fR functions that were imported from \&\f(CW\*(C`PDL::Core::Dev\*(C'\fR. They are used in conjunction with an Inline Config call to ensure that the \s-1PDL\s0 typemap, the \s-1PDL\s0 include files and the \s-1PDL\s0 Core routines are found during compilation and later runtime execution. .PP .Vb 2 \& use PDL::LiteF; \& use PDL::Core::Dev; \& \& $a = myfloatseq(); # exercise our C piddle constructor \& \& print $a\->info,"\en"; \& \& # 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 \*(Aqdo\*(Aq\-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; \& } .Ve .SS "Wrapping your own data into a piddle" .IX Subsection "Wrapping your own data into a piddle" Sometimes you obtain a chunk of data from another source, for example an image processing library, etc. All you want to do in that case is wrap your data into a piddle struct at the C level. Examples using this approach can be found in the \s-1IO\s0 modules (where FastRaw and FlexRaw use it for mmapped access) and the Gimp Perl module (that uses it to wrap Gimp pixel regions into piddles). The following script demonstrates a simple example: .PP .Vb 3 \& use PDL::LiteF; \& use PDL::Core::Dev; \& use PDL::Graphics::PGPLOT; \& \& $b = mkpiddle(); \& \& print $b\->info,"\en"; \& \& 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 \*(Aqnpdl\*(Aq is destroyed on the \& * Perl side the function passed as the \*(Aqdelete_magic\*(Aq \& * parameter will be called with the pointer to the pdl structure \& * and the \*(Aqdelparam\*(Aq 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 \*(Aqdelete_magic\*(Aq should zero the piddle\*(Aqs 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\*(Aqt 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\*(Aqt allocate memory"); \& for (i=0;idata) \& 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; \& } .Ve .SH "The gory details" .IX Header "The gory details" .SS "The Core struct \*(-- getting at \s-1PDL\s0 core routines at runtime" .IX Subsection "The Core struct getting at PDL core routines at runtime" \&\s-1PDL\s0 uses a technique similar to that employed by the Tk modules to let other modules use its core routines. A pointer to all shared core \s-1PDL\s0 routines is stored in the \f(CW$PDL::SHARE\fR variable. \&\s-1XS\s0 code should get hold of this pointer at boot time so that the rest of the C/XS code can then use that pointer for access at run time. This initial loading of the pointer is most easily achieved using the functions \f(CW\*(C`PDL_AUTO_INCLUDE\*(C'\fR and \f(CW\*(C`PDL_BOOT\*(C'\fR that are defined and exported by \f(CW\*(C`PDL::Core::Dev\*(C'\fR. Typical usage with the Inline module has already been demonstrated: .PP .Vb 5 \& 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 .Ve .PP The code returned by \f(CW\*(C`PDL_AUTO_INCLUDE\*(C'\fR makes sure that \fIpdlcore.h\fR is included and declares the static variables to hold the pointer to the \f(CW\*(C`Core\*(C'\fR struct. It looks something like this: .PP .Vb 1 \& print PDL_AUTO_INCLUDE; \& \& #include \& static Core* PDL; /* Structure holds core C functions */ \& static SV* CoreSV; /* Gets pointer to Perl var holding core structure */ .Ve .PP The code returned by \f(CW\*(C`PDL_BOOT\*(C'\fR retrieves the \f(CW$PDL::SHARE\fR variable and initializes the pointer to the \f(CW\*(C`Core\*(C'\fR struct. For those who know their way around the Perl \s-1API\s0 here is the code: .PP .Vb 1 \& 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"); .Ve .PP The \f(CW\*(C`Core\*(C'\fR struct contains version info to ensure that the structure defined in \fIpdlcore.h\fR really corresponds to the one obtained at runtime. The code above tests for this .PP .Vb 2 \& if (PDL\->Version != PDL_CORE_VERSION) \& .... .Ve .PP For more information on the Core struct see PDL::Internals. .PP With these preparations your code can now access the core routines as already shown in some of the examples above, e.g. .PP .Vb 1 \& pdl *p = PDL\->pdlnew(); .Ve .PP By default the C variable named \f(CW\*(C`PDL\*(C'\fR is used to hold the pointer to the \&\f(CW\*(C`Core\*(C'\fR struct. If that is (for whichever reason) a problem you can explicitly specify a name for the variable with the \f(CW\*(C`PDL_AUTO_INCLUDE\*(C'\fR and the \f(CW\*(C`PDL_BOOT\*(C'\fR routines: .PP .Vb 5 \& use Inline C => Config => \& INC => &PDL_INCLUDE, \& TYPEMAPS => &PDL_TYPEMAP, \& AUTO_INCLUDE => &PDL_AUTO_INCLUDE \*(AqPDL_Corep\*(Aq, \& BOOT => &PDL_BOOT \*(AqPDL_Corep\*(Aq; .Ve .PP Make sure you use the same identifier with \f(CW\*(C`PDL_AUTO_INCLUDE\*(C'\fR and \f(CW\*(C`PDL_BOOT\*(C'\fR and use that same identifier in your own code. E.g., continuing from the example above: .PP .Vb 1 \& pdl *p = PDL_Corep\->pdlnew(); .Ve .SS "Some selected core routines explained" .IX Subsection "Some selected core routines explained" The full definition of the \f(CW\*(C`Core\*(C'\fR struct can be found in the file \&\fIpdlcore.h\fR. In the following the most frequently used member functions of this struct are briefly explained. .IP "\(bu" 5 \&\f(CW\*(C`pdl *SvPDLV(SV *sv)\*(C'\fR .IP "\(bu" 5 \&\f(CW\*(C`pdl *SetSV_PDL(SV *sv, pdl *it)\*(C'\fR .IP "\(bu" 5 \&\f(CW\*(C`pdl *pdlnew()\*(C'\fR .Sp \&\f(CW\*(C`pdlnew\*(C'\fR returns an empty pdl object that needs further initialization to turn it into a proper piddle. Example: .Sp .Vb 3 \& pdl *p = PDL\->pdlnew(); \& PDL\->setdims(p,dims,ndims); \& p\->datatype = PDL_B; .Ve .IP "\(bu" 5 \&\f(CW\*(C`pdl *null()\*(C'\fR .IP "\(bu" 5 \&\f(CW\*(C`SV *copy(pdl* p, char* )\*(C'\fR .IP "\(bu" 5 \&\f(CW\*(C`void *smalloc(int nbytes)\*(C'\fR .IP "\(bu" 5 \&\f(CW\*(C`int howbig(int pdl_datatype)\*(C'\fR .IP "\(bu" 5 \&\f(CW\*(C`void add_deletedata_magic(pdl *p, void (*func)(pdl*, int), int param)\*(C'\fR .IP "\(bu" 5 \&\f(CW\*(C`void allocdata(pdl *p)\*(C'\fR .IP "\(bu" 5 \&\f(CW\*(C`void make_physical(pdl *p)\*(C'\fR .IP "\(bu" 5 \&\f(CW\*(C`void make_physdims(pdl *p)\*(C'\fR .IP "\(bu" 5 \&\f(CW\*(C`void make_physvaffine(pdl *p)\*(C'\fR .IP "\(bu" 5 \&\f(CW\*(C`void qsort_X(PDL_Xtype *data, int a, int b)\*(C'\fR and \&\f(CW\*(C`void qsort_ind_X(PDL_Xtype *data, int *ix, int a, int b)\*(C'\fR .Sp where X is one of B,S,U,L,F,D and Xtype is one of Byte, Short, Ushort, Long, Float or Double. .IP "\(bu" 5 \&\f(CW\*(C`float NaN_float\*(C'\fR and \&\f(CW\*(C`double NaN_double\*(C'\fR .Sp These are constants to produce the required NaN values. .IP "\(bu" 5 \&\f(CW\*(C`void pdl_barf(const char* pat,...)\*(C'\fR and \&\f(CW\*(C`void pdl_warn(const char* pat,...)\*(C'\fR .Sp These are C\-code equivalents of \f(CW\*(C`barf\*(C'\fR and \f(CW\*(C`warn\*(C'\fR. They include special handling of error or warning messages during pthreading (i.e. processor multi-threading) that defer the messages until after pthreading is completed. When pthreading is complete, perl's \f(CW\*(C`barf\*(C'\fR or \f(CW\*(C`warn\*(C'\fR is called with the deferred messages. This is needed to keep from calling perl's \f(CW\*(C`barf\*(C'\fR or \f(CW\*(C`warn\*(C'\fR during pthreading, which can cause segfaults. .Sp Note that \f(CW\*(C`barf\*(C'\fR and \f(CW\*(C`warn\*(C'\fR have been redefined (using c\-preprocessor macros) in pdlcore.h to \f(CW\*(C`PDL\->barf\*(C'\fR and \f(CW\*(C`PDL\->warn\*(C'\fR. This is to keep any \s-1XS\s0 or \s-1PP\s0 code from calling perl's \f(CW\*(C`barf\*(C'\fR or \f(CW\*(C`warn\*(C'\fR directly, which can cause segfaults during pthreading. .Sp See PDL::ParallelCPU for more information on pthreading. .SH "SEE ALSO" .IX Header "SEE ALSO" \&\s-1PDL\s0 .PP Inline .SH "BUGS" .IX Header "BUGS" This manpage is still under development. Feedback and corrections are welcome. .SH "COPYRIGHT" .IX Header "COPYRIGHT" Copyright 2010 Christian Soeller (c.soeller@auckland.ac.nz). You can distribute and/or modify this document under the same terms as the current Perl license. .PP See: http://dev.perl.org/licenses/