Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
UDT problems
#21
I need to know because I am using the following method to read/write a fixed length UDT array string to a random record in a file:

Code: (Select All)
' define an array as string.
Type Datatype
  Array As String * 16
End Type
Dim DataRecord As Datatype
Dim Array(8) As Integer
Open "datatest.dat" For Random As #1 Len = Len(DataRecord)
' store array.
For L = 1 To 8
  Array(L) = L
Next
' put array into UDT string.
For L = 1 To 8
  Mid$(DataRecord.Array, (L - 1) * 2 + 1, 2) = MKI$(Array(L))
Next
' put 10 records into file.
For X = 1 To 10
  Put 1, X, DataRecord
Next
' get random record from file.
X = Int(Rnd * 10 + 1)
Get 1, X, DataRecord
' get array from UDT string.
For L = 1 To 8
  M = CVI(Mid$(DataRecord.Array, (L - 1) * 2 + 1, 2))
  Print M;
Next
End
Reply
#22
(11-13-2023, 12:38 AM)eoredson Wrote: I need to know because I am using the following method to read/write a fixed length UDT array string to a random record in a file:

Code: (Select All)
' define an array as string.
Type Datatype
  Array As String * 16
End Type
Dim DataRecord As Datatype
Dim Array(8) As Integer
Open "datatest.dat" For Random As #1 Len = Len(DataRecord)
' store array.
For L = 1 To 8
  Array(L) = L
Next
' put array into UDT string.
For L = 1 To 8
  Mid$(DataRecord.Array, (L - 1) * 2 + 1, 2) = MKI$(Array(L))
Next
' put 10 records into file.
For X = 1 To 10
  Put 1, X, DataRecord
Next
' get random record from file.
X = Int(Rnd * 10 + 1)
Get 1, X, DataRecord
' get array from UDT string.
For L = 1 To 8
  M = CVI(Mid$(DataRecord.Array, (L - 1) * 2 + 1, 2))
  Print M;
Next
End

Why go through such a complicated setup?   Why not just use an array directly?

Code: (Select All)
DIM DataRecord(1 TO 8) AS INTEGER

OPEN "datatest.dat" FOR RANDOM AS #1 LEN = 16
FOR j = 1 TO 10
    FOR l = 1 TO 8
        count = count + 1
        DataRecord(l) = count 'set the data
    NEXT
    PUT 1, j, DataRecord() '10 records from 1 to 80
NEXT

FOR l = 1 TO 8
    DataRecord(l) = 0 'clear the old data
NEXT

x = INT(RND * 10 + 1)
PRINT "Fetching record #"; x
PRINT "Which starts at"; (x - 1) * 8 + 1;
PRINT "and ends at"; x * 8
GET 1, x, DataRecord() 'get the random record

FOR i = 1 TO 8
    PRINT DataRecord(i) 'print the array
NEXT
Reply
#23
Quote:btw: is
Code: (Select All)
Code: (Select All)
array AS _MEM
 
variable length?
Yes and No. You set the length when you set 'cMAXELEMENTS'. If you want to change the length of the '_MEM' you have to create a new one with the length desired and copy the contents from the old one to the new one, and not forget '_MEMFREE ' the old memory location.

I updated this code a bit and it allows for resizing the array. BEWARE there is no error checking, so if you try to 'set' or 'get' a value outside of whats allocated then it will pop an error.

Code: (Select All)
' Program to create an array of Doubles in a UDT
DIM AS LONG i
DIM AS DOUBLE v
CONST cMAXELEMENTS = 10

TYPE tARRAY
  array AS _MEM
END TYPE

DIM AS tARRAY object

SCREEN 12: _FONT 8

' initialize the array
createObject object, cMAXELEMENTS

' set the array to random values
PRINT "Create initial Values"
FOR i = 0 TO cMAXELEMENTS
  v = INT(RND * 5)
  setElement object, i, v
  PRINT "index:"; i; "->"; v
NEXT

' retrieve values from array
PRINT "Retrieve Values"
FOR i = 0 TO cMAXELEMENTS
  PRINT "index:"; i; "->"; getElement(object, i)
NEXT

'resize array
resizeObject object, cMAXELEMENTS * 2

' retrieve values from array
PRINT "Double the size of the array"
FOR i = 0 TO cMAXELEMENTS * 2
  PRINT "index:"; i; "->"; getElement(object, i)
NEXT

'resize array
resizeObject object, cMAXELEMENTS / 2

' retrieve values from array
PRINT "Half the size of the array"
FOR i = 0 TO cMAXELEMENTS / 2
  PRINT "index:"; i; "->"; getElement(object, i)
NEXT


SUB createObject (o AS tARRAY, size AS LONG)
  ' make array one larger than number of elements
  o.array = _MEMNEW((size + 1) * 8) ' 8 is the number of bytes in a double
END SUB

