1API(1)                User Contributed Perl Documentation               API(1)
2
3
4

NAME

6       PDL::API - making piddles from Perl and C/XS code
7

DESCRIPTION

9       A simple cookbook how to create piddles manually.  It covers both the
10       Perl and the C/XS level.  Additionally, it describes the PDL core rou‐
11       tines that can be accessed from other modules. These routines basically
12       define the PDL API. If you need to access piddles from C/XS you proba‐
13       bly need to know about these functions.
14

SYNOPSIS

16         use PDL;
17         sub mkmypiddle {
18          ...
19         }
20

Creating a piddle manually from Perl

22       Sometimes you want to create a piddle manually from binary data. You
23       can do that at the Perl level.  Examples in the distribution include
24       some of the IO routines. The code snippet below illustrates the
25       required steps.
26
27          use Carp;
28          sub mkmypiddle {
29            my $class = shift;
30            my $pdl  = $class->new;
31            $pdl->set_datatype($PDL_B);
32            my @dims = (1,3,4);
33            my $size = 1;
34            for (@dims) { $size *= $_ }
35            $pdl->setdims([@dims]);
36            my $dref = $pdl->get_dataref();
37
38            # read data directly from file
39            open my $file, '<data.dat' or die "couldn't open data.dat";
40            my $len = $size*PDL::Core::howbig($pdl->get_datatype);
41            croak "couldn't read enough data" if
42              read( $file, $$dref, $len) != $len;
43            close $file;
44            $pdl->upd_data();
45
46            return $pdl;
47          }
48

Creating a piddle in C

