[Implemented] CopyStructure()
[Implemented] CopyStructure()
I didn't realize until just now that there is no way to copy a structure (with it's data)..
It'd be nice to have a CopyStructure() and some way to compare whole structures (and the data within).
It'd be nice to have a CopyStructure() and some way to compare whole structures (and the data within).
-Mitchell
Check out kBilling for all your billing software needs!
http://www.k-billing.com
Code Signing / Authenticode Certificates (Get rid of those Unknown Publisher warnings!)
http://codesigning.ksoftware.net
Check out kBilling for all your billing software needs!
http://www.k-billing.com
Code Signing / Authenticode Certificates (Get rid of those Unknown Publisher warnings!)
http://codesigning.ksoftware.net
-
- Enthusiast
- Posts: 767
- Joined: Sat Jan 24, 2004 6:56 pm
in C I would do something like
Can't something similar be done in Pure?
Code: Select all
memcopy(source, dest, sizeof(structure));
// source & dest being pointers to previously allocated memory here
Last edited by dell_jockey on Sun Mar 28, 2004 11:23 pm, edited 1 time in total.
-
- Enthusiast
- Posts: 423
- Joined: Fri Apr 25, 2003 5:22 pm
- Contact:
Here's a workaround, but it doesn't work with strings atm.
But I would apprentice a CopyStructure()-command, too !
Code: Select all
Structure mystruct ; must not contain strings
a.b
b.w
c.l
d.l[20]
EndStructure
s1.mystruct
s1\a = 1
s1\b = 2
s1\c = 3
s1\d[11] = 4
*s2.mystruct = AllocateMemory(SizeOf(mystruct))
CopyMemory(@s1, *s2, SizeOf(mystruct))
s1\a = 11
s1\b = 12
s1\c = 13
s1\d[11] = 14
Debug s1\a
Debug s1\b
Debug s1\c
Debug s1\d[11]
Debug *s2\a
Debug *s2\b
Debug *s2\c
Debug *s2\d[11]
%1>>1+1*1/1-1!1|1&1<<$1=1
-
- Enthusiast
- Posts: 767
- Joined: Sat Jan 24, 2004 6:56 pm
-
- Enthusiast
- Posts: 423
- Joined: Fri Apr 25, 2003 5:22 pm
- Contact:
- Psychophanta
- Always Here
- Posts: 5153
- Joined: Wed Jun 11, 2003 9:33 pm
- Location: Anare
- Contact:
Allocate memory isn't needed, coz when you define a variable, you are allocating memory for it.
Keep in mind that a structure is a variable with one or more fields data stored SEQUENTIALLY in mem. So, Froggerproger's example should be more coherent:
...and of course, if you define a linked list with whatever data structure, you can copy one existing element to another using CopyMemory(@list1(), @list2(), memoryamount).
And also you can copy only one or more data fields inside a structure, or copy a field to another, etc.; for example: CopyMemory(@list1()+4, @list2()+8, 4).
Keep in mind that a structure is a variable with one or more fields data stored SEQUENTIALLY in mem. So, Froggerproger's example should be more coherent:
Code: Select all
Structure mystruct ; can contain strings but keep in mind that a string variable is in fact, a pointer to a characters string.
a.b
b.w
df.s[10]
c.l
d.l[20]
EndStructure
s1.mystruct
s1\a = 1
s1\b = 2
s1\df[5]="hola tu"
s1\c = 3
s1\d[11] = 4
s2.mystruct
CopyMemory(@s1, @s2, SizeOf(mystruct))
s1\a = 11
s1\b = 12
s1\c = 13
s1\d[11] = 14
Debug s1\a
Debug s1\b
Debug s1\c
Debug s1\d[11]
Debug s2\a
Debug s2\b
Debug s2\df[5]
Debug s2\c
Debug s2\d[11]
And also you can copy only one or more data fields inside a structure, or copy a field to another, etc.; for example: CopyMemory(@list1()+4, @list2()+8, 4).
-
- Enthusiast
- Posts: 423
- Joined: Fri Apr 25, 2003 5:22 pm
- Contact:
@Psycho
Yes, of course, this method you mentioned is the more elegant way (and the first way that should come to mind - normally)
But does anybody has an idea how to solve the string-problem ?
I think there's no NextStructureElement() and TypeOf() - command to step sequentially through the structure to find all strings and duplicate them manually.
So is there any general workaround for that?
(The CopyStructure() should do this of course)
Yes, of course, this method you mentioned is the more elegant way (and the first way that should come to mind - normally)

