QB64.org Forum

Active Forums => QB64 Discussion => Topic started by: jack on June 11, 2021, 07:04:18 pm

Title: array in type
Post by: jack on June 11, 2021, 07:04:18 pm
apparently arrays are not allowed in a type, that's a pity
is there a work-around for this limitation?
Title: Re: array in type
Post by: SpriggsySpriggs on June 11, 2021, 07:18:16 pm
Use MEM and then store the array in the MEM
Title: Re: array in type
Post by: jack on June 11, 2021, 07:21:29 pm
yes, but mem requires a lot of house keeping, not user friendly
I thinking of faking an array using a string*size
Title: Re: array in type
Post by: SpriggsySpriggs on June 11, 2021, 07:27:36 pm
Do it however you wish
Title: Re: array in type
Post by: jack on June 11, 2021, 07:50:21 pm
here's my attempt at a fake array
Code: QB64: [Select]
  1. Type dec
  2.     m As String * 50
  3.  
  4. Dim As dec d
  5.  
  6. j = 1
  7. For i = 1 To 12
  8.     v = MKL$(i)
  9.     Mid$(d.m, j, 4) = v
  10.     j = j + 4
  11.  
  12. j = 1
  13. For i = 1 To 12
  14.     n = CVL(Mid$(d.m, j, 4))
  15.     j = j + 4
  16.     Print i, n
  17.  
Title: Re: array in type
Post by: bplus on June 11, 2021, 08:06:21 pm
I've been talking about String arrays like forever!
So has Luke: https://www.qb64.org/forum/index.php?topic=1511.msg129084#msg129084

Right after that reply there is one for variable length strings.
Title: Re: array in type
Post by: SpriggsySpriggs on June 11, 2021, 08:58:15 pm
I fail to see how that is more elegant than MEM.
Title: Re: array in type
Post by: luke on June 11, 2021, 09:22:55 pm
It doesn't require initialising the men block, and (more importantly) is automatically collected by the garbage collector when it goes out of scope.
Title: Re: array in type
Post by: FellippeHeitor on June 11, 2021, 09:57:02 pm
I've used string arrays quite often too.
Title: Re: array in type
Post by: NOVARSEG on June 11, 2021, 10:22:45 pm

from https://stackoverflow.com/questions/53410020/use-an-array-in-a-user-defined-type-in-qbasic

Quote
Although you CANNOT do this in QB1.1, QB4.5, or QB64, you CAN do this in supersets of the BASIC dialect known as QB7.1(BC7/PDS), and VBDOS(v1.00):
Title: Re: array in type
Post by: Cobalt on June 11, 2021, 10:24:58 pm
It must be time for my YEARLY or MULTI-YEARLY petition for ARRAYs in UDT!

ARRAYs IN UDTs PLEASE!
Title: Re: array in type
Post by: bplus on June 12, 2021, 10:09:15 am
It must be time for my YEARLY or MULTI-YEARLY petition for ARRAYs in UDT!

ARRAYs IN UDTs PLEASE!

What! and waste all these great work-arounds? ;-))

Title: Re: array in type
Post by: jack on June 12, 2021, 11:08:39 am
thanks bplus, my example above can be simplified a bit if our simulated array index starts at 0
Code: QB64: [Select]
  1. For i = 0 To 12-1
  2.     v = MKL$(i)
  3.     Mid$(d.m, 4 * i + 1, 4) = v
  4.  
no need for a dedicated variable for the index
Title: Re: array in type
Post by: jack on June 12, 2021, 12:47:00 pm
here's the start of my project, a decimal floating-point package and hence the need for array in type
I chose unsigned long for the elements because the result of multiplying two longs fits in a 64-bit integer
the code here is only the foundation, as a test it converts strings to decfloat and back, I also did a proof of concept addition
Quote
3.14159265 358979323 846264338 327950288 419716939 937510582E+00000
 3.14159265 358979323 846264338 327950288 419716939 937510582E+00000
 6.28318530 717958647 692528676 655900576 839433879 875021164E+00000

