* Messing with access types...
@ 2020-12-28 9:44 Marek
2020-12-28 10:14 ` Dmitry A. Kazakov
0 siblings, 1 reply; 6+ messages in thread
From: Marek @ 2020-12-28 9:44 UTC (permalink / raw)
Hello,
I have some code:
- util.ads:
with System;
package Util is
type Handle is record
Str : access String;
Data : System.Address;
end record;
type Handle_Access is access all Handle;
Null_Handle : constant Handle := (null, System.Null_Address);
type Handle_Array is array (Natural range <>) of aliased Handle;
generic
type T is private;
type T_Access is access all T;
function Get_Data (H : access Handle; Str : access String) return
T_Access;
generic
type T is private;
type T_Access is access all T;
function Get_Query
(H : access Handle; Str : access String; Data : in out T_Access;
Required : Boolean) return access String;
end Util;
- util.adb
pragma Ada_2012;
with Interfaces.C.Pointers;
with System.Address_To_Access_Conversions;
package body Util is
package Ptr is new Interfaces.C.Pointers
(Index => Natural,
Element => Handle,
Element_Array => Handle_Array,
Default_Terminator => Null_Handle);
use Ptr;
--------------
-- Get_Data --
--------------
function Get_Data (H : access Handle; Str : access String) return
T_Access
is
Pointer : Ptr.Pointer := Ptr.Pointer (H);
package ATA is new System.Address_To_Access_Conversions (T);
begin
if H /= null then
loop
declare
F : access Handle := Pointer;
begin
if Str.all = F.Str.all then
return T_Access (ATA.To_Pointer (F.Data));
end if;
end;
Ptr.Increment (Pointer);
exit when Pointer = null;
end loop;
end if;
return null;
end Get_Data;
---------------
-- Get_Query --
---------------
function Get_Query
(H : access Handle; Str : access String; Data : in out T_Access;
Required : Boolean) return access String
is
function Get is new Get_Data (T, T_Access);
begin
Data := Get (H, Str);
if Required and (Data /= null) then
return Str;
end if;
return null;
end Get_Query;
end Util;
- test.adb
pragma Ada_2012;
with Util;
procedure Test is
use Util;
type Some_Record is record
Foo : Integer;
end record;
type Some_Record_Access is access all Some_Record;
Test_Record : Some_Record_Access;
H : access Handle := null;
Str : access String := new String'("Test");
function Query is new Get_Query (Some_Record, Some_Record_Access);
Result : access String := Query (H, Str, Test_Record, False);
begin
null;
end Test;
When I try to compile test.adb I get some warnings:
Compile
[Ada] test.adb
test.adb:20:04: warning: in instantiation at util.adb:34
test.adb:20:04: warning: in instantiation at util.adb:56
test.adb:20:04: warning: accessibility check failure
test.adb:20:04: warning: "Program_Error" will be raised at run time
test.adb:20:04: warning: in instantiation at util.adb:34
test.adb:20:04: warning: in instantiation at util.adb:56
test.adb:20:04: warning: cannot convert local pointer to non-local
access type
test.adb:20:04: warning: Program_Error will be raised at run time
[Ada] util.adb
Bind
[gprbind] test.bexch
[Ada] test.ali
Link
[link] test.adb
[2020-12-28 10:30:50] process terminated successfully, elapsed time: 00.92s
I tried also to move every local (to Test procedure) variables to global
scope but result is the same.
What is going on? Can you explain where is the problem?
thanks in advance
Marek
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Messing with access types...
2020-12-28 9:44 Messing with access types Marek
@ 2020-12-28 10:14 ` Dmitry A. Kazakov
2020-12-28 11:43 ` Marek
0 siblings, 1 reply; 6+ messages in thread
From: Dmitry A. Kazakov @ 2020-12-28 10:14 UTC (permalink / raw)
On 2020-12-28 10:44, Marek wrote:
> I have some code:
[...]
> When I try to compile test.adb I get some warnings:
>
> Compile
> [Ada] test.adb
> test.adb:20:04: warning: in instantiation at util.adb:34
> test.adb:20:04: warning: in instantiation at util.adb:56
> test.adb:20:04: warning: accessibility check failure
> test.adb:20:04: warning: "Program_Error" will be raised at run time
> test.adb:20:04: warning: in instantiation at util.adb:34
> test.adb:20:04: warning: in instantiation at util.adb:56
> test.adb:20:04: warning: cannot convert local pointer to non-local
> access type
> test.adb:20:04: warning: Program_Error will be raised at run time
> [Ada] util.adb
> Bind
> [gprbind] test.bexch
> [Ada] test.ali
> Link
> [link] test.adb
> [2020-12-28 10:30:50] process terminated successfully, elapsed time: 00.92s
>
> I tried also to move every local (to Test procedure) variables to global
> scope but result is the same.
>
> What is going on? Can you explain where is the problem?
What are you trying to achieve? Because the code does not make much
sense to me.
P.S. If you are trying to do some C bindings flat arrays are easier
choice than Interfaces.C.Pointers. C has no arrays, but pointers. Ada's
arrays are never compatible with any pointers, except when flat.
Therefore using access to String would be wrong in most, if not all, cases.
--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Messing with access types...
2020-12-28 10:14 ` Dmitry A. Kazakov
@ 2020-12-28 11:43 ` Marek
2020-12-28 13:56 ` Dmitry A. Kazakov
0 siblings, 1 reply; 6+ messages in thread
From: Marek @ 2020-12-28 11:43 UTC (permalink / raw)
On 28.12.2020 11:14, Dmitry A. Kazakov wrote:
>
> What are you trying to achieve? Because the code does not make much
> sense to me.
>
> P.S. If you are trying to do some C bindings flat arrays are easier
> choice than Interfaces.C.Pointers. C has no arrays, but pointers. Ada's
> arrays are never compatible with any pointers, except when flat.
> Therefore using access to String would be wrong in most, if not all, cases.
>
Code is a fragment some plugin framework for host written in C. When
plugin is initialized it receives pointer to host features. Then I can
scan them to find concrete feature (Id) and retrieve data.
Problem is with instantiation generic function Get_Data, more precisely
in line:
return T_Access (ATA.To_Pointer (F.Data));
OK, some changes to code to clear view:
with System;
package Util is
type Feature is record
Id : Integer;
Data : System.Address;
end record;
type Feature_Access is access all Feature;
Null_Feature : constant Feature := (0, System.Null_Address);
type Feature_Array is array (Natural range <>) of aliased Feature;
generic
type T is private;
type T_Access is access all T;
function Get_Data (H : access Feature; Id : Integer) return T_Access;
generic
type T is private;
type T_Access is access all T;
function Get_Query
(H : access Feature; Id : Integer; Data : in out T_Access;
Required : Boolean) return Integer;
end Util;
------------------------
pragma Ada_2012;
with Interfaces.C.Pointers;
with System.Address_To_Access_Conversions;
package body Util is
package Ptr is new Interfaces.C.Pointers
(Index => Natural,
Element => Feature,
Element_Array => Feature_Array,
Default_Terminator => Null_Feature);
use Ptr;
--------------
-- Get_Data --
--------------
function Get_Data (H : access Feature; Id : Integer) return T_Access
is
Pointer : Ptr.Pointer := Ptr.Pointer (H);
package ATA is new System.Address_To_Access_Conversions (T);
begin
if H /= null then
loop
declare
F : access Feature := Pointer;
begin
if Id = F.Id then
return T_Access (ATA.To_Pointer (F.Data));
end if;
end;
Ptr.Increment (Pointer);
exit when Pointer = null;
end loop;
end if;
return null;
end Get_Data;
---------------
-- Get_Query --
---------------
function Get_Query
(H : access Feature; Id : Integer; Data : in out T_Access;
Required : Boolean) return Integer
is
function Get is new Get_Data (T, T_Access);
begin
Data := Get (H, Id);
if Required and (Data /= null) then
return Id;
end if;
return 0;
end Get_Query;
end Util;
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Messing with access types...
2020-12-28 11:43 ` Marek
@ 2020-12-28 13:56 ` Dmitry A. Kazakov
2020-12-28 18:56 ` Marek
0 siblings, 1 reply; 6+ messages in thread
From: Dmitry A. Kazakov @ 2020-12-28 13:56 UTC (permalink / raw)
On 2020-12-28 12:43, Marek wrote:
> On 28.12.2020 11:14, Dmitry A. Kazakov wrote:
>>
>> What are you trying to achieve? Because the code does not make much
>> sense to me.
>>
>> P.S. If you are trying to do some C bindings flat arrays are easier
>> choice than Interfaces.C.Pointers. C has no arrays, but pointers. Ada's
>> arrays are never compatible with any pointers, except when flat.
>> Therefore using access to String would be wrong in most, if not all, cases.
>
> Code is a fragment some plugin framework for host written in C. When
> plugin is initialized it receives pointer to host features. Then I can
> scan them to find concrete feature (Id) and retrieve data.
> Problem is with instantiation generic function Get_Data, more precisely
> in line:
>
> return T_Access (ATA.To_Pointer (F.Data));
You should never convert access types, because to do so, you must first
learn the accessibility rules. No man can do that while keeping sanity.
So, just do this:
return ATA.To_Pointer (F.Data).all'Unchecked_Access;
-- Mind your business, COMPILER!
> OK, some changes to code to clear view:
>
> with System;
>
> package Util is
>
> type Feature is record
> Id : Integer;
> Data : System.Address;
> end record;
type Feature is record
Id : Interfaces.C.int; -- If that is int
Data : System.Address; -- Could be a named access type [*]
end record;
pragma Convention (C, Feature);
> type Feature_Access is access all Feature;
>
> Null_Feature : constant Feature := (0, System.Null_Address);
> type Feature_Array is array (Natural range <>) of aliased Feature;
type Feature_Array is array (size_t) of aliased Feature; -- Flat
pragma Convention (C, Feature_Array);
type Feature_Array_Ptr is access all Feature_Array;
pragma Convention (C, Feature_Array_Ptr);
function Get_Me_Features return Feature_Array_Ptr;
pragma Import (C, Get_Me_features, "???");
That should be all necessary to do this:
List : Feature_Array renames Get_Me_Features.all;
begin
for I in size_t'Range loop
exit when List (I) = Null_Feature;
declare
Data : Whatever_C_Type;
for Data'Address use List (I).Data;
pragma Import (Ada, Data);
begin
...
end;
end loop;
-------------------------------------
* Here is a variant without using addresses
type Whatever_C_Type is record
...
end record;
pragma Convention (C, Whatever_C_Type);
type Whatever_C_Type_Ptr is access all Whatever_C_Type;
pragma Convention (C, Whatever_C_Type_Ptr);
type Feature is record
Id : Interfaces.C.int;
Data : Whatever_Ptr;
end record;
pragma Convention (C, Feature);
...
for I in size_t'Range loop
exit when List (I) = Null_Feature;
declare
Data : Whatever_C_Type renames List (I).Data.all;
begin
...
end;
end loop;
--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Messing with access types...
2020-12-28 13:56 ` Dmitry A. Kazakov
@ 2020-12-28 18:56 ` Marek
2020-12-28 19:53 ` Dmitry A. Kazakov
0 siblings, 1 reply; 6+ messages in thread
From: Marek @ 2020-12-28 18:56 UTC (permalink / raw)
Thanks a lot Dmitry for your time.
Now I got everything working. But... I see a lot of mess by trying to
play with pointers <-> access types. Then my plugin code looks like the
work of Frankenstein.
I think I'll try another approach: just write extra layer in C, which
will direct communicate with host and will provide prepared data for Ada
part.
regards
Marek
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Messing with access types...
2020-12-28 18:56 ` Marek
@ 2020-12-28 19:53 ` Dmitry A. Kazakov
0 siblings, 0 replies; 6+ messages in thread
From: Dmitry A. Kazakov @ 2020-12-28 19:53 UTC (permalink / raw)
On 2020-12-28 19:56, Marek wrote:
> I think I'll try another approach: just write extra layer in C, which
> will direct communicate with host and will provide prepared data for Ada
> part.
The standard approach is somewhat different:
1. Thin Ada bindings mapping to C, mostly 1-to-1 with minor adjustments,
e.g.
- replacing BOOL with Ada Boolean
- translating C strings into Ada Strings
- replacing C pointer parameters with Ada out or in out, as appropriate
- making proper functions where C cannot, e.g. returning string results
where C API uses a buffer to store string copy. The buffer is made
local, C function is called to fill it. Then the contents is converted
to Ada string and returned out.
2. On top of that you do thick Ada bindings:
- reasonable interfaces
- all implementation types made private
- return codes replaced with exceptions
- C's malloc/free pairs wrapped by Ada controlled types
- similarly resources seizing/releasing pairs go into controlled types
- messages/events loops encapsulated into Ada tasks
- these tasks are wrapped by a controlled type (AKA active object)
You do not need to change anything on the C side. You can incrementally
advance #2 as far as you feel necessary since you can always fall back
to #1.
--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2020-12-28 19:53 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-28 9:44 Messing with access types Marek
2020-12-28 10:14 ` Dmitry A. Kazakov
2020-12-28 11:43 ` Marek
2020-12-28 13:56 ` Dmitry A. Kazakov
2020-12-28 18:56 ` Marek
2020-12-28 19:53 ` Dmitry A. Kazakov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox