Copy and Swap of Structured Elements
- Kaeru Gaman
- Addict
- Posts: 4826
- Joined: Sun Mar 19, 2006 1:57 pm
- Location: Germany
Copy and Swap of Structured Elements
It would be nice to have a Swap and a Copy command for structured elements (e.g. within an array).
the swap should work via registers, not using a buffer.
should be a short and simple ASM-loop, easy to implement.
sure it demands using elements of the same structure,
but I think we could live with "professional" commands that just check for the size.
the swap should work via registers, not using a buffer.
should be a short and simple ASM-loop, easy to implement.
sure it demands using elements of the same structure,
but I think we could live with "professional" commands that just check for the size.
Last edited by Kaeru Gaman on Tue May 29, 2007 12:02 am, edited 1 time in total.
oh... and have a nice day.
I agree.
But, it should also work with structuredLinkedList-Elemnts and structures Variables!

But, it should also work with structuredLinkedList-Elemnts and structures Variables!
PB 4.30
Code: Select all
onErrorGoto(?Fred)
- Kaeru Gaman
- Addict
- Posts: 4826
- Joined: Sun Mar 19, 2006 1:57 pm
- Location: Germany
Now, it's partially possible...
It's only usuable for strings' structured arrays /!\
Between two arrays (thanks kaeru
), I wrote(edition of the ASM commented file) this procedure named ssCopy() (String Structure Copy)
It's only usuable for strings' structured arrays /!\
Between two arrays (thanks kaeru

Code: Select all
Procedure ssCopy(*a,*b, Size.L)
Goto OnPasseLInutile
UnTrucCommeCa.S = UneChoseCommeCa.S
OnPasseLInutile:
Global PrivateValueA0.L
For PrivateValueA0 = 0 To Size Step 4
! MOV ecx, dword [v_PrivateValueA0]
! MOV ebp,dword [esp + 0x10]
! MOV edx,dword [ebp + ecx]
! PUSH dword [_PB_StringBasePosition]
! CALL _SYS_CopyString@0
! MOV ecx, dword [v_PrivateValueA0]
! MOV ebp,dword [esp + 0x10]
! LEA ecx,[ebp+ecx]
! POP edx
! CALL SYS_AllocateString
Next
EndProcedure
Structure ID
Nom.S
Prenom.S
Adresse.S
EndStructure
Dim Perso.ID(99)
Perso(0)\Nom = "Durand"
Perso(0)\Prenom = "Jack"
Perso(0)\Adresse = "3 Rue des stockosses 25000 Fleury"
;La ligne qui couine dans la boucle For ci-dessous...
;Perso(I) = Perso(0)
For I = 1 To 5
ssCopy(Perso(I),Perso(0),SizeOf(ID)) ; ...remplacée par ssCopy()
Next
;...Et qui équivaudrait à ça:
; Perso(I)\Nom = Perso(0)\Nom
; Perso(I)\Prenom = Perso(0)\Prenom
; Perso(I)\Adresse = Perso(0)\Adresse
; On remplace la source pour vérifier que ce ne sont pas seulement les pointeurs qui ont été copiés...
Perso(0)\Nom = "Dupont"
Perso(0)\Prenom = "Patrick"
Perso(0)\Adresse = "2020 rue du fin fin"
For Index = 0 To 5
; ...Et on affiche le résultat
Debug Perso(Index)\Nom
Debug Perso(Index)\Prenom
Debug Perso(Index)\Adresse
Debug ""
Next
Last edited by Ollivier on Mon Aug 20, 2007 2:01 am, edited 1 time in total.
-
- Enthusiast
- Posts: 105
- Joined: Wed Jan 18, 2006 7:40 pm
- Location: Hamburg
Maybe this will help for a start:
Code: Select all
EnableExplicit
Macro SwapStructure(element1, element2, struc)
_SwapStructure(@element1, @element2, SizeOf(struc))
EndMacro
Procedure _SwapStructure(*element1, *element2, elementSize.l)
!mov ecx, [p.v_elementSize]
!mov eax, [p.p_element1]
!mov edx, [p.p_element2]
!pushfd
!push edi
!push esi
!cld
!mov edi, edx
!mov edx, $FFFFFFFC
!mov esi, eax
!and edx, ecx
!jz swapstructure_no_dword
!
!shr edx, 2
!swapstructure_dword_loop:
!mov eax, [edi]
!xchg eax, [esi]
!stosd
!dec edx
!lea esi, [esi + 4]
!jnz swapstructure_dword_loop
!
!swapstructure_no_dword:
!and ecx, 3
!jz swapstructure_no_byte
!
!swapstructure_byte_loop:
!mov al, [edi]
!xchg al, [esi]
!stosb
!dec ecx
!lea esi, [esi + 1]
!jnz swapstructure_byte_loop
!
!swapstructure_no_byte:
!pop esi
!pop edi
!popfd
EndProcedure
Structure st1
l.l
s.s
d.d
EndStructure
Define i.l
Dim a1.st1(3)
a1(1)\l = 12
a1(1)\s = "Swap1"
a1(1)\d = 34
a1(2)\l = 56
a1(2)\s = "Swap2"
a1(2)\d = 78
SwapStructure(a1(1), a1(2), st1)
For i = 0 To 3
Debug "Index " + Str(i)
Debug a1(i)\l
Debug "'" + a1(i)\s + "'"
Debug a1(i)\d
Debug ""
Next i
Debug ""
SwapStructure(a1(0), a1(2), st1)
For i = 0 To 3
Debug "Index " + Str(i)
Debug a1(i)\l
Debug "'" + a1(i)\s + "'"
Debug a1(i)\d
Debug ""
Next i
-
- Enthusiast
- Posts: 105
- Joined: Wed Jan 18, 2006 7:40 pm
- Location: Hamburg
Small improvement on the code, and I removed the "@" from the parameters,
the compiler will automaticly take the address for structures.
And now you can also swap elements of the same list by saving on liste-element address
and using this and the element you want swap directly.
But unfortunately, I can't offer a copy function,
there's no way to know what structure-element is a string,
and copying just the pointer would mean disaster.
Happy coding,
technicorn
the compiler will automaticly take the address for structures.
And now you can also swap elements of the same list by saving on liste-element address
and using this and the element you want swap directly.
But unfortunately, I can't offer a copy function,
there's no way to know what structure-element is a string,
and copying just the pointer would mean disaster.
Code: Select all
EnableExplicit
Macro SwapStructure(element1, element2, struc)
_SwapStructure(element1, element2, SizeOf(struc))
EndMacro
Procedure _SwapStructure(*element1, *element2, elementSize.l)
!pushfd
!push edi
!push esi
!mov ecx, [p.v_elementSize + 12]
!mov esi, [p.p_element1 + 12]
!mov edi, [p.p_element2 + 12]
!cld
!mov edx, $FFFFFFFC
!and edx, ecx
!jz swapstructure_no_dword
!
!shr edx, 2
!swapstructure_dword_loop:
!mov eax, [edi]
!xchg eax, [esi]
!stosd
!dec edx
!lea esi, [esi + 4]
!jnz swapstructure_dword_loop
!
!swapstructure_no_dword:
!and ecx, 3
!jz swapstructure_no_byte
!
!swapstructure_byte_loop:
!mov al, [edi]
!xchg al, [esi]
!stosb
!dec ecx
!lea esi, [esi + 1]
!jnz swapstructure_byte_loop
!
!swapstructure_no_byte:
!pop esi
!pop edi
!popfd
EndProcedure
Structure st1
l.l
s.s
d.d
b.b
EndStructure
Define i.l, *p
Dim a1.st1(3)
NewList l1.st1()
a1(1)\l = 12
a1(1)\s = "SwapArray1"
a1(1)\d = 34
a1(1)\b = -1
a1(2)\l = 56
a1(2)\s = "SwapArray2"
a1(2)\d = 78
a1(1)\b = -2
AddElement(l1())
AddElement(l1())
l1()\l = 120
l1()\s = "SwapList1"
l1()\d = 340
l1()\b = -3
AddElement(l1())
l1()\l = 560
l1()\s = "SwapList2"
l1()\d = 780
l1()\b = -4
AddElement(l1())
Debug "Swapping array elements:"
SwapStructure(a1(1), a1(2), st1)
For i = 0 To 3
Debug "Array index " + Str(i) + ": " + Str(a1(i)\l) + ", '" + a1(i)\s + "', " + StrD(a1(i)\d) + ", " + Str(a1(i)\b)
Next i
Debug ""
SwapStructure(a1(0), a1(2), st1)
For i = 0 To 3
Debug "Array index " + Str(i) + ": " + Str(a1(i)\l) + ", '" + a1(i)\s + "', " + StrD(a1(i)\d) + ", " + Str(a1(i)\b)
Next i
Debug "":Debug ""
Debug "Swapping list elements:"
SelectElement(l1(), 1)
; If you want to swap elements of the same list,
; you have to save on of the addresses
*p = @l1() ; Save address for first element to swap
NextElement(l1())
SwapStructure(*p, l1(), st1)
ForEach l1()
Debug "List index " + Str(ListIndex(l1())) + ": " + Str(l1()\l) + ", '" + l1()\s + "', " + StrD(l1()\d) + ", " + Str(l1()\b)
Next
Debug "":Debug ""
Debug "Swapping list/array elements:"
SelectElement(l1(), 1)
SwapStructure(a1(0), l1(), st1)
ForEach l1()
Debug "List index " + Str(ListIndex(l1())) + ": " + Str(l1()\l) + ", '" + l1()\s + "', " + StrD(l1()\d) + ", " + Str(l1()\b)
i + 1
Next
Debug ""
For i = 0 To 3
Debug "Array index " + Str(i) + ": " + Str(a1(i)\l) + ", '" + a1(i)\s + "', " + StrD(a1(i)\d) + ", " + Str(a1(i)\b)
Next i
technicorn
Thank you!
I think the real problem is the confusion between a long, a float, a pointor and a string (which is really a pointor too). Same size : 4 bytes.
One solution consists replacing the parameter 'size' by a string.
This string would be created at the same time that the structure writing.
Example:
To copy, we must specify this string 'StrucStruc' instead of specifying the global size of one field in the structure. We haven't better way.
What do you think so?
I think the real problem is the confusion between a long, a float, a pointor and a string (which is really a pointor too). Same size : 4 bytes.
One solution consists replacing the parameter 'size' by a string.
This string would be created at the same time that the structure writing.
Example:
Code: Select all
Structure Struc
Byte.B
Word.W
String.S
*Pointor
LongsTable.L[10]
EndStructure
StrucStruc.S = "BWS*L[10]"
What do you think so?
-
- Enthusiast
- Posts: 105
- Joined: Wed Jan 18, 2006 7:40 pm
- Location: Hamburg
But I think, that's more hassle to scan that string in a procedure to copy
things, than writing a special proc. for every struc. you want to copy.
To take your example:
But it would make your code just more readable, not faster, indeed it would slow it down,
with to overhead of proc. calling.
It would be faster to insert that code directly where you want to copy,
you could use a Macro to save typing and make code better readable.
That would still leave the problem of a pointer in the struc. pointing to another struc. with strings in it, than this code will shurely crash your prog.
And I wouldn't even consider to touch a struc. like this with a general copy routine:

things, than writing a special proc. for every struc. you want to copy.
To take your example:
Code: Select all
Procedure CopyStruc(*struc1.struc, *struc2.struc)
Protected memSize.l
*struc2\b = *struc1\b
*struc2\w = *struc1\w
*struc2\String = *struc1\String
If *struc1\Pointer
memSize = MemorySize(*struc1\Pointer)
*struc2\Pointer = ReAllocateMemory(*struc2\Pointer, memSize)
CopyMemory(*struc1\Pointer, *struc2\Pointer, memSize)
Else
FreeMemory(*struc2\Pointer)
*struc2\Pointer = 0
EndIf
CopyMemory(@*struc1\LongsTable[0], @*struc2\LongsTable[0], 40)
EndProcedure
with to overhead of proc. calling.
It would be faster to insert that code directly where you want to copy,
you could use a Macro to save typing and make code better readable.
That would still leave the problem of a pointer in the struc. pointing to another struc. with strings in it, than this code will shurely crash your prog.
And I wouldn't even consider to touch a struc. like this with a general copy routine:
Code: Select all
Structure NoCopyStruc
StructureUnion
st.AnotherStruc
s.s
b.b
d.d
EndStructureUnion
EndStructure

Since strings are special a solution would be to indicate which parts of the structure are strings and handle those seperately?
Or, perhaps the string copy can be handled in a seperate procedure altogether. You would first copy the structure (and its string pointers) then create new copies of the strings and overwrite the copied string pointers. This would requre having a list of which elements were strings(their offsets) in the structure similiar to what I gave above. I haven't come up with a calling method for parameters where strings are not grouped in a structure though.
Code: Select all
Structure foo
a.l
b.l
c.w
d.b
string1.s
string2.s
e.l
f.d
EndStructure
numStrings=2
CopyStruc(struc1.foo,struc2.foo,OffsetOf(foo\string1),numStrings)
@technicorn
>> To speed and not to speed
>> 'StructureUnion'
It's over! Like 'extends'
@demivec
I thank about 'compiling' image structure. It's near you are describing.
Syntax:
With it, structure description string changes into image structure memory area.
For example:
1) Basic structure
2) Structure Description String (That the programmer must recreate from basic structure)
3) Structure image (Stored in area memory) created by the procedure Struc()
[long]
>> To speed and not to speed

