Tlist and Type

Started by Baggey, September 18, 2023, 14:12:08

Previous topic - Next topic

Baggey

In this Runable Example

Type AType
    Global List:TList = New TList
    Field X:int

    Function Set()
        Print "Hello"
    End Function
End Type


Type BType
    '....

    Function GetBack:AType()
        local A:AType = New AType
        Return A
    End Function

    Function WhatTheFuck()
        Print AType.List.Count()
        ATyp.Set()
    End Function

End Type


Type CType
    Field Y:A_Type

    Function WhatEver()
        local loc:CType = New CType
        loc.Y = B_Type.GetBack()
        AType.List.AddLast loc.Y
    End Function
End Type


I want to change the Size of the set [99]. So i change the Code to this

Type InterruptList Extends Cpu

    Global ListArray:InterruptList[] ' <------ Null ListArray to 0 for resizing

    Field A:Int, B:Int, C:Int, Opcode:String, ArrayNum:Int
    'Field flag:FlagReg = New flagReg

     Function AddToList(Nr:Int)
      
         Local loc:InterruptList= New InterruptList
         ListArray[] = New ListArray[] ' <------ I try to resize by adding one element at a time.
       
         loc.A = Nr Shr 3 ' Divide by 8
         loc.B = Nr Shl 2 ' Multiply by 4
         loc.C = Nr Shl 3 ' Multiply by 8
         loc.Opcode="Array Element="+Nr
         loc.ArrayNum=Nr
         loc.Interrupt=Rnd(2)
       
        ' Note Array wasnt ammended here so should always return "zero"!
        ' But when Element 29 will Force To 255 illegal cant happen!
        If Nr=29 Then loc.Carry=255

         ListArray[Nr] = loc
     End Function

Im getting a Compile Error not sure if trying to resize the intial array can be Done? or what am i doing wrong there.
Im trying to resize the Array of Type's one Element at a time rather fixing it rigid with [99] Elements.

Any ideas.

Kind Regards Baggey
Running a PC that just Aint fast enough!? i7 4Ghz Quad core 24GB ram 1TB SSD and NVIDIA Quadro K620 . DID Technology stop! Or have we been assimulated!

ZX Spectrum 48k, C64, ORIC Atmos 48K, Enterprise 128K, The SID chip. Im Misunderstood!

Midimaster

#16
there are some typos in your code:

1. Define a New array without the brackets!

Global A:Int[]
...
'wrong
A[] = New Int[10]

'right:
A   = New Int[10]


2. Define a complete New array with setting the number of elements!

Global A:Int[]
...
'wrong
A = New Int[]

'right:
A = New Int[10]


3. Use a TYPE after new

Global A:Int[]
...
'wrong
A = New A[10]

'right:
A   = New Int[10]


4. Conclusio

so you need to write:

Global ListArray:InterruptList[]
...
'wrong
ListArray[] = New ListArray[]

'right:
ListArray   = New InterruptList[10]



5. Single Element Definition


so you need to pre-dim a size in a user-type array ! you can use a high number that is big enough for all elements. Then add elements to any free position, the array will store it. But attention. When you created element 45, this does not mean that now also already element 43 is existing:

InterruptList.AddToList 45
Print InterruptList.ListArray[45].A
Print InterruptList.ListArray[43].A  ' <---- this will cause a crash

Type InterruptList
    Global ListArray:InterruptList[9999]
    Field A:Int

     Function AddToList(Nr:Int)   
         Local loc:InterruptList = New InterruptList
         loc.A =12345
         ListArray[Nr] = loc
     End Function
End Type

...back from Egypt

Baggey

So i Modify and adapt! ;D

Here is Runable code to a Stacked! Resizable Array List of Types! Which is very useful if you get me :-X
SuperStrict

' Here we use a Global index for our List Array So we add to it like a STACK!
' Its used as a last on first off! However we can go back and (.FIND!) So it's very flexible!
' we can use this to know how many adds to the list we have done Sequentially! or occurred!
' This will cause our array to expand in Size/Elements and if we try to access anything less than the Elements we've Sequentially added
' It wont crash! As we add one by one to the Global ListArrayElement each time we add to this ListArray!

Global ListArrayElement:Int=0

InterruptList.AddToList(ListArrayElement)
Print InterruptList.ListArray[ListArrayElement].A ' <---- Here we should get 1!


' I tried to automate this in .AddToList()
'
' Now lets add to Our ListArray
  ListArrayElement:+1         ' <---- This Works Here WTF!?
'
'

InterruptList.AddToList(ListArrayElement)
Print InterruptList.ListArray[ListArrayElement].A ' ,---- Here we should get 2!

Type flagReg

    Field Interrupt:Int=Rnd(2)
    Field Carry:Int

End Type

Type CPU Extends flagreg

    Field Ticks:Int=Rand(24000)

End Type

Type InterruptList Extends Cpu

    Global ListArray:InterruptList[]
    Field A:Int, B:Int, C:Int, Opcode:String, ArrayNum:Int
    'Field flag:FlagReg = New flagReg

