• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Distinguish between integer and struct?

Status
Not open for further replies.
Level 15
Joined
Aug 7, 2013
Messages
1,338
Hi,

Suppose I have a function that takes an integer as its single argument.

From inside that function, I have to return true if the integer actually points to a created struct, or false if it doesn't (therefore an integer).

Would this work?

JASS:
function isIntMyStruct takes integer i returns boolean
  local MyStruct my = i
  if my == 0 then
    return false
  endif
  return true
endfunction
 
Sadly, it isn't that straightforward.

The best way is to write your own allocation and then keep a field that keeps track of it. Theoretically, you could modify Sevion's Alloc just a little bit to get it to work for you:
JASS:
library Alloc 
    module Alloc
        private static integer instanceCount = 0
        private thistype recycle

        static method isInstance takes thistype instance returns nothing
            return instance.recycle == -1 // should get the job done
        endmethod
    
        static method allocate takes nothing returns thistype
            local thistype this
    
            if (thistype(0).recycle == 0) then
                debug if (instanceCount == 8190) then
                    debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Alloc ERROR: Attempted to allocate too many instances!")
                    debug return 0
                debug endif
                set instanceCount = instanceCount + 1
                set this = instanceCount
            else
                set this = thistype(0).recycle
                set thistype(0).recycle = thistype(0).recycle.recycle
            endif

            set this.recycle = -1
    
            return this
        endmethod
    
        method deallocate takes nothing returns nothing
            debug if (this.recycle != -1) then
                debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Alloc ERROR: Attempted to deallocate an invalid instance at [" + I2S(this) + "]!")
                debug return
            debug endif

            set this.recycle = thistype(0).recycle
            set thistype(0).recycle = this
        endmethod
    endmodule
endlibrary

All I did was remove the "debug" in front of "set this.recycle = -1", and add the "isInstance" function. Basically, setting that to -1 serves as a flag to determine that the instance is taken up. Upon deallocation, it'll use that knowledge to determine whether the instance was already destroyed (to prevent double-free errors, where you deallocate the same instance twice). You can also use it yourself to check if an instance exists.

The internal struct allocation does something like that, but we aren't given access to those variables (at least not in a clean way), so I recommend using your own allocation as shown above. Just implement it in your struct and you should be good to go. Just use "isInstance".
 
Level 15
Joined
Aug 7, 2013
Messages
1,338
Thank you again Purgeandfire for a very comprehensive and detailed answer.

So in the function I gave, it wouldn't really work, because when the int gets cast to the struct, it could actually be a valid struct (not a 1-1 correspondence between the two). I see why it doesn't work now.

I have read a lot about "Alloc" and allocation in structs. But I don't know exactly why there's so much discussion about it.

So if I understand correctly, any structs which extend array need to handle allocation/deallocation on their own? And Alloc library is the state of the art for allocating/deallocation any struct that extends array? Where would I put the code for Alloc in each struct?
 
So in the function I gave, it wouldn't really work, because when the int gets cast to the struct, it could actually be a valid struct (not a 1-1 correspondence between the two). I see why it doesn't work now.

Right. When you cast an integer to a struct, it doesn't check whether that struct exists. It just assumes you know what you're doing. :p

sethmachine said:
I have read a lot about "Alloc" and allocation in structs. But I don't know exactly why there's so much discussion about it.

It first started off as a disagreement with the way jasshelper allocates structs. It saves a variable or so, and it became common practice to use alloc instead of regular struct allocation. But IMO, just use the default one unless you really need to overwrite the allocation/deallocation for a good reason (such as this one).

sethmachine said:
So if I understand correctly, any structs which extend array need to handle allocation/deallocation on their own? And Alloc library is the state of the art for allocating/deallocation any struct that extends array? Where would I put the code for Alloc in each struct?

Yep. Extending array is kind of like creating a wrapper. It pretty much lets you use the struct syntax (dots, "this", etc.) without the usual allocation or deallocation. You can mix it up or completely ignore it, even.

"Alloc" is used as a better allocation method--one that is slightly more efficient than the standard one because the safety is debug-mode only and there is 1 fewer variable (or 2 fewer, if you use a different method).

You would implement alloc at the top of the struct, usually. e.g.:
JASS:
struct A
    implement Alloc
    
    real x
    real y
    
    // code
endstruct

Some people will put them after the variables. It doesn't really matter. But you generally want it above the other methods. If you try to call a method below your own method, jasshelper won't even attempt to rearrange the methods. It'll create copies and go through a convoluted method of evaluating it.
 
Status
Not open for further replies.
Top