SUB resizeObject (o AS tARRAY, size AS LONG)
  DIM AS _MEM old
  DIM AS _OFFSET l
  DIM AS LONG iter
  ' Copy old _MEM to a temp _MEM
  old = o.array
  ' Create new array of the new size
  createObject o, size
  ' Copy data from old array to new array
  iter = 0: DO WHILE iter < o.array.SIZE AND iter < old.SIZE
    _MEMPUT o.array, o.array.OFFSET + iter, _MEMGET(old, old.OFFSET + iter, _BYTE) AS _BYTE
  iter = iter + 1: LOOP
  ' free old array
  _MEMFREE old
END SUB

FUNCTION getElement# (o AS tARRAY, element AS LONG)
  getElement = _MEMGET(o.array, o.array.OFFSET + (element * 8), DOUBLE)
END FUNCTION

SUB setElement (o AS tARRAY, element AS LONG, v AS DOUBLE)
  _MEMPUT o.array, o.array.OFFSET + (element * 8), v AS DOUBLE
END SUB
Reply
#24
Quote:Why go through such a complicated setup?   Why not just use an array directly?
Because I might have more stuff in the UDT in addition to a single array:

Code: (Select All)
' define an array as string.
Type Datatype
  Array As String * 16
  Var As Integer
  Array2 As String * 16
  Var2 As Integer
  Array3 As String * 16
  Var3 As Integer
End Type
Dim DataRecord As Datatype
Dim Array(8) As Integer
Open "datatest.dat" For Random As #1 Len = Len(DataRecord)
' store array.
For L = 1 To 8
  Array(L) = L
Next
' put array into UDT string.
For L = 1 To 8
  Mid$(DataRecord.Array, (L - 1) * 2 + 1, 2) = MKI$(Array(L))
Next
' put 10 records into file.
For X = 1 To 10
  Put 1, X, DataRecord
Next
' get random record from file.
X = Int(Rnd * 10 + 1)
Get 1, X, DataRecord
' get array from UDT string.
For L = 1 To 8
  M = CVI(Mid$(DataRecord.Array, (L - 1) * 2 + 1, 2))
  Print M;
Next
End
Reply
#25
Code: (Select All)
CONST NITEMS = 20, ARLEN = 8
Type Datatype
  'Array1 field
  Var As Integer
  'Array2 field
  Var2 As Integer
  'Array3 field
  Var3 As Integer
End Type
Dim DataRecord(1 to NITEMS) As Datatype
Dim As Integer Array1(1 to NITEMS, 1 to ARLEN), Array2(1 to NITEMS, 1 to ARLEN), Array3(1 to NITEMS, 1 to ARLEN)
' store first array "field".
FOR N = 1 TO NITEMS
For L = 1 To ARLEN
  Array1(N, L) = L
Next
NEXT

The "Array1" was the "Array" field in the previous example, which was defined as "STRING * 16". The "Array2" and "Array3" were also supposed to be UDT fields. But they are actually arrays independent of the UDT variable. In QB45 and QB64 it has to be done this way whether you like it or not. Otherwise in QB64 you have ```_MEM``` and its association of statements and functions where you don't have to put a static limit on data storage, but is more difficult sometimes to be counting off things by bytes working in this way. Also needing to ask permission from the operating system to allocate a block of memory, and then in the middle of program run, needing to release that memory for other purposes.

It's sloppy but it works.
Reply
#26
(11-13-2023, 01:48 AM)mnrvovrfc Wrote:
Code: (Select All)
CONST NITEMS = 20, ARLEN = 8
Type Datatype
  'Array1 field
  Var As Integer
  'Array2 field
  Var2 As Integer
  'Array3 field
  Var3 As Integer
End Type
Dim DataRecord(1 to NITEMS) As Datatype
Dim As Integer Array1(1 to NITEMS, 1 to ARLEN), Array2(1 to NITEMS, 1 to ARLEN), Array3(1 to NITEMS, 1 to ARLEN)
' store first array "field".
FOR N = 1 TO NITEMS
For L = 1 To ARLEN
  Array1(N, L) = L
Next
NEXT

The "Array1" was the "Array" field in the previous example, which was defined as "STRING * 16". The "Array2" and "Array3" were also supposed to be UDT fields. But they are actually arrays independent of the UDT variable. In QB45 and QB64 it has to be done this way whether you like it or not. Otherwise in QB64 you have ```_MEM``` and its association of statements and functions where you don't have to put a static limit on data storage, but is more difficult sometimes to be counting off things by bytes working in this way. Also needing to ask permission from the operating system to allocate a block of memory, and then in the middle of program run, needing to release that memory for other purposes.

It's sloppy but it works.
And how does that put the arrays into the UDT!?
Reply
#27
For multiple arrays within a UDT you could do this.

Code: (Select All)
' Program to create an array of Doubles in a UDT
DIM AS LONG i
DIM AS DOUBLE v
CONST cMAXELEMENTS = 10

TYPE tARRAYS
  array0 AS _MEM
  array1 AS _MEM
  array2 AS _MEM
END TYPE

DIM AS tARRAYS object

SCREEN 12: _FONT 8