Function AddToList(Nr:Int)
  
Local loc:InterruptList= New InterruptList
loc.A = (Nr+1) ' Divide by 8
loc.B = Nr Shl 2 ' Multiply by 4
loc.C = Nr Shl 3 ' Multiply by 8
loc.Opcode="Array Element="+Nr
loc.ArrayNum=Nr
loc.Interrupt=Rnd(2)

' Note Array wasnt ammended here so should always return "zero"!
' But when Element 29 will Force To 255 illegal cant happen!
If Nr=29 Then loc.Carry=255

ListArray[Nr] = loc

' Now lets add to Our ListArray
     'ListArrayElement:+1               '  <---- But it Dosent Work here? But its Global!?

End Function

    Function PrintPosition(Number:Int)
        ListArray[Number].PrintOne
    End Function

    Method PrintOne()
            Print "Array["+ArrayNum+"]"
            Print Opcode
            Local Remainder:Int=(ArrayNum Mod 8)
            Print "( "+(ArrayNum Shr 3) +" * 8 ) + "+ Remainder + " = "+ArrayNum
            Print A
            Print B
            Print C
            Print "fINTERRUPT="+Interrupt
            Print "Cycles="+Ticks
            Print "fCARRY="+Carry
    End Method

End Type

Now, This Works but ive commented lines of code OUT! that if i add 1 to   ListArrayElement:+1   within the Function within the type, like 

' Now lets add to Our ListArray
'ListArrayElement:+1               '  <---- But it Dosent Work here? But its Global
it wont work?! :o

Kind Regards Baggey



Running a PC that just Aint fast enough!? i7 4Ghz Quad core 24GB ram 1TB SSD and NVIDIA Quadro K620 . DID Technology stop! Or have we been assimulated!

ZX Spectrum 48k, C64, ORIC Atmos 48K, Enterprise 128K, The SID chip. Im Misunderstood!

Midimaster

#18
I think I wrote some nonsense. This nonsense is the reason for your error message. We need to fix the dimension of the array, before we can use it. When we forget it the app will crash unexepected anywhere, because our writing to a non dimensioned array will write directly into the RAM (..where other variables or code are)

With this change you can of course change "outside GLOBAL variables" from inside the type.

But you should not do it for ListArrayElement! Because this counter should be part of the type.

And it is no good idea to call Array-Elements directly from outside, because you never know, whether they existing.

The PRINT line will crash now:

Global ListArrayElement:Int=0

InterruptList.AddToList(ListArrayElement)
Print InterruptList.ListArray[ListArrayElement].A

Type InterruptList Extends Cpu
    Global ListArray:InterruptList[9999]
    ....
    Function AddToList(Nr:Int)     
        ListArray[Nr] = loc
    ListArrayElement:+1   
    ....

Reason: You add element 0, then increment the counter to 1, then try to print element 1, which does not exist!



The better way is to do all those jobs inside the type:


InterruptList.AddToList(0)
InterruptList.PrintElement_A(1)

Type InterruptList Extends Cpu
    Global ListArray:InterruptList[9999]
    ....
    Function AddToList(Nr:Int)     
        ListArray[Nr] = loc
    ListArrayElement:+1   
    ....

    Function PrintElement_A(Nr:Int)     
        if ListArray[Nr] = NULL Return
    Print ListArray[Nr].A    
    ....



TList with TLinks

But this can all be done also with TLISTs. For me it sounds like you need a LIFO "stack" (last in - first out) For this the TList is optimal. So why not using it?


Also in a Tlist you can go reverse throught the list:

Global TopStack:TStack  ' points always to the top of the stack

' put some thing on the stack:
TopStack = TStack.Push(1234)
TopStack = TStack.Push(2345)
TopStack = TStack.Push(3456)
TopStack = TStack.Push(4567)

Print "Stack now:"
TopStack.Info()
TopStack.Before().Info()
TopStack.Before().Before().Info()
Print "...."
Print

' now remove an object from the stack:

TopStack = TStack.Pop()

Print "Stack now:"
TopStack.Info()
TopStack.Before().Info()


Type TStack
    Global List:TList=New TList
    Field Pos:Int, Value:Int
   
    Function Push:TStack(Value:Int)
        ' pushes objects on the stack
        Local loc:TStack = New TStack
        loc.Value =Value
        List.AddLast loc
        loc.Pos=List.Count()
        Return loc
    End Function

    Function Pop:TStack()
        ' removes objects on the stack
        List.RemoveLast()
        Return TStack(List.Last())
    End Function
   
    Method Before:TStack()
        ' return the object, which lays under the current object
        Local MyLink:TLink = List.FindLink(Self)
        Return TStack(MyLink.PrevLink().Value())
    End Method
   
    Method Info()
        ' do something with the objects... here printing
        Print "POS=" +  pos + "   Value=" + Value
    End Method
End Type



...back from Egypt

Baggey