Code: QB64: [Select]
  1.  
  2. Const NUM_DIGITS = 9 * 10
  3. Const NUM_DWORDS = NUM_DIGITS \ 9
  4. Const NUM_BYTES = 2 + 4 * NUM_DWORDS
  5. Const BIAS = 1073741824 '2 ^ 30
  6.  
  7. ' Error definitions
  8.  
  9. Const DIVZ_ERR = 1 'Divide by zero
  10. Const EXPO_ERR = 2 'Exponent overflow error
  11. Const EXPU_ERR = 3 'Exponent underflow error
  12.  
  13. Type decfloat
  14.     sign As _Unsigned Integer
  15.     exponent As _Unsigned Long
  16.     mantissa As String * Num_bytes
  17.  
  18. Dim As decfloat x, y
  19.  
  20. pi = "3.14159265358979323846264338327950288419716939937510582097494459"
  21. pi = pi + "230781640628620899862803482534211706798214808651328230664709384"
  22.  
  23. Call str2dec(pi, x)
  24. Call str2dec(pi, y)
  25.  
  26. Print dec2str(x)
  27. Print dec2str(y)
  28.  
  29. ' =====================================================
  30. ' add x + y = 2 * Pi
  31.  
  32. c = 0
  33. For i = NUM_DWORDS - 1 To 0 Step -1
  34.     v = CVL(Mid$(x.mantissa, 4 * i + 1, 4)) + CVL(Mid$(y.mantissa, 4 * i + 1, 4)) + c
  35.     If v > 999999999 Then
  36.         v = v - 1000000000
  37.         c = 1
  38.     Else
  39.         c = 0
  40.     End If
  41.     Mid$(y.mantissa, 4 * i + 1, 4) = MKL$(v)
  42.  
  43. Print dec2str(y)
  44. Call RSHIFT_1(y)
  45. Call LSHIFT_1(y)
  46. Print "the last digit before E should be 0 due to right-shift"
  47. Print dec2str(y)
  48.  
  49. Sub str2dec (value As String, n As decfloat)
  50.     Dim As Integer j, s, d, e, ep, ex, es, i, f, fp, fln
  51.     Dim As String c, f1, f2, f3, ts
  52.     Dim As _Unsigned Long ulng
  53.  
  54.     j = 1
  55.     s = 1
  56.     d = 0
  57.     e = 0
  58.     ep = 0
  59.     ex = 0
  60.     es = 1
  61.     i = 0
  62.     f = 0
  63.     fp = 0
  64.     f1 = ""
  65.     f2 = ""
  66.     f3 = ""
  67.     value = UCase$(value)
  68.     fln = Len(value)
  69.  
  70.     While j <= fln
  71.         c = Mid$(value, j, 1)
  72.         If ep = 1 Then
  73.             If c = " " Then
  74.                 j = j + 1
  75.                 GoTo skip_while
  76.             End If
  77.             If c = "-" Then
  78.                 es = -es
  79.                 c = ""
  80.             End If
  81.             If c = "+" Then
  82.                 j = j + 1
  83.                 GoTo skip_while
  84.             End If
  85.             If (c = "0") And (f3 = "") Then
  86.                 j = j + 1
  87.                 GoTo skip_while
  88.             End If
  89.             If (c > "/") And (c < ":") Then 'c is digit between 0 and 9
  90.                 f3 = f3 + c
  91.                 ex = 10 * ex + (Asc(c) - 48)
  92.                 j = j + 1
  93.                 GoTo skip_while
  94.             End If
  95.         End If
  96.  
  97.         If c = " " Then
  98.             j = j + 1
  99.             GoTo skip_while
  100.         End If
  101.         If c = "-" Then
  102.             s = -s
  103.             j = j + 1
  104.             GoTo skip_while
  105.         End If
  106.         If c = "+" Then
  107.             j = j + 1
  108.             GoTo skip_while
  109.         End If
  110.         If c = "." Then
  111.             If d = 1 Then
  112.                 j = j + 1
  113.                 GoTo skip_while
  114.             End If
  115.             d = 1
  116.         End If
  117.         If (c > "/") And (c < ":") Then 'c is digit between 0 and 9
  118.             If ((c = "0") And (i = 0)) Then
  119.                 If d = 0 Then
  120.                     j = j + 1
  121.                     GoTo skip_while
  122.                 End If
  123.                 If (d = 1) And (f = 0) Then
  124.                     e = e - 1
  125.                     j = j + 1
  126.                     GoTo skip_while
  127.                 End If
  128.             End If
  129.             If d = 0 Then
  130.                 f1 = f1 + c
  131.                 i = i + 1
  132.             Else
  133.                 If (c > "0") Then
  134.                     fp = 1
  135.                 End If
  136.                 f2 = f2 + c
  137.                 f = f + 1
  138.             End If
  139.         End If
  140.         If c = "E" Then
  141.             ep = 1
  142.         End If
  143.         j = j + 1
  144.         skip_while:
  145.     Wend
  146.     If fp = 0 Then
  147.         f = 0
  148.         f2 = ""
  149.     End If
  150.  
  151.     If s = -1 Then s = &H8000 Else s = 0
  152.     n.sign = s
  153.     ex = es * ex - 1 + i + e
  154.     f1 = f1 + f2
  155.     f1 = Mid$(f1, 1, 1) + Right$(f1, Len(f1) - 1)
  156.     fln = Len(f1)
  157.     If Len(f1) > ((NUM_DWORDS * 9) + 1) Then
  158.         f1 = Mid$(f1, 1, ((NUM_DWORDS * 9) + 1))
  159.     End If
  160.     While Len(f1) < ((NUM_DWORDS * 9) + 1)
  161.         f1 = f1 + "0"
  162.     Wend
  163.     j = 1
  164.     For i = 0 To NUM_DWORDS - 1
  165.         ts = Mid$(f1, j, 9)
  166.         ulng = Val(ts)
  167.         Mid$(n.mantissa, 4 * i + 1, 4) = MKL$(ulng)
  168.         If ulng <> 0 Then fp = 1
  169.         j = j + 9
  170.     Next
  171.     If fp Then n.exponent = (ex + BIAS + 1) Else n.exponent = 0
  172.  
  173. Function dec2str$ (n As decfloat)
  174.     Dim As Integer i, ex
  175.     Dim As String v, f, ts
  176.     If n.exponent > 0 Then
  177.         ex = (n.exponent And &H7FFFFFFF) - BIAS - 1
  178.     Else
  179.         ex = 0
  180.     End If
  181.     If n.sign Then v = "-" Else v = " "
  182.     ts = _Trim$(Str$(CVL(Mid$(n.mantissa, 4 * 0 + 1, 4))))
  183.     If Len(ts) < 9 Then
  184.         ts = ts + String$(9 - Len(ts), "0")
  185.     End If
  186.     v = v + Left$(ts, 1) + "." + Mid$(ts, 2)
  187.     For i = 1 To NUM_DWORDS - 1
  188.         ts = _Trim$(Str$(CVL(Mid$(n.mantissa, 4 * i + 1, 4))))
  189.         If Len(ts) < 9 Then
  190.             ts = String$(9 - Len(ts), "0") + ts
  191.         End If
  192.         v = v + ts
  193.     Next
  194.     f = _Trim$(Str$(Abs(ex)))
  195.     f = String$(5 - Len(f), "0") + f
  196.     If ex < 0 Then v = v + "E-" Else v = v + "E+"
  197.     v = v + f
  198.     dec2str = v
  199.  
  200. Sub RSHIFT_1 (mantissa As decfloat)
  201.     Dim As _Unsigned Long v1, v2
  202.     Dim As Long i
  203.     For i = NUM_DWORDS - 1 To 1 Step -1
  204.         v1 = CVL(Mid$(mantissa.mantissa, 4 * i + 1, 4)) \ 10
  205.         v2 = CVL(Mid$(mantissa.mantissa, 4 * (i - 1) + 1, 4)) Mod 10
  206.         v2 = v2 * 100000000 + v1
  207.         Mid$(mantissa.mantissa, 4 * i + 1, 4) = MKL$(v2)
  208.     Next
  209.     Mid$(mantissa.mantissa, 4 * 0 + 1, 4) = MKL$(CVL(Mid$(mantissa.mantissa, 4 * 0 + 1, 4)) \ 10)
  210.  
  211. Sub LSHIFT_1 (mantissa As decfloat)
  212.     Dim As _Unsigned Long v1, v2
  213.     Dim As Long i
  214.     For i = 0 To NUM_DWORDS - 2
  215.         v1 = CVL(Mid$(mantissa.mantissa, 4 * i + 1, 4)) Mod 100000000
  216.         v2 = CVL(Mid$(mantissa.mantissa, 4 * (i + 1) + 1, 4)) \ 100000000
  217.         Mid$(mantissa.mantissa, 4 * i + 1, 4) = MKL$(v1 * 10 + v2)
  218.         Mid$(mantissa.mantissa, 4 * (i + 1) + 1, 4) = MKL$(CVL(Mid$(mantissa.mantissa, 4 * (i + 1) + 1, 4)) Mod 100000000)
  219.     Next
  220.     Mid$(mantissa.mantissa, 4 * (NUM_DWORDS - 1) + 1, 4) = MKL$(10 * CVL(Mid$(mantissa.mantissa, 4 * (NUM_DWORDS - 1) + 1, 4)) Mod 100000000)
  221.  
