Is there any way to do this?

BlitzMax Forums/BlitzMax Programming/Is there any way to do this?

Sonic(Posted 2007) [#1]
What I'm doing at the moment is writing a simplified GUI system for my level editor. I have textboxes, buttons etc...

What I'd like to be able to do is this:

Let the contents of (for example) a text box point to an actual memory address, the one that is used in fields of my real objects. This is so that when I alter the contents of the text box, it will automatically change the contents of a string field within an object. At the moment I'm having to read the object's field into the textbox every frame, then get user input, then read back into the object's field. As far as I'm concerned this is a really ugly way to go about it. I'd like to operate on the field's directly.

I think I could do this with ints using Varptr etc, but for strings I can't seem to get the actual memory addresss, as they are a kind of object I suppose. Using the .ToCString() method just returns the address of a new copy of the string in memory... So no use.

Is this just the downside to a managed-memory environment? If so, I miss C!

[edit: typo]


ImaginaryHuman(Posted 2007) [#2]
You could, instead of using an array, use a memory bank and pass the BankPtr as the address.?


Gabriel(Posted 2007) [#3]
I don't understand AngelDaniel's suggestion, so he may have offered you just what you need, but I wanted to do exactly what you're trying to do with Car Jockey, and found as you did that since strings are objects, you can't use VarPtr as you can with values. What I ended up doing was passing a function pointer instead and having the function the pointer points to put the data in the right variable. It's not ideal because it means you're hardcoding a function for every variable, but it does still give you the clean method of operating.


H&K(Posted 2007) [#4]
LOL
Well, I dont understand Sonics question, so Ill also assume angel has answered it. Surly Atpye.Field is a pointer to a memory address?


smilertoo(Posted 2007) [#5]
why dont you just check to see if the text box has changed? if it hasnt theres no need to update anything else.


Sonic(Posted 2007) [#6]
Hi Smilertoo, I do this actually, but that's not the issue really... I'd just like to do away with the reading in and out of the texbox altogether by having its contents refer to the same address in memory of the field it refers to.

I'm basically using Gabriel's solution, but I find it ugly, and there's all sorts of dependencies issues, as for example changing the object I'm editing the fields of should then update all the texboxes... Kind of difficult to explain but I hope you get my drift.

Angel, I think you might just have something there, I'm just thinking of the implications of what you said, it might just work... Hmmm...


Sonic(Posted 2007) [#7]
Right, so this system (AngelDaniel's system) is working for the moment... The only problem is I have to allocate far more memory than I should because the data within strings can change at any point.

Is there cleaner way to go about it? I'll try to give an example of what I"m doing...

Say we have a type 'Hotspot' with fields 'name' and 'description' - both Byte pointers to somewhere within a data bank.

During the update() method of the textbox, the contents is read from the Byte pointer referring to the property being edited (eg name_ptr). Then read back at the end of the update loop. This is nice as I only have to assign the pointer once, when I change which 'hotspot' is being edited.

For now, I allocate the potential maximum length of name and description within the bank... However in an application that requires hundreds, nay, thousands of these strings, memory soon creeps upwards.

Better would be some kind of dynamic allocation - all strings are placed head-to-tail within the memory bank, and when a string increases in length, a new place in the bank would need to be found.

This would require some clever memory management tricks that I'm struggling to design.

Can anyone give me some pointers as to how I would organise this? I've tried searching for tutorials in C - but of course in C there's a much simpler way of doing it, because strings are not Objects, merely arrays of Char, so I've come up empty-handed.

Thanks in advance...

Jasper

[edit: typo]


ImaginaryHuman(Posted 2007) [#8]
VarPtr is a good idea. You can make even an Int variable and varptr to it.


Sonic(Posted 2007) [#9]
Hi Angel could you elaborate on that? How exactly should I use Varptr? I take it you get what I'm trying to do?

I've spent all day writing a dynamic memory management system which does its job...

But then pointers which are passed to the textbox may be altered when a string is enlarged, which doesn't alter the original 'hotspot' field... So I'm kind back to square one.. with a really cool dynamic memory thing.

Here's the code I'm using at the moment - any way it could be modified?

[code

Strict

Const BY_SIZE=0,BY_OFFSET=1

Global bank:TBank=CreateBank(100)
Global bank_ptr:Byte Ptr=bank.Buf()
Global hotspot_offset:Int
Global free_space:TList=New TList
Global used_space:TList=New TList

Local m:memory=New memory

m.size=bank.Capacity()
m.offset=bank_ptr
ListAddLast free_space,m




memory.display_memory()

Local p:Byte Ptr

p=string_alloc("Hello World!")
Print srd(p)
memory.display_memory()
Print""

p=swr("Hello!",p)
Print srd(p)
memory.display_memory()
Print""


p=swr("Hello everyone!",p)
Print srd(p)
memory.display_memory()
Print""


p=swr("Hello!",p)
Print srd(p)
memory.display_memory()
Print""


' Here was can see the problem - imagine this is within the textbox...

Local p2:Byte Ptr=p ' this is the pointer to the textbox's contents...

p2=swr("Hi!",p2)
Print srd(p)

' well that works fine... but what if the string gets bigger?


p2=swr("Hello everybody in the universe!",p2)
Print srd(p) ' as we can see p no longer points to the same place!

Type memory
Field offset:Byte Ptr
Field size

Global sort_method

Function display_memory()

Print "*FREE*"

For Local m:memory=EachIn free_space
Print " >> "+m.ToString()
Next

Print "*USED*"

For Local m:memory=EachIn used_space
Print " >> "+m.ToString()+" contains:"+srd(m.offset)
Next
End Function

Function find_space:memory(space)
free_space.Sort(True)
For Local m:memory=EachIn free_space
If m.size>=space
Return m
EndIf
Next
EndFunction

Function add_space:memory(in_memory:memory,space)
Local m:memory=New memory
m.offset=in_memory.offset
m.size=space
in_memory.offset:+space
in_memory.size:-space
If in_memory.size<=0
ListRemove free_space,in_memory
EndIf
Return m
EndFunction

Function join_free_space()

sort_method=BY_OFFSET
free_space.Sort(True)

Local m1:memory=Memory(free_space.First())
Local m2:memory

Local new_list:TList=New TList

Local dont_add_last

For Local m:memory=EachIn free_space
m2=m

dont_add_last=False

If m2<>free_space.First()
If m2.offset=m1.offset+m1.size
'Print " >> Joining >> "+m1.ToString()+" + "+m2.ToString()
m1.size:+m2.size
ListAddLast new_list,m1
dont_Add_last=True
Else
ListAddLast new_list,m1
m1=m2
EndIf
Else
m1=m2
EndIf

Next

If Not dont_add_last Then ListAddLast new_list,m1

free_space=new_list

sort_method=BY_SIZE
free_space.Sort(True)
End Function

Method ToString:String()
Return "Location: "+(offset-bank_ptr)+" Size: "+size
EndMethod

Method Compare(Obj:Object)
Select sort_method
Case BY_SIZE If memory( Obj ).size < size Return 1 Else Return -1
Case BY_OFFSET If (memory( Obj ).(offset)-bank_ptr) < (offset-bank_ptr) Return 1 Else Return -1
End Select
EndMethod


End Type


Function string_alloc:Byte Ptr(a$)

Local m:memory
m=memory.find_space(Len(a$)+1)
m=memory.add_space(m,Len(a$)+1)
stringwrite(a$,m:memory)
free_space.Sort(True)
ListAddLast used_space,m

Print "Allocated: "+a$

Return m.offset

End Function

Function srd:String(m:Byte Ptr) ' read string
Return String.FromCString(m)
EndFunction



Function swr:Byte Ptr(a$,b:Byte Ptr) ' write string


Local m:memory

For Local m2:memory=EachIn used_space
If b=m2.offset
m=m2 ; Print "position found -> "+(m.offset-bank_ptr) ; Exit
EndIf
Next

If Len(a$)+1>m.size

Print "++ enlarging -> removing at: "+(m.offset-bank_ptr)

' NOTE: For some crazy reason, Listremove is not working here - I have no idea why, so I put in this completely wasteful loop...

ListRemove used_space,m

Local new_used_space:TList=New TList

For Local m2:memory=EachIn used_space
If m2<>m Then ListAddLast new_used_space,m
Next

used_space=new_used_space

ListAddLast free_space,m

m=memory.find_space(Len(a$)+1)
m=memory.add_space(m,Len(a$)+1)
ListAddLast used_space,m
Print " -> adding at: "+(m.offset-bank_ptr)

ElseIf Len(a$)+1<m.size

Local new_free_size=m.size
m.size=Len(a$)+1
new_free_size:-m.size
Local m2:memory=New memory
m2.size=new_free_size
m2.offset=m.offset+m.size
ListAddLast free_space,m2
EndIf

m=stringwrite(a$,m)

memory.join_free_space()

Local new_offset=m.offset-b

b:+new_offset

Return b

End Function

Function stringwrite:memory(a$,m:memory)

Local offset=m.offset-bank_ptr
Local l=Len(a$)
Local p:Byte Ptr = a$.ToCString()

For Local c=0 To l

bank.PokeByte(offset,p[c])
offset:+1

Next

bank.PokeByte(offset,0) ' null terminate
offset:+1

Return m

End Function


]

Sorry - call me brainless but I can't find for the life of me the codebox switch - anyone tell me and I'll update it...