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

List

Level 8
Joined
Aug 4, 2006
Messages
357
Requires
JassNewGenPack
Warcraft 3 v1.24 or above
Some Jass and vJass knowledge

What is this?

A List is basically like an array that keeps its contents stored between index 0 and the current size of the List. It is an easy way to store structs, handles, reals, and whatever the hell you want. It imitates the functionality of ArrayLists (from Java), but uses hashtables instead of arrays.

Pros:

  • Keeps its contents together and preserves the order in which they were added.
  • Unlike arrays, Lists can be parameters of functions.
  • Due to the above 2, List is easy to sort and loop through.
  • Lists can always have an unlimited number of elements, whereas arrays can only have 8191 (or much less if the array is a member of a struct).
  • Due to the above, List is great for using as a struct member.
  • O(1) to get or set any object in the list.
  • O(1) to add or remove an object from the front or back of the list
  • O(N/2) worst case to add or remove an object from a random position in the list.
  • Can store any form of data.
Cons:
  • Slower than working with arrays.
  • Removing, replacing, or clearing handle objects can leak bad if not done responsibly. Oh wait, that can happen with any data storage system in wc3...
  • Each List textmacro that you run will add ~2.6kb to your map size. If this actually matters to you, only run the textmacros for List types that you will actually use. If you are really desparate, you can delete any methods you won't use. However, this is not recommended since some List methods may make calls to other List methods.
  • O(N) worst case to find the index of an object, but you should be keeping track of the indexes of your objects anyway.

JASS:
//---------important methods-------------
method operator size takes nothing returns integer
//purpose: returns the number of elements in the list.

method addLast takes $type$ object returns nothing
//purpose: appends the specified object to the end of the list.
// increases the size of the list by 1. does not shift the list.
//example:
    local IntegerList intList = IntegerList.create()
    call intList.addLast(35) 
    //intList is now {  35}
    call intList.addLast(62) 
    //intList is now {  35,  62}
    call intList.addLast(1)
    //intList is now {  35,  62,   1}

method addFirst takes $type$ object returns nothing
//purpose: appends the specified object to the beginning of the list.
// increases the size of the list by 1.
// objects will seem to shift right, but the method does not loop.
//example (continued from above):
    call intList.addFirst(92)
    //intList is now {  92,  35,  62,   1}
         
method removeLast takes nothing returns $type$
//purpose: detaches the last object from the list and returns it.
// decreases .size by 1.
//example (continued):
    intList.removeLast() //removes intList[3] and returns 1 
    //intList is now {  92,  35,  62}
         
method removeFirst takes nothing returns $type$
//purpose: detaches the first object from the list and returns it.
// decreases .size by 1.
// objects will seem to shift left, but the method does not loop.
//example (continued):
    intList.removeFirst() //remove intList[0] and returns 92
    //intList is now {  35,  62}
            
method operator [] takes integer index returns $type$
//purpose: get the object stored at the specified position
//example (continued):
    intList[2]  //reports an error if in debug mode, returns 0 by default
    intList[1]  //returns 62
        
method operator []= takes integer index, $type$ object returns nothing
//purpose: replace the object at the specified position with the specified object
//example (continued):
    set intList[5] = 98 //reports an error if in debug mode, returns 0 by default
    set intList[0] = 22 //replace 35 with 22 
    //intList is now {  22,  62}
        
method add takes integer index, $type$ object returns nothing
//purpose: inserts the specified object at the specified position.
//Any objects at or after this position will seem to shift right one position.
//Increases .size by 1
//example (continued):
    call intList.add(2, 573)  //adding at .size works the same as addLast
    //intList is now {  22,  62, 573}
    call intList.add(0, 6)  //adding at 0 works the same as addFirst
    //intList is now {   6,  22,  62, 573}
    call intList.add(1, 59)
    //intList is now {   6,  59,  22,  62, 573}

method remove takes integer index returns $type$
//purpose: removes the object at the specified index and returns it.
//Any objects after this will appear to shift left one slot.
//example (continued):
    intList.remove(2) //returns 22 
    //intList is now {   6,  59,  62, 573}