Title: Re: array in type
Post by: jack on June 12, 2021, 03:21:35 pm
instead of using the convoluted CVL, Mkl$ and Mid$ to access the memory I think using a temporary array would be far better
proof of concept
<edit> not reliable
Code: QB64: [Select]
  1.     Sub memcpy (ByVal dest As _Offset, Byval source As _Offset, Byval bytes As Long)
  2.  
  3. Type dec
  4.     m As String * 46
  5.  
  6. Dim As Long i, m
  7. Dim As Long a(0 To 10), b(0 To 10)
  8. Dim x As dec
  9.  
  10. For i = 0 To 10
  11.     a(i) = i * i
  12.  
  13. memcpy _Offset(x.m), _Offset(a()), Len(a())
  14.  
  15. For i = 0 To 10
  16.     m = CVL(Mid$(x.m, 4 * i + 1, 4))
  17.     Print i, m
  18.  
  19. memcpy _Offset(b()), _Offset(x.m), Len(b())
  20.  
  21. For i = 0 To 10
  22.     Print i, b(i)
  23.  
Title: Re: array in type
Post by: Ivan on June 14, 2021, 07:42:36 am
Is arrays of types also missing?
Title: Re: array in type
Post by: SpriggsySpriggs on June 14, 2021, 07:44:02 am
You can have arrays of types. You just can't have arrays IN types.
Title: Re: array in type
Post by: Ivan on June 14, 2021, 01:29:47 pm
You can have arrays of types. You just can't have arrays IN types.

