[Snippet] RawCodeIndexer

This snippet just makes my life easier. I won't have to keep saving data into hashtables,
I can simply use arrays and store data based on some index below 8190.
It may seem stupid to you, but it makes things seem a bit more readable for me.

JASS:
/*******************************************
*
*   RawCodeIndexer
*   v2.0.0.0
*   By Magtheridon96
*
*   - Generates a very small index for very large integers. (For array storage)
*   - Basically a wrapper.
*
*   Optional Requirements:
*   ----------------------
*
*       - Table by Bribe
*           - hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
*
*   API:
*   ----
*
*       - function RawCode2Id takes integer rawCode returns integer
*           - Converts a RawCode to an Id. GetRawCodeId will be usable at this point. (It's much faster and inlines)
*       - function Id2RawCode takes integer id returns integer
*           - Converts an Id to a raw code. (inlines)
*       - function GetRawCodeId takes integer rawCode returns integer
*           - Retrieves the Id for a given raw code (0 if not converted with RawCode2Id at least once) (inlines)
*
*******************************************/
library RawCodeIndexer requires optional Table
    
    globals
        private integer array codes
        private integer count = 0
    endglobals
    
    static if LIBRARY_Table then
        private module Init
            private static method onInit takes nothing returns nothing
                set tb = Table.create()
            endmethod
        endmodule
    endif
    
    private struct Hash extends array
        static if LIBRARY_Table then
            static Table tb
            implement Init
        else
            static hashtable ht = InitHashtable()
        endif
    endstruct
    
    // Just to make RawCode2Id look shorter
    private function SetRawCodeId takes integer raw, integer id returns nothing
        static if LIBRARY_Table then
            set Hash.tb[raw] = id
        else
            call SaveInteger(Hash.ht, raw, 0, id)
        endif
    endfunction

    function GetRawCodeId takes integer raw returns integer
        static if LIBRARY_Table then
            return Hash.tb[raw]
        else
            return LoadInteger(Hash.ht, raw, 0)
        endif
    endfunction

    function RawCode2Id takes integer i returns integer
        local integer x = GetRawCodeId(i)
        if x == 0 then
            set x = count + 1
            set count = x
            call SetRawCodeId(i, x)
            set codes[x] = i
        endif
        return x
    endfunction
    
    function Id2RawCode takes integer id returns integer
        return codes[id]
    endfunction
    
endlibrary

Feel free to comment..
 
Last edited:

LeP

LeP

Level 10
Joined
Feb 13, 2008
Messages
498
I don't think this is any useful (not before i've seen any usecase, and then one still has to evaluate the usecase).

So you store an integer inside some hashtable because you don't want to use a hashtable to store something on rawcodes?

Then i *think* a plain old selfmade hashtable would be actually faster than this.

And finaly why do i have to register the code myself? Why not simply return a new index if the rawcodes was not found inside the hashtable?
 

BBQ

BBQ

Level 4
Joined
Jun 7, 2011
Messages
97
And finaly why do i have to register the code myself? Why not simply return a new index if the rawcodes was not found inside the hashtable?
That's probably because Magtheridon96 wanted the GetId function to be inline-friendly, but I agree with you. There is no point in manual indexing.
 
It's not about speed. I said so myself, this is a wrapper that makes things easier to read.
BBQ, you're right about why I added manual indexing.

edit

I was going to call this IntegerIndexer, but that made it sound extremely pointless :x

I don't think this is any useful (not before i've seen any usecase, and then one still has to evaluate the usecase).

Well, I only coded it because I was just about to use it in a system of mine.

edit

Updated.
Kept it at 1.x.x.x because I doubt anyone's been using it.
 
Level 6
Joined
Jun 20, 2011
Messages
249
RawCode is an accurate name because this aims to index numbers that are above the 8192 limit which happen to be RawCodes and Handles (not sure how these two would collide)
I find this very useful, not so sure about that "automatic" allocation you wrote there to index new rawcodes when you ask for their index... mabe the user should manually index them for faster retrieval
 
