• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[Textmacro] ArrayStructInit

Level 9
Joined
Aug 26, 2010
Messages
573

Content:



  1. Content
  2. Intro
  3. Macros
  4. API description (example here)
  5. Changelog


Intro:


I am not sure if such script doesn't exist, but if it doesn't I think it worth submission because it saves u some time if u work with array-structs.
I writed it for my SoD map recently when I understood I have to add dozen array-structs. Also thanks to Nestharus for his [thread=187477]Coding efficient vJASS structs[/thread] guide and Bribe for his Table lib.

Macros:


JASS:
//! textmacro ArrayStructCreateBegin takes createParams
    private static Table recicleNext
    private static thistype recicle = 0
    private static integer instanceCount = 0
    
    static method create takes $createParams$ returns thistype
        local thistype t
        if recicle == 0 then
            set instanceCount = instanceCount + 1
            set t = instanceCount
        else
            set t = recicle
            set recicle = recicleNext[recicle]
        endif
//! endtextmacro
//! textmacro ArrayStructCreateEnd
        return t
    endmethod
//! endtextmacro
//! textmacro ArrayStructDestroyBegin
    method destroy takes nothing returns nothing
        debug local thistype t
        debug if this != 0 then
            debug set t = recicle
            debug loop
                debug exitwhen t == 0 or t == this
                debug set t = recicleNext[t]
            debug endloop
            debug if t != this then
                set recicleNext[this] = recicle
                set recicle = this
//! endtextmacro
//! textmacro ArrayStructDestroyEnd
            debug else
                debug call BJDebugMsg("Double free of array struct")
            debug endif
        debug else
            debug call BJDebugMsg("Trying to free null array struct")
        debug endif
    endmethod
//! endtextmacro
//! textmacro ArrayStructInitBegin
    static method onInit takes nothing returns nothing
        set recicleNext = Table.create()
//! endtextmacro
//! textmacro ArrayStructInitEnd
    endmethod
//! endtextmacro

API description:


This macro requires Table!!! This macro is divided into 3 parts:
  • ArrayStructInitCreate...
  • ArrayStructInitDestroy...
  • ArrayStructInitInit...
You have to past their calls in your array struct like this:
JASS:
struct MyArrayStruct extends array
    <your code>
    
    //! runtextmacro ArrayStructCreateBegin("<create method parameters>")
        <initializing code in create method>
    //! runtextmacro ArrayStructCreateEnd()
    //! runtextmacro ArrayStructDestroyBegin()
        <deinitializing code in destroy method>
     //! runtextmacro ArrayStructDestroyEnd()
    //! runtextmacro ArrayStructInitBegin()
        <deinitializing code in onInit method>
    //! runtextmacro ArrayStructInitEnd()
endstruct
U can also use t variable of your struct type in initializing part.

Example of my struct with this macro:
JASS:
struct Item extends array
    ItemType Type
    item it
    
    method operator[] takes item k returns thistype
        return GetItemUserData(k)
    endmethod
    
    //! runtextmacro ArrayStructCreateBegin("ItemType Type, real x, real y")
        set t.Type = Type
        set t.it = CreateItem(Type.typeId, x, y)
        call SetItemUserData(t.it, t)
    //! runtextmacro ArrayStructBeginEnd()
    //! runtextmacro ArrayStructDestroyBegin()
        if it != null then
            call RemoveItem(it)
            set it = null
        endif
     //! runtextmacro ArrayStructDestroyEnd()
    //! runtextmacro ArrayStructInitBegin()
    //! runtextmacro ArrayStructInitEnd()
  endstruct

Changelog:



  1. Added onInit part
  2. Changed interface a lot
Changed array -> Table

  1. Bug fix
  2. Removed onInit
  3. Changed lastInstance -> instanceCount
First version
 
Last edited:
The best way to allocate and deallocate is like this:

JASS:
private static integer ic = 0
private static integer array rn

// allocate
local thistype this = rn[0]
if this == 0 then
    set ic = ic + 1
    set this = ic
else
    set rn[0] = rn[this]
endif

// deallocate
set rn[this] = rn[0]
set rn[0] = this

I know I might sound like a speedfreak here, but if a resource is dedicated to perform a certain task, it should do that task as efficiently as possible if and only if it's not too much trouble.

Since this is a dynamic indexer, it's code is going to spammed everywhere, so it might as well be as short as possible.

edit
By the way, you don't need to set array values to 0 since they are defaulted to 0 either way.
Also, lastInstance has no value, so this won't even run correctly at the moment.
You can set the value of 'recicle' (You meant recycle), to 0 from the declaration and you can do the same for lastInstance, so the onInit is redundant.
 
JASS:
private thistype recicleNext
    private static thistype recicle = 0
    private static integer instanceCount = 0

Gets compiled to

JASS:
integer array recicleNext
    integer recicle = 0
    integer instanceCount = 0

So yours does the same thing as mine.

The only way to have unlimited instances is to use Tables for storing struct data and a Table for the recycler array instead of an array.
 
This looks like an over-simplification of a greater issue. I see exactly what you are trying to do and it has good merit, however the execution is not user-friendly and the results will be significantly less efficient than doing non-array structs, thanks to the hashtable reads provided by Table instances.

The user would require a hashtable or Table for every single instance in the struct in the event where this went out of bounds (8190 being the maximum non-buggy array index).

In order to provide a friendly interface, one would need a compiler that essentially based structs on hashtables instead of arrays. I tried to imagine this for the LuckyParser project but I gave up on that project. The idea was to create the "class" keyword which acted as an "infinite" struct, but the interface would be the same on the user-side. Compiling would involve hashtable lookups instead of array reads, which is what structs use.

Seeing as how one needs to run not one not two but three textmacros for the user to run, as well as eating the struct's onInit method, this resource looks primed for disaster unless it gets some heavy refinement.

To be honest, there are also lots of resources that have tried this. Many of them were never published or simply discarded due to the utility not being work the cost of implementation, and I see a very similar fate in the near future for ArrayStructInit. I think the only surviving approach was "Alloc".
 
I plan to never finish/release LuckyParser. It requires fewer working hours for the entire community to work slightly harder with a more verbose language than it is for me to develop a several-thousand line parser and to debug everything. Look at JassHelper's source code and try to read that. The community was larger then and there were more people willing to help write, develop and debug the source.
 
Top