50       The following example creates a piddle at the C level.  We use the
51       "Inline" module which is really the way to interface Perl and C these
52       days. Note the use of the "PDL_INCLUDE", "PDL_TYPEMAP",
53       "PDL_AUTO_INCLUDE" and "PDL_BOOT" functions that were imported from
54       "PDL::Core::Dev". They are used in conjunction with an Inline Config
55       call to ensure that the PDL typemap, the PDL include files and the PDL
56       Core routines are found during compilation and later runtime execution.
57
58          use PDL::LiteF;
59          use PDL::Core::Dev;
60
61          $a = myfloatseq(); # exercise our C piddle constructor
62
63          print $a->info,"\n";
64
65          # the reason for this config call is explained below
66          use Inline C => Config =>
67            INC           => &PDL_INCLUDE,  # make sure we find pdlcore.h etc
68            TYPEMAPS      => &PDL_TYPEMAP,  # use the PDL typemap
69            AUTO_INCLUDE  => &PDL_AUTO_INCLUDE,  # global declarations and includes
70            BOOT          => &PDL_BOOT;     # boot code to load the Core struct
71
72          use Inline C;
73          Inline->init; # useful if you want to be able to 'do'-load this script
74
75          __DATA__
76
77          __C__
78
79          static pdl* new_pdl(int datatype, PDL_Long dims[], int ndims)
80          {
81            pdl *p = PDL->pdlnew();
82            PDL->setdims (p, dims, ndims);  /* set dims */
83            p->datatype = datatype;         /* and data type */
84            PDL->allocdata (p);             /* allocate the data chunk */
85
86            return p;
87          }
88
89          pdl* myfloatseq()
90          {
91            PDL_Long dims[] = {5,5,5};
92            pdl *p = new_pdl(PDL_F,dims,3);
93            PDL_Float *dataf = (PDL_Float *) p->data;
94            int i;
95
96            for (i=0;i<5*5*5;i++)
97              dataf[i] = i; /* the data must be initialized ! */
98            return p;
99          }
100
101       Wrapping your own data into a piddle
102
103       Sometimes you obtain a chunk of data from another source, for example
104       an image processing library, etc.  All you want to do in that case is
105       wrap your data into a piddle struct at the C level. Examples using this
106       approach can be found in the IO modules (where FastRaw and FlexRaw use
107       it for mmapped access) and the Gimp Perl module (that uses it to wrap
108       Gimp pixel regions into piddles).  The following script demonstrates a
109       simple example:
110
111          use PDL::LiteF;
112          use PDL::Core::Dev;
113          use PDL::Graphics::PGPLOT;
114
115          $b = mkpiddle();
116
117          print $b->info,"\n";
118
119          imag1 $b;
120
121          use Inline C => Config =>
122            INC           => &PDL_INCLUDE,
123            TYPEMAPS      => &PDL_TYPEMAP,
124            AUTO_INCLUDE  => &PDL_AUTO_INCLUDE,
125            BOOT          => &PDL_BOOT;
126
127          use Inline C;
128          Inline->init;
129
130          __DATA__
131
132          __C__
133
134          /* wrap a user supplied chunk of data into a piddle
135           * You must specify the dimensions (dims,ndims) and
136           * the datatype (constants for the datatypes are declared
137           * in pdl.h; e.g. PDL_B for byte type, etc)
138           *
139           * when the created piddle 'npdl' is destroyed on the
140           * Perl side the function passed as the 'delete_magic'
141           * parameter will be called with the pointer to the pdl structure
142           * and the 'delparam' argument.
143           * This gives you an opportunity to perform any clean up
144           * that is necessary. For example, you might have to
145           * explicitly call a function to free the resources
146           * associated with your data pointer.
147           * At the very least 'delete_magic' should zero the piddle's data pointer:
148           *
149           *     void delete_mydata(pdl* pdl, int param)
150           *     {
151           *       pdl->data = 0;
152           *     }
153           *     pdl *p = pdl_wrap(mydata, PDL_B, dims, ndims, delete_mydata,0);
154           *
155           * pdl_wrap returns the pointer to the pdl
156           * that was created.
157           */
158          typedef void (*DelMagic)(pdl *, int param);
159          static void default_magic(pdl *p, int pa) { p->data = 0; }
160          static pdl* pdl_wrap(void *data, int datatype, PDL_Long dims[],
161                               int ndims, DelMagic delete_magic, int delparam)
162          {
163            pdl* npdl = PDL->pdlnew(); /* get the empty container */
164
165            PDL->setdims(npdl,dims,ndims); /* set dims      */
166            npdl->datatype = datatype;     /* and data type */
167            npdl->data = data;             /* point it to your data */
168            /* make sure the core doesn't meddle with your data */
169            npdl->state ⎪= PDL_DONTTOUCHDATA ⎪ PDL_ALLOCATED;
170            if (delete_magic != NULL)
171              PDL->add_deletedata_magic(npdl, delete_magic, delparam);
172            else
173              PDL->add_deletedata_magic(npdl, default_magic, 0);
174            return npdl;
175          }
176
177          #define SZ 256
178          /* a really silly function that makes a ramp image
179           * in reality this could be an opaque function
180           * in some library that you are using
181           */
182          static PDL_Byte* mkramp(void)
183          {
184            PDL_Byte *data;
185            int i;
186
187            if ((data = malloc(SZ*SZ*sizeof(PDL_Byte))) == NULL)
188              croak("mkramp: Couldn't allocate memory");
189            for (i=0;i<SZ*SZ;i++)
190              data[i] = i % SZ;
191
192            return data;
193          }
194
195          /* this function takes care of the required clean-up */
196          static void delete_myramp(pdl* p, int param)
197          {
198            if (p->data)
199              free(p->data);
200            p->data = 0;
201          }
202
203          pdl* mkpiddle()
204          {
205            PDL_Long dims[] = {SZ,SZ};
206            pdl *p;
207
208            p = pdl_wrap((void *) mkramp(), PDL_B, dims, 2,
209                         delete_myramp,0); /* the delparam is abitrarily set to 0 */
210            return p;
211          }
212

The gory details