method clear takes nothing returns nothing
//purpose: clears the entire list quickly
//example (continued):
    call intList.clear() 
    //intList is now {    }
          
//----------end important methods--------------
      
//------------------other methods-------------
          
method removeRange takes integer fromIndex, integer toIndex returns nothing
//purpose: removes from this List all of the elements whose index is between
// fromIndex (inclusive) and toIndex (exclusive).
          
method indexOf takes $type$ object returns integer
//purpose: returns the index of the first occurance of the given object.
// returns -1 if the object is not found.
          
method lastIndexOf takes $type$ object returns integer
//purpose: returns the index of the last occurance of the given object.
// returns -1 if the object is not found.
          
method swap takes integer index1, integer index2 returns nothing
//purpose: swaps the positions of two elements in the same list.
          
method exists takes integer index returns boolean
//purpose: returns true if there is an object stored at the specified position
          
method isEmpty takes nothing returns boolean
//purpose: returns true if list is empty
          
//--------------end other methods--------------------
JASS:
library List
//==================================================================================
// List version 1.1
//----------------------------
//  Use this version in your map.
//==================================================================================
// - made by MaskedPoptart
// - imitates the functionality of ArrayLists (from Java)
//   using a hashtable.
//==================================================================================
//       Basic Usage:
//  set arr = IntegerList.create()      - instantiate a List of integers
//  arr.size                            - get the current number of elements
//  call arr.addLast(5732)              - add 5732 to the end of the list,
//                                        increase .size by 1
//  arr.removeLast()                    - remove the last element in the list,
//                                        decrease .size by 1, return removed element
//  arr.remove(6)                       - remove the 6th element, decrease .size by 1,
//                                        return removed element, shift elements down
//  arr[3]                              - get the element at index 3
//  set arr[23] = 815                   - replace the value at index 23 with 815
//  call arr.clear()                    - remove all objects from the list
//  call arr.destroy()                  - clear list and recycle the struct index
//
// WARNING:     Most attempts to work with indexes <0 or >=.size will fail and
//  generate an error message in debug mode. Returns default to 0 for integers/
//  reals, null for handles, false for booleans, etc.
//
// LEAK WARNING:    List does no automatic garbage collection. If a List
//  is the only place you store a variable, make sure the variable will not leak when
//  you remove it or replace it.
//===================================================================================
//    Credits:
// - Vexorian for JassHelper
// - Vexorian for Table 3.0 (which I used for reference)
// - All the other people who worked on JassNewGenPack
//===================================================================================
    globals
        private constant integer MAX_INSTANCES = 8190
    endglobals
    
    //! textmacro List takes type, listType, typeName
    struct $listType$List [MAX_INSTANCES]
        private integer min = -1
        private integer max = 0
        private static hashtable contents = InitHashtable()
        private static $type$ tempObject
        private static $type$ DEFAULT_VALUE
        
        private static method onInit takes nothing returns nothing
            set thistype.DEFAULT_VALUE = Load$typeName$(thistype.contents,0,0)
        endmethod
        
        private method getActualIndex takes integer publicIndex returns integer
            return publicIndex + this.min + 1
        endmethod
        
        private method getPublicIndex takes integer actualIndex returns integer
            return actualIndex - this.min - 1
        endmethod
        
        private method isValidIndex takes integer actualIndex returns boolean
            return actualIndex > this.min and actualIndex < this.max
        endmethod
        
