Massassi Forums Logo

This is the static archive of the Massassi Forums. The forums are closed indefinitely. Thanks for all the memories!

You can also download Super Old Archived Message Boards from when Massassi first started.

"View" counts are as of the day the forums were archived, and will no longer increase.

ForumsCog Forum → Heap Functions
Heap Functions
2004-12-28, 11:29 PM #1
This is going to be pretty long.
I wrote some documentation for the heap verbs, because the datamaster is definitely lacking, and is also wrong about a few things. There's also plenty of new stuff, it's worth reading through it all.



HeapNew(size);
Sets the size of the cog's heap to the value passed.
In terms of memory used, it will be about 16 bytes per element (enough room for storing vectors, floats, ints, etc.). Indices go from 0 to size - 1, so the first element is 0 and the last size - 1.
HeapNew(0) has no effect, it doesn't change the array size or the values stored in it. Calling HeapNew() with a size less than the current heap size will truncate the array, leaving the original values intact up to the new size. Calling HeapNew() with a size greater than the current size will destroy all existing values.
I have tested array sizes up to about 15 million, but beyond that point the values towards the end of the array will not be stored. The point at which this occurs may depend either on jk or on the available memory, but probably more on jk. Values that don't get stored due to this will just return 0 when using HeapGet(), but not crash. Values before the point where they are lost (near the beginning) work just fine.
Calling HeapNew() multiple times will not cause multiple heaps to be allocated; each time you call it, it resizes the array in memory, so the amount of memory used will just be based on the last call to HeapNew().
There is only one heap per instance of a cog, they don't overlap with other cogs in any way. Heaps (their values, memory consumption) will remain intact between levels if they are created in a cog that is always loaded (cogs from items.dat, which also retain their symbol/variable values between levels...), or if they are created in a cog that is loaded with the level then they will be unloaded on exiting the level.

The reason the datamaster shows this function as having two parameters and having a return value equal to the first parameter is because of how jk handles parameter passing in cogs. It's probably done like the printf functions in C, so it is designed to handle a variable number of arguments. If a function is passed more parameters than it needs, it will only use the number it needs from the right side, ie, if you pass 4 parameters, and it only needs 3, the 1st one will be ignored and the last 3 will be used. However, if the function has no return value, and you try to assign a variable to that function's return value (which doesn't exist), and you pass extra parameters, then one of the extra parameters will end up being assigned to the variable.
There is no start/end pointer stuff going on. There's only one heap per cog, and it always starts at index 0.



HeapSet(index, value);
Assigns a value to the index.
Flex, int, vector, etc. Indices go from 0 to size - 1.



HeapGet(index); returns stored value
Gets the value assigned to an index.
If the heap has not been allocated, returns 0. If the heap has been allocated, but no value has been assigned to that index, then jk crashes. So, you should only call this on an index that has had a value assigned with HeapSet() since the last call to HeapNew(), unless the last call to HeapNew() was to resize the array smaller, in which case the values in the heap should still be valid up to the new size. Calling HeapGet() with an index greater than the heap size just returns 0.



HeapFree();
HeapFree() should not be used in most cases; it appears to work correctly for small arrays (below a couple hundred elements), but either causes a crash on exiting jk (several hundred or more elements) or a crash in game after the 2nd call (several thousand or more elements). HeapFree()'s purpose is to free the heap and the memory associated with it. Since multiple calls to HeapNew() do not result in memory leaks, there is no real reason to use this function anyway. If you do need to free the memory associated with the cog's heap, you should use HeapNew(1), which does nearly the same thing (HeapNew(0) has no effect). You might want to do this if you are using the heap functions in a cog that stays resident after exiting the level, or if you will possibly be creating many heaps in different cogs.



Basically, indices go from 0 to size - 1, HeapNew() only takes one parameter, size, you shouldn't use HeapFree() (instead use HeapNew(1)), and there is no practical limit on the size of the array you can create. Performance, other than the existing speed of cogs, does not seem to be an issue aside from when allocating huge arrays there is a slight pause. Also, arrays created in cogs that remain active between levels will retain their heap values along with symbol values.

I think this should be kept somewhere, so it doesn't get lost in the forums...
Air Master 3D (my iPhone game)
My Programming Website
2004-12-29, 9:51 AM #2
I have tested some of this, and Sige is correct. (I always thought something was strange with the indexes not being 0 to size-1.)

I am noting this on the "Updates for DataMaster" list I will be sending to SaberMaster.

It will also go into the JKTechReference. (Yes, it has been awhile since the last update. *sigh*)

Thanks, Sige, for letting us know about this.

:)
2004-12-29, 5:03 PM #3
Interesting. From what little I remember of my own fiddling with the heap verbs, you seem to be correct on all counts.

