Template Classes via a macro

Share your advanced PureBasic knowledge/code with the community.
User avatar
idle
Always Here
Always Here
Posts: 5915
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Template Classes via a macro

Post by idle »

An example of using a macro to effectively make a class template
this will make a BTree of any arbitrary structured type.
PB 4.51

Thanks for the bug fixes

Code: Select all

;how you can use a macro as a class template
;creates a bTree object class of any structured type

;Template Class of a Btree
;Author Idle
;updated to PB 4.51
EnableExplicit 

Macro Template_class_Btree(T)

Structure Tree#T
   *vt
   item.T;
   key.i
   *left.Tree#T;
   *right.Tree#T;
EndStructure

Declare Free_Tree_#T(*this.Tree#T)
Declare Find_Tree_#T(*this.Tree#T,*item,key)
Declare Insert_Tree_#T(*this.Tree#T,*item,key)
     
Interface Tree_obj_#T
    Insert(*item,key)
    Find(*item,key)
    Free()
EndInterface

Procedure Find_Tree_#T(*this.Tree#T,*item,key.i)
     
    If Not *this
       ProcedureReturn #False
    EndIf
    If *this\key = key
      CopyStructure(*this\item,*item,T) 
      ProcedureReturn #True;
    ElseIf key < *this\key
       ProcedureReturn Find_Tree_#T(*this\left,*item,key);
    Else
       ProcedureReturn Find_Tree_#T(*this\right,*item,key);
    EndIf
           
EndProcedure

