Concatenate 2 arrays using operator & and Union

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
Post Reply
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Concatenate 2 arrays using operator & and Union

Post by Tourist Trap »

Hello,

it's a very limited example but it really concatenates 2 arrays with the help of the standard operators, like & on strings, and a simple user defined Union. This is an alternative to the writing of a for loop reading old arrays index by index and writting them to the new array. This is not what is done here at all.

Code: Select all

'suppose we work with those kind of length=4 byte arrays
'let's construct 2 arrays
dim as ubyte bytearray1(3)
dim as ubyte bytearray2(3)

for i as integer = lbound(bytearray1) to ubound(bytearray1)
    bytearray1(i) = &hFE - i*16
next i
for i as integer = lbound(bytearray1) to ubound(bytearray1)
    bytearray2(i) = &hAE - i*16
next i

'change the arrays content into plain integers
dim as uinteger<4*8> ptr uiptr1
uiptr1 = Cast(uinteger<4*8> ptr, @bytearray1(0))      '' *uiptr eats the byte array on its 4bytes integer length
dim as uinteger<4*8> ptr uiptr2
uiptr2 = Cast(uinteger<4*8> ptr, @bytearray2(0))


'append the 2 arrays in a 3rd one via a Union and & operator
union U
    as uinteger<8*8>   ui
    as string*8        s8
end union

dim as U uu1, uu2, uu3
uu1.ui = *uiptr1
uu2.ui = *uiptr2

uu3.s8 = uu1.s8 & uu2.s8

dim as ubyte finalsum(7)
*( cptr(uinteger<8*8> ptr, @finalsum(0)) ) = uu3.ui


''result:
for i as integer = lbound(finalsum) to ubound(finalsum)
    ? hex(finalsum(i));
next i : ?

'(eof)
It would be great with bigger arrays but I don't have a clue on how extending that at the moment. ( edit: Ah maybe yes, after all (I'll think of it ;) )
Last edited by Tourist Trap on Dec 15, 2018 14:58, edited 1 time in total.
sancho3
Posts: 358
Joined: Sep 30, 2017 3:22

Re: Concatenate 2 arrays using operator & and Union

Post by sancho3 »

Nice job Tourist,
You can remove the warnings with a cast:

Code: Select all

'change the arrays content into plain integers
dim as uinteger<4*8> ptr uiptr1
uiptr1 = Cast(uinteger<32> ptr, @bytearray1(0))      '' *uiptr eats the byte array on its 4bytes integer length
dim as uinteger<4*8> ptr uiptr2
uiptr2 = Cast(uinteger<32> ptr, @bytearray2(0))
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Concatenate 2 arrays using operator & and Union

Post by Tourist Trap »

sancho3 wrote:Nice job Tourist,
You can remove the warnings with a cast:
Hi sancho, thanks. Change made.
I'm trying an alternative and more classical approach now (always based on 'concatenate strings = concatenate arrays'):

Code: Select all

type BYTESTRING
    declare constructor()
        as ubyte    ubytearray(any)
        as string   charstring
end type
constructor BYTESTRING()
    redim as ubyte  THIS.ubytearray(1 to 4)
    for i as integer = lbound(THIS.ubytearray) to ubound(THIS.ubytearray)
        THIS.ubytearray(i) = &h46 + i
    next i
    THIS.charstring = *( cptr(zstring ptr, @THIS.ubytearray(1)) )
end constructor
operator +(Bs1 as BYTESTRING, Bs2 as BYTESTRING) as BYTESTRING
    dim as BYTESTRING   bs
    redim bs.ubytearray(1 to ubound(Bs1.ubytearray) + ubound(Bs2.ubytearray))
    bs.charstring = Bs1.charstring & Bs2.charstring
    *( cptr(zstring ptr, @bs.ubytearray(1)) ) = bs.charstring
    '
    return bs
end operator

dim as BYTESTRING   bs1
dim as BYTESTRING   bs2
dim as BYTESTRING   bs3

bs3 = bs1 + bs2
? ubound( bs3.ubytearray )
for i as integer = 1 to 8
    ? hex( bs3.ubytearray(i) ); 
next i : ?
? bs3.charstring

getKey()
'(eof)
I'm a little confused for now when I try (bs1 + bs2).ubytearray(i) rather than bs3.ubytearray(i) in the last loop that shows the sum as a byte array. It doesn't really work.
Also if we put the value 0 in the array of bytes, apparently it's dead (truncature).
sancho3
Posts: 358
Joined: Sep 30, 2017 3:22