//---------------------USER METHODS------------------------

        method operator size takes nothing returns integer
            return this.max-this.min-1
        endmethod
        
        method addFirst takes $type$ object returns nothing
            call Save$typeName$(this.contents, integer(this), this.min, object)
            set this.min = this.min - 1
        endmethod
        
        method addLast takes $type$ object returns nothing
            call Save$typeName$(this.contents, integer(this), this.max, object)
            set this.max = this.max + 1
        endmethod
        
        method removeFirst takes nothing returns $type$
            if(this.size>0)then
                set this.min = this.min + 1
                return Load$typeName$(this.contents, integer(this), this.min)
            endif
            debug call BJDebugMsg("ERROR: $listType$List \"removeFirst\" method. Cannot remove from an empty List.")
            return this.DEFAULT_VALUE
        endmethod
        
        method removeLast takes nothing returns $type$
            if(this.size>0)then
                set this.max = this.max - 1
                return Load$typeName$(this.contents, integer(this), this.max)
            endif
            debug call BJDebugMsg("ERROR: $listType$List \"removeLast\" method. Cannot remove from an empty List.")
            return this.DEFAULT_VALUE
        endmethod
        
        method operator [] takes integer index returns $type$
            local integer actualIndex = this.getActualIndex(index)
            if(this.isValidIndex(actualIndex))then
                return Load$typeName$(this.contents, integer(this), actualIndex)
            endif
            debug call BJDebugMsg("ERROR: $listType$List \"[]\" method. Index Out of Bounds ("+I2S(index)+").")
            return this.DEFAULT_VALUE
        endmethod
        
        method operator []= takes integer index, $type$ object returns nothing
            local integer actualIndex = this.getActualIndex(index)
            if(this.isValidIndex(actualIndex))then
                call Save$typeName$(this.contents, integer(this), actualIndex, object)
            debug else
                debug call BJDebugMsg("ERROR: $listType$List \"[]=\" method. Index Out of Bounds ("+I2S(index)+").")
            endif
        endmethod
        
        method add takes integer index, $type$ object returns nothing
            local integer i
            local integer actualIndex = this.getActualIndex(index)
            if(actualIndex > this.min and actualIndex <= this.max)then
                if(actualIndex <= 0.5*(this.min+this.max))then
                    set actualIndex = actualIndex - 1
                    set i = this.min
                    loop
                        exitwhen i >= actualIndex
                        call Save$typeName$(this.contents, integer(this), i, Load$typeName$(this.contents, integer(this), i+1))
                        set i = i + 1
                    endloop
                    set this.min = this.min - 1
                else
                    set i = this.max
                    loop
                        exitwhen i <= actualIndex
                        call Save$typeName$(this.contents, integer(this), i, Load$typeName$(this.contents, integer(this), i-1))
                        set i = i - 1
                    endloop
                    set this.max = this.max + 1
                endif
                call Save$typeName$(this.contents, integer(this), actualIndex, object)
            debug else
                debug call BJDebugMsg("ERROR: $listType$List \"add\" method. Index Out of Bounds ("+I2S(index)+").")
            endif
        endmethod
        
        method remove takes integer index returns $type$
            local integer i
            local integer actualIndex = this.getActualIndex(index)
            if(this.isValidIndex(actualIndex))then
                set this.tempObject = Load$typeName$(this.contents, integer(this), actualIndex)
                set i = actualIndex
                if(actualIndex <= 0.5*(this.min+this.max))then
                    set this.min = this.min + 1
                    loop
                        exitwhen i <= this.min
                        call Save$typeName$(this.contents, integer(this), i, Load$typeName$(this.contents, integer(this), i-1))
                        set i = i - 1
                    endloop               
                else
                    set this.max = this.max - 1
                    loop
                        exitwhen i >= this.max
                        call Save$typeName$(this.contents, integer(this), i, Load$typeName$(this.contents, integer(this), i+1))
                        set i = i + 1
                    endloop
                endif
                return this.tempObject
            endif
            debug call BJDebugMsg("ERROR: $listType$List \"remove\" method. Index Out of Bounds ("+I2S(index)+").")
            return this.DEFAULT_VALUE
        endmethod
        
        method clear takes nothing returns nothing
            call FlushChildHashtable(this.contents, integer(this))
            set this.min = -1
            set this.max = 0
        endmethod
        
        method removeRange takes integer fromIndex, integer toIndex returns nothing
            local integer i
            local integer actualFromIndex = this.getActualIndex(fromIndex)
            local integer actualToIndex = this.getActualIndex(toIndex-1)
            if(this.isValidIndex(actualFromIndex))then
                if(this.isValidIndex(actualToIndex) and toIndex>fromIndex)then
                    if(actualFromIndex-this.min < this.max-actualToIndex)then
                        set i = actualFromIndex
                        loop
                            set i = i - 1
                            exitwhen i<=this.min
                            call Save$typeName$(this.contents, integer(this), i-fromIndex+toIndex, Load$typeName$(this.contents, integer(this), i))
                        endloop
                        set this.min = this.min-fromIndex+toIndex
                    else
                        set i = actualToIndex
                        loop
                            set i = i + 1
                            exitwhen i>=this.max
                            call Save$typeName$(this.contents, integer(this), i+fromIndex-toIndex, Load$typeName$(this.contents, integer(this), i))
                        endloop
                        set this.max = this.max+fromIndex-toIndex
                    endif
                debug else
                    debug call BJDebugMsg("ERROR: $listType$List \"removeRange\" method. Index Out of Bounds ("+I2S(toIndex)+").")
                endif
            debug else
                debug call BJDebugMsg("ERROR: $listType$List \"removeRange\" method. Index Out of Bounds ("+I2S(fromIndex)+").")
            endif
        endmethod
        
        method indexOf takes $type$ object returns integer
            local integer i = this.min
            loop
                set i = i + 1
                exitwhen i>=this.max
                if(Load$typeName$(this.contents, integer(this), i) == object)then
                    return this.getPublicIndex(i)
                endif
            endloop
            return -1
        endmethod
        
        method lastIndexOf takes $type$ object returns integer
            local integer i = this.max
            loop
                set i = i - 1
                exitwhen i<=this.min
                if(Load$typeName$(this.contents, integer(this), i) == object)then
                    return this.getPublicIndex(i)
                endif
            endloop
            return -1
        endmethod
        
        method swap takes integer index1, integer index2 returns nothing
            local integer actualIndex1 = this.getActualIndex(index1)
            local integer actualIndex2 = this.getActualIndex(index2)
            if(this.isValidIndex(actualIndex1))then
                if(this.isValidIndex(actualIndex2))then
                    set this.tempObject = Load$typeName$(this.contents, integer(this), actualIndex1)
                    call Save$typeName$(this.contents, integer(this), actualIndex1, Load$typeName$(this.contents, integer(this), actualIndex2))
                    call Save$typeName$(this.contents, integer(this), actualIndex2, this.tempObject)
                debug else
                    debug call BJDebugMsg("ERROR: $listType$List \"swap\" method. Index Out of Bounds ("+I2S(index2)+").")
                endif
            debug else
                debug call BJDebugMsg("ERROR: $listType$List \"swap\" method. Index Out of Bounds ("+I2S(index1)+").")
            endif
        endmethod

        method exists takes integer index returns boolean
            return index >= 0 and index < this.size
        endmethod
        
        method isEmpty takes nothing returns boolean
            return this.max == 0
        endmethod
        