Procedure Insert_Tree_#T(*this.Tree#T,*item,key.i)
     
    If Not *this
      *this = AllocateMemory(SizeOf(Tree#T))
      InitializeStructure(*this,T)
      *this\key = key
      CopyStructure(*item,*this\item,T)
     
    Else
      If key <= *this\key
         *this\left = insert_Tree_#T(*this\left,*item,key)
      Else
        *this\right = insert_Tree_#T(*this\right,*item,key)
      EndIf
    EndIf
   
    ProcedureReturn(*this)
   
EndProcedure
   
Procedure Del_Nodes_Tree_#T(*this.Tree#T)
    Static dct
    If *this\left Or *this\right
      If *this\left
        del_nodes_Tree_#T(*this\left)
      EndIf
      If *this\right
        del_nodes_Tree_#T(*this\right)
      EndIf
    EndIf
    If *this\key
      ClearStructure(*this\item,T)
      FreeMemory(*this)
       dct+1
    EndIf
    ProcedureReturn dct   
EndProcedure
     
Procedure Free_Tree_#T(*this.Tree#T)
   Protected ct 
   ct = del_nodes_Tree_#T(*this)
   ClearStructure(*this,Tree#T)
   FreeMemory(*this)
   ProcedureReturn ct
EndProcedure

Procedure New_Tree_#T(*obj.Tree#T)
    *obj = AllocateMemory(SizeOf(Tree#T))
    If *obj
      *obj\vt=?vt_tree#T
    EndIf
    ProcedureReturn *obj
EndProcedure

DataSection: vt_tree#T:
   Data.i @Insert_Tree_#T()
   Data.i @Find_Tree_#T()
   Data.i @Free_Tree_#T()
EndDataSection
   
EndMacro

Structure mixed
  a.i
  str.s 
EndStructure   

;1) call the macro to create the class with your structure
Template_class_BTree(mixed)

 
;2) use the class 
Global mTree.Tree_obj_mixed = new_Tree_mixed(@mTree)
Global Dim aKeys.i(100)
Global tm.mixed
Define a, tstr.s 

For a = 1 To 100
   tstr.s = Str(Random(100)+1)
   aKeys(a) = a
   tm\a = aKeys(a)
   tm\str = tstr
   mTree\insert(@tm,aKeys(a)) ;insert item with a key
Next     
;
For a = 1 To 100
     If mTree\find(@tm,aKeys(a)) ;look up item from key array 
       Debug "item number " + Str(a) + " Found " + tm\str + " " + Str(tm\a)     
     EndIf
Next

Debug mTree\Free()

Last edited by idle on Tue Oct 05, 2010 9:26 pm, edited 4 times in total.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Template Classes via a macro

Post by Kwai chang caine »

Hello IDLE... :D

I have not all understand what is a template class :(
Don't worry it's like usually. :oops:

Perhaps there are a link with the template of PB ???

But i have an error line 110 :(

Code: Select all

Template_class_BTree(mixed)
ImageThe happiness is a road...
Not a destination
User avatar
idle
Always Here
Always Here
Posts: 5915
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Template Classes via a macro

Post by idle »

No error here with 4.51
What PB version are you using kcc?

A template allows a class to work on many different data types without being rewritten for each one.
So from the users point of view it looks and functions like a PB internal class like a List or Map
It just wasn't as easy to do before because of issues you'd encounter handling strings
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Re: Template Classes via a macro

Post by rsts »

On my system the final statement

Code: Select all

debug mTree\Free()
produces a memory error at line 110

cheers
PB 4.51 final
Window 7 x86
User avatar
idle
Always Here
Always Here
Posts: 5915
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Template Classes via a macro

Post by idle »

I'm still on RC2, maybe I was to quick then, will try it with the final.

Installed 4.51 final and still no error or warnings, i'm on XP
also tossed in an InitializeStructure in case that makes any difference edited the first post.
User avatar
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

Re: Template Classes via a macro

Post by ts-soft »

Tested with WinXP, x86: no errors

Tested with Win7, x86: error at line 111

PB 4.51 Final
User avatar
idle
Always Here
Always Here
Posts: 5915
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Template Classes via a macro

Post by idle »

what could be the problem there?
back to fixed size strings then I suppose
User avatar
idle
Always Here
Always Here
Posts: 5915
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Template Classes via a macro

Post by idle »

ok so using a fixed size string does it crash on win7 x86

Code: Select all

;how you can use a macro as a class template
;creates a bTree object class of any structured type

;Template Class of a Btree
;Author Idle
;updated to PB 4.51
Macro Template_class_Btree(T)

Structure Tree#T
   *vt
   item.T;
   key.i
   *left.Tree#T;
   *right.Tree#T;
EndStructure

Declare Free_Tree_#T(*this.Tree#T)
Declare Find_Tree_#T(*this.Tree#T,*item,key)
Declare Insert_Tree_#T(*this.Tree#T,*item,key)
     
Interface Tree_obj_#T
    Insert(*item,key)
    Find(*item,key)
    Free()
EndInterface

Procedure Find_Tree_#T(*this.Tree#T,*item,key)
     
    If Not *this
       ProcedureReturn #False
    EndIf
    If *this\key = key
      CopyStructure(*this\item,*item,T) 
      ProcedureReturn #True;
    ElseIf key < *this\key
       ProcedureReturn Find_Tree_#T(*this\left,*item,key);
    Else
       ProcedureReturn Find_Tree_#T(*this\right,*item,key);
    EndIf
           
EndProcedure

Procedure Insert_Tree_#T(*this.Tree#T,*item,key)
     
    If Not *this
      *this = AllocateMemory(SizeOf(Tree#T))
      ;InitializeStructure(*this,T)
      *this\key = key
      CopyStructure(*item,*this\item,T)
     
    Else
      If key <= *this\key
         *this\left = insert_Tree_#T(*this\left,*item,key)
      Else
        *this\right = insert_Tree_#T(*this\right,*item,key)
      EndIf
    EndIf
   
    ProcedureReturn(*this)
   
EndProcedure
   
Procedure Del_Nodes_Tree_#T(*this.Tree#T)
    Static dct
    If *this\key
      ClearStructure(*this,T)
      FreeMemory(*this)
       dct+1
    EndIf
    If *this\left Or *this\right
      If *this\left
        del_nodes_Tree_#T(*this\left)
      EndIf
      If *this\right
        del_nodes_Tree_#T(*this\right)
      EndIf
    EndIf
    ProcedureReturn dct   
EndProcedure
     
Procedure Free_Tree_#T(*this.Tree#T)
   Protected ct   
   ct = del_nodes_Tree_#T(*this)
   ClearStructure(*this,Tree#T)
   FreeMemory(*this)
   ProcedureReturn ct
EndProcedure

Procedure New_Tree_#T(*obj.Tree#T)
    *obj = AllocateMemory(SizeOf(Tree#T))
    If *obj
      *obj\vt=?vt_tree#T
    EndIf
    ProcedureReturn *obj
EndProcedure

DataSection: vt_tree#T:
   Data.i @Insert_Tree_#T()
   Data.i @Find_Tree_#T()
   Data.i @Free_Tree_#T()
EndDataSection

   
EndMacro

Structure mixed
  a.i
  str.s{256}   ;<-fixed size string should not crash 
EndStructure   

;1) call the macro to create the class with your structure
Template_class_BTree(mixed)

 
;2) use the class 
Global mTree.Tree_obj_mixed = new_Tree_mixed(@mTree)
Global Dim aKeys.i(100)
Global tm.mixed

For a = 1 To 100
   tstr.s = Str(Random(100)+1)
   aKeys(a) = a
   tm\a = aKeys(a)
   tm\str = tstr
   mTree\insert(@tm,aKeys(a)) ;insert item with a key
Next     
;
For a = 1 To 100
     If mTree\find(@tm,aKeys(a)) ;look up item from key array 
       Debug "item number " + Str(a) + " Found " + tm\str + " " + Str(tm\a)     
     EndIf
Next

Debug mTree\Free()

User avatar
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

Re: Template Classes via a macro

Post by ts-soft »

This works fine :D
User avatar
idle
Always Here
Always Here
Posts: 5915
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Template Classes via a macro

Post by idle »

yes the fixed string would.
So I wonder what could be the problem on win7, maybe it's a bug with PB
Also in the dynamic sting version
In FreeTree the var ct wasn't declared, though I don't see why that would have made a difference
I only put it there for debugging purposes.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Template Classes via a macro

Post by srod »

It crashes because you have the wrong structure in the ClearStructure() in the Del_Nodes_Tree_#T(*this.Tree#T) function.

Change :

Code: Select all

ClearStructure(*this,T)
to

Code: Select all

ClearStructure(*this,Tree#T)
**EDIT : btw, very difficult to debug when embedded within a macro like this! :) I removed the macro in order to find the line which was actually causing the problem. This is why I hate the damn things! :wink:
I may look like a mule, but I'm not a complete ass.
User avatar
idle
Always Here
Always Here
Posts: 5915
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Template Classes via a macro

Post by idle »

I'm not sure if that's right either, I'm only trying to clear the items structure which is mixed
if I change it to Tree#T the debug free is only 1 instead of 100
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Template Classes via a macro

Post by srod »

Then you need :

Code: Select all

ClearStructure(*this\item,T)
I may look like a mule, but I'm not a complete ass.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Template Classes via a macro

Post by srod »

The whole Del_Nodes_Tree_#T(*this.Tree#T) procedure looks flawed.

You are possibly freeing the *this structure before then using it again! I think you need to reorder it as follows :

Code: Select all

Procedure Del_Nodes_Tree_#T(*this.Tree#T)
    Static dct
    If *this\left Or *this\right
      If *this\left
        del_nodes_Tree_#T(*this\left)
      EndIf
      If *this\right
        del_nodes_Tree_#T(*this\right)
      EndIf
    EndIf
    If *this\key
      ClearStructure(*this\item,T)
      FreeMemory(*this)
       dct+1
    EndIf
    ProcedureReturn dct   
EndProcedure
Last edited by srod on Tue Oct 05, 2010 9:25 pm, edited 1 time in total.
I may look like a mule, but I'm not a complete ass.
User avatar
idle
Always Here
Always Here
Posts: 5915
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Template Classes via a macro

Post by idle »

Thanks
anyone would think I had milk bottles for glasses. :lol:

yes maybe your right there too about the recursion
Post Reply