HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

KaTaNNa Code Safe Update

07-17-2008, 11:53 PM#1
Captain Griffen
Disclaimer: This code is ugly. The bits for purging are a disaster (I'll probably redo them; any ideas on methology would be nice). It is considerably slower than KaTaNNa's system. You should not use this code for new code, nor should you use KaTaNNa's code either - both are very much outdated.

So - why would you use this code? Basically, the idea is you can just replace KaTaNNa's code with this, and it'll make the system safe, in two ways:

- No more I2H, which can get wrong handle types. (With the exception of pseudo-handles, which aren't handles, just have handle type, and act differently, believed to be safe.)
- If the subject has changed, data will NOT carry forward, even for the same handle type. (This was dropped, but won't affect you if your code was correct to start with - this is designed to fix blizzard bugs, not your buggy code; can be fixed for units by PurplePoot's RemovalDetection system.)

If your map is already lagging, for the love of all that is holy and unholy, redo your code totally, as this will only make your laggy code worse. If you don't want to or cannot redo the code, are not lagging, and are using KaTaNNa's system, then you might want to implement this to get that extra safety.

If that sounds like you, then reply here. Do not use the code yet except for testing. I have not fully tested or polished it (mainly the code for dealing with flushing of indexes).

Oh, and if at any point you are using more than 8000 handle / int / string / boolean / real data values, things'll go to pot (it'll purge it after 8000, getting rid of those without a correct subject / that's been flushed off; if it's still over 8000, then it'll do it again, and again, and again...which'll lag like crazy, I guess). That'd be 16 bits of data on 500 handles (for example), which is quite a lot, although I suppose possible.

Updated, now works fine with any amount of data. However, in the event that your handle indexes go above the maximum, it'll die. The maximum is set to 73710 atm, which should be more than ample, I think. (you'd need to leak more than 1000 indices a minute for an hour). The implementation no longer needs purging separately to deal with flushing. It's now a very neat, if very slow, implementation. For strings, booleans, integer and real attachements, there is almost no difference in speed, despite the added safety. Handle attachments are over 2 times slower, however.

In response to making the H2I function private, the H2I function was provided by the KaTTaNa system for all below it, and hence is provided by this for that as well; anything else could break compatability, and thus misses the whole point of the exercise.

Updated again: Fixed a HUGE bug that was taking every handle index it touched hostage. Removed, and now it won't do that at all. Further more, it should now run faster, since the GetIndex function (which should now be inlined) doesn't need to have a check in it. As a result, it requires the RemovalDetection script.

Needed: http://www.wc3campaigns.net/showthread.php?t=102588


Erm...yea, give me a bit to try and work out a new version that doesn't take over handle indexes.

