- Joined
- May 9, 2014
- Messages
- 1,820
Code
Includes
How-to Use/Install
API
Allocation And Linked List library
JASS:
library AllocLink requires /*
*/ optional Table, /*
* - By having this library, you can easily generate pseudo-variables that run on method
* operators, if you feel like running them.
*
*/ AllocT, /*
* - This is an allocator library that is now softcoded to allow up to 32766 for arrays.
* Since it requires a flag for such extended features, one must declare a library
* within the library to allow flag switching.
*
*/ LinkedListT, /*
* - This is a list ability with a minimal amount of methods introduced.
* - There are two versions for the linked lists, one is exclusively for the entire struct
* and the other is far more flexible.
*
* AllocLink
* - This is a library that aims to join both allocation and linked lists as it was in the
* intention of previous libraries.
*
* - This does not add any more features aside from being able to generate pseudo-variables
* at compile-time (through textmacros).
*
* Textmacros:
* op_set(varName, anyName, returnType, tableType, encapsulation, nullValue)
* - This generates two method operators with the assigned name "varName",
* which returns "returnType". The "tableType" adds some abstraction in
* case of including struct types and not just the native types. The
* "encapsulation" determines if the method operators are to be seen inside
* the class or outside. The null value is the appropriate null value for
* the returnType.
*
* op_read(varName, anyName, returnType, tableType, nullValue)
* - Fundamentally the same, but can be seen outside and only modified inside the
* class (struct).
*/
module AllocLink
implement AllocT
implement DoubleLink
endmodule
module AllocLinkBundle
implement AllocLink
endmodule
module AllocLinkBundleH
implement AllocH
implement DoubleLink
endmodule
//! textmacro op_set takes T, T1, T2, T3, E, NaN
static if LIBRARY_Table then
private static Table $T1$ = 0
$E$ method operator $T$ takes nothing returns $T2$
if $T1$ == 0 then
set $T1$ = Table.create()
endif
return $T1$.$T3$[this]
endmethod
$E$ method operator $T$= takes $T2$ new returns nothing
if $T1$ == 0 then
set $T1$ = Table.create()
endif
if not (new != $NaN$) then
call $T1$.$T3$.remove(this)
else
set $T1$.$T3$[this] = new
endif
endmethod
else
// ======================================================== //
// Textmacro op_set($T$, $T1$, $T2$, $T3$, $E$, $NaN$) //
// //
// Failed to implement the textmacro! //
// Reason: Missing library! //
// Library: Table //
// ======================================================== //
endif
//! endtextmacro
//! textmacro op_read takes T, T1, T2, T3, NaN
static if LIBRARY_Table then
private static Table $T1$ = 0
method operator $T$ takes nothing returns $T2$
if $T1$ == 0 then
set $T1$ = Table.create()
endif
return $T1$.$T3$[this]
endmethod
private method operator $T$= takes $T2$ new returns nothing
if $T1$ == 0 then
set $T1$ = Table.create()
endif
if not (new != $NaN$) then
call $T1$.$T3$.remove(this)
else
set $T1$.$T3$[this] = new
endif
endmethod
else
// ======================================================== //
// Textmacro op_read($T$, $T1$, $T2$, $T3$, $NaN$) //
// //
// Failed to implement the textmacro! //
// Reason: Missing library! //
// Library: Table //
// ======================================================== //
endif
//! endtextmacro
endlibrary
library_once AllocationAndLinks requires AllocLink
endlibrary
Allocator library
JASS:
library AllocT requires /*
*/ optional MapVersion, /*
* - Version control for the number of instances allocated.
* - Very much a snippet in itself. If you like, you can declare it below
*
*
*/ optional Table, /* https://www.hiveworkshop.com/threads/snippet-new-table.188084/
* - If found, the library generates an instance allocator with a maximum
* size of 2^31 - 1 (basically hashtables).
*
* - It also permits a textmacro (basically a generic) that generates a
* module with the same type of allocation for you.
*
* AllocT
* - Edition by MyPad
*
* What made me write it?
* - I thought of making this allocation library in anticipation of the future.
* - Due to using Wurst as well, I'm challenged to make a similarly-readable
* library dedicated to allocating.
*
* What about allocation safety?
* - Using an algorithm that reduces variable count to just one, (two if adding
* a counter for number of instances currently existing), the library can
* recursively allocate and deallocate safely.
*
* - If in debug mode, when allocating too many instances, the module will
* print an error message with the following information:
*
* Struct Name: Instance allocation method exceeded safety limit (Method: method-name)
*
* - Do note that the allocator will return -1 for this (debug mode).
* In normal mode, the allocator will just crash the thread.
*
* - If in debug mode, the deallocation method will display an error message
* with the following information:
*
* Struct Name: Instance (this) was double-freed! (Method: method-name)
**/
//! novjass
library MapVersion
globals
public constant boolean POST_128 = false
endglobals
endlibrary
//! endnovjass
module AllocT
private thistype alloc
method deallocate takes nothing returns nothing
if this.alloc != 0 then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 15, "|cffffcc00thistype|r: Instance (" + I2S(this) + ") was double-freed! (Method: deallocate)")
return
endif
set this.alloc = thistype(0).alloc
set thistype(0).alloc = this
endmethod
static method allocate takes nothing returns thistype
local thistype this = thistype(0).alloc
if this.alloc == 0 then
static if MapVersion_POST_128 then
if integer(this) < 32767 then
set this = this + 1
set thistype(0).alloc = this
return this
else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 15, "|cffffcc00{thistype}|r: Exceeded safety limit 32766! (Method: allocate)")
debug return -1
set this = 1/0
endif
else
if integer(this) < 8191 then
set this = this + 1
set thistype(0).alloc = this
return this
else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 15, "|cffffcc00{thistype}|r: Exceeded safety limit 8190! (Method: allocate)")
debug return -1
set this = 1/0
endif
endif
else
set thistype(0).alloc = this.alloc
set this.alloc = 0
endif
return this
endmethod
endmodule
//! textmacro AllocT takes T, K
$K$ module AllocT_$T$
private thistype $T$_alloc
method $T$_deallocate takes nothing returns nothing
if this.$T$_alloc != 0 then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 15, "|cffffcc00thistype|r: Instance (" + I2S(this) + ") was double-freed! (Method: $T$_deallocate)")
return
endif
set this.alloc = thistype(0).alloc
set thistype(0).alloc = this
endmethod
static method $T$_allocate takes nothing returns thistype
local thistype this = thistype(0).$T$_alloc
if this.$T$_alloc == 0 then
static if MapVersion_POST_128 then
if integer(this) < 32767 then
set this = this + 1
set thistype(0).$T$_alloc = this
return this
else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 15, "|cffffcc00{thistype}|r: Exceeded safety limit 32766! (Method: $T$_allocate)")
debug return -1
set this = 1/0
endif
else
if integer(this) < 8191 then
set this = this + 1
set thistype(0).$T$_alloc = this
return this
else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 15, "|cffffcc00{thistype}|r: Exceeded safety limit 8190! (Method: $T$_allocate)")
debug return -1
set this = 1/0
endif
endif
else
set thistype(0).$T$_alloc = this.$T$_alloc
set this.$T$_alloc = 0
endif
return this
endmethod
endmodule
//! endtextmacro
module AllocH
static if LIBRARY_Table then
private static Table Alloc
method deallocate takes nothing returns nothing
if Alloc.integer[this] != 0 then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 15, "|cffffcc00thistype[hashtable]|r: Instance (" + I2S(this) + ") was double-freed! (Method: deallocate)")
return
endif
set Alloc.integer[this] = Alloc.integer[0]
set Alloc.integer[0] = this
endmethod
static method allocate takes nothing returns thistype
local thistype this = Alloc.integer[0]
if Alloc.integer[this] == 0 then
set this = this + 1
set Alloc.integer[0] = this
else
set Alloc.integer[0] = Alloc.integer[this]
call Alloc.integer.remove(this)
endif
return this
endmethod
else
// ============================================================================================= //
// AllocH: Error! (Missing library) //
// A key library is missing, which resulted in the failure of the implementation //
// //
// Missing Library: Table (See link in documentation) //
// ============================================================================================= //
endif
private static method onInit takes nothing returns nothing
static if LIBRARY_Table then
set Alloc = Table.create()
else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 180, "|cffffcc00thistype[hashtable]|r: Cannot import the module! (AllocH)")
endif
endmethod
endmodule
//! textmacro AllocH takes T, K
$K$ module AllocH_$T$
static if LIBRARY_Table then
private static Table $T$_Alloc
method $T$_deallocate takes nothing returns nothing
if $T$_Alloc.integer[this] != 0 then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 15, "|cffffcc00thistype[hashtable]|r: Instance (" + I2S(this) + ") was double-freed! (Method: $T$_deallocate)")
return
endif
set $T$_Alloc.integer[this] = $T$_Alloc.integer[0]
set $T$_Alloc.integer[0] = this
endmethod
static method $T$_allocate takes nothing returns thistype
local thistype this = $T$_Alloc.integer[0]
if $T$_Alloc.integer[this] == 0 then
set this = this + 1
set $T$_Alloc.integer[0] = this
else
set $T$_Alloc.integer[0] = $T$_Alloc.integer[this]
call $T$_Alloc.integer.remove(this)
endif
return this
endmethod
else
// ============================================================================================= //
// AllocH_$T$: Error! (Missing library) //
// A key library is missing, which resulted in the failure of the implementation //
// //
// Missing Library: Table (See link in documentation) //
// ============================================================================================= //
endif
private static method onInit takes nothing returns nothing
static if LIBRARY_Table then
set $T$_Alloc = Table.create()
else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 180, "|cffffcc00thistype[hashtable]|r: Cannot import the module! (AllocH_$T$)")
endif
endmethod
endmodule
//! endtextmacro
endlibrary
Doubly-Linked List library
JASS:
library LinkedListT requires /*
*/ optional Table, /* https://www.hiveworkshop.com/threads/snippet-new-table.188084/
* - If not found, the library resorts to using a hashtable. Hashtables are limited to 256
* in game.
*
*/ optional AllocT, /*
* - As a manner of ordering, this library complements the LinkedListT library.
*
* LinkedListT
* - A simple library that converts classes into double-linked list classes.
* - It can dynamically create new module objects to be imported in code,
* although not as powerful as generics.
*
* Features:
* module DoubleLink
* <K> module DoubleLink_<T>
*
* The second one, which can be generated at runtime, behaves very similarly
* to the ordinary DoubleLink. What sets them apart is the suffix at the end.
*
* API:
* These modules expose the following methods:
* method insert(thistype that)
* method <T>_insert(thistype that)
* - Sets the next node of the current instance to request.
* - Adjusts the link accordingly
* - From 0 -> 1 to 0 -> 2 -> 1 (with 1 being that) or
* - From 0 -> 1 to 0 -> 1 -> 2 (with 0 being that)
*
* method queue(thistype that)
* method <T>_queue(thistype that)
* - Queues an instance as its' namesake implies.
* - From 0 -> 1 to 0 -> 1 -> 2 (with 1 being that) or
* - From 0 -> 1 to 0 -> 2 -> 1 (with 0 being that)
*
* method pop
* method <T>_pop
* - Unlinks an instance. Does not dereference it, though.
*
* Implementation:
* DoubleLink
*
* struct MyClass
* implement DoubleLink
*
* DoubleLink_<T>
*
* //! runtextmacro DLinkedListT("T", "K")
*
* struct MyClass
* implement DoubleLink_<T>
*/
private struct TableCheck extends array
static if not LIBRARY_Table then
static constant hashtable HASH = InitHashtable()
static method newTable takes nothing returns integer
local thistype this = LoadInteger(HASH, 0, 0)
set this = this + 1
call SaveInteger(HASH, 0, 0, this)
return this
endmethod
endif
endstruct
module DoubleLink
static if LIBRARY_Table then
private static Table Next = 0
private static Table Prev = 0
private static Table Head = 0
else
private static integer Next = 0
private static integer Prev = 0
private static integer Head = 0
endif
method operator next= takes thistype that returns nothing
static if LIBRARY_Table then
set Next.integer[this] = that
else
call SaveInteger(TableCheck.HASH, Next, this, that)
endif
endmethod
method operator prev= takes thistype that returns nothing
static if LIBRARY_Table then
set Prev.integer[this] = that
else
call SaveInteger(TableCheck.HASH, Prev, this, that)
endif
endmethod
method operator head= takes thistype that returns nothing
static if LIBRARY_Table then
set Head.integer[this] = that
else
call SaveInteger(TableCheck.HASH, Head, this, that)
endif
endmethod
method operator next takes nothing returns thistype
static if LIBRARY_Table then
return Next.integer[this]
else
return LoadInteger(TableCheck.HASH, Next, this)
endif
endmethod
method operator prev takes nothing returns thistype
static if LIBRARY_Table then
return Prev.integer[this]
else
return LoadInteger(TableCheck.HASH, Prev, this)
endif
endmethod
method operator head takes nothing returns thistype
static if LIBRARY_Table then
return Head.integer[this]
else
return LoadInteger(TableCheck.HASH, Head, this)
endif
endmethod
method insert takes thistype that returns nothing
set this.next = that
set this.prev = that.prev
set that.prev.next = this
set that.prev = this
endmethod
method queue takes thistype that returns nothing
set this.prev = that
set this.next = that.next
set that.next.prev = this
set that.next = this
endmethod
method push takes nothing returns nothing
call insert(0)
endmethod
method enqueue takes nothing returns nothing
call queue(0)
endmethod
method pop takes nothing returns nothing
set this.prev.next = this.next
set this.next.prev = this.prev
set this.head = 0
endmethod
private static method onInit takes nothing returns nothing
static if LIBRARY_Table then
set Next = Table.create()
set Prev = Table.create()
set Head = Table.create()
else
set Next = TableCheck.newTable()
set Prev = TableCheck.newTable()
set Head = TableCheck.newTable()
endif
endmethod
endmodule
//! textmacro DLinkedListT takes T, K
$K$ module DoubleLink_$T$
static if LIBRARY_Table then
private static Table Next = 0
private static Table Prev = 0
private static Table Head = 0
else
private static integer Next = 0
private static integer Prev = 0
private static integer Head = 0
endif
method operator $T$_next= takes thistype that returns nothing
static if LIBRARY_Table then
set Next.integer[this] = that
else
call SaveInteger(TableCheck.HASH, Next, this, that)
endif
endmethod
method operator $T$_prev= takes thistype that returns nothing
static if LIBRARY_Table then
set Prev.integer[this] = that
else
call SaveInteger(TableCheck.HASH, Prev, this, that)
endif
endmethod
method operator $T$_head= takes thistype that returns nothing
static if LIBRARY_Table then
set Head.integer[this] = that
else
call SaveInteger(TableCheck.HASH, Head, this, that)
endif
endmethod
method operator $T$_next takes nothing returns thistype
static if LIBRARY_Table then
return Next.integer[this]
else
return LoadInteger(TableCheck.HASH, Next, this)
endif
endmethod
method operator $T$_prev takes nothing returns thistype
static if LIBRARY_Table then
return Prev.integer[this]
else
return LoadInteger(TableCheck.HASH, Prev, this)
endif
endmethod
method operator $T$_head takes nothing returns thistype
static if LIBRARY_Table then
return Head.integer[this]
else
return LoadInteger(TableCheck.HASH, Head, this)
endif
endmethod
method $T$_insert takes thistype that returns nothing
set this.$T$_next = that
set this.$T$_prev = that.$T$_prev
set that.$T$_prev.$T$_next = this
set that.$T$_prev = this
endmethod
method $T$_queue takes thistype that returns nothing
set this.$T$_prev = that
set this.$T$_next = that.$T$_next
set that.$T$_next.$T$_prev = this
set that.$T$_next = this
endmethod
method $T$_push takes nothing returns nothing
call $T$_insert(0)
endmethod
method $T$_enqueue takes nothing returns nothing
call $T$_queue(0)
endmethod
method $T$_pop takes nothing returns nothing
set this.$T$_prev.$T$_next = this.$T$_next
set this.$T$_next.$T$_prev = this.$T$_prev
endmethod
private static method onInit takes nothing returns nothing
static if LIBRARY_Table then
set Next = Table.create()
set Prev = Table.create()
set Head = Table.create()
else
set Next = TableCheck.newTable()
set Prev = TableCheck.newTable()
set Head = TableCheck.newTable()
endif
endmethod
// ===================================================== //
// Module DoubleLink_$T$ implemented successfully //
// //
// Implemented in class thistype //
// ===================================================== //
endmodule
// ==================================================== //
// Module DoubleLink_$T$ created in library/scope //
// Encapsulation type: $K$ //
// ==================================================== //
//! endtextmacro
endlibrary
Two allocation modules, one for arrays and another for hashtables.
A Circularly-linked double-linked list that allows traversal of points and eases linear searching (hashtable version only).
A textmacro (DLinkedListT) to ease generation of lists: (one for Tables and one for arrays)
Two more textmacros (AllocT and AllocH) for more allocation modules: (one for Tables and one for arrays)
This assumes that you have installed either the Jass NewGen Pack (for the wonderful JassHelper) or WEX.
Installation:
First, create two triggers and convert them to custom text.
Then, copy and paste the library/libraries above, and voila, you are done.
Usage:
Allocation:
Convert your struct from this:
JASS:
struct WhichStruct
...
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
return this
endmethod
endstruct
to this:
JASS:
struct WhichStruct extends array
implement AllocT
...
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
return this
// Or, you could just do this...
// You can also declare an implicit static method.
return thistype.allocate()
endmethod
endstruct
Linked-List:
I prefer calling it when creating an instance, but the rest's up to you
JASS:
method destroy takes nothing returns nothing
...
call pop()
call deallocate()
endmethod
static method create takes nothing returns thistype
local thistype this = allocate()
call this.push()
// Or
call this.queue()
return this
endmethod
To get these features, all you have to do is implement the following module like this
JASS:
implement DoubleLink //or
implement DoubleLink_<T> // <T> represents whatever suffix you've provided
Created: June 27, 2017
Updated: March 22, 2018
(Note: The linked list is static)
The Linked List methods:
Removes a certain node from a list.
Inserts an instance in between the instance that and its' previous instance that.prev.
a wrapper method for insertion at head = 0
Queues the instance towards a head instance that.
a wrapper method for queue at head = 0
a wrapper static method for removal of first node at head = 0
a wrapper static method for removal of last node at head = 0
The Allocation methods:
Need I explain here? Generates a unique index for the request.
Deallocates a certain node. Has default double-free protection.
textmacros:
A textmacro for generating a module for implementation that creates a prefix_next and prefix_prev member. The status field determines whether it is only restricted onto the library or scope or public to all.
Generates allocator modules, one with arrays and the other with hashtables respectively.
The Linked List methods:
method pop takes nothing returns nothing
Removes a certain node from a list.
method insert takes thistype that returns nothing
Inserts an instance in between the instance that and its' previous instance that.prev.
method push takes nothing returns nothing
a wrapper method for insertion at head = 0
method queue takes thistype that returns nothing
Queues the instance towards a head instance that.
method enqueue takes nothing returns nothing
a wrapper method for queue at head = 0
static method remove takes nothing returns nothing
a wrapper static method for removal of first node at head = 0
static method eject takes nothing returns nothing
a wrapper static method for removal of last node at head = 0
The Allocation methods:
static method allocate takes nothing returns nothing, static method <T>_allocate takes nothing returns nothing
Need I explain here? Generates a unique index for the request.
method deallocate takes nothing returns nothing, method <T>_allocate takes nothing returns nothing
Deallocates a certain node. Has default double-free protection.
textmacros:
//! runtextmacro DLinkedListT(prefix, status)
A textmacro for generating a module for implementation that creates a prefix_next and prefix_prev member. The status field determines whether it is only restricted onto the library or scope or public to all.
//! runtextmacro AllocT(prefix, status), //! runtextmacro AllocH(prefix, status)
Generates allocator modules, one with arrays and the other with hashtables respectively.
Last edited: