HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

[script presentation] Linear Storage

12-06-2008, 09:07 PM#1
midiway
I've made this system, witch is very simple, to solve a common problem: how to save a variable number of things to a struct?

Haven't made a strong test yet, only minors with common spells. Just wanna know what you think.

Collapse JASS:
//=======================================================================================//
//  SYSTEM: LINEAR STORAGE                                           BY: MIDIWAY         //
//  VERSION: 1.0                                                                         //
//=======================================================================================//
//
//  OVERVIEW:
//---------------------------------------------------------------------------------------//
//  Provides a way to allocate at run-time a sized space in a global array:
//      * Indexed acess / ordered
//      * vJass "Dynamic Arrays" and this system are not the same thing since with this
//      you will be releasing the used space so not having a limit of intances
//      * Different from "Collections" because you are not mixing your data in a global
//      array, you are creating deticated sized spaces acessed by index
//      * More flexible than vJass "Struct Array members" cause you don't declare an
//      initial size, you reserve space dynamically and than release it to be reused
//      * Mainly aimed to spells where each instance can handle an uncertain number of data
//
//  Think it like you creating a group with a given capacity that can store elements
//  of any type. So, like with UnitGroups, you create it, add elements, manage this
//  elements, and then must destroy the group. Yeah, very simple usage.
//
//  It's called linear cause spaces are allocated in the array with one following the
//  other, one group after the other, looping in the array when end is reached.
//
//  In this linear model, limitation is made by instances that stay alive time sufficient
//  to block creation of new instances.
//
//  Lets say a situation where a space is acquired and isn´t released for a given amount
//  of time (or is never released), while continuing allocating news instances, filling the
//  array until you reach the point the space is occupying, new allocations are blocked
//  until this space is release. This system does not implemenet a 'search for gaps'
//  engine, it can´t jump trough a occupied space to reach a free space after it.
//
//  To illustrate this problem, consider a generic spell with extreme resource consuming:
//      -Each instance of this spell will manage 2000 elemets, stored using this system
//      -Will last for 6 seconds, grabbing this space of 2000 elements in the array and
//      than releasing it
//      -Every 2 seconds this spell is casted
//
//  [AT THE MOMENT 0 SECONDS]
//  > ------------------------------------------------------------------------------- <
//  0                                                                                 8190
//
//
//  [6 SECONDS] SPACE OCCUPIED BY 3 INSTANCES OF THE SPELL
//  > oooooooooooooooooo|oooooooooooooooooo|oooooooooooooooooo|---------------------- <
//  0                   2000               4000               6000                    8190
//
//
//  [8 SECONDS] FIRST SPACE IS RELEASED, WITH ANOTHER BEING OCCUPIED
//  > ------------------|oooooooooooooooooo|oooooooooooooooooo|oooooooooooooooooo|--- <
//  0                   2000               4000               6000               8000 8190
//
//
//  [10 SECONDS] MORE 1 ONE INSTANCE, NO MORE SPACE LEFT FOR A NEW INSTANCE
//  > oooooooooooo|-----|oooooooooooooooooo|oooooooooooooooooo|oooooooooooooooooo|ooo <
//  0             1810  2000               4000               6000               8000 8190
//
//
//  More 2 seconds and a new instance is created and tryies to allocate 2000 of space
//  that is not available. What happens is that .create method will return 0.
//  It's just a very extreme example to understand where the limitation of this system
//  comes from. The system is pratical only in cases where the allocated space will be
//  released (i.e not being hold forever) in a reasonable time not lasting the
//  sufficient for new allocations require this used space.
//
//
//  USAGE:
//---------------------------------------------------------------------------------------//
//
//  For a trigger to use this it MUST be inside a scope.
//  At the beginning of scope insert this macro call:
//
//     //! runtextmacro STORAGE_declare("lighs", "lightning")
//
//     "lighs"      --> this appended with "_storage" is the name of the struct you declare
//     "lightning"  --> type of data that the struct will be able to store, can be any
//                      type of variable (unit, item, integer, boolean, ...)
//
//  Now it can be declared as a struct member:
//
//      struct LightSpell
//          ... another members
//          private lighs_storage fsx
//      endstruct
//
//  A "LightSpell" can now be instantiated, and a space for his lightnings can be reserved
//  instantiating his "fsx" member. Then you acess "fsx" slots like an array and finally you
//  release "fsx":
//
//      private function OnCast takes nothing returns nothing
//          local LightSpell spelldat = LightSpell.create()
//          local lighs_storage fsx
//
//          //.create() takes an integer, the space to allocate
//          set spelldat.fsx = lighs_storage.create(10)
//          set fsx = spelldat.fsx
//          set fsx[0] = AddLightning(..)
//          set fsx[1] = AddLightning(..)
//          set fsx[2] = AddLightning(..)
//          ...
//
//          call DestroyLightning( fsx[0] )
//          call DestroyLightning( fsx[1] )
//          call DestroyLightning( fsx[2] )
//          call spelldat.fsx.destroy()
//      endfunction
//
//  
//  REQUIREMENTS:
//---------------------------------------------------------------------------------------//
//  * JassNewGenPack, or similar, containing the following:
//      - JassHelper (0.9.A.0)      (or better)
//
//=======================================================================================//

