• 🏆 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!

Qalloc

Status
Not open for further replies.
Level 13
Joined
Nov 7, 2014
Messages
571
Qalloc - fast instance allocation using a queue

Qalloc is similar to Nestharus's AllocFast and AllocQ but with 1 less variable, no save game corruption, without all the optional "extra" stuff, and with the observation that the difference in the allocation scheme is worthwhile only if the extra function call is eliminated, thus Qalloc uses textmacros.

example:
JASS:
//! runtextmacro Qalloc("Foo", "5")
struct Foo extends array
    implement Qalloc_Foo
    implement Qalloc_Default_create_destroy
endstruct

The call to the //! runtextmacro Qalloc("Foo", "5") creates a private module called Qalloc_Foo which declares a private member called qa__next which is used for the implementation of allocate and deallocate.
The module also has a private static method onInit takes nothing returns nothing that creates a queue of size 5 (in non-debug (release) mode this parameter is ignored and 8190 is used instead) at map init time.
The extra Q_SIZE (5 in the above example) argument helps with the cases in which one forgets to call deallocate at all, as opposed to calling deallocate more than once and getting a double free error.

example 2:
JASS:
//! runtextmacro Qalloc("Bar", "3")
struct Bar extends array
    implement Qalloc_Bar

    string s // = "A" we lose the ability to have default values

    static method create takes nothing returns thistype
        local string s2 = "A"

        // Qalloc_allocate must be called at the end of the locals block
        //! runtextmacro Qalloc_allocate()
        set this.s = s2

        return this
    endmethod

    method destroy takes nothing returns nothing
        local string s2 = this.s
        // Qalloc_deallocate must be called after the locals block
        //! runtextmacro Qalloc_deallocate()
    endmethod
endstruct

The benefit of using Qalloc instead of vJass's default implementation is only worthwhile for structs that are allocated and destroyed frequently, otherwise the default should be used.

Qalloc:
JASS:
library Qalloc

public function panic takes string s returns nothing
    call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 60.0, s)
    if 1 / 0 == 1 then // stop executing
    endif
endfunction

// qa__next - we use this member to create a queue of all the indicies at map init time
// qa__next[0] - we use the 0th element as the head of the queue (its initial value is 1)
// we don't need a tail member because we add to the end of the queue in an "ad-hoc" way

// This textmacro must be called outside of a struct.
// Q_SIZE can have values in the range: 1 .. 8190
//
//! textmacro Qalloc takes STRUCT_NAME, Q_SIZE
private module Qalloc_$STRUCT_NAME$
    static integer array qa__next
    private static method onInit takes nothing returns nothing
        local integer i = 1
        loop
static if DEBUG_MODE then
            exitwhen i >= $Q_SIZE$
else
            exitwhen i >= 8190
endif
            set qa__next[i] = i + 1
            set i = i + 1
        endloop
        set qa__next[0] = 1
    endmethod
endmodule
//! endtextmacro

// This textmacro must be called in the "create" method of a struct and at the end of the locals block.
//
//! textmacro Qalloc_allocate
    local thistype this = qa__next[0]
static if DEBUG_MODE then
    if this == 0 then
        call Qalloc_panic("|cffFF0000[Qalloc_allocate] error: cannot allocate a thistype instance|r")
    endif
endif
    set qa__next[0] = qa__next[this]
    debug set qa__next[this] = -1
//! endtextmacro

// This textmacro must be called in the "destroy" method of a struct after the locals block.
//
//! textmacro Qalloc_deallocate
static if DEBUG_MODE then
    if qa__next[this] != -1 then
        call Qalloc_panic("|cffFF0000[Qalloc_deallocate] error: double free for instance thistype(" + I2S(this) + ")|r")
    endif
endif
    set qa__next[this] = qa__next[0]
    set qa__next[0] = this
//! endtextmacro

module Qalloc_Default_create_destroy
    static method create takes nothing returns thistype
        //! runtextmacro Qalloc_allocate()
        return this
    endmethod

    method destroy takes nothing returns nothing
        //! runtextmacro Qalloc_deallocate()
    endmethod
endmodule

endlibrary
 
Status
Not open for further replies.
Top