LibQueue

This project is abandoned.

Whether this project is out of date or its author marked it as abandoned, this project is no longer maintained.

If you wish to take this project over, please report it and state your intentions.

LibQueue
by DrDoom (Shalune on Kargath)

This is an open-source delayed-processing and buffer queue library developed for World of Warcraft

There are three functional concepts this library works with:
Queue: Allow you to place information on it for later retrieval
        Standard queues use a FIFO buffer with rotational positioning, meaning no constant
        clientside cleanup, therefore faster access.  The queue is designed to handle any type
        of data, even nil, so prior datachecking is recommended.

Timer: Timers execute a function every x seconds until stopped by the addon.  These can be
        executed and controlled as groups, allowing you to do multiple things at once, and turn
        on or off processing of these timers en masse.

Delay: Delays execute a given function after x seconds, and do not repeat.  Delays are cleared
        automatically after they are processed.  Delay objects allow you to extend processing
        until something is done, and you can extend the time before it is executed as well.  This
        is great for events like BAG_UPDATE if you want to do an inventory scan.

Library functions are not embedded in created queue objects

CreateQueue
    Arguments:
        table QueueName            Table object to store the queue
        integer MaxSize                Maximum size of the queue in elements
        boolean AllowRecentDuplicates    Allow duplicates of the most recent entry
        boolean AllowAnyDuplicates    Allow duplicates anywhere in the table
        boolean IsStack                Queue is processed like a stack (FILO)
    Description:
        Creates a queue, you must specify a maximum size.  If given queue does not exist,
        table will be created in the global environment
        Default behavior is to allow any duplicates, if AllowAnyDuplicates is true, then
        AllowRecentDuplicates will be ignored.
    Example:
        local MyQueue = {};
        success = LibQueue:CreateQueue(MyQueue,500,true,false,false);
        success = LibQueue:CreateQueue(MyStack,50,,true,true);
    Returns:
        true = Queue created successfully
        false = Queue not created (invalid argument)

Put

    Arguments:
        table QueueName
        any Value;
    Description:
        Adds a value to the end of the Queues internal positioning, buffer will be expanded
        if needed, not to exceed the maximum size.  If the queue is full, the data is discarded.
    Example:
        success = LibQueue:Put(MyQueue,"Hello");
        success = LibQueue:Put(MyStack,123);
        success = LibQueue:Put(MyQueue, {1,"2",3} );
    Returns:
        true = Value added successfully
        false = Value discarded

Get

    Arguments:
        table QueueName
    Description:
        Extracts the next value from the table.
    Example:
        value = LibQueue:Get(MyQueue)
    Returns:
        nil = Queue is empty or value is nil
        nonnil = Next value in line

Peek

    Arguments:
        table QueueName
        boolean LastValue
    Description:
        Extracts the next value in line from the table without removing it.
        If LastValue is specified, it will extract the last value added (has no effect on a stack).
    Example:
        nextvalue = LibQueue:Peek(MyQueue)
        lastvalue = LibQueue:Peek(MyQueue,true)
        lastvalue = LibQueue:Peek(MyStack)
        lastvalue = LibQueue:Peek(MyStack,true)
    Returns:
        nil = Queue is empty or Value is nil
        nonnil = Value requested

Size

    Arguments:
        table QueueName
    Description:
        Returns the size of the current Queue or Stack.
    Example:
        Size,BufferSize = LibQueue:Size(MyQueue)
    Returns:
        Size is the number of active elements in the buffer
        BufferSize is the total number of elements in the buffer.

        nil = Queue is not valid or has not been created
        integer = Number of elements in the Queue, 0 = empty

Wipe

    Arguments:
        table QueueName
        boolean ClearBuffer
    Description:
        Empties the queue and discards all information, will also optionally clean up the unused
        buffer space
    Example:
        LibQueue:Wipe(MyQueue,false)    Does not discard buffer data, no memory is freed up
        LibQueue:Wipe(MyQueue,true)        Discards the buffer, memory is freed
    Returns:
        Nothing

CreateTimer

    Arguments:
        string Name        Name of the delay object to make
        number Time        Time interval to call Callback (seconds)
        function Callback    Function to call when delay has completed
        any Data            Data to pass to Callback function when called
        AllowDuplicates        Allow multiple timers with this name?
        InCombat            If set to false, timer will be paused in combat
    Description:
        Creates a timer, which calls Callback(Data); every Time seconds.
        Default behavior is AllowDuplicates=true, AllowExtend=false,InCombat=true
    Returns:
        false = Delay not created
        true = Delay created successfully or existing delay extended
    Example:
        function MyAddon_Func1(value)
            print("Your lucky number is "..tostring(value));
        end
        success = LibQueue:CreateDelay("MyAddon_Delay1",5,MyAddon_Func1,10);
        After 5 seconds, outputs: Your lucky number is 10

StopTimer

    Arguments:
        string Name        Name of the Timer object
    Description:
        Pauses the timers on all Timer objects named Name
    Returns:
        Nothing
    Example:
        LibQueue:StopTimer("MyAddon_Timer");

StartTimer

    Arguments:
        string Name        Name of the Timer object
    Description:
        Unpauses the timers on all Timer objects named Name
    Returns:
        Nothing
    Example:
        LibQueue:StartTimer("MyAddon_Timer");

