HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

gamecache storage script

01-19-2009, 03:58 AM#1
fX_
c bottom post

+ other posts deleted coz they only make the page longer and they are no longer relevant and it looks like the people are talking to themselves
01-21-2009, 08:47 AM#2
Vestras
And this is better... why?
01-21-2009, 08:59 AM#3
Vestras
So this isn't faster in any way?
01-21-2009, 10:56 AM#4
akolyt0r
im not sure, but i think i read somewhere that strings have a limit of 1023 chars..(totally not sure though)
01-21-2009, 11:28 AM#5
Vestras
> akolyt0r

I'm pretty sure it's 256.
01-21-2009, 01:46 PM#6
akolyt0r
yes...

because int have 32 bit...
(2^31)-1 = 2147483647 is the highest usable int
01-22-2009, 12:38 PM#7
Anitarf
It seems to me that what you have here are some very slow pools.

What happens if I name one category "foo" and another category "1foo", and then store more than 10 values in the first one?
01-31-2009, 09:33 AM#8
fX_
The script now indexes class types and category types, as well as relevant data pertaining to each so HaveStoredInteger() etc aren't used so much.
These can be indexed to limitation since there are always a limited number of types; the system affords unlimited storage - of values; there is always, naturally, a limited number of types, so it is able index them.

Also enforced appropriation of value type (boolean, integer, unit, etc.) to categories. A category can contain values of only a particular value type.

So, in a Cache of class, say, "Spell", I can have:
in category "Targets": "Targets;0 (some unit)"
in category "Targets": "Targets;1 (some unit)"
in category "Targets": "Targets;2 (some unit)"
in category "Level": "Level;0 (3)"
in category "SFX": "SFX;0 (some special effect attached to the some unit)"
in category "SFX": "SFX;1 (some special effect attached to the some unit2)"
in category "SFX": "SFX;2 (some special effect attached to the some unit3)"

Criticism? Anything I missed? Any bugs?

It compiles but I'm just not sure. I also have yet to add multiple value manipulation function things (GetFirstN, DeleteFirstN, etc).

Collapse JASS:
library Data

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //  Data
    //==========================================================================================================
    //      Organized gamecache.
    //
    //  Features:
    //  1) Unlimited storage.
    //  2) Availability of data
    //  3) Organization of data
    //  4) Simplified manipulation of data
    //
    //  * the first two are natural qualities of the gamecache; the latter are ameliorations by this system.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////

    //! textmacro Typecast takes ABBREVIATION, VALUETYPE, NULLVALUATION
    function $ABBREVIATION$2I takes $VALUETYPE$ value returns integer
        return value
        return 0
    endfunction

    function I2$ABBREVIATION$ takes integer value returns $VALUETYPE$
        return value
        return $NULLVALUATION$
    endfunction
    //! endtextmacro
    //! runtextmacro Typecast("B", "boolean", "false")
    //! runtextmacro Typecast("U", "unit", "null")
    //! runtextmacro Typecast("P", "player", "null")
    //! runtextmacro Typecast("D", "destructable", "null")
    //! runtextmacro Typecast("IT", "item", "null")

    function R2IEx takes real value returns integer
        return R2I(value * 100)
    endfunction

    function I2REx takes integer value returns real
        return I2R(value) / 100
    endfunction

globals
    private constant string SEPARATOR = ";"
    private constant string STRUCT_MISSION_KEY = "DataLibraryStructMissionKey"
    private constant integer MAX_CLASS_TYPE = 8190
    private constant integer MAX_CATEGORY_TYPE = 100

//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//

    private gamecache gGC = InitGameCache("DataLibraryGamecache.gc")
endglobals

    private function IsKeyValid takes string key returns boolean
        return key != null and key != "" and key != SEPARATOR and key != STRUCT_MISSION_KEY
    endfunction

    private function ComposeKey takes string classification, integer index returns string
        return classification + SEPARATOR + I2S(index)
    endfunction