#19
Okay thanks for more ideas. So i have my List.Array of Types working now. :D Hopefully when i use it in my emulators it dosent bog down to much! Although BlitzMax is very fast indeed comparable to C.

I hear Laugh's Nevermind :P

Also being Resizeable i hope data held within it. wont be corrupted also.

But only using it will i find out ::)

So here is a Fully Runable Piece of Code in BlitzMaxNG with examples of its use! Not much point Else :-\
This may also help people getting to grasps with types, fields, Arrays and Passing and accessing Variables from anywhere. Its not been easy. BlitzMax Documentation for me isnt the Best ::) not enough examples to go by.
I find myself Learning by trial and error? Most of the time.
As always if you find it useful, Use it. If not ignore it!

SuperStrict

' Here we have the Resizable List Array of Types! So we add to it like a STACK! LIFO.
' BUT! It's Flexible in being able to be Resizeable. We can go anywhere inside it as well
' Access some entries or all etc..
' Added Delete Last entry as well!
' I may add more functionality as i need to.
' Written By Baggey. Use if you find it Useful?
 

' EXAMPLES OF USE

' Try to Print invalid List.Array
List.PrintPosition(0)

Print
Print "1st Print"
List.AddToList(List.Pos)
Print "List Array Size "+List.Array[List.Pos].Size
Print "A="+List.Array[List.Pos].A ' <---- Here we should get 1!
Print "OPcode="+List.Array[List.Pos].OPcode

Print
Print "2nd Print"
List.AddToList(List.Pos)
Print "List Array Size "+List.Array[List.Pos].Size
Print "A="+List.Array[List.Pos].A ' ,---- Here we should get 2!
Print "OPcode="+List.Array[List.Pos].OPcode

Print
Print "3rd Print"
List.AddToList(List.Pos)
Print "List Array Size "+List.Array[List.Pos].Size
Print "A="+List.Array[List.Pos].A ' ,---- Here we should get 3!
Print "OPcode="+List.Array[List.Pos].OPcode

' Try to Print invalid List.Array
List.PrintPosition(5)

'Now Print something that exists!
Print
List.PrintPosition(1)

' Print Last entry
Print
List.PrintPosition(List.Pos)

' Now lets Delete last Entry
Print
List.RemoveFromList(List.Pos)

' Lets Print Current Pos
Print
List.PrintPosition(List.Pos)


' MAIN TYPE

Type flagReg

    Field Interrupt:Int=Rnd(2)
    Field Carry:Int

End Type

Type CPU Extends flagreg

    Field Ticks:Int=Rand(24000)

End Type

Type List Extends Cpu

    Global Array:List[]
    Global Pos:Int=-1 ' DO NOT ALTER MANUALY! or youll lose your Last Position
                      ' But it can be Altered! not like a TList
    Field A:Int, B:Int, C:Int, Opcode:String, Size:Int
 

     Function AddToList(Nr:Int)
   
       If Nr<0 Then Nr=0 Else Nr:+1 ' Needed to catch -1 on first Add to List.Array
      
     Pos:+1 ' Update Pos to current Element in our List.Array
     
         Local loc:List= New List
         loc.A = (Nr) ' Divide by 8
         loc.B = Nr Shl 2 ' Multiply by 4
         loc.C = Nr Shl 3 ' Multiply by 8
         If Nr=1 Then loc.Opcode="This Worked! I was at List.Array[1] and Didn't Print Just Array Element="+Nr Else loc.Opcode="Array Element="+Nr
         loc.Size=(Nr+1)'ListArrayElement+1
         loc.Interrupt=Rnd(2)
       
       ' Note Array wasnt amended here, So should always return "zero"!
         ' But when Element 29 will Force To 255 illegal cant happen!
         If Nr=29 Then loc.Carry=255

         Array[Nr] = loc ' Write Array List Type to our Actual List.Array[List.Pos]      
       
     End Function
   
   
     Function RemoveFromList(Nr:Int)
   
       If Nr>-1 Then Nr:-1 ' Needed to catch -1 as Last Delete
       Pos=Nr ' Update Pos to our new current Element in our List.Array
   
     End Function
   
     ' WE can Expand with RemoveAll or RemoveFirst etc.. Also
   
   Function PrintPosition(Number:Int)
        If (Number = Null) Or (Number>List.Pos) Then Print ; Print "Number "+Number+" Dosent exist!" Return ' catch invalid Print's
        Print "Number "+Number
        Array[Number].PrintOne
   End Function


   Method PrintOne()
            Print "Array["+Size+"]"
            Print Opcode
            Local Remainder:Int=(Size Mod 8)
            Print "( "+(Size Shr 3) +" * 8 ) + "+ Remainder + " = "+Size
            Print A
            Print B
            Print C
            Print "fINTERRUPT="+Interrupt
            Print "Cycles="+Ticks
            Print "fCARRY="+Carry
   End Method

End Type

Now, can i do the samething with an actual TList? Because thats what i started of trying todo. :o