IMO, automatic indexing is better. Manual indexing would kinda ruin the point of the system. (since it would probably easier to just recode it yourself)

Two hashtable lookups won't kill performance or anything like that. Overall, this is a nice system for a better interface when dealing with rawcodes. To some it might not be useful, but there are definitely a lot of times where I need to store data in accordance to some object's id, so this system makes it a bit less of a hassle. gj ;)
 
Level 38
Joined
Sep 26, 2009
Messages
8,465
This is a way simpler version of Catalog. Catalog generates IDs for high integers, but is mostly used for save/load and therefore has a ton of code bloat if you JUST want high-integer indexing.

I recommend you simplify it for faster repeat-returns:

JASS:
            local integer @[email protected] = LoadInteger(Hash.ht, i, 0)
            if @[email protected] == 0 then
                set @[email protected] = count + 1
                set count = @[email protected]
                call SaveInteger(Hash.ht, i, 0, @[email protected])
                set codes[@[email protected]] = i
            endif
            return @[email protected]

I think this is useful and I could also use it for my WarChasers map.

I recommend you to include a version which just "returns 0" if the index was not there already. Like a version which gets AND indexes (which you already have), complimented with a version that just returns (if you want to ignore things which weren't indexed).
 
Level 38
Joined
Sep 26, 2009
Messages
8,465
For the personal resources, I recommend just keeping them on your computer and maybe as a pastebin backup...

I have a lot of edited resources optimized for my specific needs, though I don't upload them ;)

I mean this resource is good for squishing integers for array-safe references, so I am down with it. If anyone wants to cry about me approving this, I will be very upset. This is a fun resource for use in conjunction with arrays, call me crazy.

Though I recommend adding this to users' API:

JASS:
    function GetRawCodeIdSimple takes integer raw returns integer
        static if LIBRARY_Table then
            return Hash.tb[raw]
        else
            return LoadInteger(Hash.ht, raw, 0)
        endif
    endfunction

Because sometimes you want to get the index, other times you just want to see if someone else created the index already. For example I could use this with SpellEffectEvent.
 
I will add something like that, but I wanna see if I can find a different name :eek:

Maybe I should change this system so that the functions are:

JASS:
function RawCode2Id takes integer raw returns integer
function Id2RawCode takes integer id returns integer
function GetRawCodeId takes integer raw returns integer

RawCode2Id would initialize the Id for the raw code while GetRawCodeId would simply return it :D
Makes a lot of sense in practice ^>^

JASS:
function exists takes nothing returns boolean
    return GetRawCodeId('hfoo') != 0
endfunction

function create takes nothing returns integer
    return RawCode2Id('hfoo')
endfunction

function convertBack takes nothing returns integer
    return Id2RawCode(1)
endfunction
 
Level 17
Joined
Jan 21, 2006
Messages
2,545
Great now I can... wait... what can I do that I couldn't before?

Does this just associate values that are higher than the array limit with values that are lower than the limit? I'm curious what I can do now that instead of having to hall around a "large" integer I can simply hall around a small one? What's the difference? They're both probably 4 bytes of memory.
 
Great now I can... wait... what can I do that I couldn't before?

Does this just associate values that are higher than the array limit with values that are lower than the limit? I'm curious what I can do now that instead of having to hall around a "large" integer I can simply hall around a small one? What's the difference? They're both probably 4 bytes of memory.

It is mostly an interface system. It will just allow for neater codes and prettier handling of things. =)
 
Table by Bribe is way better
Can Table by vexorian let you create a struct instance per raw code?
Not without checks and booleans.
This is just an interface for those who don't like spamming Tables for conversion
You'd have one table that would associate a raw code with a small integer instead of writing your own snippets within each library
See, this also helps modularity
I'm using it for an item type struct
Allocation is done by simply setting the instance to RawCode2Id
 
Level 31
Joined
Jul 10, 2007
Messages
6,307
Really now...

JASS:
library RawCode uses Table, Event