The basic i'm currently using don't have types but can have structs of arrays and can have arrays in structs, and I think I mostly can use structs like types.

Exepct that types in QB64 are more precise and more nicely listed and much easier to read.

I' in midst of programming a relational database with one to many relations using arrays with four different files.
Title: Re: array in type
Post by: SpriggsySpriggs on June 14, 2021, 02:24:31 pm
To me, this seems absolutely simple enough for an array in type:

Code: QB64: [Select]
  1.  
  2. Type arrTest
  3.     As _MEM array
  4.  
  5. Dim As arrTest arrTest
  6.  
  7. Dim As Long array(1 To 3)
  8.  
  9. array(1) = 100
  10. array(2) = 5
  11. array(3) = 34
  12.  
  13. arrTest.array = _Mem(array())
  14.  
  15. Dim As Long array2(1 To Val(Str$(arrTest.array.SIZE)) / Val(Str$(arrTest.array.ELEMENTSIZE)))
  16. _MemGet arrTest.array, arrTest.array.OFFSET, array2()
  17. '_MemFree arrTest.array
  18.  
  19. Dim x
  20. For x = LBound(array2) To UBound(array2)
  21.     Print array2(x)
Title: Re: array in type
Post by: Ivan on June 15, 2021, 03:19:47 pm
Most code I have just done seems maybe not simple, but clear. Not many days later, when i have look at the same code I think, what is going on...

I think if I dig into your code I would understand how to use it.

But I wish someting like this pseudo code in QB64:

type vector(array)
  x(array)
  y(array)
  z(array)
end type

or the basic I use (not pseudo):

dim vector_{ a(9,9,9), x(9), y(9), z(9) }
Title: Re: array in type
Post by: bplus on June 15, 2021, 04:29:18 pm
Here is how to do it (use variable length String Arrays instead of number arrays) in a Type.