Kind Regards Baggey
Running a PC that just Aint fast enough!? i7 4Ghz Quad core 24GB ram 1TB SSD and NVIDIA Quadro K620 . DID Technology stop! Or have we been assimulated!

ZX Spectrum 48k, C64, ORIC Atmos 48K, Enterprise 128K, The SID chip. Im Misunderstood!

Midimaster

Not allowed!

As I wrote in my last post this is not allowed:

Type List Extends Cpu
    Global Array:List[]

To define an array without the number of elements leads to an error message in DEBUG version and to unexpected crashes in RELEASE version.

You need to do it this way:

Type List Extends Cpu
    Global Array:List[9999]
...back from Egypt

dawlane

#21
Quote from: Baggey on September 23, 2023, 06:06:24Now, can i do the samething with an actual TList? Because thats what i started of trying todo
By not trying to directly use your CPU class in a TList.
Instead you should be wrapping the CPU object type into a simple type that contains a field for the index and a field to contain CPU object.
Type TCustomListData
    Field _index:Int
    Field _T:Object
EndType

If I get the time, I will post a working example, but if you want to have a go yourself. Then you will need to understand how to walk a TList via using TLink to do insertion, removal and retrieval at a specific index i.e. TLink node. Do not forget that insertion and removal at a specific TLink will require you to update all the _index value accordingly.

Baggey

#22
Quote from: Midimaster on September 23, 2023, 08:11:11Not allowed!

As I wrote in my last post this is not allowed:

Type List Extends Cpu
    Global Array:List[]

To define an array without the number of elements leads to an error message in DEBUG version and to unexpected crashes in RELEASE version.

You need to do it this way:

Type List Extends Cpu
    Global Array:List[9999]


Yeah, Yeah, I here you. Understood now its a bit like an 8 Bit computer with the stack if you overwrite it you get a crash! I understand now  ;)

I get why your declaring a high number for the List.Array to start with now. When your adding things you dont really know how many there are going tobe. But i suppose with gigabytes of ram now it probably dosent matter.

So, thats why, i tried the Tlist first with not much joy :-[

Dawlane, I have no idea about Tlink node and searching for good examples with the Blitzmax documentation dosent give any inspiration to someone learning the concept.
So if you do find some spare time to rewrite the above as a Tlink node thingy. Your efforts would very much not go unappreciated. :) I learn by example

If someone else would like to have ago. I would not be offended in anyway thats why im here. Trying to learn new concepts! playing and tweaking code here and there.

Its a very step learning curve! and as you get older Sponge/Brain dosent soak up new concepts as eaisily. :-X

The more i learn the better my programming gets and the more fun things i can achieve. Cant wait to win the Game Coding competition :))

Now to look at the TLink samples Midimaster sent me in this thread Thankyou.

Kind Regards Baggey
Running a PC that just Aint fast enough!? i7 4Ghz Quad core 24GB ram 1TB SSD and NVIDIA Quadro K620 . DID Technology stop! Or have we been assimulated!

ZX Spectrum 48k, C64, ORIC Atmos 48K, Enterprise 128K, The SID chip. Im Misunderstood!

Midimaster

Quote from: Baggey on September 23, 2023, 10:27:08....I have no idea about Tlink node and searching for good examples...

My post #18 did already show an example with TList & TLink!
...back from Egypt

Baggey

#24
Quote from: Midimaster on September 23, 2023, 10:36:00
Quote from: Baggey on September 23, 2023, 10:27:08....I have no idea about Tlink node and searching for good examples...

My post #18 did already show an example with TList & TLink!


I read the first part of the code got excited and wrote List.Array of Types. :-X

Now im working with the rest of the code thankyou again.

Baggey
Running a PC that just Aint fast enough!? i7 4Ghz Quad core 24GB ram 1TB SSD and NVIDIA Quadro K620 . DID Technology stop! Or have we been assimulated!

ZX Spectrum 48k, C64, ORIC Atmos 48K, Enterprise 128K, The SID chip. Im Misunderstood!

dawlane

#25
Okay, had some time to spare. It's been a while since I did anything with BlitzMax and I wrote this off the top of my head. But here is a some code that fakes an array by wrapping TList to use a container object. This would not be an ideal solution with the amount of casting that needs to be done to get the index value out of the container. A better solution would be to write your own custom types from scratch using a double linked list (see the linkedlist.mod for how it works) that includes an extra field in the link node type for an index number.

The example:
Create a file fakeArray.bmx and copy the code:
' The idea is to use a custom data type (TFakeArray) to wrap a TList container to fake a dynamic array.
' This is achived by wrapping the object type into a store a container type (TFakeArrayElement)
' TFakeArrayElement contains two field: The index number and the actual stored object

' If you want to cut out more overhead, then study the TList module of the TList module and write your own that uses an index field.

' The fake array element aka the container.
Type TFakeArrayElement
Field _index:Int
Field _tdata:Object
End Type

' Custom data type to wrap a TList to simulate an array of objects.
Type TFakeArray