//------------------END USER METHODS----------------------

        private method onDestroy takes nothing returns nothing
            call this.clear()
        endmethod
    endstruct
    //! endtextmacro

  //runtextmacro List( "type",      "listType", "typeName"  )
  
//type = type of object to store. must be exact.
//listType = prefix to the List struct name. can be whatever you want.
//ex: Timer --> TimerList
//typeName = suffix in Save, Load hashtable functions. must be exact.
//ex: Str --> LoadStr
  
//! runtextmacro List( "integer",   "Integer",  "Integer"       )
//! runtextmacro List( "string",    "String",   "Str"           )
//! runtextmacro List( "real",      "Real",     "Real"          )
//! runtextmacro List( "boolean",   "Boolean",  "Boolean"       )

//! runtextmacro List( "player",    "Player",   "PlayerHandle"  )
//! runtextmacro List( "unit",      "Unit",     "UnitHandle"    )
//! runtextmacro List( "item",      "Item",     "ItemHandle"    )
//! runtextmacro List( "widget",    "Widget",   "WidgetHandle"  )
//! runtextmacro List( "timer",     "Timer",    "TimerHandle"   )
//! runtextmacro List( "effect",    "Effect",   "EffectHandle"  )
//! runtextmacro List( "rect",      "Rect",     "RectHandle"    )
//! runtextmacro List( "group",     "Group",    "GroupHandle"   )
//! runtextmacro List( "force",     "Force",    "ForceHandle"   )

// Add as many handle list types as you want, and comment out the ones you do not use
// so they do not take up unnecessary space in your map script.

