b3d after command in bmax?

BlitzMax Forums/BlitzMax Beginners Area/b3d after command in bmax?

Robert Cummings(Posted 2005) [#1]
Hiya,

I have the following code:
For Local p:pointType = EachIn pointList
	Local p1:pointType = p
	Local p2:pointType = after p1
Next

I want to make variables from P1 to P4 be 4 objects in the list so I can calculate some interpolated values...

Basically there is no "after" command in bmax so I'm wondering how I get the object after p? and then the object after p2 and so on... I only need 4 of them.


RiK(Posted 2005) [#2]
use an array instead of a list?


Robert Cummings(Posted 2005) [#3]
I am using a list because it's essential to insert data at any point, so an array's not possible, thanks RiK.


LarsG(Posted 2005) [#4]
Method NextLink:TLink() 'Returns the next link in the list



Robert Cummings(Posted 2005) [#5]
Can you tell me how to use it please. I can't figure out how to get it to work with the above code. I have already tried...


tonyg(Posted 2005) [#6]
This might help...
nextlink
and this...
more nextlink
and this...
more more nextlink
and more...
blimey more nextlink
and possibly this...
Graphics 640,480,0
mylist:TList=CreateList()
Type mytype
  Field count:Int
End Type
For Local x = 1 To 50
   s:mytype = New mytype
   s.count=x
   ListAddLast mylist,s
Next
my_firstlink:TLink = mylist.firstlink()
currentlink:TLink = my_firstlink
s:mytype = mytype(my_firstlink.value())
mykey=37
While Not KeyHit(key_escape)
   Cls
   Select mykey
     Case key_left
		  my_firstlink:TLink = mylist.firstlink()
          currentlink:TLink = my_firstlink
          s:mytype = mytype(my_firstlink.value())
          DrawText "my_firstlink:TLink = mylist.firstlink() ; s:mytype = mytype(my_firstlink.value())",0,0
          DrawText "my_firstlink count field = " + s.count, 0,10
      
     Case key_right
          my_lastlink:TLink = mylist.lastlink()
          currentlink:TLink = my_lastlink
          s:mytype = mytype(my_lastlink.value())
          DrawText "my_lastlink:TLink = mylist.lastlink() ; s:mytype = mytype(my_lastlink.value())",0,0
          DrawText "my_lastlink count field = " + s.count, 0,10
     Case key_up
          my_prevlink:TLink = currentlink.prevlink()
          If my_prevlink <> Null
	          currentlink:TLink = my_prevlink
	          s:mytype = mytype(my_prevlink.value())
	  	      DrawText "my_prevlink:TLink = mylist.prevlink() ; s:mytype = mytype(my_prevlink.value())",0,0
	          DrawText "my_prevlink count field = " + s.count, 0,10
	      Else
	          DrawText "No prevlink. Current position : " + s.count,0,0
	      EndIf
     Case key_down
          my_nextlink:TLink = currentlink.nextlink()
          If my_nextlink <> Null
              currentlink:TLink = my_nextlink
   		      s:mytype = mytype(my_nextlink.value())
	          DrawText "my_nextlink:TLink = mylist.nextlink() ; s:mytype = mytype(my_nextlink.value())",0,0
 	          DrawText "my_nextlink count field = " + s.count, 0,10
          Else
              DrawText "No nextlink : Current position : " + s.count,0,0
          EndIf
     Default 
          DrawText "Invalid Selection. Current position " + s.count,0,0     
     End Select
     DrawText "Firstlink=left, lastlink=right, nextlink=down, prevlink=up",0,40

     Flip
     FlushMem
 	 mykey=WaitKey()
     If mykey=27 Exit
Wend



klepto2(Posted 2005) [#7]
A not so complicated example:

Global List:Tlist = New TList

Type TBase

Field ID:Int

End Type

For x = 1 To 6
Local T:TBase = New TBase
T.ID = X
List.Addlast(T)
Next
Global T1:Tlink = List.FirstLink()

For P:TBase = EachIn List
	P1:TBase = P
	T1 = T1.NextLink()
	If T1 <> Null Then
	P2:TBase = TBase(T1.Value())
	EndIf
	
	Print P1.ID
	Print P2.ID
	Print "---------"
Next




Robert Cummings(Posted 2005) [#8]
Wow thanks lads!

I didn't realise this popped up so many times. It's pretty obvious then, that blitzmax needs a proper after command!

As it's clearly something a lot of people want to do with standard eachin loops as well!


klepto2(Posted 2005) [#9]
I have written 2 Functions that should be equal to After and Before.

Here is the code:


Type TBase

Field ID:Int

End Type

For x = 1 To 6
Local T:TBase = New TBase
T.ID = X
List.Addlast(T)
Next
Global T1:Tlink = List.FirstLink()

For P:TBase = EachIn List
	P1:TBase = P
	P2:TBase = TBase(After(List,P1))
	P3:TBase = TBase(Before(List,P1))
	Print P1.ID
	Print P2.ID
	Print P3.ID
	Print "---------"
Next

Function After:Object(List:Tlist,value:Object)

	Local T1:Tlink = List.FindLink(value)
	Local T2:Tlink = T1.NextLink()
	If T2 = Null Then
		Return List.FirstLink().Value()
	Else
		Return t2.value()
	EndIf
	
End Function

Function Before:Object(List:Tlist,value:Object)

	Local T1:Tlink = List.FindLink(value)
	Local T2:Tlink = T1.PrevLink()
	If T2 = Null Then
		Return List.LastLink().Value()
	Else
		Return t2.value()
	EndIf
	
End Function


I hope that this is what you was looking for.


Robert Cummings(Posted 2005) [#10]
Perfect!

A big thanks to you klepto2! :)

Why didn't they have this built in? it makes every bit of sense for the high level programmer.


Yan(Posted 2005) [#11]
I know I'm new to this'ere OO malarky but can't you just extend a base type?...




FlameDuck(Posted 2005) [#12]
It's pretty obvious then, that blitzmax needs a proper after command!
It can't have what you call a "proper after command" as not all objects are stored in lists, or even sequential datastructures. In Blitz3D all objects had to be stored using linked lists. Thus all objects would inherently have next and previous objects. In BlitzMAX, this is no longer the case, not only can objects be stored in different lists, and data structures, but they can be stored in no datastructure at all.

I have written 2 Functions that should be equal to After and Before.
Functionally perhaps, but it will be much, much slower (Linear vs. Constant time complexity), particulary on large collections.

Why didn't they have this built in?
Huh?

it makes every bit of sense for the high level programmer.
No it doesn't. EachIn is a general purpose itterator, and returns the objects collected, in sequence. Not all collections (heaps and dictionaries for example) have data structures where data is stored linearly, and so being able to get the next and/or previous object in the collection may not make sense.


Robert Cummings(Posted 2005) [#13]
whatever.


Jay Kyburz(Posted 2005) [#14]
I'd like to know more about how fast it is to iterate through arrays rearranging the order of every entry, compared to using linked lists.

I've seen threads that compare the overall speed of arrays vs lists (arrays were much faster), but i don't remember if we looked at how long it takes to cut things out (or add things) to the middle of an array and move every entry in the array.

You could write some functions to do it in a general way too.

Anybody done any thinking on this?


DH(Posted 2005) [#15]
Flameduck is right on one point, the functions you wrote do emulate the after,before functionality however they are going to be slower (just based on the 'findlink' function).

It would be quicker if fish learned how to use the links and lists rather than slow him down (app-wise) with wrapper functions to emulate b3d. It took me a bit of asking questions to figure out what you can do with a link and what you can do with a list. And I still have to go back and look at past source I wrote to remember how the whole thing works, but at least I can write it optimally and not have to rely on slow wrappers.

Don't get me wrong klepto, they are very nice functions, they are just going to be slow.


Dreamora(Posted 2005) [#16]
The simplest thing is to open brl.linkedlist bmx file in which the whole linked list source is which is quite simple to understand ...


Robert Cummings(Posted 2005) [#17]
Hi,

I actually find the list stuff murderously difficult to understand with almost no documentation. I don't actually have the luxury of time, so the after function posted above is an absolute life-safer, for which I am deeply grateful for.

As we know, bmax is a multi levelled language. It has easy ways to do things and far more difficult but flexible ways to do things. Believe me I tried to learn the guts of lists but ended up coming away TOTALLY confused after hours and hours of effort. Thats half a days work, and I gave it a good shot.

Some programmers intuitively grasp lists: what about people who have never used lists before? Or non advanced programmers? Believe me, it's *confusing*!

Some people are better programmers than others. I really like after, and it works superbly in Blitz3D. I think judging by the above links, a lot of people want it :)


Robert Cummings(Posted 2005) [#18]
Also absent:

InsertAfter

InsertBefore

Perhaps these could get added to the next release of Blitzmax.


klepto2(Posted 2005) [#19]
I know that my Functions will be slow in comparison to the optimal way. These Functions should only be alternatives for
beginners. And maybe they should show abit about how to use TLink with its Methods.

And my Functions are based on the Valueatindex Method of Tlist.


tonyg(Posted 2005) [#20]

Also absent:

InsertAfter

InsertBefore

Perhaps these could get added to the next release of Blitzmax.



Insertbeforelink
InsertAfterlink


Dreamora(Posted 2005) [#21]
Doesn't make it faster at all.
For fast next - before with lists you best make an array out of them (there is a simple command for that) and iterate through it. Thats constant access time no "search" as any linked list command will have to do.


Robert Cummings(Posted 2005) [#22]
Insertbeforelink
InsertAfterlink

Don't work with objects do they? thats the whole point of this post - functions that work directly with objects for ease of programming and stuff - just like earlier blitz.


Yan(Posted 2005) [#23]
Also absent:

InsertAfter

InsertBefore


Did you read my previous post?


tonyg(Posted 2005) [#24]
Taken from here post somewhere on this site...
Function InsertAfter(list:TList,a:Object,b:Object)
	Local	link:TLink
	link=list.FindLink(a)
	Assert link Else "Can't find Object "+a.ToString()+" In List"
	list.InsertAfterLink(b,link)
End Function

t:TList=New TList
t.AddLast "A"
t.AddLast "B"

InsertAfter t,"B","C"

For a$=EachIn t
	Print a
Next

<edit>
here it is
and..
this


Robert Cummings(Posted 2005) [#25]
Thanks lads, you've all been very patient with my stumbling around :)


RktMan(Posted 2005) [#26]
coming from a java background ...

you have to be careful with iterators over collections and operations that modify the backing collection.

said a different way, if you are iterating over a "collection of things", where the order of that iteration, and the "things" to be iterated over were organized in a particular way, and then *inside* the iterative loop, you muck around with the source collection, bad things can happen.

in java, iterators can "fail fast" (throws an exception) if it is detected that this has happened.

also, as others pointed out, most any collection can minimally support an iterator.

some, may or may not support other types of operations such as insertbefore/insertafter etc ...

again, coming from Java, and knowing some of the pros/cons of collections and the many supporting operations that go with them, Blitz should be careful about how much overhead it takes on with the base API.

Java has seen a few iterations on the collections classes, trying to find the right types of balances on how to make polymorphism work for many of the interfaces and operations, how to make thread safety work, and how to make performance work, where none of the other things are required.

my $0.02, in the context of game development, i would opt for simple and solid datastructures that support the fundamental CS 101 datastructures, and allow developers to add whatever sugar they might need on their own.

Tony


marksibly(Posted 2005) [#27]
Hey fish,

It can sometimes be useful to store the 'link' in objects if they're only ever gonna be in a single list, ala Blitz2D/3D/Plus.
Type MyThing

  Field link:TLink

  Method AddToList( list:TList )
    RemoveFromList           'if we were already in a list, remove us.
    link=list.AddLast( self )  'track the new list we're in...
  End Method

  Method RemoveFromList()
    If link link.Remove ; link=Null
  End Method

End Type

Local thingList:TList=new TList

Local t:MyThing=new MyThing
t.AddToList thingList

For thing:MyThing=EachIn thingList
  'Do something with each thing
Next

While not quite as easy as the old system, it's potentially more flexible...

you have to be careful with iterators over collections and operations that modify the backing collection.


Oh yes!

However, I've designed the Max lists so it's always safe to remove the 'current' object when iterating over a list with EachIn, but it still pays to be careful!


Curtastic(Posted 2005) [#28]
Hey I went through everything that Fish went through, then I almost made a new topic myself (I now see there are already like 5 topics on this), but I managed to figure it out by looking through the TList code.

In the end I decided to use this After function, because links were way too much of a hassle and it was messy. I don't care about the speed difference that much because my lists are small.
Function After:Object(List:TList,Element:Object)
	Local link:TLink
	
	link=list.findlink(element)
	If link=Null Then RuntimeError "Object not in list"
	link=link.nextlink()

	If link=Null Then
		Return Null
	Else
		Return link.value()
	EndIf
	
EndFunction

This command should be built in and documented as a little slow in larger lists, right?
Right now it seems that everyone just creates a topic on blitzbasic.com when they can't find the after command.


Robert Cummings(Posted 2005) [#29]
Thanks Mark and Coorrae, thats very helpful.

I should hold my current link in a list and use that in place of findlink....

local link:tlink = mylink.nextlink() ... get the next link
then link.value() is the object?

Hope I have that right?


Yan(Posted 2005) [#30]
Oh...You obviously didn't read my previous post then! ;op


Robert Cummings(Posted 2005) [#31]
OOOOH

Thanks twoeyed :) gonna try it out. I really didn't notice it. Can I borrow one of your eyes?

Thanks - going to try extending now.


Robert Cummings(Posted 2005) [#32]
Righto, it seems to be just the ticket. I don't know how I didn't see it before. This is elegent stuff.

However how do I put error checking into After and Before? I seem to be thrashing with nulls a bit.

				'gather 4 points needed
				p2 = tPoint(p.After())
				p3 = tPoint(p2.After())
				p4 = tPoint(p3.After())


Seems to throw an error when I get to the end of the list. I tried going checking for null but it up ends anyway...

Thank you for helping though!


Robert Cummings(Posted 2005) [#33]
More info...

The problem seems to be when I call the reverse() list method. It throws a null exception.

Any idea why that could happen with your routines, TEP?


Yan(Posted 2005) [#34]
Hmm...I obviously hadn't thought this through. ;o)

This okay?




Robert Cummings(Posted 2005) [#35]
Thanks :) Do I need to call RebuildLinks whenever I insert an item as well, as I've noticed that data gets swapped around sometimes... many thanks though :)

Also, this is likely to be a lot slower on big lists isn't it? Not a problem but I need to know if thats the case...

And if there is a problem when using AddAfter/Before, how do I rebuild just the links for the item I have inserted? That should give a big speed gain...


Yan(Posted 2005) [#36]
Do I need to call RebuildLinks whenever I insert an item as well
If you use the add methods, then you shouldn't need to.

as I've noticed that data gets swapped around sometimes
Can you post a small example?


Also, this is likely to be a lot slower on big lists isn't it? Not a problem but I need to know if that's the case...
It'll iterate through the entire list once, so it will be slower.


Robert Cummings(Posted 2005) [#37]
I managed to locate the bug in my own code. Can I take this opportunity to say a big 'Thank You' as I'm using your methods now and I think it's really the best thing since sliced bread.

Thanks a lot Two Eyed Pete :)


Yan(Posted 2005) [#38]
NP, glad you found it useful...Eventually ;o)