Page 1 of 2
Why is this code now broken in v6.12?
Posted: Sat Jan 25, 2025 9:19 pm
by Randy Walker
Einander gave us a very powerful code sample to insert or delete elements in an array:
https://www.purebasic.fr/english/viewto ... rtL#p36953
But it has a memory error when you try to run his example code. How can this be fixed? And Also, can we make this a feature request? -- insert(array()) , delete(array())
Re: Why is this code now broken in v6.12?
Posted: Sat Jan 25, 2025 9:40 pm
by STARGÅTE
If you run this old code under x64 processor, all pointers or buffer addresses have to be an integer type.
Code: Select all
Procedure DeleteL(DIR.i,ELEM.L,DM.L)
However, also CopyMemory() is miss-used in this code. For CopyMemory() the source and destination buffers may not overlap. But this is the case here. So you have to replace it with MoveMemory().
Besides that, this code wouldn't work for the last element, because the size in CopyMemory or MoveMemory have to be larger than 0.
This Code is not "powerful", it is just historical.
Re: Why is this code now broken in v6.12?
Posted: Sat Jan 25, 2025 10:01 pm
by Randy Walker
Oh but it is powerful, if you need to insert or delete elelments in an array. Maybe you have better way?
Anyway I checked value of @A() and determined from that I had encountered the classic All .L need to be changed to .i instead, so I did and code ran without any issue.
Thanks!!!
Re: Why is this code now broken in v6.12?
Posted: Sat Jan 25, 2025 10:56 pm
by STARGÅTE
But this code actually do not delete or insert an element. The array size keeps constant, it just moves the data.
If you insert an element in a full array, this code shifts out the last element.
Here is my version for DeleteArrayElement and InsertArrayElement, written as a macro, to allow multiple atomic data types for the arrays. However, such code (as well as the linked code) are not working with string-arrays or structured arrays.
Code: Select all
Macro DeleteArrayElement(ArrayName, Index)
If Index >= 0 And Index <= ArraySize(ArrayName())
If Index < ArraySize(ArrayName())
MoveMemory(@ArrayName(Index+1), @ArrayName(Index), @ArrayName(ArraySize(ArrayName()))-@ArrayName(Index))
EndIf
If ArraySize(ArrayName()) > 0
ReDim ArrayName(ArraySize(ArrayName())-1)
Else
FreeArray(ArrayName())
EndIf
EndIf
EndMacro
Macro InsertArrayElement(ArrayName, Index, Value)
If Index >= 0
If ArraySize(ArrayName()) = -1
Dim ArrayName(Bool(Index>=0)*(Index)) ; Bool(Index>=0) is needed here to prevent compiler error for index < 0
ElseIf Index > ArraySize(ArrayName())
ReDim ArrayName(Bool(Index>=0)*(Index)) ; Bool(Index>=0) is needed here to prevent compiler error for index < 0
Else
ReDim ArrayName(ArraySize(ArrayName())+1)
EndIf
If Index < ArraySize(ArrayName())
MoveMemory(@ArrayName(Index), @ArrayName(Index+1), @ArrayName(ArraySize(ArrayName()))-@ArrayName(Index))
EndIf
ArrayName(Index) = Value
EndIf
EndMacro
Macro ViewArray(ArrayName)
For I = 0 To ArraySize(ArrayName())
Debug "[" + I + "] = " + ArrayName(I)
Next
EndMacro
;- Example
Define Dim MyArray.f(3)
MyArray(0) = 1.0
MyArray(1) = 2.0
MyArray(2) = 3.0
MyArray(3) = 4.0
ViewArray(MyArray)
Debug "Delete:"
DeleteArrayElement(MyArray, 2)
ViewArray(MyArray)
Debug "Insert:"
InsertArrayElement(MyArray, 0, 3.25)
ViewArray(MyArray)
Debug "Insert:"
InsertArrayElement(MyArray, 7, 100)
ViewArray(MyArray)
Re: Why is this code now broken in v6.12?
Posted: Sun Jan 26, 2025 12:26 am
by Randy Walker
Ok. I got the original code to work properly. First all the .L variables had to be changed to .i instead and because I am running PB 64 bit the "4"values in both procedures had to be raised to "8". So here is Einander's code again tested and working for PB 64 bit (windows).:
Code: Select all
;By Einander - October 21 - 2003 - PB 3.80
;Procedure DeleteL(@Array(),ELEM,DM) deletes the item indexed by ELEM from Array.i().
; All array items whose indices are >= ELEM are shifted one position up.
; The value of the last element in the array is converted to 0.
Procedure DeleteL(DIR.i,ELEM.i,DM.i)
CopyMemory(DIR+(elem+1)*8,DIR+elem*8,(DM-elem)*8)
PokeL(DIR+DM*8,0)
EndProcedure
; Procedure Insert(VA,@Array,ELEM,DM) inserts VA in Array.i() at position ELEM.
; All items in Array.i whose indices are >= ELEM are moved one position down.
; The last element in ARRAY.i() is deleted with each Insert.
; Would be nice to icrease the size of the array to fit the last element.
Procedure InsertL(VA.i,DIR.i,ELEM.i,DM.i)
CopyMemory(DIR+elem*8,DIR+(elem+1)*8,(DM-elem)*8)
PokeL(DIR+ELEM*8,VA)
EndProcedure
;::::::::::::::::::::::::::::::::::::::::
DM=10
ELEM=5 ;Element to delete
Dim A.i(DM)
For I=0 To DM : A(I)=I : Next
Gosub TEST
Debug " "
DeleteL(@A(),ELEM,DM) ;deletes item 5
Debug "Deleted "+Str(ELEM)
Debug " "
Gosub TEST
InsertL(555,@A(),5,DM) ; inserts 555 at posic 5
Debug "Inserted 555"
Gosub TEST
MessageRequester("DONE","",0)
End
; :::::::::::::::::::::::::::::::::::
TEST:
For I=0 To DM
Debug Str(I)+" "+Str(A(I))
Next I
Return
Sorry guys. I forgot to mention I was working with 64 bit PB. Master of I/O errors.
Re: Why is this code now broken in v6.12?
Posted: Sun Jan 26, 2025 12:45 am
by ChrisR
STARGÅTE wrote: Sat Jan 25, 2025 10:56 pm
Here is my version for DeleteArrayElement and InsertArrayElement, written as a macro...
Very pretty and works perfectly
In InsertArrayElement both (Re)Dim ArrayName(Bool(Index>=0)*(Index)) can be simplified to (Re)Dim ArrayName(Index), Index >= 0 is tested before
Re: Why is this code now broken in v6.12?
Posted: Sun Jan 26, 2025 12:56 am
by miso
@Randy Walker
If you want to use that version, then PokeL()-s should be replaced with PokeI()-s, *4 for 32 bit, *8 for 64 bit. Still, Stargate's version is perfect, no need to update or fix anything.
Re: Why is this code now broken in v6.12?
Posted: Sun Jan 26, 2025 2:22 am
by Randy Walker
STARGÅTE wrote: Sat Jan 25, 2025 10:56 pm
Here is my version for DeleteArrayElement and InsertArrayElement, written as a macro
IIII Like it!!! It's beautiful!
THANKS STARGATE