ToggleTimer

    Arguments:
        string Name        Name of the Timer object
    Description:
        Toggles the paused state of the timers on all Timer objects named Name
    Returns:
        Nothing
    Example:
        LibQueue:ToggleTimer("MyAddon_Timer");

ClearTimer

    Arguments:
        string Name        Name of the Timer object
    Description:
        Removes all instances of the named timer.
    Returns:
        Nothing
    Example:
        LibQueue:ClearTimer("MyAddon_Timer");

CreateDelay

    Arguments:
        string Name        Name of the delay object to make
        number Time        Time to delay processing (seconds)
        function Callback    Function to call when delay has completed
        any Data            Data to pass to Callback function when called
        AllowDuplicates        Allow multiple delays with this name?
        AllowExtend        Allow subsequent calls of this delay to extend the time?
        InCombat            If set to false, timer will be paused in combat
    Description:
        Creates a delay event, waits for given time and calls Callback(Data);
        AllowDuplicates and AllowExtend will be ignored if AllowDuplicates is set to true.
        Default behavior is AllowDuplicates=true, AllowExtend=false,InCombat=true

        Remember that if an existing Delay is extended, all the original parameters are kept,
        except the Time, which is replaced by the value you specified in this call.
    Returns:
        false = Delay not created
        true = Delay created successfully or existing delay extended
    Example:
        function MyAddon_Func1(value)
            print("Your lucky number is "..tostring(value));
        end
        success = LibQueue:CreateDelay("MyAddon_Delay1",5,MyAddon_Func1,10);
        After 5 seconds, outputs: Your lucky number is 10

Supplemental Notes

* WHY? *

Why use timers and delays?  Why not handle everything as it is given to me?
Several times, some events are called multiple times successively, and the data isn't available
immediately.  BAG_UPDATE is a good example.  In this case, you can use a delay with AllowExtend
to wait to process the inventory of a character until after all bags have been processed.  This
reduces interface lag as well.  Bag inventory is not available until the last call of BAG_UPDATE
has fired, and if you may end up scanning the entire inventory multiple times.

In general, handling large amounts of data or doing lots of things at once will create lots of
Interface lag.  Using a timer, and adding a processing queue to your mod will decrease lag by
a noticeable amount if used properly, even in increments of 0.1 seconds.  When WoW is parsing
scripts, it can't update the screen effectively.  You may also use timers to ensure that large
or timeconsuming sections of code aren't run multiple times when they don't need to be.

The delay is also a great way to make sure the client loads fully before initializing,
this eliminates the loading lag that people with lots of addons inevitably experience.

* QUEUES vs STACKS *

Queues and Stacks are advanced data storage structures that let you process information in a
more organized manner, and are extremely helpful for sorting algorithms and other types of
advanced datahandling procedures.  Below are pictorials to help you understand.

IN   > QUEUE > OUT
12345   54321    12345

STACK < IN 12345
12345
STACK > OUT 54321

* HOW TO CREATE AN ACTION PROCESSING QUEUE *

Create a queue, and use a timer to process the queue, pulling each value out and acting on it.
Add data to the queue as tables, or string values corresponding to psuedo commands, which you
process later in the timer callback.  You can even pass the Queue itself as data in the timer
function.  Processing the queue at intervals such as 0.05 or 0.1 will help reduce lag.

This can also help eliminate redundant actions, especailly screen updates, which can
exponentially increase your lag.

* HOW TO PASS DATA EFFECTIVELY *

The data you put in a Timer, Delay, or Queue isn't fixed in stone unless you want it to be.  If
you pass an existing value that you reference elsewhere, you can change the values in between
calls or before the event fires (like say, to cancel it from having an effect).  A good idea to
pass multiple types of data at once is to pass a table as well.

Remember, as long as the WoW client has some global variable referencing a table or value, that
table or value will never be destroyed.  You can pass pointers to existing tables into the timers
and the tables will still exist after the timer processes it.

* HOW TO USE MULTIPLE TIMERS/DELAYS EFFECTIVELY *

Timers or Delays can have multiples with the same name going at once.  With this system, you
can Pause/Start/Toggle all samenamed timers at once, or ensure the same function is called
multiple times concurrently with different values.  Remember that the function called does not
correlate to the name, however.

* NAMING IS IMPORTANT *

Remember also that Timers and Delays are stored internally, and that you should apply
modspecific naming conventions to identify your timers or delays.
Naming is also CASE SENSITIVE!

Queues are stored in your own global variables, and should have modspecific naming anyway so
you don't risk it getting overwritten by another mod.

Ex. Don't call it QueueB, call it MyAddonName_QueueB

* COMBAT *

Timers or Delays that have InCombat set to false will still tick during combat, but processing
will be delayed until combat ends.

* YOU'RE NOT THINKING 4TH DIMENSIONALLY! *

Don't be like Marty, plan your code execution.  If you create two delays at the same time, and
the first one is extended, don't count on it having run already when the 2nd one fires.
Remember to be a responsible denizen of the 4th dimension, as well, bogging down the Queue
library with dozens of timers and delays will impact every other mod using it, combine what you
can.

Facts

Date created
Sep 26, 2009
Categories
Last update
Nov 14, 2009
Development stage
Abandoned
Language
  • enUS
License
Public Domain
Downloads
414
Recent files

Authors