Author Topic: Array concatenation  (Read 3315 times)

0 Members and 2 Guests are viewing this topic.

Arnold

  • Guest
Array concatenation
« on: June 30, 2019, 11:21:10 PM »
Hi Charles,

at Rosettacode I found an example dealing with array concatentation. The OxygenBasic solution seems not to work any more with the latest version. I also experimented a little bit and noticed this difference:

Code: [Select]
'Array concatenation

uses console

string s1[4] = {"The", "quick", "brown", "fox"}
string s2[5] = {"jumped", "over", "the", "lazy", "dog"}

int n1=countof(s1)
int n2=countof(s2)
int n=n1+n2

sys a=getmemory n * sizeof(string)        'ok
'sys a=getmemory(countof(s1)+countof(s2)) * sizeof(string)  'not ok
'sys a=getmemory (n1+n2) * sizeof(string)   'not ok

string s3 at a

int x
for x=1 to n1
  s3[x]=s1[x]
next

for x=1 to n2
  s3[x+n1]=s2[x]
next

printl s3[1] " " s3[2] " "s3[3] " "s3[4] " "s3[5] " "s3[6] " "s3[6] " "s3[7] " "s3[8] " " s3[9]

freememory a

===================================================

string t1[4] = {"The", "quick", "brown", "fox"}
string t2[5] = {"jumped", "over", "the", "lazy", "dog"}

int nn=countof(t1)+countof(t2)
sys addr=getmemory nn * sizeof(string)

string t3 at addr

int x
for x=1 to countof(t1)
  t3[x]=t1[x] 
next

for x=1 to countof(t2)
  t3[x+countof(t1)]=t2[x]
next

printl t3[1] " " t3[2] " "t3[3] " "t3[4] " "t3[5] " "t3[6] " "t3[6] " "t3[7] " "t3[8] " " t3[9]

freememory addr
 
printl "Enter ..."
waitkey()

getmemory using an expression in parantheses seems not to work? It is not a big problem, but I feel obliged to report the behaviour, because O2 terminates without an error message. (though the issue can be spotted quickly)

Roland

Charles Pegge

  • Guest
Re: Array concatenation
« Reply #1 on: July 01, 2019, 01:08:46 AM »
Hi Roland,

getmemory is a normal function (with optional enclosing brackets), so this won't work:

sys a=getmemory(countof(s1)+countof(s2)) * sizeof(string)


but this will:

sys a=getmemory( (countof(s1)+countof(s2)) * sizeof(string)   )

Charles Pegge

  • Guest
Re: Array concatenation
« Reply #2 on: July 01, 2019, 02:00:33 AM »
Concatenating with redim is very efficient, but strings in the new array will remain cross-linked to the originals. This could be a useful feature to be exploited :)

s3_buffer = s1_buffer + s2_buffer

Code: [Select]
uses console

redim string s1(4)
s1={"The", "quick", "brown", "fox"}
redim string s2(5)
s2={"jumped", "over", "the", "lazy", "dog"}
'
'FAST CONCATENATION BUT STRINGS REMAIN LINKED
redim string s3(0)
s3_buffer = s1_buffer + s2_buffer
@s3 = strptr s3_buffer
'
int i
for i=1 to 9
  print s3[i] " "
next
printl
s1[4]="bear" 'ALSO AFFECTS S3
for i=1 to 9
  print s3[i] " "
next
printl
printl "Enter ..." : waitkey()

Arnold

  • Guest
Re: Array concatenation
« Reply #3 on: July 01, 2019, 02:07:34 AM »
Thank you Charles. I knew that I missed something. Pay attention to the brackets. (Shame on me).

Arnold

  • Guest
Re: Array concatenation
« Reply #4 on: July 02, 2019, 05:50:58 AM »
Hi Charles,

is it possible to apply the s3_buffer approach in a similar way with e.g. floats? This is the task of Rosetta Code solved with a previous version of O2, which does not work this way any more:

Code: [Select]
'CREATE DYNAMIC ARRAY SPACES USING STRINGS

string sa=nuls 5* sizeof float
string sb=sa

'MAP ARRAY VARIABLES ONTO STRINGS

float a at *sa
float b at *sb

'ASSIGN SOME VALUES

a<=10,20,30,40,50
b<=60,70,80,90,00