Re: Why is this code now broken in v6.12?
Posted: Sun Jan 26, 2025 9:06 am
by STARGÅTE
ChrisR wrote: Sun Jan 26, 2025 12:45 am
STARGÅTE wrote: Sat Jan 25, 2025 10:56 pm
Here is my version for DeleteArrayElement and InsertArrayElement, written as a macro...
Very pretty and works perfectly
In InsertArrayElement both (Re)Dim ArrayName(Bool(Index>=0)*(Index)) can be simplified to (Re)Dim ArrayName(Index), Index >= 0 is tested before
Unfortunately not^^. Bool(Index>=0) is just a dummy to prevent evaluation during compilation.
Otherwise, for Index = -1, the Macro is evaluated to
Code: Select all
If -1 >= 0
If ArraySize(ArrayName()) = -1
Dim ArrayName(-1)
and then the compiler gives an error that Dim ArrayName(-1) have to be positive, even If -1 >= 0 would be false.
I can't use CompilerIf, because then Index must be a constant at all, which I don't want.
Re: Why is this code now broken in v6.12?
Posted: Sun Jan 26, 2025 9:54 am
by infratec
And for your 4 to 8 transitions, you should use
Else your code is not working in the x86 version of PB

Re: Why is this code now broken in v6.12?
Posted: Sun Jan 26, 2025 10:42 am
by ChrisR
STARGÅTE wrote: Sun Jan 26, 2025 9:06 am
Unfortunately not^^. Bool(Index>=0) is just a dummy to prevent evaluation during compilation.
Thanks for the explanation, not tested with Index = -1, nice workaround then

