From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,FREEMAIL_FROM autolearn=unavailable autolearn_force=no version=3.4.4 Path: eternal-september.org!reader01.eternal-september.org!feeder.eternal-september.org!news.uzoreto.com!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail From: hreba Newsgroups: comp.lang.ada Subject: Re: How can one record component be local and another not? Date: Wed, 6 May 2020 21:31:11 +0200 Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit X-Trace: individual.net 45skF9rO8RHc/JImlsbo4A1JCOcwQQHIO5wu7o6p1SvhbwqzHz Cancel-Lock: sha1:I0AbpGTqeVGHpxtBl4YkZuEACdA= X-Mozilla-News-Host: news://News.Individual.DE User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.7.0 In-Reply-To: Content-Language: en-US Xref: reader01.eternal-september.org comp.lang.ada:58617 Date: 2020-05-06T21:31:11+02:00 List-Id: On 5/5/20 9:08 PM, Niklas Holsti wrote: > > I don't understand -- System.Address is not an access type; why do you > need to use an access type to produce this parameter? Do you need a > pointer to the "params" component? > > Perhaps you can show a bit more of the actual code that has the problem? > Ok, I'll try to make it comprehensible without throwing a lot of code at you. I am writing a thick binding to the GSL library odeiv2 for numerically integrating ODEs (ordinary differential equations). I already have the thin binding gsl_odeiv2_h.ads. For initialization, I have to call the following subprogram of the thin binding: function gsl_odeiv2_driver_alloc_y_new (sys : access constant gsl_odeiv2_system; T : access constant gsl_odeiv2_step_type; hstart : double; epsabs : double; epsrel : double) return access gsl_odeiv2_driver; pragma Import (C, gsl_odeiv2_driver_alloc_y_new, "gsl_odeiv2_driver_alloc_y_new"); Parameter sys defines the ODE; its type is type gsl_odeiv2_system is record c_function : access function (arg1 : double; arg2 : access double; arg3 : access double; arg4 : System.Address) return int; jacobian : access function (arg1 : double; arg2 : access double; arg3 : access double; arg4 : access double; arg5 : System.Address) return int; dimension : aliased size_t; params : System.Address; end record; pragma Convention (C_Pass_By_Copy, gsl_odeiv2_system); Later, during integration, c_function() and jacobian() will be called with parameters of type System.Address (arg4 and arg5 resp.). These parameters must be passed as params inside sys to gsl_odeiv2_driver_alloc_y_new(). Now to my own code (most of the thin binding was created automatically with g++ -c -fdump-ada-spec-slim). Dglsys_P corresponds to c_function in the thin binding, The package is essentially generic dim: Positive; type Float is digits<>; package odeiv2 is err_noInit, -- Init_Solve() has not been called err_Precision, -- precision of C.double used in GSL not sufficient err_Method, -- integration method not implemented err_SolveAgain: -- Solve_Again() call without former Solve() Exception; type Float_Array is array (1..dim) of Float; type Float_Matrix is array (1..dim, 1..dim) of Float; type Par_Array is array (Positive range <>) of Float; type Method is (RK8PD); type Solver is limited private; type Dglsys_P is not null access procedure (t: Float; -- independent variable y: Float_Array; -- dependent variables at t dydt: out Float_Array; -- 1. ordinary derivatives at t params: Par_Array -- any parameters ); -- omitted: type Jacobi_P is access procedure... procedure Init_Solve -- Init. a dglsys, must be called once before calling -- (once or repeatedly) Solve() or Solve_Again(). -- The resulting sol must be an access type because of the internal -- interface to the GSL library. (Dglsys: Dglsys_P; -- the system of diff. equ. Jacobi: Jacobi_P; -- the jacobi calc., if avail. pars: access constant Par_Array; -- the parameters met: Method; -- the solve method h_start: Float; -- initial step size epsabs: Float; -- absolute error tolerance epsrel: Float; -- relative error tolerance sol: aliased in out Solver ); private package C renames Interfaces.C; package Ode renames gsl_odeiv2_h; type C_Array is array (Integer range <>) of aliased C.double; pragma Convention (C, C_Array); type Parameters is record dglpars: access constant Par_Array; -- pars of dglsys Dglsys: Dglsys_P; -- dglsys calc. Jacobi: Jacobi_P; -- Jacobi calc. end record; pragma Convention (C, Parameters); type Parameters_Ptr is access all Parameters; package Parameters_Conv is new System.Address_To_Access_Conversions (Parameters); type Solver is limited record initialized: Boolean:= false; -- Init_Solve() has been called firstcall_done: Boolean; -- first call done store_y: Boolean; -- copy y to ya ya: C_Array (1..dim); -- values of last Solve call sys: aliased Ode.gsl_odeiv2_system; driver: access Ode.gsl_odeiv2_driver; all_pars: aliased Parameters; all_pp: Parameters_Conv.Object_Pointer; end record; end odeiv2; In the package body I have to define the c_function above (thin binding spec.), which will call the corresponding function of type Dglsys_P (thick binding), and it finds this in the parameters. then I define the initialization subprogram. package body odeiv2 is package C_Arrays is new Interfaces.C.Pointers (Integer, C.double, C_Array, 0.0); function func (t: C.double; y,f: access C.double; params: System.Address) return C.int; pragma Convention (C, func); function func (t: C.double; y,f: access C.double; params: System.Address) return C.int -- GSL version of Dglsys is use type System.Address; all_pars: Parameters_Conv.Object_Pointer; yf, dydt: Float_Array; y0: C_Arrays.Pointer:= C_Arrays.Pointer(y); f0: C_Arrays.Pointer:= C_Arrays.Pointer(f); begin all_pars:= Parameters_Conv.To_Pointer (params); for i in 1..dim loop yf(i):= Float(y0.all); C_Arrays.Increment (y0); end loop; all_pars.Dglsys (Float(t), yf, dydt, all_pars.dglpars.all); for i in 1..dim loop f0.all:= C.double(dydt(i)); C_Arrays.Increment (f0); end loop; return gsl_errno_h.GSL_SUCCESS; end func; procedure Init_Solve (Dglsys: Dglsys_P; -- the system of diff.equ. Jacobi: Jacobi_P; -- jacobi calc., if available pars: access constant Par_Array; -- the parameters met: Method; -- the solve method h_start: Float; -- initial step size epsabs: Float; -- absolute error tolerance epsrel: Float; -- relative error tolerance sol: aliased in out Solver ) is gsl_met: access constant Ode.gsl_odeiv2_step_type; begin -- set all_pars -- sol: flags for calling logic sol.Initialized:= true; sol.firstcall_done:= false; sol.store_y:= true; sol.all_pars.dglpars:= pars; sol.all_pars.Dglsys:= Dglsys; sol.all_pars.Jacobi:= Jacobi; -- transform integration method to GSL format case met is when RK8PD => gsl_met:= Ode.gsl_odeiv2_step_rk8pd; when others => raise err_Method with "forgot to implement integration method"; end case; -- build sys and driver sol.all_pp:= sol.all_pars'Unchecked_Access; sol.sys:= (func'Access, jac'Access, C.size_t(dim), Parameters_Conv.To_Address (sol.all_pp)); sol.driver:= Ode.gsl_odeiv2_driver_alloc_y_new (sol.sys'Access, gsl_met, C.double(h_start), C.double(epsabs), C.double(epsrel)); end Init_Solve; -- %< ------------- end odeiv2; The above version compiles. At first I didn't have the Solver component all_pp, but passed app_pars'Address to the call of gsl_odeiv2_driver_alloc_y_new at the end of Init_Solve. It too compiled. But whatever I try, I don't get rid of the runtime error raised CONSTRAINT_ERROR : odeiv2.ads:92:4 access check failed It accuses the line type Parameters is record -- Frank Hrebabetzky, Kronach +49 / 9261 / 950 0565