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
11       routines that can be accessed from other modules. These routines
12       basically define the PDL API. If you need to access piddles from C/XS
13       you probably 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       Sometimes you obtain a chunk of data from another source, for example
103       an image processing library, etc.  All you want to do in that case is
104       wrap your data into a piddle struct at the C level. Examples using this
105       approach can be found in the IO modules (where FastRaw and FlexRaw use
106       it for mmapped access) and the Gimp Perl module (that uses it to wrap
107       Gimp pixel regions into piddles).  The following script demonstrates a
108       simple example:
109
110          use PDL::LiteF;
111          use PDL::Core::Dev;
112          use PDL::Graphics::PGPLOT;
113
114          $b = mkpiddle();
115
116          print $b->info,"\n";
117
118          imag1 $b;
119
120          use Inline C => Config =>
121            INC           => &PDL_INCLUDE,
122            TYPEMAPS      => &PDL_TYPEMAP,
123            AUTO_INCLUDE  => &PDL_AUTO_INCLUDE,
124            BOOT          => &PDL_BOOT;
125
126          use Inline C;
127          Inline->init;
128
129          __DATA__
130
131          __C__
132
133          /* wrap a user supplied chunk of data into a piddle
134           * You must specify the dimensions (dims,ndims) and
135           * the datatype (constants for the datatypes are declared
136           * in pdl.h; e.g. PDL_B for byte type, etc)
137           *
138           * when the created piddle 'npdl' is destroyed on the
139           * Perl side the function passed as the 'delete_magic'
140           * parameter will be called with the pointer to the pdl structure
141           * and the 'delparam' argument.
142           * This gives you an opportunity to perform any clean up
143           * that is necessary. For example, you might have to
144           * explicitly call a function to free the resources
145           * associated with your data pointer.
146           * At the very least 'delete_magic' should zero the piddle's data pointer:
147           *
148           *     void delete_mydata(pdl* pdl, int param)
149           *     {
150           *       pdl->data = 0;
151           *     }
152           *     pdl *p = pdl_wrap(mydata, PDL_B, dims, ndims, delete_mydata,0);
153           *
154           * pdl_wrap returns the pointer to the pdl
155           * that was created.
156           */
157          typedef void (*DelMagic)(pdl *, int param);
158          static void default_magic(pdl *p, int pa) { p->data = 0; }
159          static pdl* pdl_wrap(void *data, int datatype, PDL_Long dims[],
160                               int ndims, DelMagic delete_magic, int delparam)
161          {
162            pdl* npdl = PDL->pdlnew(); /* get the empty container */
163
164            PDL->setdims(npdl,dims,ndims); /* set dims      */
165            npdl->datatype = datatype;     /* and data type */
166            npdl->data = data;             /* point it to your data */
167            /* make sure the core doesn't meddle with your data */
168            npdl->state |= PDL_DONTTOUCHDATA | PDL_ALLOCATED;
169            if (delete_magic != NULL)
170              PDL->add_deletedata_magic(npdl, delete_magic, delparam);
171            else
172              PDL->add_deletedata_magic(npdl, default_magic, 0);
173            return npdl;
174          }
175
176          #define SZ 256
177          /* a really silly function that makes a ramp image
178           * in reality this could be an opaque function
179           * in some library that you are using
180           */
181          static PDL_Byte* mkramp(void)
182          {
183            PDL_Byte *data;
184            int i;
185
186            if ((data = malloc(SZ*SZ*sizeof(PDL_Byte))) == NULL)
187              croak("mkramp: Couldn't allocate memory");
188            for (i=0;i<SZ*SZ;i++)
189              data[i] = i % SZ;
190
191            return data;
192          }
193
194          /* this function takes care of the required clean-up */
195          static void delete_myramp(pdl* p, int param)
196          {
197            if (p->data)
198              free(p->data);
199            p->data = 0;
200          }
201
202          pdl* mkpiddle()
203          {
204            PDL_Long dims[] = {SZ,SZ};
205            pdl *p;
206
207            p = pdl_wrap((void *) mkramp(), PDL_B, dims, 2,
208                         delete_myramp,0); /* the delparam is abitrarily set to 0 */
209            return p;
210          }
211

The gory details

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

SEE ALSO

336       PDL
337
338       Inline
339

BUGS

341       This manpage is still under development.  Feedback and corrections are
342       welcome.
343
345       Copyright (c) 2001, Christian Soeller. All Rights Reserved.  This
346       module is free software. It may be used, redistributed and/or modified
347       under the same terms as PDL itself (see http://pdl.perl.org).
348
349
350
351perl v5.12.3                      2009-10-17                            API(1)
Impressum