private module Init
    private static method onInit takes nothing returns nothing
        set table = Table.create()
        set onIndex = Event.create()
    endmethod
endmodule
struct RawCode extends array
    private static Table table
    private static integer count = 0
    readonly static Event onIndex = 0
    readonly static integer eventIndex = 0
    readonly static integer eventRawCode = 0

    private static method onIndex takes integer index, integer rawCode returns nothing
        local integer prevIndex = eventIndex
        local integer prevRawCode = eventRawCode

        set eventIndex = index
        set eventRawCode = rawCode

        call onIndex.fire()

        set eventIndex = prevIndex
        set eventRawCode = prevRawCode
    endmethod

    static method operator [] takes integer rawcode returns integer
        local integer index = table[rawcode]
        if (0 == index) then
            set index = count + 1
            set count = index
            set table[rawcode] = index
            call onIndex(index, rawCode)
        endif
        return index
    endmethod

    implement Init
endstruct

endlibrary

Ofc, you could also do a .exists property for faster speeds, but considering how often things will be indexed, I think that the above is more suitable to promote ease of use and maintainability.
 
Level 31
Joined
Jul 10, 2007
Messages
6,307
If you have structs that generate for that index?

The event was just an idea ;p. Ofc, you'd probably always do it on init. The event is probably a bad idea.


Anyways, something like this is prob perfect.
JASS:
library RawCode uses Table

private module Init
    private static method onInit takes nothing returns nothing
        set table = Table.create()
    endmethod
endmodule
struct RawCode extends array
    private static Table table
    private static integer array id
    private static integer count = 0

    static method operator [] takes integer rawcode returns integer
        local integer index = table[rawcode]
        if (0 == index) then
            set index = count + 1
            set count = index
            set table[rawcode] = index
            set id[index] = rawCode
        endif
        return index
    endmethod
    method operator raw takes nothing returns integer
        return id[this]
    endmethod

    implement Init
endstruct

endlibrary

Examples
RawCode['hpea'] -> index
RawCode(1).raw -> raw code


You could also get rid of the [] and change it to index instead.
RawCode['hpea'].index -> index
RawCode[1].raw -> raw

which is probably better anyways. I'm essentially just showing you that your API is pretty bad ;p.
 
Level 38
Joined
Sep 26, 2009
Messages
8,465
I think if the struct & library would be renamed to "RawCodeId", "operator raw" was renamed to "method getCode" or "operator code", and there was another method named "get" or some similar name which returns the ID *only* if the rawcode was already indexed, *then* your system is *probably* "perfect".
 
Nes, I actually like that second one.
Unfortunately, it isn't so user-friendly ;/
Maybe I can work something out though:

JASS:
struct RawCode extends array
    static method r2I takes integer raw returns integer
    static method i2R takes integer index returns integer
endstruct

Simple and straight-forward, but not too beautiful.

or

JASS:
struct RawCode extends array
    static method operator [] takes integer rawOrIndex returns integer
endstruct

RawCode['hpea'] -> 1
RawCode[1] -> 'hpea'

Since Raw codes are always going to be in the range of 800,000,000-2,100,000,000, I can never have indexing errors :D
All it really does is make me use the same Table for the i2R function :p

Awesome idea bro :D
 

LeP

LeP

Level 10
Joined
Feb 13, 2008
Messages
498
[...]
Since Raw codes are always going to be in the range of 800,000,000-2,100,000,000, I can never have indexing errors :D
[...]

It does not realy matter, but rawcodes are in [16_843_009, 2_122_219_134] (at least that are the lowest and highest values i could produce with 4 char rawcodes).
 
It looks fine to me :p
I already finished coding it and I debugged it (works flawlessly):