endlibrary

Dates are MM/DD/YY. Times are GMT-10:00

1.0 (07/16/09, 1:49am)

  • initial release
1.0b (07/20/09, 1:11am)

  • added fastRemove method.
  • optimized a bunch of methods (mainly removeRange).
  • some other minor changes.
  • added struct indexer example to thread (07/22/09, 4:17pm).
1.1 (07/28/09, 4:25pm)

  • internal contents are now stored from "min" to "max" instead of 0 to "size".
    • from user perspective, contents are still stored from 0 to size.
    • internally, though, this allows for some new methods and optimizations.
  • added addFirst, removeFirst instance methods.
  • changed name of push to addLast, pop to removeLast.
  • removed fastRemove method.
  • optimized a bunch of methods, including: add, remove, removeRange.
  • some other minor changes.
  • updated struct indexer example, and included the slower (but simpler) way to do it. (07/30/09, 7:06pm)
  • replaced struct indexer examples with a Fire Wall spell (I felt they were poor examples). Replaced method test map with Fire Wall test map. (08/11/09, 12:13am)


Credits
List was made from scratch and I put a lot of work into it, so please give me credit; if you just copy/paste the List library directly into your map, I am happy. I just don't want you deleting the header comments that say I made it.

Example List Spell
So you still might be wondering how List could be useful for you. For that reason (and for fun), I made a Fire Wall spell. It has a main FireWall struct, that contains an IntegerList of all the Flame struct instances that make up the wall. List makes it easy to loop through all the flames to damage nearby units. List is also perfect to use here as the member of a struct. If you used an array to store the flames, you would limit how big of a wall you could make and/or how many FireWalls could be used at once. Since we use List, the only limit we need to worry about is how many Flame instances are on the map at one time, and your map would be doing something wrong if it ever had 8191 Flames burning at once. See the test map below for the spell code. You can just search for the parts that deal with the "flames" IntegerList.
 

Attachments

  • Fire Wall.w3x
    35.8 KB · Views: 230
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
That's one big macro Oo. 139 lines when removing all blank lines and comments o_O.

Your example uses 13 instances o_O.

13 * 139 = 1807 lines o-o

There are better ways to do this that will allow you get away from hashtables, get much smaller macros (7 lines), and retain all of ur features and code : ). It'll make ur system faster, smaller, and more powerful : D.

I sent you a pm if you're interested in learning about it ^_^.

By the way, the idea of working with common programming array properties is nice : D.

+rep ^^
 
Level 8
Joined
Aug 4, 2006
Messages
357
GetHandleId() would be useful for storing handle pointer ids in List. However, you will not be able to convert these integers back into handles in the new patch. You could, however, put your handles in container structs and use those to store your handles in List. You would be able to get the handles back just fine.
JASS:
struct Handle
    handle object

    static method create takes handle o returns thistype
        local thistype t = thistype.allocate()
        set t.object = o
        return t
    endmethod
endstruct
...
local handle h = //some handle...
local IntegerList handles = IntegerList.create()
call handles.push(Handle.create(h))
h = Handle(handles[0]).object //same handle
However, you won't be able to store more than 8190 Handle objects total. And it's a bit more work on your part to make sure you convert between handle/Handle.

P.S. Nestharus is helping me reduce the number of lines. Hopefully I can combine all the handle hashtables into one.
 
Level 8
Joined
Aug 4, 2006
Messages
357
[x] trash and use Table
==> same functionality, but better made.
Well, you have to store the instances, but that's easy.
Here are some issues with Table that I do not like:
1. Table cannot store any values besides integers. While you can attach an integer value to a handle id, you cannot actually store handles.
2. You can store structs in Table, so you can store containers for types besides integers. However, there are a lot of issues that come with using container structs that I’d rather not have to explain.
3. Table is basically just an array that can only store integer values, and can store these values in any index (rather than just 0 to 8191). It doesn't really add any features to arrays. I can only think of two times when I would want to use Table over an array: as a non-static member of a struct; attaching integers to handles (perhaps for a unit indexer system).