' Constants for the direction to iterate the fake array
Const FORWARDS:Int = 0
Const BACKWARDS:Int = 1

Field _fakeArray:TList ' Maintain our TFakeArrayElement items in a normal list

' Create a new TFakeArray object to store the fake array items
Method New()
_fakeArray = New TList()
End Method

' To try to cut some over head and searching the fake array from the first fake array element.
' Work out the if the index is closer to the start or the end of the fake array, and then start
' the search.
Method _SearchDirection:Int(index:Int)
' Unwarp both the first and the last fake array elements to get the index only.
Local startIndex:Int = TFakeArrayElement(_fakeArray.First())._index
Local lastIndex:Int = TFakeArrayElement(_fakeArray.Last())._index

' If the absoult value of the index minus the start index, is less than the
' absolute value of the index minus the last index, then the seach should start
' at the beginning of the fake array.
If Abs(index - startIndex) < Abs(index - lastIndex) Then Return FORWARDS
Return BACKWARDS
End Method

' Search backward for a given index and return the fake array elements link node.
Method _SearchBackwards:TLink(index:Int)
Local fakeArrayElementNode:TLink = _fakeArray.LastLink()

While fakeArrayElementNode <> Null
If TFakeArrayElement(fakeArrayElementNode.Value())._index = index Then Exit
fakeArrayElementNode = fakeArrayElementNode.PrevLink()
Wend

Return fakeArrayElementNode
End Method

' Search forward for a given index and return the fake array elements link node.
Method _SearchForwards:TLink(index:Int)
Local fakeArrayElementNode:TLink = _fakeArray.FirstLink()

While fakeArrayElementNode <> Null
If TFakeArrayElement(fakeArrayElementNode.Value())._index = index Then Exit
fakeArrayElementNode = fakeArrayElementNode.NextLink()
Wend

Return fakeArrayElementNode
End Method

' Check if the fake array is empty, or if the index parameter passed is less than zero,
' or is greater than the index of the last fake array element. If any of these are true, then do a runtime error.
Method _CheckIndex(index:Int)
If _fakeArray.IsEmpty() Or index < 0 Or index > TFakeArrayElement(_fakeArray.Last())._index
RuntimeError "Error: TFakeArray out of bounds. Array Size: " + _fakeArray.Count() + " - Index passed: " + index
Endif
End Method

' Create a new fake array element and add the index with the object data to store.
Method _WrapFakeArrayElement:TFakeArrayElement(index:Int,data:Object)
Local fakeArrayElement:TFakeArrayElement = New TFakeArrayElement()
fakeArrayElement._index = index
fakeArrayElement._tdata = data
Return fakeArrayElement
End Method

' Unwrap the object data out of the TLink object storing the fake array element.
Method _UnwrapFakeArrayElementNode:Object(fakeArrayElementNode:TLink)
Return TFakeArrayElement(fakeArrayElementNode.Value())._tdata
End Method

' Unwrap the object data out of the fake array element.
Method _UnwrapFakeArrayElementData:Object(fakeArrayElement:Object)
Return TFakeArrayElement(fakeArrayElement)._tdata
End Method

' Unwrap the object data in the fake array at the index given and return it.
Method Get:Object(index:Int)
_CheckIndex(index) ' Index abounds check
Local fakeArrayElementNode:TLink = Null

' Figure out which ends to start at for the search.
If _SearchDirection(index) = FORWARDS Then fakeArrayElementNode = _SearchForwards(index) Else fakeArrayElementNode = _SearchBackwards(index)

' Nothing found, so return a null object
If fakeArrayElementNode = Null Then Return Null

' Unwrap the object stored in the fake array element and return.
Return _UnwrapFakeArrayElementNode(fakeArrayElementNode)
End Method

' Unwrap the object data in the fake array at the index given and return it, while removing the fake array element at that index.
Method Remove:Object(index:Int)
_CheckIndex(index) ' Index abounds check
Local fakeArrayElementNode:TLink = Null

' Figure out which ends to start at for the search
If _SearchDirection(index) = FORWARDS Then fakeArrayElementNode = _SearchForwards(index) Else fakeArrayElementNode = _SearchBackwards(index)

If fakeArrayElementNode = Null Then Return Null

' Update the indexes in the fake array elements starting from the next link node.
Local fakeArrayNextNode:TLink = fakeArrayElementNode.NextLink()
While fakeArrayNextNode <> Null
TFakeArrayElement(fakeArrayNextNode.Value())._index:-1
fakeArrayNextNode = fakeArrayNextNode.NextLink()
Wend

' Unwrap the object first before removeing the fake array element for the list.
Local data:Object = _UnwrapFakeArrayElementNode(fakeArrayElementNode)

' Now the fake array element can be removed from the list.
_fakeArray.RemoveLink(fakeArrayElementNode)

Return data
End Method

' Wrap the object data into a fake array element and insert it at a given index of the fake array.
Method Insert(index:Int, data:Object)
_CheckIndex(index) ' Index abounds check

