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

[Snippet] Recycle

Level 31
Joined
Jul 10, 2007
Messages
6,306
JASS:
library Recycle
//settings
globals
    public constant boolean AUTO_CLEAR = true
endglobals
/*Utility Information
//===================================================================
Name: Recycle
Version: 6.0
Author: Nestharus
-Help from Jesus4Lyf for initial designs

Description:
    What does it do-
        Recycles handles so that when getting new handles of the same type,
        a recycled handle can be returned instead of creating a new handle. This
        increases map performance.
        
Requirements: NA

Installation: NA

Variables:
------------------------------------------------------------------
AUTO_CLEAN-
    If true, will automatically clear out recycled handles (GroupClear,
    PauseTimer) at a slight performance hit.

Functions:
------------------------------------------------------------------
-get returns type
    will return the type
    
    Timer.get()
    Group.get()
    
    ex-
    timer t = Timer.get()

-release(type h)
    Will release the type and stop it.
    
    Timer.release(h)
    Group.release(h)
    
    ex-
    timer t = Timer.get()
    Timer.release(t)
------------------------------------------------------------------*/
    //! textmacro CREATE_STACK takes name, type, clean, create
        struct $name$ extends array
            public $type$ handles
            public static integer index = 0
            
            public static method release takes $type$ h returns nothing
                static if DEBUG_MODE then
                    if h == null then
                        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "ERROR - Recycle: Freed null handle.")
                    endif
                    if $name$.index > 8190 then
                        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "ERROR - Recycle: Overfilled recycle stack (8191 released objects)!")
                    endif
                endif
                static if AUTO_CLEAR then
                    $clean$
                endif
                set $name$[$name$.index].handles = h
                set $name$.index = $name$.index + 1
            endmethod

            public static method get takes nothing returns $type$
                if $name$.index == 0 then
                    return $create$
                endif
                set $name$.index = $name$.index - 1
                return $name$[$name$.index].handles
            endmethod
        endstruct
    //! endtextmacro
    
    //! runtextmacro CREATE_STACK("Timer", "timer", "call PauseTimer(h)", "CreateTimer()")
    //! runtextmacro CREATE_STACK("Group", "group", "call GroupClear(h)", "CreateGroup()")
endlibrary
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
I didn't even see that : o

Guess it's up to people if they want the GetHandle style or the Handle_Get style =). I always put my stuff in libraries so that they never collide with anything so long as those other things are also in libraries, but yea, up to you guys : o.

They're virtually the same, I looked at his code ^_^.
 
Last edited:
Level 11
Joined
Nov 4, 2007
Messages
337
Ok, Ill write something like this now, and Ill measure the time, how fast I am.

edit: 1 minute, 56 seconds.

So?
This is nothing new, you didn't make the idea, I can wirte that on my own very quickly and
This has no beginning Inits, so in fact it doesn't work, the stack is empty at the beginning.
Look into my HandleIndexing thread. That recycling thing is better.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
This is a possible update ^_^.

What do people prefer?
C- get timer()
C- release timer(timer t)
C#- Timer.get()
C#- Timer.release(timer t)

Now you can use either or with cJASS : D. Both do same exact thing =P.