214       The Core struct -- getting at PDL core routines at runtime
215
216       PDL uses a technique similar to that employed by the Tk modules to let
217       other modules use its core routines. A pointer to all shared core PDL
218       routines is stored in the $PDL::SHARE variable.  XS code should get
219       hold of this pointer at boot time so that the rest of the C/XS code can
220       then use that pointer for access at run time. This initial loading of
221       the pointer is most easily achieved using the functions
222       "PDL_AUTO_INCLUDE" and "PDL_BOOT" that are defined and exported by
223       "PDL::Core::Dev". Typical usage with the Inline module has already been
224       demonstrated:
225
226          use Inline C => Config =>
227            INC           => &PDL_INCLUDE,
228            TYPEMAPS      => &PDL_TYPEMAP,
229            AUTO_INCLUDE  => &PDL_AUTO_INCLUDE, # declarations
230            BOOT          => &PDL_BOOT;         # code for the XS boot section
231
232       The code returned by "PDL_AUTO_INCLUDE" makes sure that pdlcore.h is
233       included and declares the static variables to hold the pointer to the
234       "Core" struct. It looks something like this:
235
236          print PDL_AUTO_INCLUDE;
237
238        #include <pdlcore.h>
239        static Core* PDL; /* Structure holds core C functions */
240        static SV* CoreSV;       /* Gets pointer to perl var holding core structure */
241
242       The code returned by "PDL_BOOT" retrieves the $PDL::SHARE variable and
243       initializes the pointer to the "Core" struct. For those who know their
244       way around the Perl API here is the code:
245
246          print PDL_BOOT;
247
248          perl_require_pv ("PDL::Core"); /* make sure PDL::Core is loaded */
249          CoreSV = perl_get_sv("PDL::SHARE",FALSE);  /* SV* value */
250        #ifndef aTHX_
251        #define aTHX_
252        #endif
253          if (CoreSV==NULL)
254            Perl_croak(aTHX_ "We require the PDL::Core module, which was not found");
255          PDL = INT2PTR(Core*,SvIV( CoreSV ));  /* Core* value */
256          if (PDL->Version != PDL_CORE_VERSION)
257            Perl_croak(aTHX_ "The code needs to be recompiled against the newly installed PDL");
258
259       The "Core" struct contains version info to ensure that the structure
260       defined in pdlcore.h really corresponds to the one obtained at runtime.
261       The code above tests for this
262
263          if (PDL->Version != PDL_CORE_VERSION)
264            ....
265
266       For more information on the Core struct see PDL::Internals.
267
268       With these preparations your code can now access the core routines as
269       already shown in some of the examples above, e.g.
270
271         pdl *p = PDL->pdlnew();
272
273       By default the C variable named "PDL" is used to hold the pointer to
274       the "Core" struct. If that is (for whichever reason) a problem you can
275       explicitly specify a name for the variable with the "PDL_AUTO_INCLUDE"
276       and the "PDL_BOOT" routines:
277
278          use Inline C => Config =>
279            INC           => &PDL_INCLUDE,
280            TYPEMAPS      => &PDL_TYPEMAP,
281            AUTO_INCLUDE  => &PDL_AUTO_INCLUDE 'PDL_Corep',
282            BOOT          => &PDL_BOOT 'PDL_Corep';
283
284       Make sure you use the same identifier with "PDL_AUTO_INCLUDE" and
285       "PDL_BOOT" and use that same identifier in your own code.  E.g., conti‐
286       nuning from the example above:
287
288         pdl *p = PDL_Corep->pdlnew();
289
290       Some selected core routines explained
291
292       The full definition of the "Core" struct can be found in the file pdl‐
293       core.h. In the following the most frequently used member functions of
294       this struct are briefly explained.
295
296       ·    "pdl *SvPDLV(SV *sv)"
297
298       ·    "pdl *SetSV_PDL(SV *sv, pdl *it)"
299
300       ·    "pdl *pdlnew()"
301
302            "pdlnew" returns an empty pdl object that needs further initial‐
303            ization to turn it into a proper piddle. Example:
304
305              pdl *p = PDL->pdlnew();
306              PDL->setdims(p,dims,ndims);
307              p->datatype = PDL_B;
308
309       ·    "pdl *null()"
310
311       ·    "SV *copy(pdl* p, char* )"
312
313       ·    "void *smalloc(int nbytes)"
314
315       ·    "int howbig(int pdl_datatype)"
316
317       ·    "void add_deletedata_magic(pdl *p, void (*func)(pdl*, int), int
318            param)"
319
320       ·    "void allocdata(pdl *p)"
321
322       ·    "void make_physical(pdl *p)"
323
324       ·    "void make_physdims(pdl *p)"
325
326       ·    "void make_physvaffine(pdl *p)"
327
328       ·    "void qsort_X(PDL_Xtype *data, int a, int b)" and "void
329            qsort_ind_X(PDL_Xtype *data, int *ix, int a, int b)"
330
331            where X is one of B,S,U,L,F,D and Xtype is one of Byte, Short,
332            Ushort, Long, Float or Double.
333
334       ·    "float NaN_float" and "double NaN_double"
335
336            These are constants to produce the required NaN values.
337

SEE ALSO

339       PDL
340
341       Inline
342

BUGS

344       This manpage is still under development.  Feedback and corrections are
345       welcome.
346
348       Copyright (c) 2001, Christian Soeller. All Rights Reserved.  This mod‐
349       ule is free software. It may be used, redistributed and/or modified
350       under the same terms as PDL itself (see http://pdl.perl.org).
351
352
353
354perl v5.8.8                       2003-05-21                            API(1)
Impressum