Here are reasons I like List:
1. It can store any type of value that you put into the textmacro.
2. It has plenty of extra features over arrays. It keeps your data together, kind of like unit groups, but you can actually access the value at each individual index. List is perfect for stuff that needs to be sorted and/or looped through. It can be useful as a parameter of a function (for example, a sorting function). It is an awesome replacement for struct indexers since it will do the work for you, and it also adds other useful methods.

The only thing I don't like about List is that it can take up about 2 kb per textmacro run. I have been trying to find a workaround for the large textmacro, but to no avail. There simply is no other option that can allow you to store different types of data.

P.S. update.
 
Level 11
Joined
Feb 22, 2006
Messages
752
When removing a single object from anywhere in the List, there are two ways to go. If you don't care if the list stays sorted, use the "fastRemove" method. If you want to keep the list sorted, use the "remove" method. Please note that it is slower than "fastRemove" because it needs to shift objects down.

I think it's a bad idea to have any kind of unstable remove() method in a List. The entire point of a List is that it gives the user full control of the internal ordering of the elements.
 
Level 8
Joined
Aug 4, 2006
Messages
357
aznricepuff, I do not see how the fastRemove method is unstable. It removes an element and moves the last element into the open slot. When we call fastRemove, we know exactly what is going on. If we want to make elements know their position within the List, it is actually easier to use fastRemove than remove. Take a look at the struct indexer example I put in the original post. With fastRemove, we only need to update one ID. With remove, we would need to update the IDs of possibly the entire list.

If you don't care what order the elements are, use fastRemove(...). It is faster and you will still be able to keep track of where each element is in the List.

If you want the elements to maintain their order when you remove one, use remove(...). It may be slower but it will keep things organized.

Edit: I just thought of an idea on how to use Table to keep track of objects' indexes. This will allow indexOf and lastIndexOf to work quickly without a loop. I don't have time to update it now, but hopefully I will later tonight. This will make List usage a lot easier.
 
Last edited:
Level 21
Joined
Aug 21, 2005
Messages
3,699
I think "vector" would be a more appropriate name than list, since you're shifting objects which is exactly what a list does NOT do.

Just use table, add 2 members "front" and "back" that store the index of the first and last element. push_back and push_front can be implemented easily by increasing back or decreasing front and using table. That way, you don't need to shift objects to the left or right when pushing to the front or the back, only when you're inserting objects.
 
Level 8
Joined
Aug 4, 2006
Messages
357
Okay I was about ready to update, but I realized the new stuff will screw up if the list contains multiple occurances of the same value. bleh...

wyrmlord said:
Unstable means ...
Oh I guess "unstable" must be some programming term I am not familiar with. Nevertheless, I think the user should be able to choose if he wants to keep the List stable or not; List is useful in either situation.

Eleandor said:
I think "vector" would be a more appropriate name than list, since you're shifting objects which is exactly what a list does NOT do.
Really? Doesn't sound like that on wikipedia... (http://en.wikipedia.org/wiki/List_(computing)) My "List" definitely works similar to ArrayList (Java), but uses a hashtable internally instead of an array. I thought "HashtableList" would be too long, and "HashList" has its own meaning. Thus, I came up with the name "List".

Eleandor said:
Just use table, add 2 members "front" and "back" that store the index of the first and last element. push_back and push_front can be implemented easily by increasing back or decreasing front and using table. That way, you don't need to shift objects to the left or right when pushing to the front or the back, only when you're inserting objects.
Once again, I don't understand how Table can store values besides integers (maybe you can explain that to me?). Besides that, I think you have an interesting idea... I would be taking advantage of the fact that hashtable keys can be negative... Well, I'll think about that idea more and get back to you.
 
Level 11
Joined
Feb 22, 2006
Messages
752
I think "vector" would be a more appropriate name than list, since you're shifting objects which is exactly what a list does NOT do.

I don't think vector is an appropriate name here, in C++, or in any other language that has such a named ADT. The name just invites confusion with mathematical vectors, and it's not like those vectors are uncommon in CS...

And a list, in the most abstract sense, has two definitive features:

- (user) ordered implementation
- allows multiple occurances of the same element