The whole 'values being kept between levels' might seem like a bug at first (they certainly did to me), but it opens up interesting possiblities for coop missions in MP... :D
And when the moment is right, I'm gonna fly a kite.
2004-12-29, 8:37 PM #4
Quote:
Originally posted by Sige


The reason the datamaster shows this function as having two parameters and having a return value equal to the first parameter is because of how jk handles parameter passing in cogs. It's probably done like the printf functions in C, so it is designed to handle a variable number of arguments. If a function is passed more parameters than it needs, it will only use the number it needs from the right side, ie, if you pass 4 parameters, and it only needs 3, the 1st one will be ignored and the last 3 will be used. However, if the function has no return value, and you try to assign a variable to that function's return value (which doesn't exist), and you pass extra parameters, then one of the extra parameters will end up being assigned to the variable.
There is no start/end pointer stuff going on. There's only one heap per cog, and it always starts at index 0.




Right you are Sige - I never realized that an extra parameter on the end will be returned by the function. So
Code:
PrintInt(Print(5, "Blah"));
will print out:
Code:
Blah
5


And ZeqMacaw, send me what you have on your list, so I can get everything fixed.
Author of the JK DataMaster, Parsec, Scribe, and the EditPlus Cog Files.
2004-12-29, 8:45 PM #5
Well, I think the reason why they are kept between levels is just because the cog itself is never unloaded until you actually quit jk. The ones that get loaded at startup do this, and they don't get reset or have anything done to them when exiting a level. Other cogs that get loaded when loading the level, like a door or elevator cog, would get unloaded (along with their heap) when you exit the level.

edit--
You'd think it wouldn't make much sense to have some cogs load at startup and most others when loading the level, but I think the reason why is just because jk needs to be able to setup the hotkeys for certain items, and it wants those items to have the same address throughout the whole time jk is running. I'm pretty sure it's just the cogs referenced in items.dat that work like this.
Air Master 3D (my iPhone game)
My Programming Website
2004-12-30, 9:30 AM #6
Yay for research. :D
-Hell Raiser
2004-12-30, 6:06 PM #7
Does this mean anything new, or just better reference material? (For those of us who know nothing of cog)
ᵗʰᵉᵇˢᵍ๒ᵍᵐᵃᶥᶫ∙ᶜᵒᵐ
ᴸᶥᵛᵉ ᴼᵑ ᴬᵈᵃᵐ
2004-12-30, 6:10 PM #8
Mostly just better reference material. But I think now that these functions are better documented, maybe they will be put to more use, in which case maybe people will find some new uses for them. Things like carrying over information between levels, and perhaps keeping track of large numbers of things (for ai or whatever).


Oh, and of course, stuff like what HR is doing with sprite systems based on things.
Air Master 3D (my iPhone game)
My Programming Website
2004-12-30, 6:22 PM #9
Can someone refresh me on what Heap basically is/does and how its usefulness as a function? :confused:
Cordially,
Lord Tiberius Grismath
1473 for '1337' posts.
2004-12-30, 6:31 PM #10
The heap functions are for creating an array of variables, of whatever size you want...
So, instead of listing out a bunch of variables by hand in the cog's symbols section, and then accessing them with an index (variable) you can use these functions to make a single array of any size. The size can be changed after it's created too.

So, as a simple example, to store the numbers 1,2,3,4,5 in the cog's heap, you'd do the following:

HeapNew(5);
for (n = 0; n < 5; n++)
{
HeapSet(n, n + 1); // n is the index, n + 1 is the value being stored
}

Then, to access one of the stored values, you'd use
HeapGet(i), where i is the index of the value's location in the heap.

You can use pretty much any variable type with HeapSet and HeapGet, so, you can store flex, int, vector, etc. I'm not sure about model/sound/template variables, but I think they are just numbers so maybe you can store them too.

Most cogs probably don't have any use for these functions, or at least can get by just fine without them. However, they are very useful for handling large amounts of objects, or perhaps lookup tables (for approximating math functions).
Air Master 3D (my iPhone game)
My Programming Website
2004-12-30, 6:51 PM #11
Okay, here is an example use:

In a particular cog, I wanted to transform every vertex in a surface and store the results for a later calculation. The issue was that the surface could be any surface in any level, thus the cog had to handle a variable number of vertices with no known maximum.

Using an array in the symbols section would not work because that would have a maximum size. Any surface which had more vertices than the array allowed would mess up the calculations.

So, using the Heap verbs, the cog allocated as many heap slots as was needed during the surface calculations for a particular surface.

:)
2004-12-30, 8:08 PM #12
Ooh... brilliant.
Cordially,
Lord Tiberius Grismath
1473 for '1337' posts.

↑ Up to the top!