Is there any way to do this?
BlitzMax Forums/BlitzMax Programming/Is there any way to do this?
| ||
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] |
| ||
You could, instead of using an array, use a memory bank and pass the BankPtr as the address.? |
| ||
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. |
| ||
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? |
| ||
why dont you just check to see if the text box has changed? if it hasnt theres no need to update anything else. |
| ||
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... |
| ||
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] |
| ||
VarPtr is a good idea. You can make even an Int variable and varptr to it. |
| ||
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... |