'ADD ARRAY B TO A BY STRING CONCATENATION

sa+=sb

'TEST

print a[7] 'result should be 70

This is what I have achieved so far (shameful little):

Code: [Select]
redim float aa[5]
redim float bb[5]

aa = {10,20,30,40,50}
bb = {60,70,80,90,00}

print aa[4] + ", " + bb[2]

Adding two arrays like cc=aa+bb would be a tempting option, but it is also ok to assign the values individually.

Roland

Charles Pegge

  • Guest
Re: Array concatenation
« Reply #5 on: July 02, 2019, 06:31:21 AM »
Yes, it will work more cleanly with floats and integers,since we are no longer dealing with string pointers.

cc_buffer = aa_buffer + bb_buffer


This is more efficient than transferring elements individually

Arnold

  • Guest
Re: Array concatenation
« Reply #6 on: July 02, 2019, 11:58:16 PM »
Hi Charles,

it took some time until I found my mistake: despite the type float of cc I must apply strptr for cc_buffer. So this code will show the correct results:

Code: [Select]
redim float aa(5)
redim float bb(5)

aa = {10,20,30,40.5,50}
bb = {60,70.5,80,90,00}
'print aa[4] + ", " + bb[2]

redim float cc(0)
cc_buffer = aa_buffer + bb_buffer
@cc = strptr cc_buffer              'strptr

print cc[4]  + ", " + cc[7]

Redim makes concatenation very effective.

I would like to ask two questions. Can the code of the RosettaCode example above be solved with the latest version of Oxygen too? And could redim be used with type any or with structs? FBSL offers a solution for concatenation of mixed arrays (int, string, single). If this is possible with O2 in some way then this will offer a lot of interesting aspects.

Roland 

Arnold

  • Guest
Re: Array concatenation
« Reply #7 on: July 03, 2019, 11:04:06 PM »
I found this solution for the task of RosettaCode:

Code: [Select]
'CREATE DYNAMIC ARRAY SPACES USING STRINGS

string sa=nuls 5* sizeof float
string sb=nuls 5* sizeof float

'MAP ARRAY VARIABLES ONTO STRINGS

float a at *sa
float b at *sb

'ASSIGN SOME VALUES

a = {10,20,30,40,50}
b = {60,70,80,90,00}
'print a[5] ", " b[4]

'ADD ARRAY B and A to C BY STRING CONCATENATION

string sc
sc=sa+sb
float c at *sc

'TEST

print c[7] 'result 70

Most probably there are more and better ways to do concatenation (besides using redim). But I think it is nice that there are alternatives to solve a task.

Charles Pegge

  • Guest
Re: Array concatenation
« Reply #8 on: July 04, 2019, 01:07:06 AM »
Hi Roland,

That is how redim works in o2.

The current redim macro (from oxsc\lang.inc):
Code: [Select]
def redim
  #ifndef %2_buffer
    dim string %2_buffer = ""
    dim %1 byref %2
  #endif
  scope
    int _qb_ = %3
    int _le_ = len %2_buffer
    int _qn_ = _le_ / sizeof(%1)
    #if match "%4","clear"
      int _i_
      for _i_=1 to _qn_
        #if typecodeof(%2)>=0x200
          #ifdef %1.destructor
            %2[_i_].destructor
          #endif
        #elseif typecodeof(%2)>=0xa0
          %2[_i_]=""
        #else
          %2[_i_]=0
        #endif
      next
    #endif
    #if typecodeof(%2)>=0xa0
      if _qb_<_qn_
        _qb_=_qn_ 'disallow reduction
      endif
    #endif
    if _qb_ > _qn_
      %2_buffer += nuls( sizeof(%1) * (_qb_ - _qn_))
    elseif _qb_ <  _qn_
      %2_buffer = left( %2_buffer, sizeof(%1) * _qb_ )
    endif
    @%2=strptr(%2_buffer)
  end scope
end def

Redim will support both primitives and UDTs.

Concatenation the buffers works well for direct types, but for strings and other pointered types, it requires that the underlying data is non-volatile, and the data is used as read-only.

Arnold

  • Guest
Re: Array concatenation
« Reply #9 on: July 04, 2019, 11:49:33 PM »
Thank you, Charles, for the code of redim.  In any case, it is worthwhile to learn more about the possible use of this macro.
« Last Edit: July 09, 2019, 06:36:07 AM by Arnold »