Re: Concatenate 2 arrays using operator & and Union

Post by sancho3 »

I am not %100 sure where your latest code fails.
Here is a way to accomplish the concatenation of two n sized arrays using the string concat operator & or the + operator via explicit cast.
It uses operator new[] to create enough memory for the new array.
I have no idea if there is speed gains over the for/next loop method. I would suspect they are close to the same or maybe this method might be slower.

Code: Select all

Type TByteString 
	Declare Sub dump() 
	Declare Destructor 
	Declare Operator Let(Byref rhs As Const String) 
	Declare Operator Cast() As String 
	Declare Property elements() as Integer 
	As Ubyte Ptr _pMem
	As Integer _size 
		
End Type
	Destructor TByteString() 
		Delete[] this._pMem
		this._pMem = 0 
	End Destructor
	Property TByteString.elements() as Integer 
		'
		return this._size 
	End Property
	Operator TByteString.let(Byref rhs As Const string) 
		If this._pMem <> 0 Then 
			Delete[] this._pMem 
			this._pMem = 0
		End If 
		this._size = Len(rhs) 
		this._pMem = New Ubyte[this._size]
		*Cast(Zstring ptr, this._pMem) = *Strptr(rhs)
	End Operator
	Operator TByteString.cast() As String 
		Return *Cast(Zstring ptr, this._pMem)
	End Operator
	Sub TByteString.dump() 
		With This 
			For i as Integer = 0 To ._size - 1 
				? Chr((._pMem[i]))
			Next
		end With 
	End Sub

dim As tbytestring bs1, bs2, bs3, bs4
bs1 = "abcd"
bs1.dump() 
? ">>>"; Str(bs1);"<<<"		' test to check cast 
?

bs2 = "efgh"
bs2.dump() 
?

bs3 = str(bs1) + Str(bs2)	' explicit cast here using + 
bs3.dump()

? bs3.elements 
?

bs4 = bs1 & bs2 				' using & 
bs4.dump() 
? 
Getkey() 
fxm
Moderator
Posts: 12132
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Concatenate 2 arrays using operator & and Union

Post by fxm »

Tourist Trap wrote:I'm trying an alternative and more classical approach now (always based on 'concatenate strings = concatenate arrays'):

Code: Select all

type BYTESTRING
    declare constructor()
        as ubyte    ubytearray(any)
        as string   charstring
end type
constructor BYTESTRING()
    redim as ubyte  THIS.ubytearray(1 to 4)
    for i as integer = lbound(THIS.ubytearray) to ubound(THIS.ubytearray)
        THIS.ubytearray(i) = &h46 + i
    next i
    THIS.charstring = *( cptr(zstring ptr, @THIS.ubytearray(1)) )
end constructor
operator +(Bs1 as BYTESTRING, Bs2 as BYTESTRING) as BYTESTRING
    dim as BYTESTRING   bs
    redim bs.ubytearray(1 to ubound(Bs1.ubytearray) + ubound(Bs2.ubytearray))
    bs.charstring = Bs1.charstring & Bs2.charstring
    *( cptr(zstring ptr, @bs.ubytearray(1)) ) = bs.charstring
    '
    return bs
end operator

dim as BYTESTRING   bs1
dim as BYTESTRING   bs2
dim as BYTESTRING   bs3

bs3 = bs1 + bs2
? ubound( bs3.ubytearray )
for i as integer = 1 to 8
    ? hex( bs3.ubytearray(i) ); 
next i : ?
? bs3.charstring

getKey()
'(eof)
sancho3 wrote:I am not %100 sure where your latest code fails.
You must allocate one more byte in ubyte's array for the zstring terminal character (a null byte):

Code: Select all

type BYTESTRING
    declare constructor()
        as ubyte    ubytearray(any)
        as string   charstring
end type
constructor BYTESTRING()
    redim THIS.ubytearray(1 to 5)
    for i as integer = lbound(THIS.ubytearray) to ubound(THIS.ubytearray) - 1
        THIS.ubytearray(i) = &h46 + i
    next i
    THIS.charstring = *( cptr(zstring ptr, @THIS.ubytearray(1)) )
end constructor
operator +(Bs1 as BYTESTRING, Bs2 as BYTESTRING) as BYTESTRING
    dim as BYTESTRING   bs
    redim bs.ubytearray(1 to ubound(Bs1.ubytearray) + ubound(Bs2.ubytearray) - 1)
    bs.charstring = Bs1.charstring & Bs2.charstring
    *( cptr(zstring ptr, @bs.ubytearray(1)) ) = bs.charstring
    '
    return bs
