comp.lang.ada
 help / color / mirror / Atom feed
* Help with PLplot bindings: How to pass a record of function pointers to a procedure
@ 2016-04-13 10:01 Jerry
  2016-04-13 16:43 ` Jeffrey R. Carter
  0 siblings, 1 reply; 3+ messages in thread
From: Jerry @ 2016-04-13 10:01 UTC (permalink / raw)


Sorry for the long messy post.

I'm trying to update the Ada bindings for the PLplot plotter software (http://plplot.sourceforge.net/) and am stumped.

Background: The C version has added support for the 3D plotters for z = f(x, y) data where z can be stored in various ways--the usual pointer to an array of pointers, a struct with the same thing but adding the bounds as additional struct fields, or as a one-dimensional row-major or column-major arrays. One function call to the C 3D surface plotter works for all kinds of z storage.

The C code has these declarations (I have edited out additional fields for simplicity; PLFLT maps to Ada Long_Float and PLINT maps to Integer, PLPointer is a C pointer to the z data, here called p):

typedef struct
{
    PLFLT ( *get )( PLPointer p, PLINT ix, PLINT iy );
    PLFLT ( *set )( PLPointer p, PLINT ix, PLINT iy, PLFLT z );
} plf2ops_t;

typedef plf2ops_t * PLF2OPS;

I understand the struct to have fields that are pointers to get and set functions.

Then there is, for the case where z is stored as a pointer to an array of pointers (these declarations etc. are in multiple files),

static PLFLT
plf2ops_c_get( PLPointer p, PLINT ix, PLINT iy )
{
    return ( (PLFLT **) p )[ix][iy];
}

static PLFLT
plf2ops_c_set( PLPointer p, PLINT ix, PLINT iy, PLFLT z )
{
    return ( ( (PLFLT **) p )[ix][iy] = z );
}

(These "get" and "set" functions are later offered in forms suitable for the other forms of z storage, e.g., struct-with-bounds, row-major, and column-major.)

Then there is this, for the pointer-to-pointers form of data manipulation described above:

static plf2ops_t s_plf2ops_c = {
    plf2ops_c_get,
    plf2ops_c_set,
};

which I understand to be a variable of the struct declared with the fields filled in with the appropriate functions.

Then:

PLF2OPS
plf2ops_c()
{
    return &s_plf2ops_c;
}

This is then used in the 3D surface plotter call as such:

plfsurf3d(x, y, plf2ops_c(), (PLPointer) z, XPTS, YPTS);

where x and y are arrays (pointers again) where z is evaluated, mathematically, z = f(x, y), and XPTS and YPTS are the sizes of x (XPTS), y (YPTS), z (YPTS by XPTS).

I have tried to emulate this in Ada in part as follows, but I'm doing something seriously wrong.

type Function_To_Manipulate_Matrix_A_Type is
    access function (p : Real_Matrix; ix, iy : Integer)
        return Long_Float;
type Function_To_Manipulate_Matrix_B_Type is
    access function (p : in out Real_Matrix; ix, iy : Integer; z : Long_Float)
        return Long_Float;

(Don't worry about my use of Real_Matrix here--I have a function to convert it to a pointer to an array of pointers to make C happy.)

type PLf2ops_Type is
    record
        Get    : Function_To_Manipulate_Matrix_A_Type;
        Set    : Function_To_Manipulate_Matrix_B_Type;
    end record;

function plf2ops_c_get(p : Real_Matrix; ix, iy : Integer) return Long_Float;
pragma Import(C, plf2ops_c_get, "plf2ops_c_get");

function plf2ops_c_set(p : Real_Matrix; ix, iy : Integer; z : Long_Float) return Long_Float;
pragma Import(C, plf2ops_c_set, "plf2ops_c_set");

s_plf2ops_c : PLf2ops_Type :=
   (Get => plf2ops_c_get(p : Real_Matrix; ix, iy : Integer),
    Set => plf2ops_c_set(p : Real_Matrix; ix, iy : Integer; z : Long_Float));

but this doesn't compile, nor do some variations that I have tried. How do I get this done so that I can pass a record of function pointers to plfsurf3d that is compatible with how C does it (and actually compiles in Ada)? Remember that the functions plf2ops_c_get and plf2ops_c_set have differently-named and -implemented counterparts for other z-storage methods, e.g.

plf2ops_grid_row_major_get( PLPointer p, PLINT ix, PLINT iy )
{
    PLfGrid2 *g = (PLfGrid2 *) p;
    return ( (PLFLT *) g->f )[ix * g->ny + iy];
}

then e.g.

plfsurf3d(x, y, plf2ops_grid_row_major(), ( PLPointer ) & grid_row_major, XPTS, YPTS);

Jerry


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Help with PLplot bindings: How to pass a record of function pointers to a procedure
  2016-04-13 10:01 Help with PLplot bindings: How to pass a record of function pointers to a procedure Jerry
@ 2016-04-13 16:43 ` Jeffrey R. Carter
  2016-04-15  8:08   ` Jerry
  0 siblings, 1 reply; 3+ messages in thread
From: Jeffrey R. Carter @ 2016-04-13 16:43 UTC (permalink / raw)


On 04/13/2016 03:01 AM, Jerry wrote:
>
> type Function_To_Manipulate_Matrix_A_Type is
>      access function (p : Real_Matrix; ix, iy : Integer)
>          return Long_Float;
> type Function_To_Manipulate_Matrix_B_Type is
>      access function (p : in out Real_Matrix; ix, iy : Integer; z : Long_Float)
>          return Long_Float;
>
> type PLf2ops_Type is
>      record
>          Get    : Function_To_Manipulate_Matrix_A_Type;
>          Set    : Function_To_Manipulate_Matrix_B_Type;
>      end record;
>
> function plf2ops_c_get(p : Real_Matrix; ix, iy : Integer) return Long_Float;
> pragma Import(C, plf2ops_c_get, "plf2ops_c_get");
>
> function plf2ops_c_set(p : Real_Matrix; ix, iy : Integer; z : Long_Float) return Long_Float;
> pragma Import(C, plf2ops_c_set, "plf2ops_c_set");
>
> s_plf2ops_c : PLf2ops_Type :=
>     (Get => plf2ops_c_get(p : Real_Matrix; ix, iy : Integer),
>      Set => plf2ops_c_set(p : Real_Matrix; ix, iy : Integer; z : Long_Float));

Only addressing this part, type PLf2ops_Type has 2 components, both of which are 
of access types. A value (aggregate) of this type must therefore contain 2 
access values. I suspect you want

S_Plf2ops_C : Plf2ops_Type :=
    (Get => Plf2ops_C_Get'Access, Set => Plf2ops_C_Set'Access);

Depending on what you're doing with them, you might want the access types and 
the record type declared Convention C.

-- 
Jeff Carter
"Violence is the last refuge of the incompetent."
Foundation
151

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Help with PLplot bindings: How to pass a record of function pointers to a procedure
  2016-04-13 16:43 ` Jeffrey R. Carter
@ 2016-04-15  8:08   ` Jerry
  0 siblings, 0 replies; 3+ messages in thread
From: Jerry @ 2016-04-15  8:08 UTC (permalink / raw)


On Wednesday, April 13, 2016 at 9:43:58 AM UTC-7, Jeffrey R. Carter wrote:
<snip> 
> Only addressing this part, type PLf2ops_Type has 2 components, both of which are 
> of access types. A value (aggregate) of this type must therefore contain 2 
> access values. I suspect you want
> 
> S_Plf2ops_C : Plf2ops_Type :=
>     (Get => Plf2ops_C_Get'Access, Set => Plf2ops_C_Set'Access);
> 
> Depending on what you're doing with them, you might want the access types and 
> the record type declared Convention C.
> 
> -- 
> Jeff Carter
> "Violence is the last refuge of the incompetent."
> Foundation
> 151

Many thanks, Jeff. You are correct on both counts.

Jerry


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2016-04-15  8:08 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-04-13 10:01 Help with PLplot bindings: How to pass a record of function pointers to a procedure Jerry
2016-04-13 16:43 ` Jeffrey R. Carter
2016-04-15  8:08   ` Jerry

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox