Author Topic: the problem with _MEM in UDT  (Read 3486 times)

0 Members and 1 Guest are viewing this topic.

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
the problem with _MEM in UDT
« on: October 01, 2019, 12:43:06 am »
So tried my hand, rather successfully I might add, at simulating an ARRAY in UDT with _MEM.

HOWEVER, it does create an issue when trying to save that UDT the quick and easy way.

Code: QB64: [Select]
  1. TYPE Player
  2.  Nam AS STRING * 24
  3.  Max_HP AS _UNSIGNED _BYTE
  4.  Armor AS _BYTE
  5.  Weapon AS _BYTE
  6.  Pack AS _MEM
  7.  Items AS _BYTE
  8.  
  9. DIM SHARED P(250000) AS Player
  10. P(0).Pack = _MEMNEW(32)
  11.  
  12. Add_To_Inventory 0, 1, 1
  13. Add_To_Inventory 0, 4, 5
  14. Add_To_Inventory 0, 19, 3
  15. Add_To_Inventory 0, 9, 1
  16. Add_To_Inventory 0, 29, 45
  17. Add_To_Inventory 0, 100, 103
  18. Print_Inventory 0
  19. Remove_Inventory 0, 29, 5
  20. Print_Inventory 0
  21. Remove_Inventory 0, 9, 1
  22. Print_Inventory 0
  23.  
  24. OPEN "Debug.txt" FOR BINARY AS #1
  25. PUT #1, , P()
  26.  
  27.  
  28. _MEMFREE P(0).Pack
  29.  
  30. SUB Add_To_Inventory (Who%%, Item%%, Count%%)
  31.  Match%% = false
  32.  FOR i%% = 0 TO 15
  33.   IF Item%% = _MEMGET(P(Who%%).Pack, P(Who%%).Pack.OFFSET + i%% * 2, _BYTE) THEN Match%% = i%%: i%% = 30
  34.  NEXT i%%
  35.  IF NOT Match%% THEN 'new item
  36.   _MEMPUT P(Who%%).Pack, P(Who%%).Pack.OFFSET + P(Who%%).Items * 2, Item%% 'POKE
  37.   _MEMPUT P(Who%%).Pack, P(Who%%).Pack.OFFSET + P(Who%%).Items * 2 + 1, Count%% 'POKE
  38.   P(Who%%).Items = P(Who%%).Items + 1
  39.   temp%% = _MEMGET(P(Who%%).Pack, P(Who%%).Pack.OFFSET + Match%% * 2 + 1, _BYTE)
  40.   temp%% = temp%% + 1
  41.   _MEMPUT P(Who%%).Pack, P(Who%%).Pack.OFFSET + Match%% * 2 + 1, Count%% 'POKE
  42.  
  43. SUB Remove_Inventory (who%%, Item%%, Count%%)
  44.  Match%% = false
  45.  FOR i%% = 0 TO 15 'find the item
  46.   IF Item%% = _MEMGET(P(who%%).Pack, P(who%%).Pack.OFFSET + i%% * 2, _BYTE) THEN Match%% = i%%: i%% = 30
  47.  NEXT i%%
  48.  IF Match%% = false THEN
  49.   'something went horribly wrong!
  50.   PRINT "ERROR ITEM NOT FOUND!"; Item%%; Match%%
  51.   _MEMFREE P(who%%).Pack
  52.   END
  53.   temp%% = _MEMGET(P(who%%).Pack, P(who%%).Pack.OFFSET + Match%% * 2 + 1, _BYTE)
  54.   temp%% = temp%% - Count%%
  55.  
  56.   IF temp%% = 0 THEN 'item is out so remove from inventory
  57.    temp$ = _MEMGET(P(who%%).Pack, P(who%%).Pack.OFFSET, STRING * 32) 'get entire pack string
  58.    temp$ = LEFT$(temp$, Match%% * 2 - 1) + MID$(temp$, 2 * Match%% + 2)
  59.    P(who%%).Items = P(who%%).Items - 1
  60.  
  61.    l%% = LEN(temp$)
  62.    FOR i%% = l%% TO 31 'pad temp$ to full 32 characters
  63.     temp$ = temp$ + CHR$(0)
  64.    NEXT i%%
  65.  
  66.    _MEMPUT P(who%%).Pack, P(who%%).Pack.OFFSET, temp$ 'put invetory back
  67.   ELSE
  68.    _MEMPUT P(who%%).Pack, P(who%%).Pack.OFFSET + Match%% * 2 + 1, temp%% 'put adjusted count back
  69.   END IF
  70.  
  71.  
  72.  
  73. SUB Print_Inventory (who%%)
  74.  'check that values in inventory are correct
  75.  'DEBUGGING!_-------------------------------
  76.  LOCATE 1, 1
  77.  FOR i%% = 0 TO P(who%%).Items
  78.   PRINT "Item ID#:"; _MEMGET(P(who%%).Pack, P(who%%).Pack.OFFSET + 2 * i%%, _BYTE)
  79.   PRINT "Item Count:"; _MEMGET(P(who%%).Pack, P(who%%).Pack.OFFSET + 2 * i%% + 1, _BYTE)
  80.  NEXT i%%
  81.  