Demo of building a Double Spiral without resort to arrays, storing all the points into a Type Variable:
Code: QB64: [Select]
  1. _Title "Array strings in Type Demo" ' b+ 2021-06-15
  2. Const xmx = 640
  3. Const ymx = 640
  4.  
  5. Screen _NewImage(xmx, ymx, 32)
  6. _Delay .25
  7.  
  8. Type points
  9.     xA As String
  10.     yA As String
  11. Dim sq, s2, points, ga, scale, n
  12. sq = ymx: s2 = sq / 2: points = 100: ga = 137.5
  13. scale = sq * 30 / 640
  14. Dim dblSpiral As points
  15.  
  16. ' build it into string arrays
  17. For n = 1 To points
  18.     'compare to xA(n) = s2 + scale * Sqr(n) * Cos(_D2R(n * ga))
  19.     'compare to yA(n) = s2 + scale * Sqr(n) * Sin(_D2R(n * ga))
  20.     SetLong dblSpiral.xA, n, s2 + scale * Sqr(n) * Cos(_D2R(n * ga))
  21.     SetLong dblSpiral.yA, n, s2 + scale * Sqr(n) * Sin(_D2R(n * ga))
  22.  
  23. ''display it
  24. For n = 3 To points
  25.     Line (GetLong&(dblSpiral.xA, n - 2), GetLong&(dblSpiral.yA, n - 2))-(GetLong&(dblSpiral.xA, n), GetLong&(dblSpiral.yA, n))
  26.  
  27. Sub SetLong (array$, index As Long, value&) ' Luke's Method except option explicit requires mod, no variables needed for one type
  28.     If Len(array$) < 4 * (index + 1) Then array$ = array$ + String$(4 * (index + 1) - Len(array$), Chr$(0))
  29.     Mid$(array$, index * 4 + 1) = _MK$(Long, value&)
  30.  
  31. Function GetLong& (array$, index As Long)
  32.     GetLong& = _CV(Long, Mid$(array$, index * 4 + 1, 4))
  33.  
  34.  

Of course you could display the Double Spiral immediately but you wouldn't have the points saved for further processing.
Title: Re: array in type
Post by: madscijr on July 02, 2021, 10:01:18 am
It must be time for my YEARLY or MULTI-YEARLY petition for ARRAYs in UDT!

ARRAYs IN UDTs PLEASE!

I second this motion! :-D
Title: Re: array in type
Post by: madscijr on July 02, 2021, 10:06:00 am
To me, this seems absolutely simple enough for an array in type:

Two questions for you Spriggs

Thanks
Title: Re: array in type
Post by: SpriggsySpriggs on July 02, 2021, 10:07:04 am
@madscijr The example does show how to release it from memory. I just have it commented out. And of course it is cross-platform. It's just a regular QB64 function.
Title: Re: array in type
Post by: SpriggsySpriggs on July 02, 2021, 10:28:21 am
The way that arrays are passed in Windows API from QB64 in TYPEs are always through an _Offset variable because we are passing it as a pointer in memory. What I'm showing is similar, although I'm instead passing the whole _MEM block rather than just the reference _MEM.OFFSET.

In my Task Dialog library, one passes an array of buttons in a variable called pButtons; an element of the TASKDIALOGCONFIG struct/type. The "p" in pButtons means "pointer" or, in our case, an _Offset. I pass the entire array using _Offset(btnArray()) and the Windows API handles it. I assume they are doing something similar on their end by copying the referenced memory to a newly defined array on the API side. That is why I suggested something similar for us since it works so well in all the APIs that have required an array in a struct.
Title: Re: array in type
Post by: madscijr on July 02, 2021, 10:45:40 am
@madscijr The example does show how to release it from memory. I just have it commented out. And of course it is cross-platform. It's just a regular QB64 function.

Aha, thanks. I see the _MEMFREE now, not sure how that escaped my attention, maybe I need to adjust the colors on my monitor (I see it just fine on the iPhone screen!) Or maybe I just need coffee.
Either way thanks!
Title: Re: array in type
Post by: xra7en on July 04, 2021, 02:13:48 pm
yes, but mem requires a lot of house keeping, not user friendly
I thinking of faking an array using a string*size

Use a function similar to PHP "serialize"
Quote
https://www.php.net/manual/en/function.serialize.php

when I get time, i'll dig around in one of my libs and post it. I made a "kludgy" version as I too was disappointed at the arrays in TYPED vars. :-(

However - ALWAYS follow Spriggs tips!