Page 1 of 1
Documentation about CopyStructure()
Posted: Sat Mar 01, 2025 8:18 am
by Joubarbe
The destination structure will be automatically cleared before doing the copy, it's not needed to call ClearStructure before CopyStructure. Warning: the destination should be a valid structure memory area, or a cleared memory area. If the memory area is not cleared, it could crash, as random values will be used by the clear routine.
From what I understand, it says to not use ClearStructure as it is done automatically, then it emphasises on the necessity of the structure to be cleared. How can it not be cleared, if ClearStructure is internally done?
Re: Documentation about CopyStructure()
Posted: Sat Mar 01, 2025 11:36 am
by AZJIO
ClearStructure, ResetStructure
I have tried several times to understand how these functions work and when to apply them. But I postponed it for later, because my level of knowledge is not enough to understand.
Re: Documentation about CopyStructure()
Posted: Sat Mar 01, 2025 2:41 pm
by mk-soft
The structure functions should only be used on memories that are also created with AllocateStructure or in conjunction with AllocateMemory and InitializeStructure.
AllocateStructure is always the better option:
- because AllocateStructure automatically executes InitializeStructure.
- because with FreeStructure, ClearStructure is automatically executed and thus the contents are also released. (Except for own handles or IDs)
With AllocateStructure, the structure information is also saved. The pointer to the structure information is at *StructInfo = (*MemPointer - SizeOf(Integer))
This means that FreeStructure(*MemPointer) can be called without structure information, as the structure information is known.
The structure information is complex and recursive with offsets and type identifiers. This information is internal to PB and is not available as an SDK (which is not needed)
CopyStructureMemory and FreeStructureMemory was implemented by me in 2009 and then added by Fred as standard in version 4.40 and 4.50.
Re: Documentation about CopyStructure()
Posted: Sat Mar 01, 2025 3:00 pm
by #NULL
As far as I understand, there are historic reason for some of those functions.
With normal variables there is nothing to be done, even if they are of type Array, Map, List, String or of a structure type that contains those, as the compiler will initialize everything correctly when the variable is declared/created and will reset/free everything when the variable goes out of scope, like at the end of a function for example.
When Arrays, Maps, Lists in Structures came around, because you can AllocateMemory() and assign it to / use it with a pointer to a structure, there was a need to tell PB that it should set up the allocated memory correctly so that such items are ready to use: InitializeStructure().
Likewise, before you FreeMemory() such allocated memory, you need to tell PB to to free any internally used memory and management of those items to avoid leaks: ClearStructure()
Then, for convenience and to avoid errors, AllocateStructure() (allocate and initialize) and FreeStructure() (clear and free) where introduced.
ResetStructure() is like ClearStructure() + InitializeStructure() and is probably just another convenience function if you want to reuse a structure (allocated or not) as empty, making sure none of your old data get in the way and Strings, Arrays, Maps, Lists are empty but usable.
As for CopyStructure(), the doc text is really not very good.
- from the example code given, I would think that indeed ClearStructure() is called automatically beforehand.
- it's not clear to me whether you *could* call ClearStructure() beforehand, or if this is wrong. Or how PB would know when to ClearStructure it or when it is bare allocated (not structure-initialized) memory or if only AllocateStructure()ed memory should be used with it, not an AllocateMemory()ed uninitialized one. My guess is that for example if PB encounters a non-null pointer where, according to the structure definition, a map would be, it will free the map. If there is a null pointer then the map is assumed to be already freed, or something like that. That's why the doc says "or a cleared memory area": you shouldn't pass an bare allocated memory (or any memory) containing random data to CopyStructure() because part of it could be interpreted as a map for example by accident and freed incorrectly. So if you have 'random' memory that was used in a different context, not according to the structure, you should memset it first with FillMemory() for example.
Re: Documentation about CopyStructure()
Posted: Sat Mar 01, 2025 3:23 pm
by Joubarbe
Thank you mk-soft and #NULL, you're always very helpful. I'm asking this question, because
once again, I'm running into random crashes in my game Roots of Harmony, and I use CopyStructure() quite a lot without ever using ClearStructure(). A typical case is when I save the Stat structure of a unit before combat, and restore it at the end; or when I copy some Object rules into an Object instance. I never do manual memory allocation (most of the time, source and destination are list elements).
It would be very weird that CopyStructure() would be the cause of the crashes just now, and not before, but you never know. Those crashes only started in 6.20, but then again, I have no way to tell if it's related.
Re: Documentation about CopyStructure()
Posted: Sat Mar 01, 2025 8:38 pm
by Joubarbe
Code: Select all
Structure _Stat
hp.i
attack.i
defence.i
EndStructure
Structure _Rule
id$
stats._Stat
EndStructure
Structure _Instance Extends _Rule
alias$
EndStructure
Define rules._Rule
rules\stats\hp = 15 : rules\stats\attack = 5 : rules\stats\defence = 3
Define instance._Instance
CopyStructure(rules\stats, instance\stats, _Stat)
instance\stats\hp - 5
Debug rules\stats\hp ; Outputs 15.
Debug instance\stats\hp ; Outputs 10.
Is it safe to do something like that?
Re: Documentation about CopyStructure()
Posted: Sat Mar 01, 2025 10:35 pm
by mk-soft
Yes
This is how it works, but the compiler checks whether the structures match. Internally, the compiler creates a call to SYS_CopyStructure.
Code: Select all
;CopyStructure(rules\stats, instance\stats, _Stat)
instance\stats = rules\stats
Re: Documentation about CopyStructure()
Posted: Sat Mar 01, 2025 10:59 pm
by Joubarbe
Wow, okay I didn't know you could do that... Thanks!
Re: Documentation about CopyStructure()
Posted: Sun Mar 09, 2025 9:06 am
by Joubarbe
mk-soft wrote: Sat Mar 01, 2025 10:35 pm
Yes
This is how it works, but the compiler checks whether the structures match. Internally, the compiler creates a call to SYS_CopyStructure.
Code: Select all
;CopyStructure(rules\stats, instance\stats, _Stat)
instance\stats = rules\stats
Actually when you use pointers everywhere, CopyStructure() seems unavoidable.
Code: Select all
Structure _ObjectStats
hp.i
attack.i
defence.i
EndStructure
Structure _ObjectRule Extends _ObjectStats
id$
EndStructure
Structure _ObjectInstance Extends _ObjectRule
alias$
stats_before_combat._ObjectStats
EndStructure
Define instance._ObjectInstance
instance\attack = 2
Define *instance_p._ObjectInstance = @instance
CopyStructure(*instance_p, *instance_p\stats_before_combat, _ObjectStats)
*instance_p\attack + 1
Debug *instance_p\attack ; Outputs 3.
CopyStructure(*instance_p\stats_before_combat, *instance_p, _ObjectStats)
Debug *instance_p\attack ; Outputs 2.
I'd like to know if this code is safe?
Re: Documentation about CopyStructure()
Posted: Sun Mar 09, 2025 8:59 pm
by Demivec
Joubarbe wrote: Sun Mar 09, 2025 9:06 amI'd like to know if this code is safe?
Yes it's safe.
The key points to keep it safe are that first, both the source and destination structured memory areas being used as parameters to CopyStructure() have been properly initialized (at least once) or if it's the destination it may also contain only zeroes and secondly, the memory areas match the structure parameter.
Re: Documentation about CopyStructure()
Posted: Sun Mar 09, 2025 9:31 pm
by Joubarbe
Thanks for your answer Demivec. I fail to understand how the copy is done when I extend a structure 1 to a structure 2, and that a structure 3 has an object of structure 2, like in my example. All structures extended FROM are first in memory?
Re: Documentation about CopyStructure()
Posted: Sun Mar 09, 2025 10:14 pm
by Demivec
Joubarbe wrote: Sun Mar 09, 2025 9:31 pm
Thanks for your answer Demivec. I fail to understand how the copy is done when I extend a structure 1 to a structure 2, and that a structure 3 has an object of structure 2, like in my example. All structures extended FROM are first in memory?
Here's a 'text image' to explain this:
Code: Select all
Structure _ObjectStats: hp.i
attack.i
defence.i
Structure _ObjectRule Extends _ObjectStat: id$
Structure _ObjectInstance Extends _ObjectRule: alias$
stats_before_combat._ObjectStats
;A pointer to any of the structures _ObjectStats, _ObjectRule or _ObjectInstance
; will each point to the memory where the field hp is stored.
;A copy is made made by copying the memory starting at the first field through
; the last field.
Re: Documentation about CopyStructure()
Posted: Mon Mar 10, 2025 9:36 am
by Joubarbe
Got it!