JASS:
/*******************************************
*
*   RawCodeIndexer
*   v3.0.0.0
*   By Magtheridon96
*
*   - Generates a very small index for very large integers. (For array storage)
*   - Basically a wrapper.
*
*   Optional Requirements:
*   ----------------------
*
*       - Table by Bribe
*           - hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
*
*   API:
*   ----
*
*       - struct RawCode extends array
*
*           - static method operator [] takes integer int returns integer
*               - This function converts a raw code to an index or 
*                 returns the raw code corresponding to a certain index.
*
*******************************************/
library RawCodeIndexer requires optional Table
    
    static if LIBRARY_Table then
        private module Init
            private static method onInit takes nothing returns nothing
                set data = Table.create()
            endmethod
        endmodule
    endif
    
    struct RawCode extends array
        
        private static integer count = 0
        
        static if LIBRARY_Table then
            private static Table data
            implement Init
        else
            private static hashtable data = InitHashtable()
        endif
        
        private static method getPointer takes integer i returns integer
            static if LIBRARY_Table then
                return data[i]
            else
                return LoadInteger(data, i, 0)
            endif
        endmethod
        
        private static method link takes integer i, integer j returns nothing
            static if LIBRARY_Table then
                set data[i] = j
            else
                call SaveInteger(data, i, 0, j)
            endif
        endmethod
        
        static method operator [] takes integer i returns integer
            local integer x = getPointer(i)
            if x == 0 then
                if i > 16843008 then
                    set x = count + 1
                    set count = x
                    call link(x, i)
                    call link(i, x)
                endif
            endif
            return x
        endmethod
    endstruct
    
endlibrary

