Page 2 of 2

Re: Using adresses as a key for AddMapElements ???

Posted: Thu Dec 19, 2019 5:59 pm
by wilbert
Joris wrote:it can vary by user use of the program, but I suppose it will mostly be less then 100, but yeah, that's my guess...
With that little items, you could probably also do with a simple structured array with key / value fields.
But I'll probably trie to create a simple numeric map myself.

Re: Using adresses as a key for AddMapElements ???

Posted: Thu Dec 19, 2019 6:32 pm
by C87
There are several statements in this Topic that these functions aren't referenced in the HELP file. Can I ask a what may be a stupid question? :
If they aren't in the HELP file, how on earth does anyone know they exist? :?

( an earlier Topic NumericMap by idle made reference to these functions and I just gave up in the end :oops: )

Re: Using adresses as a key for AddMapElements ???

Posted: Thu Dec 19, 2019 6:44 pm
by Tenaja
C87 wrote:If they aren't in the HELP file, how on earth does anyone know they exist? :?
Look at the asm code that is generated when you use Maps. (There are quite a few forum threads on this topic.)

This actually brings up the point that if someone were to rely on the code suggested that the PB version should be listed, as well as assumptions (such as the Map library has not been updated...).

Re: Using adresses as a key for AddMapElements ???

Posted: Thu Dec 19, 2019 9:06 pm
by idle
Tenaja wrote:
C87 wrote:If they aren't in the HELP file, how on earth does anyone know they exist? :?
Look at the asm code that is generated when you use Maps. (There are quite a few forum threads on this topic.)

This actually brings up the point that if someone were to rely on the code suggested that the PB version should be listed, as well as assumptions (such as the Map library has not been updated...).
you can find the headers in the sdk /PureBasic/sdk/c/PureLibraries/

These headers can change with a new version of PB so yes any code using them could break with a new release of PB, so version checking would be the sane thing to do.

Re: Using adresses as a key for AddMapElements ???

Posted: Tue Jan 14, 2020 7:08 pm
by chi
idle wrote:
chi wrote:This is fantastic! Thank you, idle 8)

Now I can finally get rid of converting the hWnd to a string first...
try this, think I've got it sorted so you can use native types but might not work on osx

Code: Select all

;NumericMap hack for structured Numeric keyed Maps 
;windows linux osx 

