Juergen Kuehlwein wrote:1.) as is - add it as include file (definitions and run time code in array.bi). The features are available only, if array.bi is included. This makes everything acessible to the user.
I prefer option #1, as the features you are seeking seem appropriate to place in a new library separate from the compiler and its run time library.
Juergen Kuehlwein wrote:Some more thoughts about this topic:
Exposing the array descriptor to the user would mean, that future changes of this descriptor might break user code relying on it. Fxm´s definition is correct, as far as i can tell, but it´s an undocumented and unofficial feature and thus subject to change. There are still some problems with arrays in FB in general, e.g. you can REDIM a fixed size array passed as a procedure parameter, this shouldn´t be possible and raise a compiler error, but currently the array descriptor doesn´t tell us, if an array is of fixed size or dynamic.
Therefore i think, it would be a wiser decision not to expose the descriptor itself, but to supply a method of retrieving it´s content (as far as not available yet). This way possible future changes of the descriptor will not necessarily break user code based on these new methods.
JK
I have taken a peek at source code for the array descriptor in the rtlib:
https://github.com/freebasic/fbc/blob/master/src/rtlib/fb_array.hIt would seem the critical members are the pointer to the data and the element size member.
fxm wrote:When a n-dimension array is defined, the address of the data section is get by:
@array(Lbound(array, 1), Lbound(array, 2), ..., Lbound(array, n))
For an erased dynamic array:
@array(Lbound(array, 1), Lbound(array, 2), ..., Lbound(array, n))
is still valid, corresponding to:
@array(0, 0, ..., 0)
but it returns 0.
(all other index values inducing a runtime error).
The data pointer 'ptr' can be obtained with the code provided by fxm, and the element size can be obtained by using the SizeOf() operator on the same element. The rest of the descriptor values can then be computed using these values and additional information obtainable from UBound() and LBound(). There are two difficulties with this. One is that the syntax for accessing the first element depends on the number of dimensions. The other is that there is no way for a function to accept an array as a parameter without knowing its whole data type. We can however use a macro such as the following:
Code: Select all
Type FBARRAY_DIM
elements As UInteger
_lbound As Integer
_ubound As Integer
End Type
Type FBARRAY_DESC
_data As Any Ptr
_ptr As Any Ptr
size As UInteger
element_len As UInteger
dimensions As UInteger
dimTB(7) As FBARRAY_DIM
End Type
#Macro GenArrayDesc(DESC, ARRAY)
#If UBound(ARRAY, 0) = 1
#Define FIRST_ELEMENT LBound(ARRAY)
#ElseIf UBound(ARRAY, 0) = 2
#Define FIRST_ELEMENT LBound(ARRAY, 1), LBound(ARRAY, 2)
#ElseIf UBound(ARRAY, 0) = 3
#Define FIRST_ELEMENT LBound(ARRAY, 1), LBound(ARRAY, 2), LBound(ARRAY, 3)
#ElseIf UBound(ARRAY, 0) = 4
#Define FIRST_ELEMENT LBound(ARRAY, 1), LBound(ARRAY, 2), LBound(ARRAY, 3), LBound(ARRAY, 4)
#ElseIf UBound(ARRAY, 0) = 5
#Define FIRST_ELEMENT LBound(ARRAY, 1), LBound(ARRAY, 2), LBound(ARRAY, 3), LBound(ARRAY, 4), LBound(ARRAY, 5)
#ElseIf UBound(ARRAY, 0) = 6
#Define FIRST_ELEMENT LBound(ARRAY, 1), LBound(ARRAY, 2), LBound(ARRAY, 3), LBound(ARRAY, 4), LBound(ARRAY, 5), LBound(ARRAY, 6)
#ElseIf UBound(ARRAY, 0) = 7
#Define FIRST_ELEMENT LBound(ARRAY, 1), LBound(ARRAY, 2), LBound(ARRAY, 3), LBound(ARRAY, 4), LBound(ARRAY, 5), LBound(ARRAY, 6), LBound(ARRAY, 7)
#ElseIf UBound(ARRAY, 0) = 8
#Define FIRST_ELEMENT LBound(ARRAY, 1), LBound(ARRAY, 2), LBound(ARRAY, 3), LBound(ARRAY, 4), LBound(ARRAY, 5), LBound(ARRAY, 6), LBound(ARRAY, 7), LBound(ARRAY, 8)
#EndIf
(DESC)._ptr = @(ARRAY(FIRST_ELEMENT))
(DESC).element_len = SizeOf(ARRAY(FIRST_ELEMENT))
(DESC).dimensions = UBound(ARRAY, 0)
Scope
Var TotalElements = 1, Diff = 0
For I As Integer = 0 To (DESC).dimensions - 1
(DESC).dimTB(I)._lbound = LBound(ARRAY, I + 1)
(DESC).dimTB(I)._ubound = UBound(ARRAY, I + 1)
(DESC).dimTB(I).elements = (DESC).dimTB(I)._ubound - (DESC).dimTB(I)._lbound + 1
TotalElements *= (DESC).dimTB(I).elements
Diff = Diff * (DESC).dimTB(I).elements + (DESC).dimTB(I)._lbound
Next I
(DESC)._data = CPtr(UByte Ptr, (DESC)._ptr) - Diff * (DESC).element_len
(DESC).size = TotalElements * (DESC).element_len
End Scope
#UnDef FIRST_ELEMENT
#EndMacro
Type MyUDT
Key As Double
Value As String
End Type
Dim MyArray(-5 To 5, 7) As MyUDT
Dim ArDesc As FBARRAY_DESC
GenArrayDesc(ArDesc, MyArray)
Print "data", ArDesc._data
Print "ptr", ArDesc._ptr
Print "size", ArDesc.size
Print "element_len", ArDesc.element_len
Print "dimensions", ArDesc.dimensions
For I As Integer = 0 To ArDesc.dimensions - 1
Print "dimTB(" & I & ")", ArDesc.dimTB(I).elements, ArDesc.dimTB(I)._lbound, ArDesc.dimTB(I)._ubound
Next I
Sleep
Of course most of this information is extraneous for your purposes. For a sorting routine, I would focus on 1 dimensional arrays to keep it simple.
And to implement an array sort you need 2 critical operations: an element comparison and an element position swapping routine. You can obtain the comparison from the user via a function pointer, and you can call the internal rtlib function "fb_MemSwap" to swap array elements of arbitrary size.
Code: Select all
Type ArrayRange
FirstElement As Any Ptr
Length As Integer
ElementSize As Integer
End Type
#Define WholeArray(ARRAY) Type<ArrayRange>(@ARRAY(LBound(ARRAY)), UBound(ARRAY) - LBound(ARRAY) + 1, SizeOf(ARRAY(LBound(ARRAY))))
Sub ArraySort(Range As ArrayRange, LessComp As Function(L As Any Ptr, R As Any Ptr) As Integer)
'...
'If LessComp(Range.FirstElement, Range.FirstElement) Then fb_MemSwap Range.FirstElement, Range.FirstElement, Range.ElementSize
'...
End Sub
Type MyUDT
Key As Double
Value As String
End Type
Function MyUDT_LessComp(L As Any Ptr, R As Any Ptr) As Integer
Return CPtr(MyUDT Ptr, L)->Key < CPtr(MyUDT Ptr, R)->Key
End Function
Dim MyArray(31) As MyUDT
ArraySort WholeArray(MyArray), @MyUDT_LessComp
This example is based on variable sized data referenced using the 'Any Ptr' type rather than macros, so it will not generate any significant bloat if it is reused on many different kinds of array.