• 🏆 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] ArrayList

Level 31
Joined
Jul 10, 2007
Messages
6,306
Before you comment on how remarkably useless this is, I found a need for it in AI. I am working on creating BehaviorTree and the traditional approach requires this.

JASS:
library ArrayList /* v1.0.0.0
*************************************************************************************
*
*   Used for creating cicrularly linked lists that can be of any size and that have extra functionality.
*   These lists are not built for speed but rather for functionality.
*
*   Any operation having to do with indexes will be O(n), so avoid them. Any other
*   operation, including value counts and excluding destruction, clear, removeAll, and toString, is O(1).
*
*   Destroying a list is O(2*n)
*
*   This struct was modeled after the Java Vector class.
*
*   Any node may be used with any method except for delete. Only non head nodes may be used with delete.
*
*   next/prev pointers are hashtable reads, so this is not recommended for speed.
*   The list pointer contains no data.
*
*************************************************************************************
*
*   */uses/*
*
*       */ Table /*         hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
*
*************************************************************************************
*
*   struct ArrayList extends array
*
*       integer value
*       readonly integer size
*       readonly thistype first
*       readonly thistype last
*       readonly thistype next
*       readonly thistype prev
*       readonly boolean isEmpty
*       method operator [] takes integer index returns integer
*       method operator []= takes integer index, integer value returns nothing
*
*       static method create takes nothing returns thistype
*       method destroy takes nothing returns nothing
*
*       method add takes thistype value returns nothing
*           -   adds after current node (push when list is used)
*       method addLast takes thistype value returns nothing
*           -   adds before head (enqueue)
*
*       method clear takes nothing returns nothing
*       method remove takes integer value returns nothing
*       method removeIndexes takes integer indexStart, integer indexEnd returns nothing
*       method removeAll takes integer value returns nothing

*       method contains takes integer value returns boolean
*
*       method getIndexOf takes integer value, integer startIndex returns integer
*       method getFirstIndexOf takes integer value returns integer
*       method getLastIndexOf takes integer value returns integer
*
*       method getValueCount takes integer value returns integer
*
*       method toString takes nothing returns string
*
*       method delete takes nothing returns nothing
*           -   deletes node
*           -   list.next.delete()
*
*************************************************************************************/
    struct ArrayList extends array
        private static integer hashInstanceCount = 0
        private static integer array hashRecycler
    
        private static integer instanceCount = 0
        private static Table hash_p

        private static Table recycler
        private Table next_p
        private Table prev_p
        private Table lookup_p
        
        private static Table value_p
        private static Table head_p
        private static Table size_p
        
        private static Table tied_p
        private static Table tied_p2
        
        private static method allocateHash takes nothing returns integer
            local integer i = hashRecycler[0]
            if (0 == i) then
                set i = hashInstanceCount + 1
                set hashInstanceCount = i
            else
                set hashRecycler[0] = hashRecycler[i]
            endif
            
            return i
        endmethod
        private static method deallocateHash takes integer hash returns nothing
            set hashRecycler[hash] = hashRecycler[0]
            set hashRecycler[0] = hash
        endmethod
        
        method operator value takes nothing returns integer
            return value_p[this]
        endmethod
        private method operator head takes nothing returns thistype
            return head_p[this]
        endmethod
        private method operator head= takes thistype head returns nothing
            set head_p[this] = head
        endmethod
        private method operator hash takes nothing returns thistype
            return hash_p[head]
        endmethod
        private method operator hash= takes integer value returns nothing
            set hash_p[head] = value
        endmethod
        method operator size takes nothing returns integer
            return size_p[head]
        endmethod
        private method operator size= takes integer value returns nothing
            set size_p[head] = value
        endmethod
        
        private static method operator [] takes integer index returns thistype
            return recycler[index]
        endmethod
        private static method operator []= takes integer index, integer value returns nothing
            set recycler[index] = value
        endmethod
        
        private method operator lookup2node takes nothing returns thistype
            return tied_p[this]
        endmethod
        private method operator node2lookup takes nothing returns thistype
            return tied_p2[this]
        endmethod
        private method operator tied= takes thistype node returns nothing
            set tied_p[this] = node
            set tied_p2[node] = this
        endmethod
        private method clearTies takes nothing returns nothing
            local thistype node = lookup2node
            
            set tied_p[this] = 0
            set tied_p2[node] = 0
        endmethod
        
        method operator next takes nothing returns thistype
            return hash.next_p[this]
        endmethod
        method operator prev takes nothing returns thistype
            return hash.prev_p[this]
        endmethod
        private method operator next= takes thistype i returns nothing
            set hash.next_p[this] = i
        endmethod
        private method operator prev= takes thistype i returns nothing
            set hash.prev_p[this] = i
        endmethod
        private method getLookup takes integer value returns thistype
            return hash.lookup_p[value]
        endmethod
        private method setLookup takes integer value, thistype list returns nothing
            set hash.lookup_p[value] = list
        endmethod
        method operator first takes nothing returns thistype
            return head.next
        endmethod
        method operator last takes nothing returns thistype
            return head.prev
        endmethod
        
        private method createLookup takes nothing returns nothing
            set hash.lookup_p = Table.create()
        endmethod
        private method destroyLookup takes nothing returns nothing
            call hash.lookup_p.destroy()
        endmethod
        
        method operator [] takes integer index returns integer
            set this = head
        
            loop
                set this = next
                exitwhen 0 == index
                set index = index - 1
            endloop
            
            return value
        endmethod
        
        method operator []= takes integer index, integer value returns nothing
            set this = head
        
            loop
                set this = next
                exitwhen 0 == index
                set index = index - 1
            endloop
            
            set this.value = value
        endmethod
        
        method getFirstIndexOf takes integer value returns integer
            local integer index = 0
            
            set this = head
            
            if (0 != getLookup(value)) then
                loop
                    set this = next
                    exitwhen this.value == value
                    set index = index + 1
                endloop
                
                return index
            endif
            
            return -1
        endmethod
        
        method getLastIndexOf takes integer value returns integer
            local integer index
            
            set this = head
            set index = size
            
            if (0 != getLookup(value)) then
                loop
                    set this = prev
                    set index = index - 1
                    exitwhen this.value == value
                endloop
                
                return index
            endif
            
            return -1
        endmethod
        
        method getIndexOf takes integer value, integer startIndex returns integer
            local integer index = 0
            
            set this = head
            
            if (0 == getLookup(value) or startIndex >= size) then
                return -1
            endif
            
            loop
                set this = next
                exitwhen this == head or (this.value == value and index >= startIndex)
                set index = index + 1
            endloop
            
            if (this == head) then
                return -1
            endif
            
            return index
        endmethod
        
        method operator isEmpty takes nothing returns boolean
            return 0 == size
        endmethod
        
        private static method allocate takes nothing returns thistype
            local thistype this = thistype[0]
            if (0 == this) then
                set this = instanceCount + 1
                set instanceCount = this
            else
                set thistype[0] = thistype[this]
            endif
            
            return this
        endmethod
        
        private method deallocate takes nothing returns nothing
            set thistype[this] = thistype[0]
            set thistype[0] = this
        endmethod
        
        private method initialize takes nothing returns nothing
            set head = this
            set hash = allocateHash()
            set hash.next_p = Table.create()
            set hash.prev_p = Table.create()
            set next = this
            set prev = this
        endmethod
        
        static method create takes nothing returns thistype
            local thistype this = allocate()
            
            call initialize()
            
            call createLookup()
            
            return this
        endmethod
        
        private method push takes thistype node returns nothing
            set node.head = head
            set head.size = head.size + 1
            
            set this.next.prev = node
            set node.next = this.next
            
            set node.prev = this
            set this.next = node
        endmethod
        private method pop takes nothing returns nothing
            set head.size = head.size - 1
            set prev.next = next
            set next.prev = prev
        endmethod
        
        method contains takes integer value returns boolean
            return 0 != getLookup(value)
        endmethod
        
        private static method clearLookupNode takes thistype lookupNode returns nothing
            local thistype lookupList = lookupNode.head
            local thistype this = lookupNode.lookup2node
            
            call lookupNode.clearTies()
            call lookupNode.pop()
            
            if (lookupList.next == lookupList) then
                call lookupList.deallocate()
                call setLookup(value, 0)
                call deallocateHash(lookupList.hash)
                call lookupList.hash.next_p.destroy()
                call lookupList.hash.prev_p.destroy()
            endif
            
            call lookupNode.deallocate()
        endmethod
        
        private method clearValue takes nothing returns nothing
            call clearLookupNode(getLookup(value).next)
        endmethod
        
        method operator value= takes integer value returns nothing
            local thistype lookupList
            local thistype lookupNode
            
            set lookupNode = node2lookup
            if (0 != lookupNode) then
                call clearLookupNode(lookupNode)
            endif
            
            set lookupList = getLookup(value)
            set lookupNode = allocate()
            
            if (0 == lookupList) then
                set lookupList = allocate()
                set lookupList.hash = allocateHash()
                call lookupList.initialize()
                call setLookup(value, lookupList)
            endif
        
            set value_p[this] = value
            set value_p[lookupNode] = value
            
            set lookupNode.tied = this
            
            call lookupList.prev.push(lookupNode)
        endmethod
        
        method addLast takes thistype value returns nothing
            local thistype node = allocate()
            call head.prev.push(node)
            set node.value = value
        endmethod
        
        method add takes thistype value returns nothing
            local thistype node = allocate()
            call push(node)
            set node.value = value
        endmethod
        
        method delete takes nothing returns nothing
            if (this != head) then
                call clearValue()
                call pop()
                call deallocate()
            endif
        endmethod
        
        method remove takes integer value returns nothing
            local thistype lookupList = getLookup(value)
            local thistype node = lookupList.next.lookup2node
            
            if (0 == lookupList) then
                return
            endif
            
            call node.delete()
        endmethod
        
        method removeAll takes integer value returns nothing
            local thistype lookupList = getLookup(value)
            local thistype lookupnode = lookupList
            local integer size = lookupList.size
            
            if (0 == lookupList) then
                return
            endif
            
            loop
                exitwhen 0 == size
                set size = size - 1
                call lookupnode.lookup2node.delete()
            endloop
        endmethod
        
        method getValueCount takes integer value returns integer
            return getLookup(value).size
        endmethod
        
        method removeIndex takes integer indexToRemove returns nothing
            local integer index = 0
            
            set this = head
            
            if (indexToRemove >= size) then
                return
            endif
            
            loop
                set this = next
                exitwhen index == indexToRemove
                set index = index + 1
            endloop
            
            call delete()
        endmethod
        
        method removeIndexes takes integer indexStart, integer indexEnd returns nothing
            local integer index = 0
            
            set this = head
            
            if (indexStart >= size or indexEnd < indexStart or indexEnd >= size) then
                return
            endif
            
            loop
                set this = next
                exitwhen index == indexStart
                set index = index + 1
            endloop
            
            loop
                call delete()
                exitwhen index == indexEnd
                set this = next
                set index = index + 1
            endloop
        endmethod
        
        method clear takes nothing returns nothing
            set this = head
            loop
                exitwhen 0 == size
                call next.delete()
            endloop
        endmethod
        
        method destroy takes nothing returns nothing
            set this = head
            
            call clear()
            call deallocate()
            call destroyLookup()
            call hash.next_p.destroy()
            call hash.prev_p.destroy()
            call deallocateHash(hash)
        endmethod
        
        method toString takes nothing returns string
            local string str = ""
            
            set this = head.next
            if (this == head) then
                return null
            endif
            set str = I2S(value)
            
            loop
                set this = next
                exitwhen this == head
                set str = str + ", " + I2S(value)
            endloop
            
            return str
        endmethod
        
        private static method onInit takes nothing returns nothing
            set recycler = Table.create()
            set size_p = Table.create()
            set value_p = Table.create()
            set head_p = Table.create()
            set tied_p = Table.create()
            set tied_p2 = Table.create()
            set hash_p = Table.create()
        endmethod
    endstruct
endlibrary
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
ipool is completely different... i fail to see the similarities.

How ipool works as well as its features are completely different from how this works and its features. You can't add a value multiple times to ipool for example >.>. You may say you can, but you wouldn't be able to iterate through ipool and see it pop up multiple times.

ipool is completely different.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
I see what you mean. Originally iPool had a user-iterable interface as well, I forgot that I did not include it in the public release.

It would be doable to implement a public wrapper for it to iterate/count all instances of a certain value, or just iterate/count everything as a whole. But it would be annoying to code, and since you already have this, that saves me some work.

But the rest of the API looks like it was already covered by iPool (since iPool is simply a linear stack with some optimizations for type-specific referencing).
 
Top