It works like linking (You'd link integers to eachother)
RawCode[1] -> something
RawCode[something] -> 1
Makes sense :D
 
Level 17
Joined
Jan 21, 2006
Messages
2,545
Why don't you use 2 structs, one for the RawCodeIndex operator and one for a IndexRawCode operator.

JASS:
RawCodeIndex['h000'] = 1
IndexRawCode[1] = 'h000'

You already have the functions that do this.

By the way, your layout destroys inheritance. What if I wanted to extend this for:
JASS:
struct UnitRawCode extends RawCode
struct ItemRawCode extends RawCode

Then I could have functions that take a RawCode and perform a set of actions which may differ if the raw-code is from a unit or an item. Of course determining these things would have to be done in the sub-structs because you can't really determine what is an item or a mutated raw-code for a unit.

The extension of the array is pretty useless. Obviously it doesn't make sense to destroy raw-codes so that isn't a problem. The only thing extending the array does is make polymorphism more difficult.
 
Using all your feedback and because I don't like to disappoint anyone, this is the API for now:

JASS:
function RawCode2Id takes integer rawCode returns integer
function Id2RawCode takes integer id returns integer
function GetRawCodeId takes integer rawCode returns integer

struct RawCode extends array
    static method i2R takes integer id returns integer
        - Wrapped by Id2RawCode
    static method r2I takes integer rawCode returns integer
        - Wrapped by RawCode2Id
    static method getId takes integer rawCode returns integer
        - Wrapped by GetRawCodeId
endstruct

Sorry, but .raw and .id weren't working out because I didn't know what to make them wrappers of while keeping the methods inline-friendly and the system functional and user-friendly at the same time :/

edit
Didn't see your comment there Berb, one sec ;P

edit
Well, IndexRawCode doesn't look good to me :/
I need to make an API that users could use easily and get the hang of :c

edit

JASS:
/*******************************************
*
*   RawCodeIndexer
*   v3.0.0.0
*   By Magtheridon96
*
*   - Generates a very small index for very large integers. (For array storage)
*   - Basically a wrapper.
*
*   Optional Requirements:
*   ----------------------
*
*       - Table by Bribe
*           - hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
*
*   Notes:
*   ------
*
*       - GetRawCodeId and RawCode.getId will return 0 if RawCode2Id or RawCode.r2I have 
*         not been called for a certain raw code. GetRawCodeId and RawCode.getId are inline
*         friendly that way.
*       - Id2RawCode and RawCode.i2R will return 0 for invalid Ids.
*
*   API:
*   ----
*
*       - struct RawCode extends array
*
*           - static method operator i2R takes integer id returns integer
*               - Converts an integer to its corresponding raw code
*           - static method operator r2I takes integer raw returns integer
*               - Generates/Gets an integer associated with a given raw code
*           - static method operator getId takes integer raw returns integer
*               - Gets the integer associated with a given raw code (Inline friendly)
*
*       - function GetRawCodeId takes integer raw returns integer
*           - Gets the integer associated with a given raw code (Inline friendly)
*       - function RawCode2Id takes integer raw returns integer
*           - Generates/Gets an integer associated with a given raw code
*       - function Id2RawCode takes integer id returns integer
*           - Converts an integer to its corresponding raw code
*
*******************************************/
library RawCodeIndexer requires optional Table
    
    static if LIBRARY_Table then
        private module Init
            private static method onInit takes nothing returns nothing
                set data = Table.create()
            endmethod
        endmodule
    endif
    
    struct RawCode extends array
        
        private static integer array codes
        private static integer count = 0
        
        static if LIBRARY_Table then
            private static Table data
            implement Init
        else
            private static hashtable data = InitHashtable()
        endif
        
        private static method getIndex takes integer raw returns integer
            static if LIBRARY_Table then
                return data[raw]
            else
                return LoadInteger(data, raw, 0)
            endif
        endmethod
        
        private static method setIndex takes integer raw, integer index returns nothing
            static if LIBRARY_Table then
                set data[raw] = index
            else
                call SaveInteger(data, raw, 0, index)
            endif
        endmethod
        
        static method r2I takes integer raw returns integer
            local integer x = getIndex(raw)
            if x == 0 then
                set x = count + 1
                set count = x
                call setIndex(raw, x)
                set codes[x] = raw
            endif
            return x
        endmethod
        
        static method i2R takes integer id returns integer
            return codes[id]
        endmethod
        
        static method getId takes integer raw returns integer
            return getIndex(raw)
        endmethod
    endstruct
    
    function RawCode2Id takes integer raw returns integer
        return RawCode.r2I(raw)
    endfunction
    
    function Id2RawCode takes integer id returns integer
        return RawCode.i2R(id)
    endfunction
    
    function GetRawCodeId takes integer raw returns integer
        return RawCode.getId(raw)
    endfunction

    // Textmacro for indexers will go here
    
endlibrary

Any objections?
I will update the system if no objections are made in the next 24 hours. Good bye for now.

edit

Just noticed:

By the way, your layout destroys inheritance. What if I wanted to extend this for:

You shouldn't be doing that o_O
I can provide you with a small textmacro before I update :eek:
 
Last edited:
Level 17
Joined
Jan 21, 2006
Messages
2,545
What do you mean I shouldn't be doing that?

JASS:
interface RawCodeInterface 
    method createDummy takes nothing returns nothing defaults nothing
endinterface

struct rawcode extends RawCodeInterface
    // struct members:
    private integer rawcode

    // static members:
    private static hashtable reftable = InitHashtable()
    
    // operator []
    //      allows the user to obtain the struct associated with the
    //      specified raw-code
    static method operator [] takes integer raw returns integer
        return LoadInteger(reftable, raw, 0)
    endmethod
    
    // operator .raw
    //      returns the integer raw-code associated with this struct
    method operator raw takes nothing returns integer
        return (this.rawcode)
    endmethod
    
    // constructor:
    static method create takes integer raw returns thistype
        local thistype r = allocate()
        set r.rawcode = raw
        call SaveInteger(reftable, raw, 0, r)
        return r
    endmethod
endstruct

struct UnitRawCode extends rawcode
    method createDummy takes nothing returns nothing
        call CreateUnit(Player(0), this.raw, 0, 0, 0)
    endmethod
endstruct

struct ItemRawCode extends rawcode
    method createDummy takes nothing returns nothing
        call CreateItem(this.raw, 0, 0)
    endmethod
endstruct


function UseRawCode takes rawcode raw returns nothing
    call raw.createDummy()
endfunction


function IsUnitRawCode takes rawcode raw returns boolean
    return (raw.getType() == UnitRawCode.typeid)
endfunction

function IsItemRawCode takes rawcode raw returns boolean
    return (raw.getType() == ItemRawCode.typeid)
endfunction

I don't know where you get your facts from. Inheritance is one amazing quality of vJass over JASS. Text-macros and modules are just what you seemed to have learned.

What you shouldn't be doing is extending an array for no reason.
 
Level 31
Joined
Jul 10, 2007
Messages
6,307
I don't know where you get your facts from. Inheritance is one amazing quality of vJass over JASS. Text-macros and modules are just what you seemed to have learned.

Eh, it comes from all of the stuff jasshelper generates, like the automatic trigger evaluations for onDestroy ;p. Inheritance is great yea, but the costs for doing it in JASS are also great. 99% of the time, you can get away without doing inheritance or with doing it another way.
 
I love inheritance (Pretty handy), but in vJass, it generates way too much garbage :/
I have to agree that the code you put up looks awesome, and I would totally use interfaces, but .. eh
Plus, I'm going to leave the struct to extend an array because I don't want it to generate 2 useless methods and other shit.

If you want, I could add some sort of data attachment feature so you could differentiate between raw codes ^.^

edit

You know what, I'm rewriting this resource so that it could have all the features and the efficiency at the same time.
Aiming to support:
- RawCode.type member (returns 0 if no type defined)
- RawCode data attachment
- RawCode indexing
- RawCode module interface for people who want to do some pretty weird shit.
 

LeP

LeP

Level 10
Joined
Feb 13, 2008
Messages
498
Eh, it comes from all of the stuff jasshelper generates, like the automatic trigger evaluations for onDestroy ;p. Inheritance is great yea, but the costs for doing it in JASS are also great. 99% of the time, you can get away without doing inheritance or with doing it another way.

99% of the time i don't care about the generated code.
 
Level 17
Joined
Jan 21, 2006
Messages
2,545
That really only causes a problem in few situations. This isn't one of them.

- RawCode.type member (returns 0 if no type defined)
- RawCode data attachment
- RawCode indexing
- RawCode module interface for people who want to do some pretty weird shit.

That was one abstract situation that I poorly attempted to make concrete (using the types I mean). There could be other abstract uses for this other than what type of raw-code it is, which is why inheritance is good. It allows you to keep what you've got, and add to it in any way you want without having to maintain the code you're extending from. OO.

99% of the time, you can get away without doing inheritance or with doing it another way.

Actually you can do it another way 100% of the time. But 99% of the time inheritance is a more simple approach to more complicated problems. The point isn't whether or not there are other ways. It seems the most sensible way of doing it. I'd prefer that over inserting code between module implementations any day.
 
Level 17
Joined
Jan 21, 2006
Messages
2,545
You should name the constants:
JASS:
public constant boolean BERBS_WAY 
public constant boolean NESTHARUSS_WAY

Why would you care though? There are so few utilizations of this that it makes no difference. It's not like thousands of objects can gain inheritance from this masterpiece, it was just something to think about. That's how I would do it, but you can do it however you want.
 
Level 38
Joined
Sep 26, 2009
Messages
8,465
Time Warp (http://www.hiveworkshop.com/forums/spells-569/time-warp-improved-166353) needed the module "Retro" to provide the efficiency for "onLoop". The way it was originally, it was lagging my computer (because there was an evaluation for each instance).

The less critical things like when a missile hits its target (rare) were extending Berb's "projectile" struct.

The thing is that people should keep in mind that evaluations are costly on performance, but only when these are events that happen lots of times per second.

The other thing to keep in mind, Berb, due to the way JassHelper parses the function ends up getting duplicates. This is why I have pressed to discourage function interfaces. This had nothing to do with Nestharus' opinions, I am simply not a fan of duplicated text.

From my experience, when someone is downloading a map on battle.net, they want to spend as little time as possible with the download, and function interfaces add lots of file size to a map.
 
Top