This ADT meets both of those requirements (fastRemove notwithstanding).

I don't understand how Table can store values besides integers

It can't, unless you create wrapper structs for other data types and store the structs.
 
Level 8
Joined
Aug 4, 2006
Messages
357
UPDATE (finally)

-"fastRemove" method has been removed (by request of aznricepuff). You can get the same effect using a combination of swap and pop...
-reworked internal storage of list contents through addition of "min" and "max" members (thanks to Eleandor's idea).
-two new methods: pushMin, popMin. Renamed original push, pop to pushMax, popMax.
-add and remove methods now only have to loop through half the list (maximum). Based on the removed index, the method decides which side of the list to shift.

Unfortunately, my idea for making indexOf O(1) was an epic fail when it came to storing multiple objects of the same value. :cry: indexOf and lastIndexOf still require loops.
 
Level 13
Joined
May 11, 2008
Messages
1,198
nice to see someone doing something with hashtables already. now to try to read and understand it.

edit: ok forget it, not going to understand that any time soon. idk structs.

i'll probably give you plus reputation though for the test map.

yeah looking at the test map i have no idea what's part of list and what isn't.

why don't you comment in where the list takes effect in the fire wall trigger?
 
Level 8
Joined
Aug 4, 2006
Messages
357
Ya, this is kind of hard to understand if you don't know structs. Basically List is like a type of variable you can create to store stuff, in a similar way to arrays. Instead of making an integer array, you can make an IntegerList. etc. etc.

Anyway, I took your advice and commented the fire wall trigger a bit. Hopefully this helps people understand how to use this. I think I'll submit fire wall in the spell section too.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
This can use a big re-write, typecasting is easily doable in the current patch and there are a lot of optimizations which could easily happen here.

onDestroy - These structs are not going to be extended, just overwrite the destroy method.

Struct Initializers - Fail completely thanks to modules.

This can easily use the new Table (recently developed) which would require only one hashtable instead of the dozen or so you have set up here.

For now I'm moving this back to submissions because, to quote a very wise quote, cool != useful, and in this case the usefulness is heavily diminished because of huge performance issues. The library is also named "List" which could imply anything list-related. A more specific library name to describe what kind of list this is (ArrayList from Java, so maybe make the name ArrayList).

Also, 8190 is a soft limit and increasing it higher would destroy what's left of the efficiency.

In fact, the new Table and TableArray combination renders this almost entirely obsolete.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
It's faster to use a circularly-linked-list than a linear stack no matter how you slice it. This isn't nearly as dynamic as it needs to be. Even if you change the "struct size" that would not only slow this slow thing down even further, but it is limited to 40,000 instances. Table has unlimited instances and, thanks to your clever idea, can store any type. And TableArray is another story.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
:(

I just don't see the need to limit an >unlimited< hashtable to an array size if it doesn't need it. I try to follow the Perl philosophy: "no unnecessary limits". There might be a future for a system like this to be based off a linked-list approach just to track the values you put in the hashtable, that's why I'm hesitant to graveyard such a machine.
 
Level 8
Joined
Aug 4, 2006
Messages
357
Uh... if you have 5 items currently in the list, you should only be able to access items with indices [0-4]. Those debugs just let you know that you're trying to access data that does not exist in the List. They have nothing to do with the maximum number of items you can store in the List. It's just like an ArrayList in Java, with no bound on the maximum size.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
Yes, but you can't arbitrarily set the index of a given value, meaning you must spam "appends" to the list until that value is reached. Since you're using a hashtable for the indexing you should be able to lookup by really high values like rawcodes and handle id's.

Yes, I understand that Java/Python/etc. lists work differently than this but you're treating a hashtable in a way that needlessly limits its power.
 
Level 8
Joined
Aug 4, 2006
Messages
357
Lists and Hashtables are useful in different situations. What I did was create a convenient, efficient implementation of a List (using a hashtable under the hood). Lists are good for being able to iterate over things and, in the case of ArrayLists, do constant-time random access. If you use the hashtable directly, you have no (native) way to iterate over every entry in the table. Also, if you try to randomly access a key you probably won't come up with anything, whereas a List is guaranteed to give you something.
 
Top