Passing arrays of structures/records from Ada to C routines is one thing. In this case the memory management is done in Ada. But when interfacing with third party libraries there is often the problem that Memory management is done in the C part.
For example: For the C-structure:
typedef struct _MYREC
{
int n;
char *str;
} MYREC;
the following C-routine allocates Memory and returns a pointer to a MYREC-array with n elements:
MYREC * allocMyrec(int n);
Problem is that the returned Pointer does not contain size-information which is required for memory-safe computation in Ada.
in Ada I would like to use the corresponding Array-Definition for the (MYREC *) pointer:
type MYREC_Array is array (Int range <>) of aliased MYREC;
pragma Convention (C, MYREC_Array);
How would a corresponding (size-awawre) Ada-Function allocMyrec look like or what would be the right strategy?
B.t.w. for one element it is possible to map the C-pointer to access MYREC . That is what the Gnat-Binding generator does. But this is not helpful.
Hints highly appreciated.
I finally got it working using the package Interface.C.Pointers, it is quite easy, here is the code :
with Interfaces.C, Interfaces.C.Pointers ;
use Interfaces.C ;
with Ada.Text_IO ; -- To Check
procedure MYRECTest is
package IIO is new Ada.Text_IO.Integer_IO (Int) ;
type PChar is access all Char ;
type MYREC is record
N : Int ;
Str : PChar ;
end record ;
pragma Convention(C, MYREC);
DefaultMyrec : MYREC := (0, null) ;
type MYREC_Array is array (Int range <>) of aliased MYREC ;
pragma Convention(C, MYREC_Array); -- Not sure if useful...
-- Here is the trick
package PMYREC is new Interfaces.C.Pointers (Int, MYREC, MYREC_Array, DefaultMyrec) ;
function AllocMyrec (N : in Int) return PMYREC.Pointer ;
pragma Import (C, AllocMyrec, "allocMyrec");
P : PMYREC.Pointer := AllocMyrec(5) ;
StartP : PMYREC.Pointer := P ; -- Initial pointer
A : MYREC_Array(0..4) := PMYREC.Value(P, 5) ; -- Here is a copy
begin
for I in A'Range loop
-- Real access:
IIO.Put(P.all.N) ;
P.all.N := P.all.N + 3 ; -- Here you're really accessing the allocated memory, not just a copy
PMYREC.Increment(P) ;
-- 'Fake' access:
IIO.Put(A(I).N) ;
A(I).N := A(I).N + 3 ; -- Here you're accessing a copy, so the modification is not made on the allocated memory
end loop ;
Ada.Text_IO.New_Line ;
end MYRECTest ;
I tested the above code setting the n attribute of all _MYREC elements in the C function to 42 + i and printing it in the Ada body, it worked (I got 42, 43, 44, 45, 46). The C function looked like (for test) :
typedef struct _MYREC {
int n ;
char *str ;
} MYREC ;
MYREC * allocMyrec (int n) {
MYREC *res = malloc(n * sizeof(MYREC)) ;
int i ;
for (i = 0 ; i < n ; i++) {
res[i].n = 42 + i;
}
return res ;
}
The DefaultMyrec variable is useless but necessary for the package creation. I assumed you always use the Value function with the length parameter to retrieve value.
More information about the package : http://www.adaic.org/resources/add_content/standards/05rm/html/RM-B-3-2.html
EDIT: The original code was making a copy of the memory pointed by P so if you update anything in the array A it won't be change in the memory allocated. In fact you should directly use the pointer P like shown in the edited code.
EDIT: I used a 'stupid' access all Char for the str attribute of MYREC but you can (and should) use almost the same stuff from Interfaces.C.Pointers if necessary. I tested it but did not want to put it in the answer because it did not add anything to it.
Sorry, I don't think there's a general solution. If you declare a type that's an access to MYREC_Array, e.g.
type MYREC_Array is array (Int range <>) of aliased MYREC;
type MYREC_Array_Access is access all MYREC_Array;
I think the GNAT compiler will expect that this points to data containing the bounds immediately followed by the data. And you're not going to get the C allocMyrec to leave space for the bounds, unless you have access to the C code and can write a wrapper that does leave space for the bounds. But to do this, you'd have to know exactly how the GNAT compiler works, and the answer will be tied to that particular implementation. If there's some special declaration that would tell GNAT to keep the bounds separate, I'm not aware of it.
Some compilers might be able to handle this; e.g. Irvine Compiler's Ada compiler keeps the bound information as part of the MYREC_Array_Access type, not contiguous with the data. (There are advantages and disadvantages to this approach.) For a compiler like that, you could construct a pointer that has the bounds you want and points to the data returned by allocMyrec. But doing so requires using unchecked operations and is highly implementation-specific.
In some cases you could do something like this:
procedure Do_Some_Work (Size : Integer) is
subtype MYREC_Array_Subtype is MYREC_Array (1 .. Size);
type MYREC_Array_Access is access all MYREC_Array_Subtype;
function allocMyrec (Size : Interfaces.C.int) return MYREC_Array_Subtype;
pragma Import (C, allocMyrec);
begin
...
Now, since the bounds are built into the subtype, they don't need to be stored in memory anywhere; so this will work, and any time you refer to an element of the array returned by allocMyrec, the compiler will make sure the index is in the range 1..Size. But you won't be able to use this result outside Do_Some_Work. You won't be able to convert the access object to any other access type defined outside Do_Some_Work. So this is a rather limited solution.
EDIT: I was assuming you wanted an Ada access object that points to the array; if not, then Holt's answer is a good one. Sorry if I misunderstood what you were looking for.
This is another answer for what you asked in the preview answer's comments (was too long and too different from the previous answer to only make an edit).
So your C code looks like:
typedef struct { ... } MYREC ;
MYREC *last_allocated ;
// Allocate an array of N MYREC and return N.
// The allocated array is "stored" in last_allocated.
int alloc_myrec (void) { ... }
MYREC* get_last_allocated (void) {
return last_allocated ;
}
Then your Ada body:
procedure MYREC_Test is
type MYREC is record
...
end record ;
pragma Convention(C, MYREC) ;
-- Global and unconstrained array
type MYREC_Array is array (Int range <>) of aliased MYREC ;
pragma Convention(C, MYREC_Array);
begin
declare
-- Allocate and retrieve the array
Size : Int := AllocMyrec ;
subtype MYREC_Array_Subtype is MYREC_Array (1 .. Size);
type MYREC_Array_Access is access all MYREC_Array_Subtype;
function GetAlloc return MYREC_Array_Access;
pragma Import (C, GetAlloc, "get_last_alloc");
MyArray : MYREC_Array_Access := GetAlloc ;
begin
-- Do whatever you want with MyArray
end ;
end ;
As I said in the previous comment, it's a bit ugly to work that way. The Interfaces.C.Pointers package is mean to do what you want to do and will be easier to use if you put everything you need in a package.
type MYREC is record
n: Integer;
str: System.Address;
end record with Convention => C;
This record contains data in an "unpinned" format, i.e. you don't use it directly. Instead, whenever you need to work with data, you must pin them:
declare
Pinned_MYREC : String (1 .. MYREC_Value.n)
with Import, Address => MYREC_Value.str;
begin
-- work with Pinned_MYREC
end;
This task can be automated using closures (or generics).
procedure Query_MYREC
(MYREC_Value : MYREC;
Process : not null access procedure (Pinned_MYREC : String))
is
Pinned_MYREC : String (1 .. MYREC_Value.n)
with Import, Address => MYREC_Value.str;
begin
Process.all (Pinned_MYREC);
end Query_MYREC;
And, often enough (when pragma Pack is not applied to access type), you can construct fat pointer type in a system-dependent way. Not a rocket science.
In my experience I had problems with fat pointer being not fat enough. In GNAT its second pointer points to bounds, and so they have to be allocated somewhere. So these custom crafted fat pointers can only reside within some container that provides a storage for bounds. And maybe patches fat pointer's second half to new bounds location when Adjust on new location happens.
In this project I provide type-safe string views and editors for direct Unbounded_String access; works on GNAT for Linux x86-64. In my project container is limited, so no Adjust needed. In my project fat pointers are access discriminants, so they can't leak.
Related
I have an array and I wish to assign the value of part of the array to a string, however, I get an error:
Left side cannot be assigned to
when I do this:
(s):=(Array[1]);
Does anyone know how I can resolve this problem ?
This is a feature (or bug?) of all 32/64-bit Delphi versions I tested. Even a minimal complete program like
program test;
var
s: string;
begin
(s) := 'a';
writeln(s);
end.
will not compile without this error. No problems with Turbo/Borland, Virtual, or Free Pascal (even in Delphi mode). I assume that the Delphis treat (s) as an expression, which can have a value but you cannot assign a value to it.
Of course if you write s := 'a'; Delphi works as expected.
BTW: I consider it a bad habit, that you put superfluous () around variables and expressions.
Sorry for bumping an old thread here, but I believe that you should first declare your array.
If the variable Array is considered a string then the output of Array[1] would be the first character of that string.
Try this code ....
Var
myVar : Integer;
myArray : Array[1..5] of Integer;
Begin
myArray[2] := 25;
myVar := myArray[2];
End.
Reference: http://pascal-programming.info/lesson10.php
I need an array, that is optimized for one-time-initialization at runtime, with a given length. So memory should be allocated at runtime, but I don't need to change its length.
Is there a array-type other than the pure dynamic array? (it seems to be not the optimal choice for this task)
Bonus would be, if the initialized array is indexable via pointer-iteration, so all it's elements are allocated consecutive in memory.
Is this all just a daydream of a non-experienced programmer, or is there a possibility to achieve this?
I could imagine to do this with manual memory allocation, but maybe there's another way.
Edit:
My main concern is the reading and writing speed of the array.
Just use an external Count: integer variable, and use the dynamic array length as the "capacity" of the array. It would avoid most memory allocation, if the initial capacity of the array is well defined.
In practice, TList<T>, as defined in the System.Generics.Collections unit, is using this scheme: it stores internally an array, but it has its own Count property. I suspect this is what you were looking for.
For a more low-level stuff, with more features (like JSON or binary serialization, or fast lookup via a hash of one or several properties), you may take a look at our TDynArray dynamic array wrapper. Those are just wrappers on existing dynamic arrays, not data holder like TList<T>. And they work from Delphi 5 or older, and also FPC.
You can encapsulate what you desire in a generic type. Like this:
type
TFixedLengthArray<T> = record
strict private
FItems: TArray<T>;
FLength: Integer;
function GetItem(Index: Integer): T; inline;
procedure SetItem(Index: Integer; const Value: T); inline;
public
property Length: Integer read FLength;
property Items[Index: Integer]: T read GetItem write SetItem; default;
class function New(const Values: array of T): TFixedLengthArray<T>; static;
end;
{ TFixedLengthArray<T> }
class function TFixedLengthArray<T>.New(const Values: array of T): TFixedLengthArray<T>;
var
i: Integer;
begin
Result.FLength := System.Length(Values);
SetLength(Result.FItems, Result.FLength);
for i := 0 to Result.FLength-1 do begin
Result.FItems[i] := Values[i];
end;
end;
function TFixedLengthArray<T>.GetItem(Index: Integer): T;
begin
Result := FItems[Index];
end;
procedure TFixedLengthArray<T>.SetItem(Index: Integer; const Value: T);
begin
FItems[Index] := Value;
end;
Create a new one like this:
var
MyArray: TFixedLengthArray<Integer>;
....
MyArray: TFixedLengthArray<Integer>.New([1, 42, 666]);
Access items like this:
for i := 0 to MyArray.Length-1 do
Writeln(MyArray[i]);
This just wraps a dynamic array. Elements are contiguous. The length of the array is determined once and for all then a new instance is created.
One thing to watch out for here is that the type will behave like a reference type since its data is stored in a reference type. That is, the assignment operator on this type will behave in the same manner as dynamic array assignment.
So if we have two variables of this type, arr1 and arr2 then the following occurs:
arr1 := arr2;
arr1[0] := 42;
Assert(arr2[0] = 42);
If you wanted to make the type behave like a true value then you would implement copy-on-write inside SetItem.
Update
Your edit to the question changes is significantly. It seems that you are in fact concerned more with performance than encapsulation.
The inlining of the item accessor methods in the above type means that the performance characteristics should be close to that of an array. The access will still be O(1), but it is quite plausible that the inliner/optimiser is weak and fails to emit the most optimal code.
Before you decide that you must use arrays to obtain the absolute ultimate performance, do some real world benchmarking. It seems to me to be quite unlikely that the code to read/write from an array is really a bottleneck. Most likely the bottleneck will be what you then do with the values in the array.
I read somewhere that Ada allows a function only to return a single item. Since an array can hold multiple items does this mean that I can return the array as a whole or must I return only a single index of the array?
Yes, an Ada function can return an array - or a record.
There can be a knack to using it, though. For example, if you are assigning the return value to a variable, the variable must be exactly the right size to hold the array, and there are two common ways of achieving that.
1) Fixed size array - cleanest way is to define an array type, e.g.
type Vector is new Array(1..3) of Integer;
function Unit_Vector return Vector;
A : Vector;
begin
A := Unit_Vector;
...
2) Unconstrained array variables.
These are arrays whose size is determined at runtime by the initial assignment to them. Subsequent assignments to them will fail unless the new value happens to have the same size as the old. The trick is to use a declare block - a new scope - so that each assignment to the unconstrained variable is its first assignment. For example:
for i in 1 .. last_file loop
declare
text : String := Read_File(Filename(i));
-- the size of "text" is determined by the file contents
begin
-- process the text here.
for j in text'range loop
if text(j) = '*' then
...
end loop;
end
end loop;
One warning : if the array size is tens of megabytes or more, it may not be successfully allocated on the stack. So if this construct raises Storage_Error exceptions, and you can't raise the stack size, you may need to use access types, heap allocation via "new" and deallocation as required.
Yes, an Ada function can return an array. For example, an Ada String is "A one-dimensional array type whose component type is a character type." Several of the functions defined in Ada.Strings.Fixed—including Insert, Delete, Head, Tail and Trim—return a String.
The bit-stream casting in SystemVerilog for arrays and structs does not seem very safe.
For example, the following casting issue will only be caught at runtime (which could be hours into the simulation):
bit [31:0] bit_queue[$];
logic [31:0] logic_array[5];
for (int i = 0; i < 10; i++) begin
bit_queue[i] = $urandom;
end
if (catch_issue) begin
typedef logic [31:0] logic_array_t [5];
logic_array = logic_array_t'(bit_queue); // <-- ISSUE
end
Is there a proper "safe" procedure for doing bit-stream casting? Where any issues could be caught at compile time or safely handled at runtime? Or is the language broken in this case?
Example code above on EDA Playground: http://www.edaplayground.com/x/2tp
Similar to $cast, it is up to the user to check for compatibility at runtime with
if ( $bits(bit_queue) == $bits(logic_array) )
logic_array = logic_array_t'(bit_queue);
else
$error("sizes do not match");
For casts involving dynamically sized variables, you can get a compile time error if no possible array size would produce a valid assignment, but if there is a possible size, you cannot perform that check until the cast occurs, because the size can change up until the time the cast occurs.
Because you are using a queue (implying variable size) on the RHS, I don't think the compiler can statically check this (since it is not evaluating the for loop). Note that if you change your typedef to a fixed-size unpacked array > 5 entries, then you get a compile-time error.
If I allocate a C array like this:
int array[ 5 ];
Then, set only one object:
array[ 0 ] = 7;
How can I check whether all the other keys ( array[1], array[2], …) are storing a value? (In this case, of course, they aren't.)
Is there a function like PHP's isset()?
if ( isset(array[ 1 ]) ) ...
There isn't things like this in C. A static array's content is always "set". You could, however, fill in some special value to pretend it is uninitialized, e.g.
// make sure this value isn't really used.
#define UNINITIALIZED 0xcdcdcdcd
int array[5] = {UNINITIALIZED, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED};
array[0] = 7;
if (array[1] != UNINITIALIZED) {
...
You can't
There values are all undefined (thus random).
You could explicitly zero out all values to start with so you at least have a good starting point. But using magic numbers to detect if an object has been initialized is considered bad practice (but initializing variables is considered good practice).
int array[ 5 ] = {};
But if you want to explicitly check if they have been explicitly set (without using magic numbers) since creation you need to store that information in another structure.
int array[ 5 ] = {}; // Init all to 0
int isSet[ 5 ] = {}; // Init all to 0 (false)
int getVal(int index) {return array[index];}
int isSet(int index) {return isSet[index];}
void setVal(int index,int val) {array[index] = val; isSet[index] = 1; }
In C, all the elements will have values (garbage) at the time of allocation. So you cannot really have a function like what you are asking for.
However, you can by default fill it up with some standard values like 0 or INT_MIN using memset() and then write an isset() code.
I don't know php, but one of two things is going on here
the php array is actually a hash-map (awk does that)
the php array is being filled with nullable types
in either case there is a meaningful concept of "not set" for the values of the array. On the other hand a c array of built in type has some value in every cell at all times. If the array is uninitialized and is automatic or was allocated on the heap those values may be random, but they exist.
To get the php behavior:
Implement (or find a library wit) and use a hashmap instead on an array.
Make it an array of structures which include an isNull field.
Initialize the array to some sentinal value in all cells.
One solution perhaps is to use a separate array of flags. When you assign one of the elements, set the flag in the boolean array.
You can also use pointers. You can use null pointers to represent data which has not been assigned yet. I made an example below:
int * p_array[3] = {NULL,NULL,NULL};
p_array[0] = malloc(sizeof(int));
*p_array[0] = (int)0;
p_array[2] = malloc(sizeof(int));
*p_array[2] = (int)4;
for (int x = 0; x < 3; x++) {
if (p_array[x] != NULL) {
printf("Element at %i is assigned and the value is %i\n",x,*p_array[x]);
}else{
printf("Element at %i is not assigned.\n",x);
}
}
You could make a function which allocates the memory and sets the data and another function which works like the isset function in PHP by testing for NULL for you.
I hope that helps you.
Edit: Make sure the memory is deallocated once you have finished. Another function could be used to deallocate certain elements or the entire array.
I've used NULL pointers before to signify data has not been created yet or needs to be recreated.
An approach I like is to make 2 arrays, one a bit-array flagging which indices of the array are set, and the other containing the actual values. Even in cases where you don't need to know whether an item in the array is "set" or not, it can be a useful optimization. Zeroing a 1-bit-per-element bit array is a lot faster than initializing an 8-byte-per-element array of size_t, especially if the array will remain sparse (mostly unfilled) for its entire lifetime.
One practical example where I used this trick is in a substring search function, using a Boyer-Moore-style bad-character skip table. The table requires 256 entries of type size_t, but only the ones corresponding to characters which actually appear in the needle string need to be filled. A 1kb (or 2kb on 64-bit) memset would dominate cpu usage in the case of very short searches, leading other implementations to throw around heuristics for whether or not to use the table. But instead, I let the skip table go uninitialized, and used a 256-bit bit array (only 32 bytes to feed to memset) to flag which entries are in use.