JASS:
/*Utility Information
//===================================================================
Name: Recycle
Version: 4.0
Author: Nestharus
-Help from Jesus4Lyf for initial designs

Description:
    What does it do-
        A stack of a type. When you are done using something, 
        you throw it into the stack and it is added to the stack. 
        When you need something, it'll either get something from the 
        stack, or it'll create new if the stack is empty. This is very 
        simple, but I keep having to rewrite this over and over again 
        so I figured this'd be cooler : ).
        
Requirements: NA

Installation: NA

Functions:
------------------------------------------------------------------
-get returns type
    will return the type
    
    timer t = get timer();
    group g = get group();
    hashtable h = get hashtable;
            -or-
    timer t = Timer.get();
    group g = Group.get();
    hashtable h = Hashtable.get();

-release(type h)
    Will release the type and stop it.
    
    release timer(timer h);
    release group(group h);
    release hashtable(hashtable h);
            -or-
    Timer.release(timer h);
    Group.release(group h);
    Hashtable.release(hashtable h);
------------------------------------------------------------------*/
library Recycle
{
    define
    {
        <release timer(> = Recycle_HandleSSStimer_release(
        <Timer.release(> = Recycle_HandleSSStimer_release(
        <get timer(> = Recycle_HandleSSStimer_get(
        <Timer.get(> = Recycle_HandleSSStimer_get(
        
        <release group(> = Recycle_HandleSSSgroup_release(
        <Group.release(> = Recycle_HandleSSSgroup_release(
        <get group(> = Recycle_HandleSSSgroup_get(
        <Group.get(> = Recycle_HandleSSSgroup_get(
        
        <release hashtable(> = Recycle_HandleSSShashtable_release(
        <Hashtable.release(> = Recycle_HandleSSShashtable_release(
        <get hashtable(> = Recycle_HandleSSShashtable_get(
        <Hashtable.get(> = Recycle_HandleSSShashtable_get(
    }
    //! textmacro CREATE_STACK takes type, clean, create
        scope HandleSSS$type$
        {
            private $type$ array handles;
            private int array data
            private int index = 0;
            
            public void release($type$ h)
            {
                debug if (h == null)
                debug {
                    debug print("ERROR - Recycle: Freed null handle.");
                debug }
                debug if (index > 8191)
                debug {
                    debug print("ERROR - Recycle: Overfilled recycle stack (8191 released objects)!");
                debug }
                $clean$
                handles[index] = h;
                index++;
            }
            
            public $type$ get()
            {
                if (index == 0)
                {
                    return $create$;
                }
                index--;
                return handles[index];
            }
        }
    //! endtextmacro
    
    //! runtextmacro CREATE_STACK("timer", "PauseTimer(h);", "CreateTimer();")
    //! runtextmacro CREATE_STACK("group", "GroupClear(h);", "CreateGroup();")
    //! runtextmacro CREATE_STACK("hashtable", "FlushParentHashtable(h);", "InitHashtable();")
}
 
Last edited:
Level 3
Joined
Oct 20, 2008
Messages
43
C- get timer()
C- release timer(timer t)
That's rather C++

Now you can use either or with cJASS : D. Both do same exact thing =P.
The cJass version is rather bad-coded =) You can use defines for everything as they can take arguments:

JASS:
library Recycle
{
    include "cj_types_priv.j"  // you forgot this - it's needed for void, int etc

    define
    {
        <release timer>(h) = Recycle_HandleSSStimer_release(h)
        <Timer.release>(h) = Recycle_HandleSSStimer_release(h)
        <get timer()> = Recycle_HandleSSStimer_get()
        <Timer.get()> = Recycle_HandleSSStimer_get()

        <release group>(h) = Recycle_HandleSSSgroup_release(h)
        <Group.release>(h) = Recycle_HandleSSSgroup_release(h)
        <get group()> = Recycle_HandleSSSgroup_get()
        <Group.get()> = Recycle_HandleSSSgroup_get()

        <release hashtable>(h) = Recycle_HandleSSShashtable_release(h)
        <Hashtable.release>(h) = Recycle_HandleSSShashtable_release(h)
        <get hashtable()> = Recycle_HandleSSShashtable_get()
        <Hashtable.get()> = Recycle_HandleSSShashtable_get()
    
        CREATE_STACK(type, clean, create) = 
        {
            scope HandleSSS##type
            {
                private type array handles
                private int array data
                private int index = 0

                public void release(type h)
                {
                    debug if (h == null){ print("ERROR - Recycle: Freed null handle.") }
                    debug if (index > 8191) { print("ERROR - Recycle: Overfilled recycle stack (8191 released objects)!") }
                    clean
                    handles[index++] = h
                }

                public type get()
                {
                    if (index == 0)
                    {
                        return create
                    }
                    return handles[--index]
                }
            }
        }

        CREATE_STACK(timer, PauseTimer(h), CreateTimer())
        CREATE_STACK(group, GroupClear(h), CreateGroup())
        CREATE_STACK(hashtable, FlushParentHashtable(h), InitHashtable())
    }
}
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Good update, but the include should be left up to the mappers = P. Personally, I think all the include stuff should just be auto included as elements are used ^_^.

For the defines list, my own version was updated to that yesterday shortly after this post ^_^. Still playing around with cJASS : D. I won't be able to actually update this until a serious cJASS bug is fixed tho ^_^. It's causing my computer to freeze a short while after every time I use it O-o. Also, the fact that it uses 100% of my CPU resources while it is running isn't good either : o. And 22 megs of memory?? For a tiny little compiler?? : O.

^_^.
 
Level 3
Joined
Oct 20, 2008
Messages
43
I think all the include stuff should just be auto included as elements are used
This won't be implemented in a lifetime. Optimizations, which remove excessive code, will possibly be added, but not this. In C++, you also have to include stuff =]

It's causing my computer to freeze a short while after every time I use it O-o. Also, the fact that it uses 100% of my CPU resources while it is running isn't good either : o. And 22 megs of memory?? For a tiny little compiler?? : O.
Dunno, I've got no freezes of excessive memory usage. Anyways, I'll check it out.
 
Level 11
Joined
Feb 22, 2006
Messages
752
I just graveyarded a script damn near identical to this one 2 weeks ago. Reasons:

1. TimerUtils and GroupUtils cover the two handles that make up 99.9% of everybody's recycling needs. And I'm tired of looking at rehashes of those scripts.
2. No other handle type really needs to be recycled anyway (which explains why number 1 is true).
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Actually hashtables have to be recycled because hashtables can not be un-initialized, but w/e.

If you use hashtables in structs, gl without recycling them.

Oh yea, and there are no little snippets for recycling pools.

Furthermore, as discussed in previous posts and on a couple of other threads, TimerUtils and GroupUtils automatically attach and clear out data, making them worse to use in cases where you don't need to attach data.

I personally use this any time I use a timer, and for data attachment I do something very simple to get a good offset so that it uses this in combination with the elements of standard fast action data attachment.

In cases where I am planning to attach a large amount of data or need multi dimensional arrays, I use a hashtable.

The idea of systems for attaching data seems pointless now with GetHandleId() and the hashtable handle.

This takes out the one useful thing left in them and put it with commonly used handles. This is already being widely used on one major forum as well = ).
 
Level 11
Joined
Feb 22, 2006
Messages
752
You should almost never be dynamically initializing and flushing hashtables. One or a few hashtables initialized during map initialization should be all you need.

TimerUtils and GroupUtils may perform unnecessary operations sometimes, but the efficiency drop is negligible.

And since you seem to be overly obsessed with efficiency, you should know that hashtable is slightly slower than TU and GU's attachment system (which use arrays).
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
I personally use this any time I use a timer, and for data attachment I do something very simple to get a good offset so that it uses this in combination with the elements of standard fast action data attachment.

Meaning that my attachment method is the same speed as TimeUtils and GroupUtils and only runs when I want it to ><.

In cases where I am planning to attach a large amount of data or need multi dimensional arrays, I use a hashtable.

You should almost never be dynamically initializing and flushing hashtables. One or a few hashtables initialized during map initialization should be all you need.

I've needed more than that =). For example, my system called Spawn just uses an army of hashtables, and I do mean army O-o. A hashtable is half the speed of a single array lookup, so it'd be the same speed as 2 array lookups, meaning they are just dandy for multi-dimensional arrays ^_^.

Also, I use them as array members in structs (technically multi-dimensional arrays here as well as a struct is an array).

Spawn requires multi dimensional arrays, so I need a variety of dynamically instantiated hashtables for the various structs.

The reason I submitted this snippet is because people really need simple recycling that is used globally of an entire map and is commonly used by systems ><. If it's not commonly used, it's pointless as it isn't as effective as it could be. Data attachment is too simple.. it'd only be a couple of lines

JASS:
local trigger t = CreateTrigger()
local integer offset = GetHandleId(t)-1
call DestroyTrigger(t)
set t = null

If you were doing timers or w/e, you could just recycle the timers for later use, and so on. That's exactly how fast action attachment systems like timer utils work. The offset is used like this-
array[GetHandleId(handle)-offset] = data

And in cases where you are handling mass amounts of data, you use a hashtable-
SaveInteger(hashtable, StringHash("type"), GetHandleId(handle), data)

I fail to see why using those few simple lines only when they are needed is worse than using them when they are needed and when they aren't needed.
 
Level 11
Joined
Feb 22, 2006
Messages
752
The reason I submitted this snippet is because people really need simple recycling that is used globally of an entire map and is commonly used by systems

Yea, that already exists in the form of TU and GU. Those are the de facto standards. People don't care that they carry out operations that may or may not be needed in all cases that take up a negligible (the keyword here is negligible) amount of computation power and execution time. If people cared that much about it, they could go into the scripts and simply remove the lines that aren't needed.

This has nothing to do with the main issue here, but I'm just curious...how exactly are you recycling hashtables? Once you call FlushParentHashtable() they can't be used again.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
You are right ^_^. I guess you don't need to recycle hashtables =P.

Well, I can take that out then ^_^.

As for stuff specifically for recycling Groups and Timers... I think people prefer it to be in one snippet vrs 2 =).

Oh well. People are already using this snippet on other forums because people are getting tired of 100% data attachment on TimerUtils and GroupUtils.

Typically-
Recycle for plain handles
KT2 for arbitrary code on functions with attached data
T32 for timed loops

And ... I guess the two procedures I talked about for attaching data to any given handle.

The idea here is one common thingie for everything to get its handles from and release its handles to : o.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
This may need to be discussed then: Unit Decaying

JASS:
library Udn initializer Initialization requires PTN, Recycle

Now, the requirements is linked to TheHelper and not to here
JASS:
Requirements: PTN- hiveworkshop.com/forums/jass-functions-413/system-pt-player-tracking-142554/
              Recycle- thehelper.net/forums/showthread.php?t=136087

so you could keep it up and claim it uses cross site resources. For example, TimerUtiles isn't on THW, but it is on wc3c, yet many systems use it.

You might say: "as long as a resource is linked to a major site where it is approved (wc3c, TH, here), it may be used to design resources submitted (here/THW).

All of my resources that use timer or group handles use this resource =).
 
Top