Local fakeArrayElementNode:TLink = Null

' Figure out which ends to start at for the search
If _SearchDirection(index) = FORWARDS Then fakeArrayElementNode = _SearchForwards(index) Else fakeArrayElementNode = _SearchBackwards(index)

' Nothing found, so return a null object
If fakeArrayElementNode = Null Then Return Null

' Make the fake array element and then add it to the fake array before the current fakeArrayElementNode
_fakeArray.InsertBeforeLink(_WrapFakeArrayElement(index,data), fakeArrayElementNode)

' Increase all the fake array element indexes by one from the current fake array element node.
While fakeArrayElementNode
TFakeArrayElement(fakeArrayElementNode.Value())._index:+1
fakeArrayElementNode = fakeArrayElementNode.NextLink()
Wend
End Method

' Wrap the object data into the a fake array element and add it to the back of the fake array.
Method AddLast(data:Object)
' Get the last index from the list. If the list is empty, then the last index will be zero.
Local lastIndex:Int = -1
If Not _fakeArray.IsEmpty() Then lastIndex = TFakeArrayElement(_fakeArray.Last())._index
_fakeArray.AddLast(_WrapFakeArrayElement(lastIndex + 1, data))
End Method

' Wrap the object data into the fake array element and add it to the front of the fake array.
Method AddFirst(data:Object)
' If the list is empty, then then just place it at the begining of the list an return
If _fakeArray.IsEmpty()
_fakeArray.AddFirst( _WrapFakeArrayElement(0,data))
Return
EndIf

' As the list is not empty, all indexes should be updated before adding the container to the front of the list.
Local fakeArrayElementNode:TLink = _fakeArray.FirstLink(), fakeArrayElement:TFakeArrayElement
While fakeArrayElementNode <> Null
TFakeArrayElement(fakeArrayElementNode.Value())._index:+1
fakeArrayElementNode = fakeArrayElementNode.NextLink()
Wend

_fakeArray.AddFirst(_WrapFakeArrayElement(0, data))
End Method

' Unwrap the object data from the fake array element from the back of the list and return the object
Method RemoveLast:Object()
If _fakeArray.IsEmpty() Then Return Null
Return _UnwrapFakeArrayElementData(_fakeArray.RemoveLast())
End Method

' Unwrap the object data from the fake array element from the front of the list and return the object
Method RemoveFirst:Object()
If _fakeArray.IsEmpty() Then Return Null
Local data:Object = _UnwrapFakeArrayElementData(_fakeArray.RemoveFirst())

' Update the indexes in the fake array elements starting from the first link node.
Local fakeArrayNextNode:TLink = _fakeArray.FirstLink()
While fakeArrayNextNode <> Null
TFakeArrayElement(fakeArrayNextNode.Value())._index:-1
fakeArrayNextNode = fakeArrayNextNode.NextLink()
Wend

Return data
End Method

' Return the size of the fake array
Method Length:Int()
Return _fakeArray.Count()
End Method

' Clear the fake array
Method Clear()
_fakeArray.Clear()
End Method

' Return the fake array
Method FakeArray:TList()
Return _fakeArray
End Method

End Type

Create another file named fakeCPU.bmx and copy the code:
Type TCPU
    Field _PC:Short
    Field _SP:Short
    Field _STATUS:Byte
    Field _NMEMONIC:String
    Field _NMI:Byte
End Type

Type TMos6510 Extends TCPU
    Field _A:Byte
    Field _X:Byte
    Field _Y:Byte
   
    Const NAME:String = "MOS 6150"
   
    ' Generate random stuff
    Method New()
        _PC = Short(Rnd(0, $FFFF))
        _SP = Short(Rnd(0, $FFFF))
        _STATUS = Byte(Rnd(0, $FF))
        _A = Byte(Rnd(0, $FF))
        _X = Byte(Rnd(0, $FF))
        _Y = Byte(Rnd(0, $FF))
    End Method
   
    Method Output:TList()
        Local list:TList = New TList()
        list.AddFirst("NMEMONIC: " + _NMEMONIC)
        list.AddFirst("PC: " + _PC)
        list.AddFirst("SP: " + _SP)
        list.AddFirst("STATU: " + _STATUS)
        list.AddFirst("A REG: " + _A)
        list.AddFirst("X REG: " + _X)
        list.AddFirst("Y REG: " + _Y)
        Return list
    End Method
End Type

Function Mos6510:TCPU(nmemonic:String)
    Local cpu:TMos6510 = New TMos6510()
    cpu._NMEMONIC = nmemonic
    Return cpu
End Function

And finally the test code. Create a file named fakeArrayText.bmx
Include "fakeArray.bmx"
Include "fakeCPU.bmx"

Graphics 1024, 768

Global CPUList:TFakeArray = New TFakeArray()