struct Cache

    //---------------------------------------------------------------------------------------------------//
    // -- Cache Object Functions --

    private string strClassType
    private integer intClassIndex
    private string strMissionKey

    //Creates a new Cache.
    public static method Create takes string class returns Cache
        local Cache New = 0

        //Validate class.
        if IsKeyValid(class) then
            //If class is not yet indexed, index it.
            if Cache.GetClassIndex(class) == -1 then
                call Cache.IndexClass(class)
            endif
            set New = Cache.allocate()
            set New.strClassType = class
            set New.intClassIndex = Cache.GetClassLastInstanceIndex(class) + 1
            set New.strMissionKey = ComposeKey(class, New.intClassIndex)
            call StoreInteger(gGC, New.strMissionKey, STRUCT_MISSION_KEY, New)
        endif

        return New
    endmethod

    //Deletes all values in a category of a Cache.
    public method EmptyCategory takes string category returns boolean
        local integer INT_Index

        //Validate category.
        //If the category is indexed (exists) that it may bear values, proceed to empty it.
        if IsKeyValid(category) and .GetCategoryIndex(category) != -1 then
            set INT_Index = .GetCategoryLastInstanceIndex(category)
            loop
                exitwhen INT_Index < 0
                call FlushStoredInteger(gGC, .strMissionKey, ComposeKey(category, INT_Index))
                set INT_Index = INT_Index - 1
            endloop
            set .intCategoryCountInst[INT_Index] = 0

            return true
        endif

        return false
    endmethod

    //Deletes all values in a Cache; deletes all values in all categories in a Cache.
    public method Empty takes nothing returns nothing
        local integer INT_Index = 0

        loop
            exitwhen INT_Index == .intCountCategory
            call .EmptyCategory(.strCategory[INT_Index])
            set INT_Index = INT_Index + 1
        endloop
    endmethod

    //Copies all values in a category of a Cache to a category of another.
    //This operation can be done if the concerned categories store the same value type (e.g., boolean, integer, unit, etc.).
    //If the boolean parameter 'replace' is specified as 'true', the category copied to will be preliminarily emptied such
    //that the values of the category copied from shall replace the values of the category copied to.
    public method CopyCategory takes Cache to, string category, string toCategory, boolean replace returns boolean
        local integer INT_Index = .GetCategoryIndex(category)
        local integer INT_Index2 = to.GetCategoryIndex(toCategory)

        //Validate categories.
        //At least the copied category must exist for copying to take place.
        if IsKeyValid(category) and IsKeyValid(toCategory) and INT_Index != -1 then
            //If the Cache copied to does not have the 'toCategory' index such category for it, if parameter 'replace'
            //is true in this case, it will not need to be applied since the newly-indexed will be as empty.
            if INT_Index2 == -1 then
                call to.IndexCategory(toCategory, .strCategoryValueType[INT_Index])
            elseif replace then
                call to.EmptyCategory(toCategory)
            endif

            //Copy values.
            set INT_Index = .intCategoryCountInst[INT_Index] - 1
            set INT_Index2 = to.GetCategoryLastInstanceIndex(toCategory)
            loop
                exitwhen INT_Index < 0
                set INT_Index2 = INT_Index2 + 1
                call StoreInteger(gGC, to.strMissionKey, ComposeKey(toCategory, INT_Index2), GetStoredInteger(gGC, .strMissionKey, ComposeKey(category, INT_Index)))
                set INT_Index = INT_Index - 1
            endloop

            return true
        endif

        return false
    endmethod

    //Copies all values in a Cache to another; copies all values in all a Cache's categories to corresponding categories
    //in another Cache.
    //Only Caches alike in class can be copied between, since only like Caches have corresponding categories.
    //The Cache copied to can be preliminarily flushed.
    public method Copy takes Cache to, boolean replace returns boolean
        local integer INT_Index = 0

        if .strClassType == to.strClassType then
            if replace then
                call to.Empty()
            endif

            loop
                exitwhen INT_Index == .intCountCategory
                call .CopyCategory(to, .strCategory[INT_Index], .strCategory[INT_Index], false)
                set INT_Index = INT_Index + 1
            endloop

            return true
        endif

        return false
    endmethod

    //Destroys a Cache.
    public method Destroy takes nothing returns nothing
        local Cache CACHE_Last = GetStoredInteger(gGC, ComposeKey(.strClassType, Cache.GetClassLastInstanceIndex(.strClassType)), STRUCT_MISSION_KEY)

        //Allocate the gamecache place of the destroyed Cache to last-indexed Cache in its class.
        call CACHE_Last.Copy(this, true)
        call StoreInteger(gGC, .strMissionKey, STRUCT_MISSION_KEY, CACHE_Last)
        call FlushStoredMission(gGC, CACHE_Last.strMissionKey)
        set CACHE_Last.intClassIndex = .intClassIndex
        set CACHE_Last.strMissionKey = .strMissionKey

        //Flush the Cache object.
        set this = 0
    endmethod
    
    //! textmacro Save takes TYPE, VALUETYPE, VALUATION, ANTIVALUATION
    public method Save$TYPE$ takes string category, $VALUETYPE$ value returns boolean
        local integer INT_Index = 0

        if IsKeyValid(category) then
            set INT_Index = .GetCategoryIndex(category)
            if INT_Index == -1 then
                call .IndexCategory(category, "$VALUETYPE$")
            elseif .strCategoryValueType[INT_Index] != "$VALUETYPE$" then
                return false
            endif
            call StoreInteger(gGC, .strMissionKey, ComposeKey(category, .GetCategoryLastInstanceIndex(category) + 1), $VALUATION$)

            return true
        endif

        return false
    endmethod
    
    public method Delete$TYPE$ takes string category, $VALUETYPE$ value returns boolean
        local integer INT_Value = $VALUATION$
        local integer INT_Index = .GetCategoryIndex(category)
        local integer INT_Index2 = 0
        local integer INT_Index3 = 0

        if IsKeyValid(category) and INT_Index != -1 and .intCategoryCountInst[INT_Index] > 0 and .strCategoryValueType[INT_Index] == "$VALUETYPE" then
            loop
                exitwhen INT_Index2 == .intCategoryCountInst[INT_Index]
                if GetStoredInteger(gGC, .strMissionKey, ComposeKey(category, INT_Index2)) == INT_Value then
                    set INT_Index3 = .GetCategoryLastInstanceIndex(category)
                    if INT_Index2 != INT_Index3 then
                        call StoreInteger(gGC, .strMissionKey, ComposeKey(category, INT_Index2), GetStoredInteger(gGC, .strMissionKey, ComposeKey(category, INT_Index3)))
                    endif
                    call FlushStoredInteger(gGC, .strMissionKey, ComposeKey(category, INT_Index3))
                    set .intCategoryCountInst[INT_Index] = .intCategoryCountInst[INT_Index] - 1

                    return true
                endif
                set INT_Index2 = INT_Index2 + 1
            endloop
        endif

        return false
    endmethod

    public method Get$TYPE$ByIndex takes string category, integer index returns $VALUETYPE$
        local integer INT_Value = 0

        if IsKeyValid(category) and .strCategoryValueType[.GetCategoryIndex(category)] == "$VALUETYPE$" then
            set INT_Value = GetStoredInteger(gGC, .strMissionKey, ComposeKey(category, index))
        endif

        return $ANTIVALUATION$
    endmethod
    public method Get$TYPE$First takes string category returns $VALUETYPE$
        local integer INT_Value = 0

        if IsKeyValid(category) and .strCategoryValueType[.GetCategoryIndex(category)] == "$VALUETYPE$" then
            set INT_Value = GetStoredInteger(gGC, .strMissionKey, ComposeKey(category, 0))
        endif

        return $ANTIVALUATION$
    endmethod
    public method Get$TYPE$Last takes string category returns $VALUETYPE$
        local integer INT_Value = 0

        if IsKeyValid(category) and .strCategoryValueType[.GetCategoryIndex(category)] == "$VALUETYPE$" then
            set INT_Value = GetStoredInteger(gGC, .strMissionKey, ComposeKey(category, .GetCategoryLastInstanceIndex(category)))
        endif

        return $ANTIVALUATION$
    endmethod
    public method Get$TYPE$Random takes string category returns $VALUETYPE$
        local integer INT_Value = 0

        if IsKeyValid(category) and .strCategoryValueType[.GetCategoryIndex(category)] == "$VALUETYPE$" then
            set INT_Value = GetStoredInteger(gGC, .strMissionKey, ComposeKey(category, GetRandomInt(0, .GetCategoryLastInstanceIndex(category))))
        endif

        return $ANTIVALUATION$
    endmethod
    //! endtextmacro
    //! runtextmacro Save("Boolean", "boolean", "B2I(value)", "I2B(INT_Value)")
    //! runtextmacro Save("Real", "real", "R2IEx(value)", "I2REx(INT_Value)")
    //! runtextmacro Save("Integer", "integer", "value", "INT_Value")
    //! runtextmacro Save("Unit", "unit", "U2I(value)", "I2U(INT_Value)")
    //! runtextmacro Save("Player", "player", "P2I(value)", "I2P(INT_Value)")
    //! runtextmacro Save("Destructable", "destructable", "D2I(value)", "I2D(INT_Value)")
    //! runtextmacro Save("Item", "item", "IT2I(value)", "I2IT(INT_Value)")
    //NOTE: More value types can be accomodated by addintg to this list.

    //---------------------------------------------------------------------------------------------------//
    // -- Class Instance Indexing Functions --

    private static string array strClass[MAX_CLASS_TYPE]
    private static integer array intClassCountInst[MAX_CLASS_TYPE]
    private static integer intCountClass = 0

    private static method IndexClass takes string class returns boolean
        if Cache.intCountClass < MAX_CLASS_TYPE then
            set Cache.strClass[Cache.intCountClass] = class
            set Cache.intClassCountInst[Cache.intCountClass] = 0
            set Cache.intCountClass = Cache.intCountClass + 1

            return true
        endif

        return false
    endmethod

    private static method GetClassIndex takes string class returns integer
        local integer INT_Index = 0

        loop
            exitwhen INT_Index == Cache.intCountClass
            if Cache.strClass[INT_Index] == class then
                return INT_Index
            endif
            set INT_Index = INT_Index + 1
        endloop

        return -1
    endmethod

    private static method GetClassLastInstanceIndex takes string class returns integer
        local integer INT_Index = Cache.GetClassIndex(class)

        if INT_Index != -1 then
            return Cache.intClassCountInst[INT_Index] - 1
        endif

        return -2
    endmethod

    //---------------------------------------------------------------------------------------------------//
    // -- Category Instance Indexing Functions --

    private string array strCategory[MAX_CATEGORY_TYPE]
    private string array strCategoryValueType[MAX_CATEGORY_TYPE]
    private integer array intCategoryCountInst[MAX_CATEGORY_TYPE]
    private integer intCountCategory = 0

    private method IndexCategory takes string category, string valueType returns boolean
        if .intCountCategory < MAX_CATEGORY_TYPE then
            set .strCategory[.intCountCategory] = category
            set .strCategoryValueType[.intCountCategory] = valueType
            set .intCategoryCountInst[.intCountCategory] = 0
            set .intCountCategory = .intCountCategory + 1

            return true
        endif

        return false
    endmethod

    private method GetCategoryIndex takes string category returns integer
        local integer INT_Index = 0

        loop
            exitwhen INT_Index == .intCountCategory
            if .strCategory[INT_Index] == category then
                return INT_Index
            endif
            set INT_Index = INT_Index + 1
        endloop

        return -1
    endmethod

    private method GetCategoryLastInstanceIndex takes string category returns integer
        local integer INT_Index = .GetCategoryIndex(category)

        if INT_Index != -1 then
            return .intCategoryCountInst[INT_Index] - 1
        endif

        return -2
    endmethod

endstruct

endlibrary