Returning Arrays

General FreeBASIC programming questions.
dodicat
Posts: 6690
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Returning Arrays

Postby dodicat » Feb 09, 2017 1:51

Using macros can make your code general.
Here is an example of a general arrayinsert/arraydelete for a udt via macros.
Please note, the whole udt is transferred, i.e. all the fields at once.
To show the results, as before, stipulate the fields.
(If you want to be generic, it is either macros or overloaded procedures, I would say!)

Code: Select all

type udt
    as single f
    as zstring * 30 st
end type


type array
    as any ptr p(any)
end type

#define value(U,datatype,UDT_Field) *cast(datatype ptr,u.p(n)) UDT_Field


#macro show(u,datatype,UDT_Field)
print #datatype; #UDT_field
    for n as long=lbound(u.p) to ubound(u.p)
        print value(u,datatype,UDT_Field);" ";
    next
    print
#endmacro


#macro transfer(u,a)
redim (u.p)(lbound(a) to ubound(a)) as typeof(a)
    for z as long=lbound(a) to ubound(a)
        u.p(z)=@a(z)
    next
#endmacro

#macro arrayinsert(a,index,insert)
If index>=Lbound(a) And index<=Ubound(a)+1 Then
    Var index2=index-Lbound(a)
    Redim Preserve a(Lbound(a) To  Ubound(a)+1)
    For x As Integer= Ubound(a) To Lbound(a)+index2+1 Step -1
        Swap a(x),a(x-1)
    Next x
    a(Lbound(a)+index2)=insert
End If
#endmacro

#macro arraydelete(a,index)
If index>=Lbound(a) And index<=Ubound(a) Then
    For x As Integer=index To Ubound(a)-1
        a(x)=a(x+1)
    Next x
    Redim Preserve a(Lbound(a) To Ubound(a)-1)
End If
#endmacro

dim as double d(...)={1.5,2.5,3.5}
dim as long L(...)={1,2,3,4,5,6,7,8,9,0}
dim as string s(...)={"Free","BASIC"}

redim as udt g(1 to 2)
g(1)=type(13.3,"ABC")
g(2)=type(14.4,"DEF")


dim as array x(1 to 4)

'fill up the array of pointers
transfer(x(1),d)
transfer(x(2),l)
transfer(x(3),s)
transfer(x(4),g)

'show the results
show(x(1),double,)
show(x(2),long,)
show(x(3),string,)
show(x(4),udt,.f)
show(x(4),udt,.st)
print

'use the insert/delete macros with the array of udt's (which was g into x(4))

arrayinsert(g,1,type(99.9,"HELLO"))
'transfer the new vaues and show them
transfer(x(4),g)
show(x(4),udt,.f)
show(x(4),udt,.st)

arraydelete(g,2)
'transfer the new vaues and show them
transfer(x(4),g)
show(x(4),udt,.f)
show(x(4),udt,.st)

sleep
grindstone
Posts: 752
Joined: May 05, 2015 5:35
Location: Germany

Re: Returning Arrays

Postby grindstone » Feb 09, 2017 12:39

Only as a suggestion: What about a Union of all desired types?

Code: Select all

Union universal
   i As Integer
   ui As UInteger
   l As Long
   ul As ULong
   s As Single
   d As Double
   c As ZString*20
   '...
End Union

Dim As universal value
value.i = 20
? value.i

value.d = 5.38
? value.d

value.c = "Hello"
? value.c

Sleep
Then the data type would be a component of the variable name, similar to the hungarian notation.
fxm
Posts: 9948
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Returning Arrays

Postby fxm » Feb 09, 2017 20:23

Around this topic:

Referring to my other topic How accessing to the array's descriptor structure?, we can get the address of the descriptor of any dynamic array, and then return this address from of a function in which the array has been created.

By the means of a Type containing a non-sized array, the initial array can be easily recovered from the function return (as a array field of an object pointed by the returned value), fully usable (with Redim [Preserve], L/Ubound, ...), and even duplicated into a pure array with few instructions only (2 lines).

Example (for 64-bit, compile with '-exx'):

Code: Select all

Function arrayDescriptorPtrFunction (Byval p As Any Ptr) As Any Ptr
  Return p