But does anybody has an idea how to solve the string-problem ?
I think there's no NextStructureElement() and TypeOf() - command to step sequentially through the structure to find all strings and duplicate them manually.
So is there any general workaround for that?
(The CopyStructure() should do this of course)
%1>>1+1*1/1-1!1|1&1<<$1=1
I am confused. (Situation normal)
If the structure is copied as is, and the structure contains addresses of strings, surely everything is ok as the string addresses remain the same.
So if "ABC" is at address 1,650,000 and the structure field points to 1,650,000, then moving the structure (and therefore the field) to another address has no impact. The field still points to 1,650,000
What am I missing here?
If the structure is copied as is, and the structure contains addresses of strings, surely everything is ok as the string addresses remain the same.
So if "ABC" is at address 1,650,000 and the structure field points to 1,650,000, then moving the structure (and therefore the field) to another address has no impact. The field still points to 1,650,000
What am I missing here?
What if some code changes the value in s2. It will also update s1.What am I missing here?
At the moment the behaviour appears to be as follows:
If the new string fits into the space allocated for the original string both s1 and s2 will contain the new value.
If the string is larger than the space allocated then s2 will contain the new
value but s1 will contain something unpredictable. When the memory is deallocated it wil contain a null value. However, that memory may be reallocated elsewhere.
Code: Select all
Structure mystruct ; can contain strings but keep in mind that a string variable is in fact, a pointer to a characters string.
a.b
b.w
df.s[10]
c.l
d.l[20]
EndStructure
s1.mystruct
s1\a = 1
s1\b = 2
s1\df[5]="hola tu"
s1\c = 3
s1\d[11] = 4
s2.mystruct
CopyMemory(@s1, @s2, SizeOf(mystruct))
s1\a = 11
s1\b = 12
s1\c = 13
s1\d[11] = 14
Debug s2\df[5]
Debug @s2\df[5]
Debug s1\df[5]
Debug @s1\df[5]
s2\df[5]="changed the string"
Debug s2\df[5]
Debug @s2\df[5]
Debug s1\df[5]
Debug @s1\df[5]
The following link explains how it is done in C++, using copy-on-write:
http://www.cppinaction.com/book/tech/6lib.html
Good a similar scheme be used in Purebasic, Fred?
Perhaps the compiler could flag strings within copied structures. When one of these is written too then a new string is allocated and just that structure is updated. I'm sure all of this could be done at compile time with no runtime cost.
http://www.cppinaction.com/book/tech/6lib.html
Good a similar scheme be used in Purebasic, Fred?
Perhaps the compiler could flag strings within copied structures. When one of these is written too then a new string is allocated and just that structure is updated. I'm sure all of this could be done at compile time with no runtime cost.
The problem is that the struct only stores the pointer to the string (long value, 4 bytes) so you are never actually copying the data - only a pointer!
According to Bericko there is no solution as yet, that's why I suggested the feature!
According to Bericko there is no solution as yet, that's why I suggested the feature!
-Mitchell
Check out kBilling for all your billing software needs!
http://www.k-billing.com
Code Signing / Authenticode Certificates (Get rid of those Unknown Publisher warnings!)
http://codesigning.ksoftware.net
Check out kBilling for all your billing software needs!
http://www.k-billing.com
Code Signing / Authenticode Certificates (Get rid of those Unknown Publisher warnings!)
http://codesigning.ksoftware.net
-
- Enthusiast
- Posts: 423
- Joined: Fri Apr 25, 2003 5:22 pm
- Contact:
Okay, I had the time and made a workaround:
The following procedure can duplicate a structure including all data-types, arrays and further structures, but it has one important limitation:
It is designed is this way, that you must specify an offset-position, before that all data is interpretated as numerical values (so it's just copied), and all further data is interpretated as stringpointers.
So you have to sort your structure in this way, that first all numeric data is mentioned, and then all the strings.
(Only if you definitely want to copy the stringpointer, not the stringdata, you could left this string inside the 'numerical' area)
The biggest problem was, that pb doesn't simply allocate fixed 64k for each string, but handles the position and the allocated length dynamically. So you could easily ran into problems with using PokeS() on Stringspointer that show to shorter strings. e.g. the following crashes:
The trick now is, that the procedure calls the Space()-function on the targetstring before calling PokeS(). But to keep it general this had to happen from ASM, because we cannot explicite call the string's variablename.
So, blahblah, here it is (it's not THAT much code, the most of it is the example and comments)
The following procedure can duplicate a structure including all data-types, arrays and further structures, but it has one important limitation:
It is designed is this way, that you must specify an offset-position, before that all data is interpretated as numerical values (so it's just copied), and all further data is interpretated as stringpointers.
So you have to sort your structure in this way, that first all numeric data is mentioned, and then all the strings.
(Only if you definitely want to copy the stringpointer, not the stringdata, you could left this string inside the 'numerical' area)
The biggest problem was, that pb doesn't simply allocate fixed 64k for each string, but handles the position and the allocated length dynamically. So you could easily ran into problems with using PokeS() on Stringspointer that show to shorter strings. e.g. the following crashes:
Code: Select all
str.s = "test"
PokeS(@str, Space(50000))
So, blahblah, here it is (it's not THAT much code, the most of it is the example and comments)
Code: Select all
Declare CopyStructure(*posfrom.l, *posto.l, structuresize.l, stringoffset.l)
;- CopyStructure(*posfrom.l, *posto.l, structuresize.l, stringoffset.l)
;- copies the content of one structure to another of same type
;- It may include all types inclusive strings, arrays and other structures.
;- IMPORTANT: The whole structure (at it's 'highest level' - if it contains also structures)
;- must be sorted in this way, that first >all< the numeric values are listed,
;- which are then followed by >all< the strings.
;-
;- *posfrom = pointer to the structure you want to copy from
;- *posto = pointer to the structure/memoryarea you want to copy to
;- structuresize = SizeOf('Structure')
;- stringoffset = OffsetOf(FirstStringInStructure) In fact you may use a higher value than this,
;- if you explicitely want to copy only the pointer to the string, so that it would not
;- be duplicated.
dummystring.s = Space(0) ;this one is NECCESSARY unless you call the Space()-function anywhere else in your code
Procedure CopyStructure(*posfrom.l, *posto.l, structuresize.l, stringoffset.l)
Protected tempS.s, tempSLen.l, *actposto.l ; [esp+20], [esp+24], [esp+28]
; first copy all the numeric values inside the structure
CopyMemory(*posfrom, *posto, stringoffset)
; now process all the strings
While stringoffset < structuresize
; read in the actual string. If it is not specified until now, interpret it as an empty string
If PeekL(*posfrom + stringoffset) <> 0
tempS = PeekS(PeekL(*posfrom + stringoffset))
Else
tempS = ""
EndIf
; store it's length
tempSLen = Len(tempS)
; calculate the position of the targetstring-pointer
*actposto = *posto + stringoffset
; The following block calls the Space()-function via ASM for the target-string,
; that returns a pointer to a new string of sufficient allocated memory
; and probably deletes the previous one.
; If this code is left out, the program would crash in some cases (e.g. sourcesize >> allocated stringsize)
; for the 'PB_Space'-call-environment it is neccessary, that somewhere else in code Space() is called
!PUSH dword [PB_StringBase]
!MOV eax, dword [esp+24] ; size for Space() = tempSLen
!CALL PB_Space
!MOV ecx, [esp+28]
!POP edx
!CALL SYS_AllocateString
; now write the string to the pointer stored by the above Space()-call
PokeS(PeekL(*actposto), tempS)
stringoffset + 4 ; 4 = SizeOf(STRING)
Wend
EndProcedure
;-
;- an example:
;-
Structure numericOnly
num1.l
num2.l
EndStructure
Structure stringsOnly
str1.s
str2.s
EndStructure
Structure mystr
num1.f
num2.b
num3.w
num4.l
nums.l[10]
morenums.numericOnly ; until here no strings
str1.s ; from here on no numeric values
str2.s
strs.s[10]
morestr.stringsOnly
EndStructure
; define a new instance of this structure and fill it with some data
; (it is not neccessary for CopyStructure() that the values have been defined before calling it)
s1.mystr
s1\num1 = 1.111
s1\num2 = 2
s1\num3 = 3
s1\num4 = 4
For i=0 To 9
s1\nums[i] = 5+i
Next
s1\morenums\num1 = 15
s1\morenums\num2 = 16
s1\str1 = "Hello"
s1\str2 = "World"+Space(30000)
For i=0 To 9
s1\strs[i] = "Number "+Str(i)
Next
s1\morestr\str1 = "structure in structure string 1"
s1\morestr\str2 = "structure in structure string 2"
; define another one and fill it with some data
s2.mystr
s2\num2 = 21
s2\str2 = "Happy New Year"
; Now call the Copy-procedure
CopyStructure(@s1, @s2, SizeOf(mystr), OffsetOf(mystr, str1))
; Let's see what has 'arrived' in s2
Debug s2\num1
Debug s2\num2
Debug s2\num3
Debug s2\num4
For i=0 To 9
Debug s2\nums[i]
Next
Debug s2\morenums\num1
Debug s2\morenums\num2
Debug s2\str1
Debug s2\str2
For i=0 To 9
Debug s2\strs[i]
Next
Debug s2\morestr\str1
Debug s2\morestr\str2
; destroy the data in s1
Debug ""
Debug "xxxxxxxxxxxxxx scrumbling the data in s1................."
Debug ""
For i=0 To 1000
PokeB(@s1 + Random(SizeOf(mystr)), Random(255))
Next
; Let's see what's left in s2
Debug s2\num1
Debug s2\num2
Debug s2\num3
Debug s2\num4
For i=0 To 9
Debug s2\nums[i]
Next
Debug s2\morenums\num1
Debug s2\morenums\num2
Debug s2\str1
Debug s2\str2
For i=0 To 9
Debug s2\strs[i]
Next
Debug s2\morestr\str1
Debug s2\morestr\str2
End
%1>>1+1*1/1-1!1|1&1<<$1=1