Updated AGAIN: Now should be fine, no more handle index leaks, since they get cleaned by a nice efficient way (the exception to this is effects, locations and a few others; triggers and timers are deliberately not recycled, so as to avoid the bugs associated with that). This relies upon at least one get (that isn't a generic handle get) being called on each handle, and on your coding being correct (but it'll bug less with this than under KaTaNNa's for those of you with buggy code due to your own crap coding). Locations can easily be added, but only if you have a function for getting locations directly and use it (rather than getting it as a handle then type casting to location). That isn't in the KaTaNNa code I have, but it'd be fairly easy to add it, just drop me a PM or something.

Pseudo handles now use I2H. Since they aren't actually handles, and aren't involved in the handle stack, that should be safe. If you only attach one type of pseudohandle (eg: just lightning), then you could avoid using I2H, but it shouldn't be anything to worry about. Attaching to pseudohandles is okay, but attaching to more than one type of pseudohandle could cause collisions, same as with KaTaNNa's.

Long story short, if you coded correctly for KaTaNNa's system, this shouldn't bug, but will be a bit slower, if you didn't code correct for it, this'll be slower and still safer, but you may still get bugs due to your own coding (obviously).

Anyway, the code:

Expand JASS:
07-18-2008, 12:21 AM#2
moyack
Set the H2I function private and add a constant string, so the user can change easily the gamecache filename. Everything else looks fine and elegant.

I'll do a test when I finish some setups of my linux box.
07-18-2008, 12:24 AM#3
Rising_Dusk
Of course, you could also just use StoreInteger() to store a struct to anything that can then point to whatever data you'd want it to. :)
07-18-2008, 03:36 AM#4
darkwulfv
And Dusk's method is probably a lot safer. That's what I do, personally. Attach struct with SetHandleInt, then get it where I need it.

EDIT: I also just scanned the code I have (KaTaNNa's), and I see no use of "I2H" anywhere; only "H2I" and "I2S". unless "I2H" is used in a way I'm not seeing, or I have a more recent version... or something.
07-18-2008, 03:59 AM#5
Rising_Dusk
KaTTaNa's Handle Vars abuses the return bug to return integers to their respective types. The problem is that you can return any integer to a type; there is no type safety, thus handle indexing corruptions cause the game to go haywire and break.

Something like GetHandleUnit() abuses such I2H conversions. (Integer to Handle)
07-18-2008, 04:49 AM#6
darkwulfv
Collapse JASS:
    function GetHandle$TYPECAP$ takes handle subject, string name returns $TYPELOWER$
        local cachehandle ch = GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
        if ch.subject == subject then
            return ch.value
            return null
        else
            return null
        endif
    endfunction
Looks very very similar to:

Collapse JASS:
function GetHandleHandle takes handle subject, string name returns handle
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction

They use similar data retrieval methods (I2S(H2I(subject))). I guess I must be missing something, so pardon my ignorance if I am.

Whatever, I'll trust that CG's is safer and whatnot, and I'll wait for an official release to use it. It works like the previous Handle Vars, right? call SetHandlehandle and call GetHandleHandle etc.?
07-18-2008, 09:20 AM#7
Captain Griffen
Quote:
Of course, you could also just use StoreInteger() to store a struct to anything that can then point to whatever data you'd want it to. :)

Then the code would need to be updated to use a new syntax, at which point you really shouldn't be using the code. This is more of a hot-fix for system/maps that may still use it.

Quote:
Originally Posted by darkwulfv
Collapse JASS:
    function GetHandle$TYPECAP$ takes handle subject, string name returns $TYPELOWER$
        local cachehandle ch = GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
        if ch.subject == subject then
            return ch.value
            return null
        else
            return null
        endif
    endfunction
Looks very very similar to:

Collapse JASS:
function GetHandleHandle takes handle subject, string name returns handle
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction

They use similar data retrieval methods (I2S(H2I(subject))). I guess I must be missing something, so pardon my ignorance if I am.

Whatever, I'll trust that CG's is safer and whatnot, and I'll wait for an official release to use it. It works like the previous Handle Vars, right? call SetHandlehandle and call GetHandleHandle etc.?

Whoops, I just forgot to remove the 'return null' in the GetHandleXXX. Since it's actually stored in a handle variable, it's perfectly safe and doesn't need to abuse the return bug for I2H.

And yes, the syntax is exactly the same. Code that works with the old should work almost the same with this; the only difference should be the improved safety (no transference between subjects due to recycling, no I2H mistaken returns) and the somewhat reduced performance.

I should re-iterate that it isn't designed to be used for new code, but to fix old code easily. (Although if speed isn't important, and you don't use the FlushHandle function, then it should be perfectly viable and safe, if very slow, alternative that is very flexible).
07-18-2008, 10:42 AM#8
d07.RiV
Can you tell me how is it better than this:
Collapse JASS:
//! textmacro GetSetHandle takes TYPE, TYPENAME
function SetHandle$TYPENAME$ takes handle subject, string name, $TYPE$ value returns nothing
  if value == null then
    call FlushStoredInteger (hcache, I2S (H2I (subject)), "$type$" + name)
  else
    call StoreInteger (hcache, I2S (H2I (subject)), "$type$" + name, H2I (value))
  endif
endfunction
function GetHandle$TYPENAME$ takes handle subject, string name returns $TYPE$
  return GetStoredInteger (hcache, I2S (H2I (subject)), "$type$" + name)
  return null
endfunction
//! endtextmacro

And what do you mean by "If the subject has changed, data will NOT carry forward"?
Doesn't comparing handles give the same result as comparing their H2I's?
07-18-2008, 11:03 AM#9
Captain Griffen
Quote:
Originally Posted by d07.RiV
Can you tell me how is it better than this:
Collapse JASS:
//! textmacro GetSetHandle takes TYPE, TYPENAME
function SetHandle$TYPENAME$ takes handle subject, string name, $TYPE$ value returns nothing
  if value == null then
    call FlushStoredInteger (hcache, I2S (H2I (subject)), "$type$" + name)
  else
    call StoreInteger (hcache, I2S (H2I (subject)), "$type$" + name, H2I (value))
  endif
endfunction
function GetHandle$TYPENAME$ takes handle subject, string name returns $TYPE$
  return GetStoredInteger (hcache, I2S (H2I (subject)), "$type$" + name)
  return null
endfunction
//! endtextmacro

And what do you mean by "If the subject has changed, data will NOT carry forward"?
Doesn't comparing handles give the same result as comparing their H2I's?

I2H is bad. That's what KaTTaNa's system uses to return handle type objects. This can result in all sorts of bad stuff happening. We have several threads on why it's bad, so look them up, as otherwise this thread will get deluged by it.

And comparing handles doesn't give the same result as their H2Is, as handle variables keep a reference, which means that, when a handle is recycled, it doesn't incorrectly carry stuff over. Hmm...I should probably have it return null/0 when a null subject is used.
07-18-2008, 01:03 PM#10
Vexorian
A lot of people that use handle vars don't clean the stuff properly, so I'd say this will eventually end up using all available slots...
07-18-2008, 01:49 PM#11
Captain Griffen
Quote:
Originally Posted by Vexorian
A lot of people that use handle vars don't clean the stuff properly, so I'd say this will eventually end up using all available slots...

When it purges, it removes those on subjects that have since turned to null. That should avoid the issue; it depends on how much lee-way there is on real slot usage, how long handles are around, etc. I may need to change it to use big arrays and manually deal with stuff.
07-18-2008, 02:30 PM#12
darkwulfv
I'm just not fully understanding where the Handle Vars I use (I posted an example) used I2H, because I see it nowhere, and the data retrieval lines are exactly the same between that and this system. Maybe I have a weird offshoot of KaTTaNa's system, or this has a safety feature I'm not seeing somewhere.

But if, for example, I took the old one out and plugged this one in, it would basically keep everything the same? (I wouldn't have to run around and change function calls?)
07-18-2008, 02:47 PM#13
Captain Griffen
Quote:
Originally Posted by darkwulfv
I'm just not fully understanding where the Handle Vars I use (I posted an example) used I2H, because I see it nowhere, and the data retrieval lines are exactly the same between that and this system. Maybe I have a weird offshoot of KaTTaNa's system, or this has a safety feature I'm not seeing somewhere.

KaTaNNa's system uses the return bug to typecast from integer to handle (it doesn't actually use a function called I2H, but it uses the same principle). That is unsafe. It also has no protection against handle recycling.

Quote:
But if, for example, I took the old one out and plugged this one in, it would basically keep everything the same? (I wouldn't have to run around and change function calls?)

That is the entire point of it.
07-18-2008, 02:54 PM#14
darkwulfv
Alright, I think I understand now. It just didn't make sense to me when your system used (what looked like) almost the exact same setup, just with structs and privates and the like. I do see the comparison checks in there for recycling safety and stuff though, which is good.
07-18-2008, 03:53 PM#15
d07.RiV
Why would a handle become 0 if you don't set it to 0?
Its like

integer a = 2
integer b = a
set a = 0
B IS NOT 0 ?!?

How is it different with handles? Unless blizzard were really high when they made it, because anyone in right mind would have at least made proper reference counting.