| 01-25-2009, 05:34 AM | #1 |
What are my options? I need dynamic arrays that will be long term use (long-term meaning the life of a unit in a non unit slaughtering map). Creation/destruction does not have to be instant, and the arrays don't have to be re-sizable (although it would be cool if they were). Don't want to use LinkedList since I need O(1) for read/write and don't plan to remove. I looked at DARY, but it's still pre-vJass and it talks about the arrays being meant for short-term use. DARY mentioned CSCache, but that is horribly out-dated. I could use Table, but not as clean as I would have hopped. Any recommendations or suggestions? edit: I created my own dynamic array library and so far, I am rather impressed by how simple it is. It does not do array re-sizing, nor does it initialize array values, but it allocates and destroys arrays with worse case O(n) complexity (where n is number of dynamic arrays). Reading and writing is O(1). JASS:library DynamicArrays initializer init // note: DataArray is used to store used/free space while MainArray is used for the dynamic array data. // note2: a negative number in the Data array means the magnitude is being used while a positive number // means the magnitude is free. globals private constant integer MAX_SIZE = 32760 private integer array MainArray[MAX_SIZE] private integer array DataArray[MAX_SIZE] endglobals struct DynamicArray private integer start private integer size static method create takes integer size returns DynamicArray local DynamicArray a = DynamicArray.allocate() local integer temp = 0 local integer tempsize if size <= 0 then call a.destroy() return 0 endif loop if temp >= MAX_SIZE then call a.destroy() return 0 endif if DataArray[temp] > size then // enough free set a.start = temp set a.size = size set tempsize = DataArray[temp] set DataArray[temp] = -size set temp = temp + size if DataArray[temp] == 0 then set DataArray[temp] = tempsize - size endif exitwhen true else if DataArray[temp] < 0 then // slots taken till set temp = temp - DataArray[temp] else // not enough room in this allocation set temp = temp + DataArray[temp] endif endif endloop return a endmethod method operator [] takes integer i returns integer if not (i < .size) then return 0 else return MainArray[.start+i] endif endmethod method operator []= takes integer i, integer data returns nothing if not (i < .size) then return else set MainArray[.start+i] = data endif endmethod method onDestroy takes nothing returns nothing local integer temp = 0 local integer tempback = 0 local integer tempforward = 0 loop exitwhen temp == .start set tempback = temp if DataArray[temp] > 0 then set temp = temp + DataArray[temp] else set temp = temp - DataArray[temp] endif endloop set DataArray[temp] = .size set tempforward = temp + .size if DataArray[tempforward] > 0 then // sub it's index and add to front set DataArray[temp] = DataArray[temp] + DataArray[tempforward] set DataArray[tempforward] = 0 endif if tempback != temp and DataArray[tempback] > 0 then // add to it's index set DataArray[tempback] = DataArray[tempback] + DataArray[temp] set DataArray[temp] = 0 endif set .start = 0 set .size = 0 endmethod endstruct function CheckDynamicArraysData takes nothing returns nothing local integer i = 0 local string out = "" loop exitwhen i >= MAX_SIZE if DataArray[i] > 0 then set out = out + "[|cff00ff00"+I2S(i)+" - "+I2S(i+DataArray[i]-1)+"|r]" set i = i + DataArray[i] else set out = out + "[|cffff0000"+I2S(i)+" - "+I2S(i-DataArray[i]-1)+"|r]" set i = i - DataArray[i] endif endloop call BJDebugMsg(out) endfunction private function init takes nothing returns nothing set DataArray[0] = MAX_SIZE endfunction endlibrary I could speed up the linear search destroy by added a forward/backward data, but the extra over-head for creation may not be desired. I could also skip part of the linear search in the create method by specifying the first free index. This I will probably do. Any other thoughts or criticisms? |
| 01-25-2009, 10:53 AM | #2 |
Do you actually need differing array sizes? If not you could use a stack implementation (aka: Struct), which'd give you pretty quick O(1) creation and destruction. |
| 01-25-2009, 12:19 PM | #3 |
The create method should have another case for when DataArray[temp] == size. Also, the create method should have the option of initializing the array values, or do that by default. Organizationally, I'd change the init function to an onInit method and make those three globals into static struct members so the entire arrays code would be contained in one struct. |
| 01-25-2009, 03:52 PM | #4 | ||
Quote:
Yes I do, part of the reason why I didn't just define an array in the struct I plan to be using this in. Quote:
I think initializing the arrays is too costly of a performance, and since people can declare their size, I would only assume they would fill the array instantly (at least thats what I will be doing). I will though add another argument and can do it if the user wants. |
| 01-25-2009, 04:29 PM | #5 |
Use table? Use type meh extends integer array [3,400000] ? |
| 01-25-2009, 04:38 PM | #6 | |
Quote:
Table per struct instance is not what I want. I would also like to stay away from gamecache for this. vJass dynamic arrays do not allow for different sizes for the same type, something I need. |
| 01-25-2009, 05:18 PM | #7 | |||
Quote:
why? Quote:
Quote:
-- You could use what I did for CSCache's dynamic arrays, I doubt anyone can do better than pipe's idea there of using fibonacci heaps and crazy things like that. You basically have N stacks instead of a single one. Each of these stacks contains indexes for arrays of some size equal to a fibonacci number, for example, Stack[0] contains the indexes of arrays of size 1.., Stack[1] for size 2, Stack[2] for 3, Stack[3] for 5, Stack[4] for 8 , etc... Then say someone needs to allocate an array of size 9, you have to round it to the next fibonacci number, which would be 13. So you request an array index of size 13. You ask Stack[5] for that index. Of course, chances are, Stack[5] could be empty, so what to do? Well, you can request an array of size 21 (8+13) you then take this array's first 8 indexes and push them to Stack[4] (Of size 8), keep the rest for what you want to store. If there aren't stacks of size 6, try with [7], (13+21) , there's one of 12 you can get from it, else try getting a 6-size one from [8], then get the 5-size from the 6-size, etc... So, you begin with Stack[N] which contains a single dynamic array of size Fib(N), a big enough to cover most of your available space. The remaining Stacks[0..N-1] begin empty. If you ever run out of stacks, you should have used gamecache... After deallocation you need something that would restore indexes of larger sizes. |
| 01-25-2009, 06:38 PM | #8 | |
Quote:
Using a table per instance would mean I may have to increase the number of Tables, thus removing the in-line awesomeness of table. Cause I would have to use Table, and therefore see above. The Fib sequence is really interesting. I read about powers of 2, but the wasted space is considerable when asking for arrays of 2^n + c where c << 2^(n+1). My only issue is that the arrays will not be quickly added or destroyed, so space allocation is more of an importance versus creation/destruction times. |
| 01-25-2009, 07:05 PM | #9 |
Ok, now we've come to the point where you need to explain what you need this for. |
| 01-25-2009, 07:17 PM | #10 | |
Quote:
|
| 01-25-2009, 07:34 PM | #11 | |
Quote:
I guess table would work fine for what I need it for... but dynamic arrays are sexy. |
| 01-25-2009, 08:09 PM | #12 |
DARY is awesome, use DARY. I told people to use something else for long term stuff because people wanted to use DARY for what structs are used for now. If you really wanted short term arrays, an obstack would be much better. DARY needs vJass on three accounts - templates for multiple allocation pools, array extension for larger pools, function pointers for less clumsy generic programming. Each of these any given user almost certainly does not need. But Anitarf is right, you have to explain application. |
| 01-25-2009, 11:29 PM | #13 |
What is 'dynamic array'? |
| 01-25-2009, 11:52 PM | #14 |
dynamic allocated (=runtime) arrays with custom size ... |
| 01-26-2009, 12:55 AM | #15 |
I was planning on using it for re-writing part of an inventory system I have been slowly writing ( specifically the part where I store the items a unit carries. Part of my hesitation was that some unit may only have 6 items while others could have 20 to 30. I didn't feel comfortable with with allocating a table instance that would only be holding 6 integers, when a dynamic array wouldn't matter. My only issue with DARY is that it does not have the vJass wrappers that make it look and work like a native dynamic array would. Part of the beauty of this item system is that the users write the code for their items, which can iherit proprties from sub-classes of items. Making the system feel as standard looking as possible would ease the coding for the users who use the system, including me. If DARY had wrappers and was setup as a struct, I would be more inclined to use it. |