Import ""
  PB_NewNumericMap(ElementSize.i,*StructureMap,*Address,HashTabelSize.l);
  PB_FreeMap(*Map)                                                      ;
  PB_ResetMap(*Map)                                                     ;
  PB_ClearMap(*Map)                                                     ;
  PB_MapSize(*Map)                                                      ;
  PB_PushMapPosition(*map)                                              ;
  PB_PopMapPosition(*map)                                               ;
  PB_NextMapElement(*Map)                                               ;
  PB_FindNumericMapElement(*Map,Key.i)                                  ;
  PB_AddNumericMapElement(*Map,Key.i)                                   ;
  PB_AddNumericMapElement2(*Map,Key.i,ElementCheck=#PB_Map_ElementCheck);
  PB_DeleteNumericMapElement2(*Map,Key.i)                               ;
  PB_DeleteNumericMapElement(*Map)                                      ;
  PB_CopyMap(*Map,*DestinationMap)                                      ;
  PB_CopyMap2(*Map,*DestinationMap,Clear.l)                             ;
EndImport

Macro NewNumericMap(pmap,HashTableSize,StructureType,IsStructure=0) 
  Global structadr=0
  EnableASM
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    CompilerIf IsStructure 
      lea rax,[s_#StructureType]
      mov [v_structadr],rax
    CompilerEndIf 
  CompilerElse
    CompilerIf IsStructure  
      lea eax,[s_#StructureType]
      mov [v_structadr],eax
    CompilerEndIf 
  CompilerEndIf
  DisableASM
  PB_NewNumericMap(SizeOf(StructureType),structadr,@pmap,HashTableSize)
EndMacro   

Procedure NumericMapkey(*Map) 
  Protected ele,key   
  ele = PeekI(*map)
  key = PeekI(ele+SizeOf(Integer)) 
  ProcedureReturn key 
EndProcedure   

CompilerIf #PB_Compiler_IsMainFile 
  
  ;Note you need to use a structured element pointer even for native types 
  
  Structure foo
    List controls.i()
    i.i 
    s.s 
  EndStructure   
  
  
  Procedure test() 
    Protected mp, *el.foo 
    NewNumericMap(mp,512,foo,#PB_Structure) ;create the map and pass map variable, number of elements, the name of the structure  
    
    *el = PB_AddNumericMapElement(mp,123)   
    
    AddElement(*el\controls())
    *el\controls() = 111
    AddElement(*el\controls())
    *el\controls() = 112
    *el\i = 123
    *el\s = "Hello" 
    ;
    *el = PB_AddNumericMapElement2(mp,345)
    AddElement(*el\controls())
    *el\controls() = 113
    AddElement(*el\controls())
    *el\controls() = 114
    
    *el\i = 345
    *el\s = "World"
    ;
    *el = PB_FindNumericMapElement(mp,123)
    ForEach *el\controls() 
      Debug "list Controls " + *el\controls() 
    Next   
    Debug "integer " + *el\i
    Debug "string "  + *el\s 
    
    *el = PB_FindNumericMapElement(mp,345)
    ForEach *el\controls() 
      Debug "list Controls " + *el\controls() 
    Next   
    Debug "integer " + *el\i
    Debug "string "  + *el\s 
    
    Debug "+++++++++++"
    Debug "walk the map"
    Debug "+++++++++++"
    
    PB_ResetMap(mp) 
    Repeat 
      *el = PB_NextMapElement(mp) 
      If *el  
        Debug "mapkey " + NumericMapkey(mp) 
        ForEach *el\controls() 
          Debug "list Controls " + *el\controls() 
        Next   
        Debug "integer " + *el\i
        Debug "string "  + *el\s 
      EndIf   
    Until *el=0   
    
    Debug "++++++++++++++"
    Debug "clear map" 
    PB_ClearMap(mp);
    PB_ResetMap(mp) 
    Repeat 
      *el = PB_NextMapElement(mp) 
      If *el  
        Debug "mapkey " + NumericMapkey(mp) 
        ForEach *el\controls() 
          Debug "list Controls " + *el\controls() 
        Next   
        Debug "integer " + *el\i
        Debug "string "  + *el\s 
      EndIf   
    Until *el=0   
    Debug "should be nothing" 
    
    PB_FreeMap(mp)
    
    Debug "++++++++++++"
    Debug "test with a native type via pointer"  
    Protected *elf.float   
    NewNumericMap(mp,512,float) ;create the map and pass map variable, number of elements, the name of the structure 
    *elf = PB_AddNumericMapElement(mp,123)
    *elf\f = #PI 
    *elf = PB_AddNumericMapElement(mp,345)
    *elf\f = 2*#PI 
    *elf = PB_FindNumericMapElement(mp,123)
    Debug *elf\f 
    
    *elf = PB_FindNumericMapElement(mp,345)
    If *elf 
      Debug *elf\f 
    EndIf 
    
    Debug NumericMapkey(mp)
    
    PB_FreeMap(mp) 
    
  EndProcedure 
  
  test() 
  
CompilerEndIf 
[/size]
@idle: Unfortunately your code only works with the Debugger enabled. With a disabled Debugger or trying to create an executable, I get a bunch of POLINK errors :(

Edit: Btw, it works if you call "NewMap dummy.foo()" somewhere and remove all "PB_FreeMap(mp) " calls...

Re: Using adresses as a key for AddMapElements ???

Posted: Wed Jan 15, 2020 12:31 am
by idle
hmmm never thought to try it without the debugger, still need to create dummy map and the PB_FreeNumericMap macro will need some fix up for x86 linux and osx.

Code: Select all

;NumericMap hack for structured Numeric keyed Maps
;windows linux osx
NewMap dummy() 
FreeMap(dummy())

Import ""
  PB_InitMap()
  PB_NewNumericMap(ElementSize.i,*StructureMap,*Address,HashTabelSize.l);
  PB_FreeMap(*Map)                                                      ;
  PB_ResetMap(*Map)                                                     ;
  PB_ClearMap(*Map)                                                     ;
  PB_MapSize(*Map)                                                      ;
  PB_PushMapPosition(*map)                                              ;
  PB_PopMapPosition(*map)                                               ;
  PB_NextMapElement(*Map)                                               ;
  PB_FindNumericMapElement(*Map,Key.i)                                  ;
  PB_AddNumericMapElement(*Map,Key.i)                                   ;
  PB_AddNumericMapElement2(*Map,Key.i,ElementCheck=#PB_Map_ElementCheck);
  PB_DeleteNumericMapElement2(*Map,Key.i)                               ;
  PB_DeleteNumericMapElement(*Map)                                      ;
  PB_CopyMap(*Map,*DestinationMap)                                      ;
  PB_CopyMap2(*Map,*DestinationMap,Clear.l)                             ;
EndImport


Macro PB_FreeNumericMap(pmap) 
  EnableASM 
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    PUSH pmap 
    POP rdi 
    CALL PB_FreeMap
  CompilerElse 
    PUSH   pmap
    CALL  _PB_FreeMap@4   ;might need changing for x86 linux osx
  CompilerEndIf 
  
  DisableASM 
EndMacro  

Macro NewNumericMap(pmap,HashTableSize,StructureType,IsStructure=0)
  Global structadr=0 
  
  EnableASM
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    CompilerIf IsStructure
      lea rax,[s_#StructureType]
      mov [v_structadr],rax
    CompilerEndIf
  CompilerElse
    CompilerIf IsStructure 
      lea eax,[s_#StructureType]
      mov [v_structadr],eax
    CompilerEndIf
  CompilerEndIf
  DisableASM
  
  PB_NewNumericMap(SizeOf(StructureType),structadr,@pmap,HashTableSize)
  
EndMacro   

Procedure NumericMapkey(*Map)
  Protected ele,key   
  ele = PeekI(*map)
  key = PeekI(ele+SizeOf(Integer))
  ProcedureReturn key
EndProcedure   

CompilerIf #PB_Compiler_IsMainFile
 
  ;Note you need to use a structured element pointer even for native types
  OpenConsole()   
  
  ;PB_InitMap()
  
  Structure foo
    List controls.i()
    i.i
    s.s
  EndStructure   
 
 
  Procedure test()
    Protected mp, *el.foo
    NewNumericMap(mp,512,foo,#PB_Structure) ;create the map and pass map variable, number of elements, the name of the structure 
   
    *el = PB_AddNumericMapElement(mp,123)   
   
    AddElement(*el\controls())
    *el\controls() = 111
    AddElement(*el\controls())
    *el\controls() = 112
    *el\i = 123
    *el\s = "Hello"
    ;
    *el = PB_AddNumericMapElement2(mp,345)
    AddElement(*el\controls())
    *el\controls() = 113
    AddElement(*el\controls())
    *el\controls() = 114
   
    *el\i = 345
    *el\s = "World"
    ;
    *el = PB_FindNumericMapElement(mp,123)
    ForEach *el\controls()
      PrintN( "list Controls " + *el\controls())
    Next   
    PrintN( "integer " + *el\i)
    PrintN( "string "  + *el\s)
   
    *el = PB_FindNumericMapElement(mp,345)
    ForEach *el\controls()
      PrintN( "list Controls " + *el\controls())
    Next   
    PrintN( "integer " + *el\i)
    PrintN( "string "  + *el\s)
   
    PrintN( "+++++++++++")
    PrintN( "walk the map")
    PrintN( "+++++++++++")
   
    PB_ResetMap(mp)
    Repeat
      *el = PB_NextMapElement(mp)
      If *el 
        PrintN( "mapkey " + NumericMapkey(mp))
        ForEach *el\controls()
          PrintN( "list Controls " + *el\controls())
        Next   
        PrintN( "integer " + *el\i)
        PrintN( "string "  + *el\s)
      EndIf   
    Until *el=0   
   
    PrintN( "++++++++++++++")
    PrintN( "clear map")
    PB_ClearMap(mp);
    PB_ResetMap(mp)
    Repeat
      *el = PB_NextMapElement(mp)
      If *el 
        PrintN( "mapkey " + NumericMapkey(mp))
        ForEach *el\controls()
          PrintN( "list Controls " + *el\controls())
        Next   
        PrintN( "integer " + *el\i)
        PrintN( "string "  + *el\s)
      EndIf   
    Until *el=0   
    PrintN( "should be nothing")
   
    PB_FreeNumericMap(mp)
   
    PrintN( "++++++++++++")
    PrintN( "test with a native type via pointer") 
    Protected *elf.float   
    NewNumericMap(mp,512,float) ;create the map and pass map variable, number of elements, the name of the structure
    *elf = PB_AddNumericMapElement(mp,123)
    *elf\f = #PI
    *elf = PB_AddNumericMapElement(mp,345)
    *elf\f = 2*#PI
    *elf = PB_FindNumericMapElement(mp,123)
    PrintN(StrF(*elf\f))
   
    *elf = PB_FindNumericMapElement(mp,345)
    If *elf
      PrintN(StrF(*elf\f))
    EndIf
   
    PrintN(Str(NumericMapkey(mp))) 
   
    PB_FreeNumericMap(mp)
   
  EndProcedure
 
  test()
  Input() 
  
CompilerEndIf

Re: Using adresses as a key for AddMapElements ???

Posted: Thu Jan 16, 2020 12:17 pm
by chi
idle wrote:hmmm never thought to try it without the debugger...
Neither did I :)
idle wrote:...and the PB_FreeNumericMap macro will need some fix up for x86 linux and osx
Now I get an IMA on PB_FreeNumericMap (Win7 x64, PB5.71 x64) with the debugger enabled

But don't waste your precious time on this! Who knows in what state Fred left NumericMaps and since he never bothered to answer what's wrong with it and why he didn't finish the implementation, one can only say: "Don't use 'em". I personally switched to wilbert's NKMaps, which are even slightly faster in my tests...

Re: Using adresses as a key for AddMapElements ???

Posted: Thu Jan 16, 2020 9:14 pm
by idle
chi wrote:
idle wrote:hmmm never thought to try it without the debugger...
Neither did I :)
idle wrote:...and the PB_FreeNumericMap macro will need some fix up for x86 linux and osx
Now I get an IMA on PB_FreeNumericMap (Win7 x64, PB5.71 x64) with the debugger enabled

But don't waste your precious time on this! Who knows in what state Fred left NumericMaps and since he never bothered to answer what's wrong with it and why he didn't finish the implementation, one can only say: "Don't use 'em". I personally switched to wilbert's NKMaps, which are even slightly faster in my tests...
That's the problem with dirty hacks they often fall over. Wilberts NKMap should be fine :)