>> 'StructureUnion'

@demivec
I thank about 'compiling' image structure. It's near you are describing.
Syntax:
Code: Select all
*ImageStructure = Struc(StructureDescription.S)
For example:
1) Basic structure
Code: Select all
Structure X
Byte.B
Word.W
StringA.S
StringB.S
LongA.L
LongB.L
String.S[10]
Long.L[3]
EndStructure
Code: Select all
DescStruc.S = "BWSSLLS[10]L[3]"
[long]
Code: Select all
[Size of the structure (bytes) ]
[Number of string areas]
Area #1:
[Number of strings]
[Offset of the first string]
Area #2:
[Number of strings]
[Offset of the first string]
...
Area #n
[Number of strings]
[Offset of the first string]
Last edited by Ollivier on Sun Aug 26, 2007 8:52 am, edited 4 times in total.
Now, there's the copy procedure named sCopy().
As Technicorn said, speed of its execution is not as fast as a CopyMemory() but it can be used in lots of applications.
As Technicorn said, speed of its execution is not as fast as a CopyMemory() but it can be used in lots of applications.
Code: Select all
Procedure Struc(Input.S)
Structure StringAreaStruc
AreaStringQty.L
AreaOffset.L
EndStructure
Input = UCase(Input)
Static Intermed.S = ""
Static LInput.L
Static Char.S{1}
Static Actual.S{1}
Static Number.S = ""
Static DuppMode.L
Static i.L
Static j.L
Static Output.S
LInput = Len(Input)
For i = 1 To LInput
Char = Mid(Input, i, 1)
If Char = "]"
DuppMode = 0
Actual = Right(Intermed, 1)
For j = 2 To Val(Number)
Intermed + Actual
Next
Number = ""
Else
If Char = "["
DuppMode = 1
Else
If DuppMode
Number + Char
Else
Intermed + Char
EndIf
EndIf
EndIf
Next
Global NewList Area.StringAreaStruc()
Static StructureSize.L
Static IsString.L
Static StringQty.L
Static StringAreaQty.L
StringAreaQty = 0
Input = Intermed
LInput = Len(Input)
For i = 1 To LInput
Char = Mid(Input, i, 1)
If Char <> "S"
IsString = 0
EndIf
Select Char
Case "B"
StructureSize + 1
Case "W"
StructureSize + 2
Case "F"
StructureSize + 4
Case "L"
StructureSize + 4
Case "D"
StructureSize + 8
Case "Q"
StructureSize + 8
Case "*"
StructureSize + 4
Case "S"
If IsString = 0
If i = LInput
StringQty = 1
EndIf
For j = i + 1 To LInput
If Mid(Input, j, 1) <> "S"
StringQty = j - i
Break
EndIf
If j = LInput
StringQty = (LInput - i) + 1
EndIf
Next
AddElement(Area() )
Area()\AreaStringQty = StringQty
Area()\AreaOffset = StructureSize
StringAreaQty + 1
IsString = 1
StringQty = 0
EndIf
StructureSize + 4
EndSelect
Next
*Output = AllocateMemory(8 + StringAreaQty << 3)
*Start = *Output
PokeL(*Start, StructureSize)
*Start + 4
PokeL(*Start, StringAreaQty)
*Start + 4
ForEach Area()
PokeL(*Start, Area()\AreaStringQty)
*Start + 4
PokeL(*Start, Area()\AreaOffset)
*Start + 4
Next
ClearList(Area() )
ProcedureReturn *Output
EndProcedure
Procedure ssCopy(*a,*b)
Global ssCopyOffset.L
Goto OnPasseLInutile
UnTrucCommeCa.S = UneChoseCommeCa.S
OnPasseLInutile:
! MOV ecx, dword [v_ssCopyOffset]
! MOV ebp,dword [esp+16]
! MOV edx,dword [ebp+ecx]
! PUSH dword [_PB_StringBasePosition]
! CALL _SYS_CopyString@0
! MOV ecx, dword [v_ssCopyOffset]
! MOV ebp,dword [esp+16]
! LEA ecx,[ebp+ecx]
! POP edx
! CALL SYS_AllocateString
EndProcedure
Procedure sCopy(*Source, *Dest, *x)
*EndArea = 0
*Start = *x + 8
For Area = 1 To PeekL(*x + 4)
CopyMemory(*Source + *EndArea, *Dest + *EndArea, PeekL(*Start + 4) - *EndArea)
*StartString = PeekL(*Start + 4)
For String = 0 To PeekL(*Start) - 1
ssCopyOffset = *StartString + String << 2
ssCopy(*Dest, *Source)
Next
*EndArea = PeekL(*Start + 4) + 4 * PeekL(*Start)
*Start + 8
Next
CopyMemory(*Source + *EndArea, *Dest + *EndArea, PeekL(*x) - *EndArea)
EndProcedure
Example:
Structure Example
ID.L
Age.B
xx.B
yy.W
Hobby.S[3]
Born.L
Comment.S
Num.L
EndStructure
*Ex = Struc("LBBWS[3]LSL")
Dim St.Example(3)
St(0)\ID = 321
St(0)\Age = 29
St(0)\Hobby[0] = "Foot"
St(0)\Hobby[1] = "Hand"
St(0)\Hobby[2] = "Basket"
St(0)\born = 1978
St(0)\Comment = "No more informations"
St(0)\Num = 303030
sCopy(St(0), St(1), *Ex) ;<< Copy of the structure (Source, Dest and structure description pointor)
St(0)\Comment = "Other comment (modified after copy)"
St(0)\born = 1973
For i = 0 To 1
Debug "St(" + Str(i) + "):"
Debug St(i)\ID
Debug St(i)\Age
Debug St(i)\Hobby[0]
Debug St(i)\Hobby[1]
Debug St(i)\Hobby[2]
Debug St(i)\born
Debug St(i)\Comment
Debug St(i)\Num
Debug " "
Next