/****************************************************************************
*
* $Id: pdl.c,v 1.6 2005/01/03 18:08:31 dburke Exp $
*
* pdl.c
* PDL support for Inline::SLang (at least the utility functions,
* since some PDL-specific code will appear in other files)
*
****************************************************************************/
/*
This software is Copyright (C) 2003, 2004, 2005 Smithsonian
Astrophysical Observatory. All rights are reserved.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA
Or, surf on over to
http://www.fsf.org/copyleft/gpl.html
*/
#include "util.h"
#include "pdl.h"
/* Should only ever be compiled if I_SL_HAVE_PDL is 1 so do not need to check */
/*
* access the PDL internals
* - this is essentially the output of
* use PDL::Core::Dev; print &PDL_AUTO_INCLUDE();
*/
Core* PDL; /* Structure holds core C functions */
SV* CoreSV; /* Gets pointer to perl var holding core structure */
/*
* initialize the pointers that will allow us to call PDL functions
* - this is called from the BOOT section of the XS code
* we do it this way so that the PDL-related variables can be
* localised to this file (which now seems a bit pointless
* as they're no longer static)
*/
void initialize_pdl_core( void ) {
/*
* a 'use PDL::LiteF;' in SLang.pm would be simpler...
* - using a flags setting of 0 (ie rather than PERL_LOADMOD_NOIMPORT)
* causes problems on OS-X and Linux [but not Solaris].
* I find the perl docs on this somewhat opaque; this was the
* first flag I guessed at using other than 0...
*/
load_module( PERL_LOADMOD_NOIMPORT, newSVpv("PDL::Lite",0), NULL );
/*
* this code fragment is essentially the output of:
* use PDL::Core::Dev; print &PDL_BOOT();
* minus the require_pv line and the aTHX_ defines
*/
CoreSV = perl_get_sv("PDL::SHARE",FALSE);
if( NULL == CoreSV )
Perl_croak(aTHX_ "The Inline::SLang module requires the PDL::Core module, which was not found");
PDL = INT2PTR(Core*,SvIV( CoreSV ));
if ( PDL_CORE_VERSION != PDL->Version )
Perl_croak(aTHX_ "The Inline::SLang module needs to be recompiled against the latest installed PDL");
} /* initialize_pdl_core() */
/* Used by sl2pl.c - convert a S-Lang array into a piddle */
/*
* see 'pdldoc API' for explanation of what's going on here
*
* SV *sl2pl_array_pdl( SLang_Array_Type * )
* convert the S-Lang array into a piddle
*
* void pl2sl_array_pdl( SV * )
* convert the piddle into a S-Lang array and
* push this array onto the S-Lang stack
*/
SV *
sl2pl_array_pdl( SLang_Array_Type *at ) {
PDL_Long dims[SLARRAY_MAX_DIMS];
pdl *out;
SV *sv;
size_t dsize;
int i;
/*
* copy over the dims
* (we reverse them since PDL and S-Lang use different
* array-access schemes)
*/
Printf( ("*** converting S-Lang array tp Piddle: ndims=%d [", at->num_dims) );
for ( i = 0; i < at->num_dims; i++ ) {
dims[at->num_dims-1-i] = at->dims[i];
Printf( (" %d", at->dims[i]) );
}
Printf( ("] dtype=%d", at->data_type) );
/* should we check for failure? */
out = PDL->pdlnew();
PDL->setdims( out, dims, at->num_dims );
#include "topdl.h"
/*
* copy the memory from the array since I don't know when S-Lang may delete it
* (would be quicker to just point to it but that leads to memory-managment issues)
*
* It is not entirely clear to me from the S-Lang docs whether I can safely
* access the data field of the array directly.
*/
PDL->allocdata( out );
(void) memcpy( out->data, at->data, (size_t) at->num_elements * dsize );
/* covert the piddle into a 'SV *' */
sv = sv_newmortal();
PDL->SetSV_PDL( sv, out );
SvREFCNT_inc( sv );
return sv;
} /* sl2pl_array_pdl() */
void
pl2sl_array_pdl( SV *item ) {
int dims[SLARRAY_MAX_DIMS];
SLang_Array_Type *at;
pdl *pdl;
SLtype otype;
size_t dsize;
int i;
/*
* we have a piddle. I appear to have to call PDL->make_physdims()
* on it (eg if it is a slice of another piddle), but is that
* all, or should I call PDL.make_physvaffine() instead?
*
* If we do have a piddle that is just a transformation of another
* one then I 'cheat' and make it physical; in that way we can use
* memcpy() to copy the data across rather than process the
* transformation ourselves. It would be nice if there were a function
* in the PDL API which would copy the contents of a "virtual" piddle
* into a contiguous block of memory. Maybe there is one?
*
*/
pdl = PDL->SvPDLV(item);
PDL->make_physdims(pdl);
/* PDL->make_physvaffine(pdl); - do not need this since call make_physical() below */
if ( pdl->ndims > SLARRAY_MAX_DIMS )
croak( "Error: max number of dimensions for a S-Lang array is %d",
SLARRAY_MAX_DIMS );
if ( pdl->ndims == 0 )
croak( "Error: S-Lang does not allow a 0d array - perhaps should promote to 1d or convert to a scalar?" );
/*
* as in sl2pl_array_pdl() we need to reverse the dimensions
*/
Printf( ("*** converting Piddle to S-Lang: ndims=%d [", pdl->ndims) );
for ( i = 0; i < pdl->ndims; i++ ) {
dims[pdl->ndims-1-i] = pdl->dims[i];
Printf( (" %d", dims[i]) );
}
Printf( ("] dtype=%d", pdl->datatype) );
#include "toslang.h"
Printf( (" -> %s\n", SLclass_get_datatype_name(otype)) );
at = SLang_create_array( otype, 0, NULL, dims, pdl->ndims );
if ( at == NULL )
croak( "Error: Unable to create a S-Lang array of %ld elements",
pdl->nvals );
/* copy over the data */
if ( pdl->trans ) {
/*
* hack to make things easier for us; ensure that pdl->data contains
* the actual data
*/
Printf( ("*** NOTE: calling PDL->make_physical") );
PDL->make_physical(pdl);
}
(void) memcpy( at->data, pdl->data, (size_t) pdl->nvals * dsize );
/* stick array on the stack */
(void) SLang_push_array (at, 1);
} /* pl2sl_array_pdl() */
/* pdl.c */