TList save/load complication

BlitzMax Forums/BlitzMax Programming/TList save/load complication

Taron(Posted May) [#1]
I've got a weird one for y'all...

I've made a type that contains TLinks to previous and ahead Tlinks.

Pseudo...
Type element
field prev:element
field ahead:element
EndType 


How would you save and load this again?

I've tried a number of things, including providing IDs and then parsing for them, which works, but is awfully slow and seems dumb to me?!

Thanks in advance for any advice!


GfK(Posted May) [#2]
I wouldn't even bother saving that information. Is there a special reason why you need to?

As the element objects are held in a TList you know for a fact that you'll be loading the data in the same order as you saved it, so once you've done that, just recalculate the prev/ahead links at load-time if you really need them. It's probably only going to take a couple of millisecs, if that - no biggie when loading data. It's not like you're doing it every frame (is it)?


Taron(Posted May) [#3]
Oh...you're saying they will remain relative? So...hmmm...I'll make some experiments. Sounds great! THANKS! 8D


Taron(Posted May) [#4]
This stuff really remains foggy to me...
I know, I must be hovering over the solution, but it's tiring...

...I'm so sorry, I don't know why I never went into that deeply enough? 8{

Ahaha, .ToString will return a hex number as string, but then .ToInt will return nonsense, of course...meh.
So, I could consider trying to figure out how I convert a hex out of a string to an int or simply have faith that it's all proper addresses, hahaha...dang.

Anyway, another curious little journey into BlitzMax.


GfK(Posted May) [#5]
Not that answering a question with a question is a solution, but, what on earth do you need the memory address for?

Maybe more info would help, i.e. what are you trying to achieve? Wondering if you might be over-thinking something.


Taron(Posted May) [#6]
Yeh, I'm not yet sure how I can do that... cast the object as...danged, I don't know.

Any idea on how you would actually write a recalculation? A tiny hint might help me already...

I can't very well do current_object:-first_object to get to some address that then could be relative a new first_object. At least, i don't know how?!


GfK(Posted May) [#7]
I'm not sure it's even possible. AFAIK you can't rely on data being in the same memory address, not even relative to each other.


Taron(Posted May) [#8]
Yes, I'm afraid I'm overthinking it!

All I need would be an INDEX, but I don't know how I could get that unless I'd convert it to an array, but even then I'd have to find the IDs again.

Ok, here's the situation:

I made a cute little vector painter just as a test, which automatically smooths curves at draw time. For that I store the previous and next line element to ensure I know what has to happen. Since I want those vectors modifiable afterwards, I don't want to just store coordinates.

The above pseudo code illustrates the problem perfectly, though!

Now, I can ask for an object VIA index (ValueAtIndex), but I don't know how I can GET the index of an object. If that would be possible, then I could easily store that instead. But I don't know how I can get the index...I think, I must have missed something?!


GfK(Posted May) [#9]
ValueAtIndex can be slow, particularly with huge lists. Fine for one-shot/occasional use but as much as I remember, if you want the value at index 100, it has to iterate through the first 99 in order to get it. Obviously this is all going to get silly with thousands of objects in a list.

Have you considered using a TMap? It sounds like it might be better suited to your situation. That way each node (I presume) can have its own unique index and be retrieved with node:element = element(myTMap.ValueForKey(myIndex)). Note that the index must be cast to a string, and you must also manually cast the result to whatever you know it to be - an object of type 'element', in this case.


Taron(Posted May) [#10]
Yes, that is a great idea! I thought about it a moment ago, using maps instead. Sounds like it would be the rare kind of ideal case. 8)

I've never done it, so that would be interesting all by itself.

THANKS and sorry, if I come across just as frustrated as I am about this. I keep thinking about just doing everything manually, because that would be the least trouble for my brains. Using faith based concepts always gets me on edge somehow.

Ironic, of course, considering that I am truly considering to try TMaps, haha! 8P

Anyhow...you're awesome, Gfk! 8D


TomToad(Posted May) [#11]
Are you looking for something like this?



Taron(Posted May) [#12]
Hihi, no, but that's sweet, thank you!

This is a piece of what I have, and you'll see the insane ID solution...



Taron(Posted May) [#13]
I should clarify: The issue is that I can't rely on the previous or next element to really be previous or next in the list. They could be anywhere in the list, you know.


GfK(Posted May) [#14]
So to summarise:

1. You have a bunch of nodes (currently stored in a TList).
2. The nodes immediately before and after a node on screen, won't necessarily be next to each other in the list (presumably the user can insert nodes and so on, and a new node would simply be added to the end of the list?), hence the requirement for storing the previous and next nodes.


That being correct, then I would suspect that you were thinking along the right lines having a unique ID per node.

In the interests of speed, what I would do is have the ID as an integer field in the object. When you reload, load the objects into a temporary TMap, rather than a TList. Something like this should do it.

myTMap.Insert(String(myElement.ID),myElement))


Then you can iterate through each object in the TMap:

For e:element = EachIn myTMap.Values()
  If e.prevID <> 0 ' is there a previous node?
    e.prev = element(myTMap.ValueForKey(String(e.prevID)))
  EndIf
  If e.nextID <> 0 ' is there a next node?
    e.next = element(myTMap.ValueForKey(String(e.prevID)))
  EndIf
  myListOrWhatever.AddLast(e)
Next
myTMap = Null


...or something like that. Code typed straight into the reply box, so it's untested but you get the idea.


Floyd(Posted May) [#15]
This is really a list isn't it? There is a first item. Then the ahead link gives the one after that, and that one's ahead link gives the next one etc. You somehow know when you are at the end, presumably a Null ahead link.

So you traverse the list in this way and save each one. When they are reloaded they will be in the desired order.


Taron(Posted May) [#16]
@GfK:
Yes, the type has a field id:int and ahead_id and prev_id.
I must try the TMap for sure! Thanks for the further example, that's great!

@Floyd:
It's not a simple array, if that's what you mean. Though it currently generates a seemingly connected strip of elements, each one may be redirected along other elements, things could be cut or reconstructed in other ways, it's meant to be very open.
My very first test was to simply go one step back and one forth to get previous and ahead items, but it was flawed.
Though, come to think of it, I later found out that I forgot a field for the total length of the segment...hmmm...

Anyway, I'll try more! Thanks all three of you! 8D


Taron(Posted May) [#17]
Floyd...it's quite funny, I have to say. You know how sometimes one little mistake can send you off on a tangent to roam the nightmarish realm of confusion, frustration and denial... (pfffmaha) ...and every now and then you emerge from it with a great deal of additional clarity and real discoveries about what likely will be needed later on, BUT ... (THE GIANT KIND OF BUTS) ... then it turns out that you remember the little neglected mistake that you fixed later, sort of knowing that it could've been the source of all evil, but the stuff that scared you into full focus seemed more relevant so that the little mistake sort of lost weight or at least all attention...

Well, so I literally, literally, literally just held down my friendly Ctrl+Z for a while to see Blide take away allllll the pretty nonsense I wrote right up until the crucial very first take on the issue and right before I started the huge, confusing stumble into TLink madness...two steps before I noticed and fixed that little mistake.
I then fixed it right there and voila... problem solved (for now!).

Funny how that sometimes goes. (blush)

I will, as my personal walk of shame, post my entire code here promptly, but it ain't much, yet, and likely not very pretty. If you have a tablet, though, you might get a kick out of it already, too! 8)


Taron(Posted May) [#18]
As promised, a real big mess...but quit fun already!

Instructions:
(m) to toggle modes VECTOR | FREEHAND
(g) to toggle Grid
(space)+LMB or MMB to pan canvas
(space)+{ctrl}+LMB or MW to zoom
(home) to reset zoom and pan
hold (delete) and hover over lines to delete individual lines
(shift)+(delete) clears the canvas
(ctrl)+(z) undo ...endless
...no redo, yet!
(s) to save
(o) to open

If you have a graphics tablet (Wacom or the likes), pressure controls opacity in FREEHAND mode.

Vector mode has snapping and drag or click/click solution for making vectors. Snapping with RMB!



It's a messy code, as I said, probably plenty of stupid things in there, but I post it as some kind of an apology for all the ruckus. 8]


Derron(Posted May) [#19]
Compile Error: Can't find interface for module 'pub.tablet'


bye
Ron


Taron(Posted May) [#20]
You have to look for the tablet mod. Should be in archives or there about!
I wished there was a 64bit compile of it for BlitzMaxNG. I couldn't do it, thus far... pity.

But, yeah, you'll find the tablet.mod!
If you don't have a tablet, you might as well just take out all the tablet stuff. It'll work fine with the mouse. Just no "pressure".


Taron(Posted May) [#21]
Ha, imagine that, I've had to share it again years ago...funny.
http://www.blitzbasic.com/Community/posts.php?topic=102767