' initialize the array
createObject object.array0, cMAXELEMENTS
createObject object.array1, cMAXELEMENTS
createObject object.array2, cMAXELEMENTS
PRINT "ARRAY 0          ARRAY 1          ARRAY 2"
' set the array to random values
PRINT "Create initial Values"
FOR i = 0 TO cMAXELEMENTS
  v = INT(RND * 5)
  setElement object.array0, i, v
  PRINT "index:"; i; "->"; v; "   ";
  v = INT(RND * 5)
  setElement object.array1, i, v
  PRINT "index:"; i; "->"; v; "   ";
  v = INT(RND * 5)
  setElement object.array2, i, v
  PRINT "index:"; i; "->"; v
NEXT

' retrieve values from array
PRINT "Retrieve Values"
FOR i = 0 TO cMAXELEMENTS
  PRINT "index:"; i; "->"; getElement(object.array0, i); "  ";
  PRINT "index:"; i; "->"; getElement(object.array1, i); "  ";
  PRINT "index:"; i; "->"; getElement(object.array2, i)
NEXT

'resize array
resizeObject object.array0, cMAXELEMENTS * 2
resizeObject object.array1, cMAXELEMENTS * 2
resizeObject object.array2, cMAXELEMENTS * 2



' retrieve values from array
PRINT "Double the size of the array"
FOR i = 0 TO cMAXELEMENTS * 2
  PRINT "index:"; i; "->"; getElement(object.array0, i); "  ";
  PRINT "index:"; i; "->"; getElement(object.array1, i); "  ";
  PRINT "index:"; i; "->"; getElement(object.array2, i)
NEXT

'resize array
resizeObject object.array0, cMAXELEMENTS / 2
resizeObject object.array1, cMAXELEMENTS / 2
resizeObject object.array2, cMAXELEMENTS / 2

' retrieve values from array
PRINT "Half the size of the array"
FOR i = 0 TO cMAXELEMENTS / 2
  PRINT "index:"; i; "->"; getElement(object.array0, i); "  ";
  PRINT "index:"; i; "->"; getElement(object.array1, i); "   ";
  PRINT "index:"; i; "->"; getElement(object.array2, i)
NEXT


SUB createObject (o AS _MEM, size AS LONG)
  ' make array one larger than number of elements
  o = _MEMNEW((size + 1) * 8) ' 8 is the number of bytes in a double
END SUB

SUB resizeObject (o AS _MEM, size AS LONG)
  DIM AS _MEM old
  DIM AS LONG iter
  ' Copy old _MEM to a temp _MEM
  old = o
  ' Create new array of the new size
  createObject o, size
  ' Copy data from old array to new array
  iter = 0: DO WHILE iter < o.SIZE AND iter < old.SIZE
    _MEMPUT o, o.OFFSET + iter, _MEMGET(old, old.OFFSET + iter, _BYTE) AS _BYTE
  iter = iter + 1: LOOP
  ' free old array
  _MEMFREE old
END SUB

FUNCTION getElement# (o AS _MEM, element AS LONG)
  getElement = _MEMGET(o, o.OFFSET + (element * 8), DOUBLE)
END FUNCTION

SUB setElement (o AS _MEM, element AS LONG, v AS DOUBLE)
  _MEMPUT o, o.OFFSET + (element * 8), v AS DOUBLE
END SUB
Reply
#28
Quote:For multiple arrays within a UDT you could do this.
@justsomeguy: Very good! I had considered multiple _MEM in UDT as well..

Erik.
Reply
#29
(11-13-2023, 01:34 AM)eoredson Wrote:
Quote:Why go through such a complicated setup?   Why not just use an array directly?
Because I might have more stuff in the UDT in addition to a single array:

Code: (Select All)
' define an array as string.
Type Datatype
  Array As String * 16
  Var As Integer
  Array2 As String * 16
  Var2 As Integer
  Array3 As String * 16
  Var3 As Integer
End Type
Dim DataRecord As Datatype
Dim Array(8) As Integer
Open "datatest.dat" For Random As #1 Len = Len(DataRecord)
' store array.
For L = 1 To 8
  Array(L) = L
Next
' put array into UDT string.
For L = 1 To 8
  Mid$(DataRecord.Array, (L - 1) * 2 + 1, 2) = MKI$(Array(L))
Next
' put 10 records into file.
For X = 1 To 10
  Put 1, X, DataRecord
Next
' get random record from file.
X = Int(Rnd * 10 + 1)
Get 1, X, DataRecord
' get array from UDT string.
For L = 1 To 8
  M = CVI(Mid$(DataRecord.Array, (L - 1) * 2 + 1, 2))
  Print M;
Next
End

Wouldn't this still be easier to just use Array1, Array2, Array3 and Var1, Var2, Var3 naturally?  Just swap over to BINARY instead of RANDOM and read each array/variable as needed.   Their position is still going to be set in stone and easy to calculate.   ((record - 1) * 54 + 1) is the position of the first array record in the data.  The other arrays are just offset by 18, if you ever need to get them individually.
Reply
#30
The only real reason I brought up this thread is because I have an old project in PDS that has many UDTs with arrays that I ported to 32-bit QB64 and
needed a way to retrieve the UDT from the database to be backwards compatible with PDS..
Reply




Users browsing this thread: 7 Guest(s)