Re: Why is this code now broken in v6.12?
Posted: Sun Jan 26, 2025 9:13 pm
by Randy Walker
infratec wrote: Sun Jan 26, 2025 9:54 am
And for your 4 to 8 transitions, you should use
Else your code is not working in the x86 version of PB
Ok, this i a curious comment. When I try this code (below) I get syntax error on line 2. What did I do wrong?
a.i = 42
Debug SizeOf(a.i)
I tried the original code modified like this (below) but even on a 32 bit machine, it gave results that should happen only on a 64 bit machine. And of course both procedures failed to produce any results.
Code: Select all
;By Einander - October 21 - 2003 - PB 3.80
;Procedure DeleteL(@Array(),ELEM,DM) deletes the item indexed by ELEM from Array.i().
; All array items whose indices are >= ELEM are shifted one position up.
; The value of the last element in the array is converted to 0.
Global bits
a.i = 2147483648 ;<< This is max value for 4 byte integer Plus one!!!
If a.i = 2147483648
bits = 64
Debug "64 bit"
Else
Debug "32 bit"
EndIf
Procedure DeleteL(DIR.i,ELEM.i,DM.i)
If bits = 64
CopyMemory(DIR+(elem+1)*8,DIR+elem*8,(DM-elem)*8)
PokeL(DIR+DM*8,0)
Else
CopyMemory(DIR+(elem+1)*4,DIR+elem*4,(DM-elem)*4)
PokeL(DIR+DM*4,0)
EndIf
EndProcedure
; Procedure Insert(VA,@Array,ELEM,DM) inserts VA in Array.i() at position ELEM.
; All items in Array.i whose indices are >= ELEM are moved one position down.
; The last element in ARRAY.i() is deleted with each Insert.
; Would be nice to icrease the size of the array to fit the last element.
Procedure InsertL(VA.i,DIR.i,ELEM.i,DM.i)
If bits = 64
CopyMemory(DIR+elem*8,DIR+(elem+1)*8,(DM-elem)*8)
PokeL(DIR+ELEM*8,VA)
Else
CopyMemory(DIR+elem*4,DIR+(elem+1)*4,(DM-elem)*4)
PokeL(DIR+ELEM*4,VA)
EndIf
EndProcedure
;::::::::::::::::::::::::::::::::::::::::
DM=10
ELEM=5 ;Element to delete
Dim A.i(DM)
For I=0 To DM : A(I)=I : Next
Gosub TEST
Debug " "
DeleteL(@A(),ELEM,DM) ;deletes item 5
Debug "Deleted "+Str(ELEM)
Debug " "
Gosub TEST
InsertL(555,@A(),5,DM) ; inserts 555 at posic 5
Debug "Inserted 555"
Gosub TEST
MessageRequester("DONE","",0)
End
; :::::::::::::::::::::::::::::::::::
TEST:
For I=0 To DM
Debug Str(I)+" "+Str(A(I))
Next I
Return
I still get "64 bit" from the debug line when run on the 32 bit machine, so I'm very lost on this issue. Fortunately STARGATE provideed a working solution.
Re: Why is this code now broken in v6.12?
Posted: Mon Jan 27, 2025 6:25 am
by idle
use sizeof(integer)
Code: Select all
;By Einander - October 21 - 2003 - PB 3.80
;Procedure DeleteL(@Array(),ELEM,DM) deletes the item indexed by ELEM from Array.i().
; All array items whose indices are >= ELEM are shifted one position up.
; The value of the last element in the array is converted to 0.
Procedure DeleteI(DIR.i,ELEM.i,DM.i)
CopyMemory(DIR+(elem+1)*SizeOf(integer),DIR+elem*SizeOf(integer),(DM-elem)*SizeOf(integer))
PokeI(DIR+DM*SizeOf(integer),0)
EndProcedure
; Procedure Insert(VA,@Array,ELEM,DM) inserts VA in Array.i() at position ELEM.
; All items in Array.i whose indices are >= ELEM are moved one position down.
; The last element in ARRAY.i() is deleted with each Insert.
; Would be nice to icrease the size of the array to fit the last element.
Procedure InsertI(VA.i,DIR.i,ELEM.i,DM.i)
CopyMemory(DIR+elem*SizeOf(integer),DIR+(elem+1)*SizeOf(integer),(DM-elem)*SizeOf(integer))
PokeI(DIR+ELEM*SizeOf(integer),VA)
EndProcedure
;::::::::::::::::::::::::::::::::::::::::
DM=10
ELEM=5 ;Element to delete
Dim A.i(DM)
For I=0 To DM : A(I)=I : Next
Gosub TEST
Debug " "
DeleteI(@A(),ELEM,DM) ;deletes item 5
Debug "Deleted "+Str(ELEM)
Debug " "
Gosub TEST
InsertI(555,@A(),5,DM) ; inserts 555 at posic 5
Debug "Inserted 555"
Gosub TEST
MessageRequester("DONE","",0)
End
; :::::::::::::::::::::::::::::::::::
TEST:
For I=0 To DM
Debug Str(I)+" "+Str(A(I))
Next I
Return
Re: Why is this code now broken in v6.12?
Posted: Mon Jan 27, 2025 8:49 am
by IceSoft
See the different sizes:
Code: Select all
Debug SizeOf(Integer)
Debug SizeOf(Long)
Debug SizeOf(Word)
Debug SizeOf(Byte)
And last but Not least:
A PureBasic pointer variable should be ALWAYS a Integer like:
Re: Why is this code now broken in v6.12?
Posted: Mon Jan 27, 2025 10:56 am
by mk-soft
Better *myPointer