End function
#Define arrayDescriptorPtr(array) Cast(Function (() As Typeof((array))) As Any Ptr, @arrayDescriptorPtrFunction)(array())

Function test () As Any Ptr
  Static As Integer array(Any)
  Function = arrayDescriptorPtr(array)
  Redim array(-3 To +5)
  For I As Integer = Lbound(array) To Ubound(array)
    array(I) = I * 10
  Next I
End Function


Type UDT
  Dim As Integer _array(Any)
End Type

Dim As UDT Ptr pu1 = test()
For I As Integer = Lbound(pu1->_array) To Ubound(pu1->_array)
  Print pu1->_array(I)
Next I
Print


Dim As Integer array(Any)
Dim As UDT Ptr pu2 = arrayDescriptorPtr(array)
*pu2 = *pu1
For I As Integer = Lbound(array) To Ubound(array)
  Print array(I)
Next I

Sleep

Explaining notes:
- A Type containing a dynamic array contains a field which is in fact only the array descriptor (similarly to a var-len string field).
- When a dynamic array is declared, even still non-sized, its descriptor is created immediately.
- In the above example, none UDT object has been created but only UDT-typed pointers to the existing array descriptors.
Last edited by fxm on May 19, 2017 15:56, edited 3 times in total.
fxm
Posts: 9948
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Returning Arrays

Postby fxm » Feb 11, 2017 10:20

I had thought of making a syntax challenge around the same principle as above, in order to copy an array in another in a global way, but I found it a little too hard!
(for 64-bit, compile with '-exx')

Code: Select all

Function arrayDescriptorPtrFunction (Byval p As Any Ptr) As Any Ptr
  Return p
End function
#Define arrayDescriptorPtr(array) Cast(Function (() As Typeof((array))) As Any Ptr, @arrayDescriptorPtrFunction)(array())


Dim As Integer array1(Any)
Redim array1(-3 To +5)
For I As Integer = Lbound(array1) To Ubound(array1)
  array1(I) = I * 10
Next I
For I As Integer = Lbound(array1) To Ubound(array1)
  Print array1(I)
Next I
Print


Dim As Integer array2(Any)
Type UDT
  Dim As Integer array(Any)
End Type
Dim As UDT Ptr pu1 = arrayDescriptorPtr(array1)
Dim As UDT Ptr pu2 = arrayDescriptorPtr(array2)
*pu2 = *pu1
For I As Integer = Lbound(array2) To Ubound(array2)
  Print array2(I)
Next I


Sleep
Last edited by fxm on May 20, 2017 18:52, edited 4 times in total.
Tourist Trap
Posts: 2933
Joined: Jun 02, 2015 16:24

Re: Returning Arrays

Postby Tourist Trap » Feb 11, 2017 14:01

fxm wrote:I had thought of making a syntax challenge around the same principle as above, in order to copy an array in another in a global way, but I found it a little too hard!

It's between the too hard and the impossible.

By the way I'm not sure if it's me or something already corrected, or where I'm mistaken but after an array has been erased it seems to me quite weird that in some cases we still can evaluate array(0). I've posted there an example, in some other context, but the things are the same in general (no this is only in byref context, I was mistaken, but still weird):
viewtopic.php?p=229018#p229018
dodicat
Posts: 6690
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Returning Arrays

Postby dodicat » Feb 11, 2017 16:10

The use of the ANY keyword with arrays seems strange.
truths and falsehoods seem not to pan out, as in politics.

Code: Select all

dim as boolean a(1 to 300)=any
dim as long n
for z as long=1 to 300
    if a(z)=true then n+=1
    print a(z);",";
next
print
print
print "Number of true results =  ";n
print
for z as long=1 to 300
    print a(z);",";
next



sleep 
fxm
Posts: 9948
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Returning Arrays

Postby fxm » Feb 11, 2017 16:45

Code: Select all

    if a(z) then n+=1  '' or: if a(z)<>false then n+=1

The above behavior is not specific to array:

Code: Select all

Dim As Boolean b = Any
Print Cast(Byte, b)
Print
Print b
If b = True Then Print True Else Print False
If b Then Print True Else Print False
If b <> False Then Print True Else Print False

Sleep

Return to “General”

Who is online

Users browsing this forum: No registered users and 5 guests