end operator

dim as BYTESTRING   bs1
dim as BYTESTRING   bs2
dim as BYTESTRING   bs3

bs3 = bs1 + bs2

? ubound( bs3.ubytearray )
for i as integer = 1 to 8
    ? hex( bs3.ubytearray(i) );
next i : ?
? bs3.charstring

getKey()
'(eof)
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Concatenate 2 arrays using operator & and Union

Post by dodicat »

Hi TT
Here is a method using memcpy

Code: Select all

 
#include "crt.bi"
Type Point
    As Single x,y
    As Ulong colour
End Type

Type arrayOfPoints
    As Point  p(Any)
    As Point centre
    Declare Sub createCircle(As Single,As Single,As Long,As Ulong)
End Type

Function rotate(pivot As Point,p As Point,a As Single,scale As Single=1) As Point
    Return Type<Point>(scale*(Cos(a*.0174533)*(p.x-pivot.x)-Sin(a*.0174533)*(p.y-pivot.y))+pivot.x, _
    scale*(Sin(a*.0174533)*(p.x-pivot.x)+Cos(a*.0174533)*(p.y-pivot.y))+pivot.y,p.colour)
End Function

Sub JoinArraysOfPoints(a As arrayOfPoints,b As arrayOfPoints,c As arrayOfPoints)
        Dim As Long k
        If (Ubound(c.p)-Lbound(c.p)+1)>0 Then k=Ubound(c.p)+1
        Redim Preserve c.p((Ubound(a.p)-Lbound(a.p)+1)+(Ubound(b.p)-Lbound(b.p)+1)-1+(Ubound(c.p)-Lbound(c.p)+1))
        memcpy(@c.p(Lbound(c.p)+k),@a.p(Lbound(a.p)),(Ubound(a.p)-Lbound(a.p)+1)*Sizeof(a.p))
        memcpy(@c.p(Ubound(a.p)+1+k),@b.p(Lbound(b.p)),(Ubound(b.p)-Lbound(b.p)+1)*Sizeof(b.p))
End Sub

Sub arrayOfPoints.createCircle(xm As Single, ym As Single, r As Long,c As Ulong)
    #define CIRC(r)  ( ( Int( (r)*(1 + Sqr(2)) ) - (r) ) Shl 2 )
    Dim As Long x = -r, y = 0, e = 2 - r Shl 1
    Dim As Long count=-1
    Redim p(CIRC(r)+4-1)
    Do
        count+=1:p(count)=Type<Point>(xm-x,ym+y,c)
        count+=1:p(count)=Type<Point>(xm-y,ym-x,c)
        count+=1:p(count)=Type<Point>(xm+x,ym-y,c)
        count+=1:p(count)=Type<Point>(xm+y,ym+x,c)
        r = e
        If r<=y Then
            y+=1
            e+=y Shl 1+1
        End If
        If r>x Or e>y Then
            x+=1
            e+=x Shl 1+1
        End If
    Loop While x<0
    Redim Preserve p(count)
    centre=Type(xm,ym)
End Sub


Screen 19
Dim As arrayOfPoints z(1 To 4)
z(1).createCircle(200,200,100,2)
z(2).createCircle(400,300,150,3)
z(3).createCircle(600,400,50,4)
z(4).createCircle(400,100,80,5)

Dim As arrayOfPoints Ptr  x =New arrayOfPoints

For n As Long=1 To 3 step 2
    JoinArraysOfPoints(z(n),z(n+1),*x) 
Next n



Dim As Single angle,scaler=1,k=1
Do
    scaler-=.0005*k
    if scaler<.1 then k=-k
    if scaler>1 then k=-k
    angle+=.1
    Screenlock
    Cls
    For n As Long=Lbound(x->p) To Ubound(x->p)
        Dim As Point p=rotate(Type<Point>(400,300),(x->p(n)),angle,scaler)
        Pset(p.x,p.y),p.colour
    Next
    
    Screenunlock
    Sleep 1,1
Loop Until Multikey(1):sleep

sleep
Delete x

  
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Concatenate 2 arrays using operator & and Union

Post by Tourist Trap »

dodicat wrote:Hi TT
Here is a method using memcpy
Hi dodi,
Thanks, I'll test that (can't right now). I played with memcopy times ago but decided to forget it because it seemed prone to crash. I will focus at it again, thanks for the reminder ansd for adding a sample of yours :)
Post Reply