| 12-06-2008, 09:07 PM | #1 |
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. 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 |
What happens when storages aren't destroyed in the same order they were created in? |
| 12-07-2008, 07:55 PM | #3 |
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 |
And...? |