now if you run this program you will see it creates an inventory and modifies it a time or two then saves it to a file,
but if you open the file you will not see any of the inventory data there. just the _MEM TYPE data in its place.

so everything now has to be saved one item at a time one record at a time. and while 250000 players may(WILL) never actually happen (though its only using ~23megs, or so, of memory total if we created all the _MEM areas too) but if we had to cycle a FOR\NEXT 250000 (or say even 2,500,000!) times to save each player is not good.

My yearly plea for arrays in types, not REDIMable arrays just standard arrays. surely easier than variable length strings(attempted valiantly by Luke, I believe), as this would be a fixed area in memory with the rest of the UDT memory.

Granted after becoming radioactive I only have a half-life!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: the problem with _MEM in UDT
« Reply #1 on: October 01, 2019, 01:06:48 am »
Question:  Why not just make P().Pack as string * 32?

TYPE Player
....
  Pack AS STRING * 32
....
END TYPE



Then, in SUB Add_To_Inventory, use _MEM to reference that string...

SUB Add...
   STATIC m as _MEM ‘no need to initialize/free it over and over
   STATIC String_Offset AS _OFFSET
   m = _MEM(P(WHO%%)) ‘Just change where you want to point it to.
   String_Offset = m.OFFSET + 28 ‘move to where P(Who%%).Pack starts at in memory


At this point, you memget/memput as you were, but from String_Offset instead of from P(Who%%).Pack.Offset and such, as before...

I haven’t tried it, but it should work for you, and still preserve the Type in such a manner so you can GET/PUT it to file like normal, with no issues.

Example — INSTEAD OF:
    _MEMGET(P(Who%%).Pack, P(Who%%).Pack.OFFSET + i%% * 2, _BYTE)
YOU WOULD:
    _MEMGET(m, String_Offset + i% * 2, _BYTE)
« Last Edit: October 01, 2019, 01:11:29 am by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: the problem with _MEM in UDT
« Reply #2 on: October 01, 2019, 01:15:51 am »
Question2: If you DIM P(250000), doesn’t Who need to be larger than a %%?  Shouldn’t you make it a LONG(&), instead?
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Re: the problem with _MEM in UDT
« Reply #3 on: October 01, 2019, 10:23:15 am »
Question:  Why not just make P().Pack as string * 32?
SUB Add...
   STATIC m as _MEM ‘no need to initialize/free it over and over
   STATIC String_Offset AS _OFFSET
   m = _MEM(P(WHO%%)) ‘Just change where you want to point it to.
   String_Offset = m.OFFSET + 28 ‘move to where P(Who%%).Pack starts at in memory


At this point, you memget/memput as you were, but from String_Offset instead of from P(Who%%).Pack.Offset and such, as before...

I haven’t tried it, but it should work for you, and still preserve the Type in such a manner so you can GET/PUT it to file like normal, with no issues.

Example — INSTEAD OF:
    _MEMGET(P(Who%%).Pack, P(Who%%).Pack.OFFSET + i%% * 2, _BYTE)
YOU WOULD:
    _MEMGET(m, String_Offset + i% * 2, _BYTE)

Oh just lack of experience with _MEM, I was trying something new for me.
I won't have to keep _MEMFREEing each time too will I?

Question2: If you DIM P(250000), doesn’t Who need to be larger than a %%?  Shouldn’t you make it a LONG(&), instead?
I kind of embellished it a bit when I posted to make the issue a little more prominent, though some of the routines do indeed use ~& variables.
Granted after becoming radioactive I only have a half-life!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: the problem with _MEM in UDT
« Reply #4 on: October 01, 2019, 11:08:03 am »
Oh just lack of experience with _MEM, I was trying something new for me.
I won't have to keep _MEMFREEing each time too will I?

Nope.   That’s the whole idea behind writing it like this:

STATIC m as _MEM ‘no need to initialize/free it over and over
   m = _MEM(P(WHO%%)) ‘Just change where you want to point it to.

Keep the MEM variable for use all the time, and just change where it points to, when you call the sub.  No need to waste the time and effort to endlessly free and reset it over and over.

Just don’t exit a sub with a MEM variable DIMed, without freeing it, or you’ll make a memory leak in your program.  STATIC lets us just reuse the same MEM variable over and over, whereas DIM would create a new temp MEM variable with each call, and slowly raise the program’s memory usage.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Re: the problem with _MEM in UDT
« Reply #5 on: October 01, 2019, 10:57:03 pm »
  _MEMPUT m, Pack, _memget(m, pack, string * (34-(match%%*2))) 'put invetory back

"Invalid TYPE name" ???

Take it thats a 'no can do'?.

I was trying to clean up removing an item from inventory by padding the pack string with 2 extra unused 0s. and just _MEMGETing the pack string from just after the item to be dropped and copying it over the now gone item.

example pack:(as: item,count   item,count   item,count   ect..)
11 21 31 41 51 61 71 81 91 A1 B1 C1 D1 E1 F1 00

dropping item 6, so copy from item 7 to end and just paste back 2 bytes

11 21 31 41 51 71 81 91 A1 B1 C1 D1 E1 F1 00 00

take it I can't just use _MEMGET in place of the variable in _MEMPUT?
Granted after becoming radioactive I only have a half-life!