Arnold

  • Guest
Re: Array concatenation
« Reply #10 on: August 30, 2019, 08:07:48 AM »
Hi Charles,

I am looking for a way to reset some structures in an array. At the moment I do this by resetting the values in the fields of the corresponding structures. Is there a more general way to achieve this without specifying the fields? I assume the solution is included in the redim macro, but it seems I am not able to find it.

Roland

Code: [Select]
string cr=chr(13,10)
string pr

type info
  char name[40]
  int  age
end type
'print hex(typecodeof info)

int countof_staff=6
redim info staff[countof_staff]
int i
for i = 1 to 5
   staff[i].name = "Officer " + str(i)
   staff[i].age = 40-i
   pr += i ": " + staff[i].name + ": " + staff[i].age +cr
next
pr += i ": " + staff[countof_staff].name + ": " + staff[countof_staff].age +cr
int used_mem = countof_staff*sizeof(info)
pr += "Used memory: " + used_mem +cr +cr

   'print sizeof(info) + cr
   staff[4].name = "" : staff[4].age = 0
   staff[5].name = "" : staff[5].age = 0

for i = 1 to countof_staff
   pr += i ": " + staff[i].name + ": " + staff[i].age +cr
next
used_mem = countof_staff*sizeof(info)
pr += "Used memory: " + used_mem +cr

print pr

Charles Pegge

  • Guest
Re: Array concatenation
« Reply #11 on: August 30, 2019, 02:01:17 PM »
Hi Roland,

Resetting individual fields is good enough, and safe for non-flat structures. You can make the UDT into a class with a destructor, for clearing individual members.

The current redim clear option looks for a destructor and, it it exists,  invokes it for each member of the dynamic array.

redim typ v(10) clear



Arnold

  • Guest
Re: Array concatenation
« Reply #12 on: August 31, 2019, 02:00:45 AM »
Thank you, Charles. I wondered about the clear option, but I have not found an example of it yet, and I am not brave enough to test this.

I tried another approach and added an additional member dta in type info. Would this be applicable? If there are side-effects I will delete the values individually, although using a type with e.g. 10 members it would be interesting to do this with a single statement.

Roland

Code: [Select]
$ filename "test.exe"
'uses rtl32
'uses rtl64

string cr=chr(13,10)
string pr

type info
  char name[40]
  sys  age               'test for 64-bit
  =
  char dta[sizeof(info)] 
end type
'print sizeof info
'print hex(typecodeof info)

int countof_staff=6
redim info staff[countof_staff]
int i
for i = 1 to 5
   staff[i].name = "Officer " + str(i)
   staff[i].age = 40-i
   pr += i ": " + staff[i].name + ": " + staff[i].age +cr
next
pr += i ": " + staff[countof_staff].name + ": " + staff[countof_staff].age +cr
int used_mem = countof_staff*sizeof(info)
pr += "Used memory: " + used_mem +cr +cr

   staff[4].dta=nuls sizeof(info)
   staff[5].dta=nuls sizeof(info)
   
   'staff[4].name = "New Officer" : staff[4].age = 22
   
for i = 1 to countof_staff
   pr += i ": " + staff[i].name + ": " + staff[i].age +cr
next
used_mem = countof_staff*sizeof(info)
pr += "Used memory: " + used_mem +cr

print pr

Charles Pegge

  • Guest
Re: Array concatenation
« Reply #13 on: August 31, 2019, 03:19:25 AM »
instead of:

staff[4].dta=nuls sizeof(info)

this code avoids the string intermediary, and could be applied to any flat structure:

Code: [Select]
sub clear(sys p, int n)
  byte b at (p)
  while n>0
    b=0 : @b++ : n--
  wend
end sub

in assembler:

Code: [Select]
sub clear(sys p, int n)
mov ecx,n
mov rsi,p
(
 dec ecx : jl exit
 mov byte [rsi],0
 inc rsi
 repeat
)
end sub

clear @staff[4], sizeof(info)
« Last Edit: August 31, 2019, 03:36:12 AM by Charles Pegge »

Arnold

  • Guest
Re: Array concatenation
« Reply #14 on: August 31, 2019, 04:13:56 AM »
Wow! This is impressive. I will not need an extra dta member and will get the expected result. Thank you again for this little helpful routine.