Type TTest
    Field _expectedCount:Int
    Field _title:String
    Field _object:Object = Null
   
    Method DisplayItems:Int()
        DrawText("----- " + _title + " -----", 0, 0)
        Local y:Int = 21
        DrawText("Current Fake Array Element Total Count: " + CPUList.Length() + " - Expected Fake Array Element Count " + _expectedCount, 0, y)
        y = y + 21
        For Local i:Object = EachIn CPUList.FakeArray()
            Local fakeArrayElement:TFakeArrayElement = TFakeArrayElement(i)
            DrawText("FakeArrayElement index: " + fakeArrayElement._index + " - CPU DATA:" + TMos6510(fakeArrayElement._tdata)._NMEMONIC, 0, y)
            y = y + 21
        Next
        Return y
    End Method
   
    Method Display()
        Local y:Int = DisplayItems() + 21
        If _object <> Null
            DrawText("DATA RETRIEVED", 0, y)
            y = y + 21
            For Local s:String = Eachin TMos6510(_object).Output()
                DrawText(s, 0, y)
                y = y + 21
            Next
        End If
    End Method
   
    Method Setup() Abstract
End type

Type TTest_ADDLAST Extends TTest
    Method Setup()
        _title = "ADD LAST TEST: SHOULD SEE INDEX 0-4 WITH LD A,$01 - LD A,$05"
        CPUList.AddLast(Mos6510("LD A,$01"))
        CPUList.AddLast(Mos6510("LD A,$02"))
        CPUList.AddLast(Mos6510("LD A,$03"))
        CPUList.AddLast(Mos6510("LD A,$04"))
        CPUList.AddLast(Mos6510("LD A,$05"))
        _expectedCount = 5
    End Method
End Type

Type TTest_ADDFIRST Extends TTest
    Method Setup()
        _title = "ADD FIRST TEST LD A,$00"
        CPUList.AddFirst(Mos6510("LD A,$00"))
        _expectedCount = 6
    End Method
End Type

Type TTest_INSERT Extends TTest
    Method Setup()
        Local random:Int = Int(Rnd(0, CPUList.Length() - 1))
        _title = "INSERT DATA `LD A,$10` AT RANDOM INDEX TEST (" + random + ")"
        CPUList.Insert(random, Mos6510("LD A,$10"))
        _expectedCount = 7
    End Method
End Type

Type TTest_GET Extends TTest
    Method Setup()
        Local random:Int = Int(Rnd(0, CPUList.Length() - 1))
        _title = "GET DATA AT RANDOM INDEX TEST (" + random + ")"
        _object = CPUList.Get(random)
        _expectedCount = 7
    End Method
End Type

Type TTest_REMOVE Extends TTest
    Method Setup()
        Local random:Int = Int(Rnd(0, CPUList.Length() - 1))
        _title = "REMOVE DATA AT RANDOM INDEX (" + random + ")"
        _object = CPUList.REMOVE(random)
        _expectedCount = 6
    End Method
End Type

Type TTest_REMOVELAST Extends TTest
    Method Setup()
        _title = "REMOVE LAST ITEM TEST"
        _object = CPUList.RemoveLast()
        _expectedCount = 5
    End Method
End Type

Type TTest_REMOVEFIRST Extends TTest
    Method Setup()
        _title = "REMOVE FIRST ITEM TEST: LAST TEST SHOULD SEE INDEX 0-3"
        _object = CPUList.RemoveFirst()
        _expectedCount = 4
    End Method
End Type

Global TEST_LIST:TLIST = New TList
TEST_LIST.AddLast(New TTest_ADDLAST())
TEST_LIST.AddLast(New TTest_ADDFIRST())
TEST_LIST.AddLast(New TTest_INSERT())
TEST_LIST.AddLast(New TTest_GET())
TEST_LIST.AddLast(New TTest_REMOVE())
TEST_LIST.AddLast(New TTest_REMOVELAST())
TEST_LIST.AddLast(New TTest_REMOVEFIRST())

Global TEST_CURRENT:TLink = TEST_LIST.FirstLink()
Global TEST:TTest = Null

Repeat
    Cls
    If KeyHit(KEY_SPACE) Then
        If TEST_CURRENT = Null Exit
        TEST = TTest(TEST_CURRENT.Value())
        TEST.Setup()
        TEST_CURRENT = TEST_CURRENT.NextLink()
    Endif
    If TEST <> Null Then test.Display() Else DrawText("Hit Space key to start", 0, 0)
    Flip()
Until KeyHit(KEY_ESCAPE)

Derron

#26
Quote from: dawlane on September 28, 2023, 07:10:02Okay, had some time to spare. It's been a while since I did anything with BlitzMax and I wrote this off the top of my head. But here is a some code that fakes an array by wrapping TList to use a container object. This would not be an ideal solution with the amount of casting that needs to be done to get the index value out of the container. A better solution would be to write your own custom types from scratch using a double linked list (see the linkedlist.mod for how it works) that includes an extra field in the link node type for an index number.

with brl.objectlist you get a TList-like interface based on an array. So a TList which uses an array but manages resizing for you. Means you could extend this class and add operator overloads (and some code to not "compact" the top of the arrays, only the bottom) to be able to use it like this:

local list:TObjectList = new TObjectList()
list[10] = "hello world"
print string(list[10])
print string(list.last()) 'should be the same too)
Just suggesting it as a "it's been a while" and you might not know brl.objectlist.


----


I did not grasp what is really requested here (because I did not deeply read all posts) but if the interest is in a kind of "sparse array" (so length of array is "n elements" but the keys can be "> n") then one would simply wrap two arrays with the right kinds into a type and use it appropriately:
Type TCPUList
  Field keys:int[]
  Field cpus:TCPU[]

  Method InsertCPU(key:Int, cpu:TCPU)
    local index:Int = GetKeyIndex(key)
    'override
    if index >= 0
      cpus[index] = cpu
    'append
    else
      'todo if interested: resize arrays in blocks and use "used" counts to see when to resize again
      keys :+ [key]
      cpus :+ [cpu]
    endif
  End Method

  Method GetKeyIndex:Int(key:Int)
    For Local i:int = 0 until keys.length
      if keys[i] = key Then return i
    Next
    Return -1
  End Method


  Method GetCPU:TCPU(key:Int)
    Local index:int = GetKeyIndex(key)
    If index = -1 Then Return Null
    Return cpus[key]
  End Method


  Method Operator [] :TCPU(key:Int)
    'same code as GetCPU - but we want to avoid an additional function call...
    Local index:int = GetKeyIndex(key)
    if index = -1 Then Return Null
    Return cpus[index]
  End Method


  Method Operator []= (key:Int, cpu:TCPU)
    'same code as insertCPU - but we want to avoid an additional function call...
    local index:Int = GetKeyIndex(key)
    'override
    if index >= 0
      cpus[index] = cpu
    'append
    else
      'todo if interested: resize arrays in blocks and use "used" counts to see when to resize again
      keys :+ [key]
      cpus :+ [cpu]
    endif
  End Method
End Type


Type TCPU
  Field name:String

  Method New(name:String)
    self.name = name
  End Method
End Type

Local cpu1:TCPU = new TCPU("cpu1")
Local cpu2:TCPU = new TCPU("cpu2")


Local cpuList:TCPUList = New TCPUList
cpuList[1234] = cpu1
cpuList[4567] = cpu2

print cpuList[4567].name
Operator overloading:
https://blitzmax.org/docs/en/language/user_defined_types/

Of course it is NOT fast as the key retrieval will iterate over each entry.
If speed is a concern you might need something different than this.

Maybe a TIntMap - which will do way faster "key->value" but has more memory overhead I guess.
So yeah, would prefer a TIntMap here but forgot about it when typing in the example of a 2array-combination :)


Read some more lines in the thread and it looks more like there is the desire to have some "stack" type  ... brl.mod/collections.mod contains some different "containers". Maybe you find a suitable one.


bye
Ron



Baggey

QuoteOkay, had some time to spare. It's been a while since I did anything with BlitzMax and I wrote this off the top of my head. :))

Just logged on and seen your reply @dawlane.Thankyou!

Im going to need sometime to digest! and start playing with the Code. Maybe ill have some questions.

Kind Regards
Running a PC that just Aint fast enough!? i7 4Ghz Quad core 24GB ram 1TB SSD and NVIDIA Quadro K620 . DID Technology stop! Or have we been assimulated!

ZX Spectrum 48k, C64, ORIC Atmos 48K, Enterprise 128K, The SID chip. Im Misunderstood!

Baggey

QuoteRead some more lines in the thread and it looks more like there is the desire to have some "stack" type  ... brl.mod/collections.mod contains some different "containers". Maybe you find a suitable one.

@Derron  i have no idea what you mean by brl.mod/collections.mod and i do not understand "containers" :-[

I Thankyou for your code example idea. Its All good learning even though you say it may be a slow way?

Ive yet to digest Dawlane's code. However what i think im trying to achieve is a Stacked Array of "Types" which is resizable with random access to it. But mostly ill be using it as LIFO.

Speed is of the Essence as its going to be called every TCycle.

Kindest Regards Baggey
Running a PC that just Aint fast enough!? i7 4Ghz Quad core 24GB ram 1TB SSD and NVIDIA Quadro K620 . DID Technology stop! Or have we been assimulated!

ZX Spectrum 48k, C64, ORIC Atmos 48K, Enterprise 128K, The SID chip. Im Misunderstood!

Midimaster

Quote from: Baggey on September 28, 2023, 17:19:12...i have no idea what you mean by brl.mod/collections.mod and i do not understand "containers" :-[ ...

Im also suprised. But it looks like there is a default TStack type in BlitzMax NG. There is no thematic description in the BlitzIDE HELP, but if you write...
a:TStack = New TStack... and then press F1, the related command reference will appear.

Perhaps we should write some tutorial about this collection.mod based new Data Types... there are much more: TStack, TSet, TArraySort, TTreeMap, TQueue


...back from Egypt