globals
    constant integer STORAGE_limit = 8191
endglobals


//! textmacro STORAGE_declare takes IDENTIFIER, TYPE

globals
    private $TYPE$ array store_array
    private integer next = 0
    private integer base = 0
endglobals


private struct $IDENTIFIER$_storage
    private integer init
    private integer size
    
    static method create takes integer allocsize returns $IDENTIFIER$_storage
        local $IDENTIFIER$_storage data
        
        if allocsize > IntegerTertiaryOp(base>next, base-next, STORAGE_limit-next+base) then
            debug call BJDebugMsg("|cffff0000*Linear Storage Error*: Not enough free space")
            return 0
        endif
        set data = $IDENTIFIER$_storage.allocate()
        set data.init = next
        set data.size = allocsize
        
        if next+allocsize>=STORAGE_limit then
            set next = next+allocsize - STORAGE_limit
        else
            set next = next+allocsize
        endif
        return data
    endmethod
    
    method onDestroy takes nothing returns nothing
        if .init==base then
            if .init+.size>=STORAGE_limit then
                set base = .init+.size - STORAGE_limit
            else
                set base = .init+.size
            endif
        endif
    endmethod
    
    method operator[] takes integer index returns $TYPE$
        debug if index>.size then
        debug     call BJDebugMsg("|cffff0000*Linear Storage Error*: Tried to read outside of limit")
        debug     return null
        debug endif
        
        if .init+index>=STORAGE_limit then
            return store_array[.init+index - STORAGE_limit]
        endif
        return store_array[.init+index]
    endmethod
    
    method operator[]= takes integer index, $TYPE$ content returns nothing
        debug if index>.size then
        debug     call BJDebugMsg("|cffff0000*Linear Storage Error*: Tried to write outside of limit")
        debug endif
        
        if .init+index>=STORAGE_limit then
            set store_array[.init+index - STORAGE_limit] = content
        else
            set store_array[.init+index] = content
        endif
    endmethod
    
endstruct

//! endtextmacro
12-07-2008, 01:50 PM#2
Anitarf
What happens when storages aren't destroyed in the same order they were created in?
12-07-2008, 07:55 PM#3
midiway
The order doesn't matter.

There is an integer (private integer base = 0) which tracks where start the space occupied in the array, and another (private integer next= 0) which say where it ends and where new spaces will be created. So this two integers delimit the interval of occupied space.

If what's being destroyed is in the beginning of this interval, then integer base is incremented with the space being freed, so increasing the free space.

Else, if it's not in the beginning, it's in somewhere in the middle of this interval, and will not increase the space left.
12-08-2008, 04:32 PM#4
Anitarf
And...?