Share your advanced PureBasic knowledge/code with the community.
mk-soft
Always Here
Posts: 6250 Joined: Fri May 12, 2006 6:51 pm
Location: Germany
Post
by mk-soft » Sun Sep 03, 2017 12:38 am
I have too much time
Code: Select all
;-TOP
; -----------------------------------------------------------------------------
CompilerIf #PB_Compiler_Version > 561
CompilerError "Warning: Check ASM-Compiler for valid RBP-Register!"
CompilerEndIf
Macro GetCaller(self) ; Get frame pointer from caller
CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
EnableASM
mov self, ebp
DisableASM
CompilerElse
EnableASM
mov self, rbp
DisableASM
CompilerEndIf
EndMacro
; -----------------------------------------------------------------------------
Prototype protoAdd(Value.i)
Prototype protoSub(Value.i)
Prototype protoResult()
Structure sObject
Add.protoAdd
Sub.protoSub
Result.protoResult
Value.i
EndStructure
Procedure Add(Value.i)
Protected *self.sObject
GetCaller(*self)
;Debug *self
*self\Value + Value
EndProcedure
Procedure Sub(Value.i)
Protected *self.sObject
GetCaller(*self)
;Debug *self
*self\Value - Value
EndProcedure
Procedure Result()
Protected *self.sObject
GetCaller(*self)
;Debug *self
ProcedureReturn *self\Value
EndProcedure
Procedure Init(*self.sObject)
; set procedure address
*self\Add = @Add()
*self\Sub = @Sub()
*self\Result = @Result()
; set default values
*self\Value = 0
EndProcedure
; -----------------------------------------------------------------------------
;-Test
Define a1.sObject
Debug "Init Object"
Init(a1)
;Debug @a1
Debug "Add and Sub"
a1\Add(100)
a1\Sub(20)
Debug "Result = " + a1\Result()
;-Test 2
Debug "Array of object"
Dim args.sObject(1000)
For i = 1 To 1000
Init(args(i))
Next
For i = 1 To 1000
args(i)\Add(Random(100))
;args(i)\Add(1); Random(100))
Next
For i = 1 To 1000
r1 + args(i)\Result()
Next
Debug "Result = " + r1
Last edited by
mk-soft on Sun Sep 03, 2017 11:48 am, edited 1 time in total.
uweb
User
Posts: 98 Joined: Wed Mar 15, 2006 9:40 am
Location: Germany
Post
by uweb » Sun Sep 03, 2017 9:52 am
It is weekend.
So you are not alone.
Code: Select all
;-TOP
; -----------------------------------------------------------------------------
Macro GetCaller(self) ; Get frame pointer from caller
CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
EnableASM
mov self, ebp
DisableASM
CompilerElse
EnableASM
mov self, rbp
DisableASM
CompilerEndIf
EndMacro
; -----------------------------------------------------------------------------
; Simpler Procedures:
Procedure Add(ObjectValue.i, OperationValue.i) : ProcedureReturn ObjectValue + OperationValue : EndProcedure : Add = @Add()
Procedure Sub(ObjectValue.i, OperationValue.i) : ProcedureReturn ObjectValue - OperationValue : EndProcedure : Sub = @Sub()
Procedure Result(ObjectValue.i, OperationValue.i) : ProcedureReturn ObjectValue : EndProcedure : Result = @Result()
; For additional operators there is no need to change anything elsewhere. - e.g:
Procedure Mult(ObjectValue.i, OperationValue.i) : ProcedureReturn ObjectValue * OperationValue : EndProcedure : Mult = @Mult()
; -----------------------------------------------------------------------------
Prototype protoExecute(*Operation, OperationValue.i=0)
; Needs a little less memory:
Structure sObject
Execute.protoExecute
Value.i
EndStructure
Procedure Execute(*Operation, OperationValue.i=0)
Protected *self.sObject
GetCaller(*self)
;Debug *self
*self\Value = CallFunctionFast(*Operation, *self\Value, OperationValue.i)
ProcedureReturn *self\Value
EndProcedure
Procedure Init(*self.sObject)
; set procedure address
*self\Execute = @Execute()
; set default values
*self\Value = 0
EndProcedure
; -----------------------------------------------------------------------------
;-Test
Define a1.sObject
Debug "Init Object"
Init(a1)
;Debug @a1
Debug "Add and Sub"
a1\Execute(Add, 100)
a1\Execute(Sub, 20)
Debug "Result = " + a1\Execute(Result)
a1\Execute(Mult, 42)
Debug "Result * 42 = " + a1\Execute(Result)
;-Test 2
Debug "Array of object"
Dim args.sObject(1000)
For i = 1 To 1000
Init(args(i))
Next
For i = 1 To 1000
args(i)\Execute(Add, Random(100))
;args(i)\Execute(Add, 1); Random(100))
Next
For i = 1 To 1000
r1 + args(i)\Execute(Result)
Next
Debug "Result = " + r1
Last edited by
uweb on Sun Sep 03, 2017 10:57 am, edited 1 time in total.
Please pardon my English, my native tongue is German.
mk-soft
Always Here
Posts: 6250 Joined: Fri May 12, 2006 6:51 pm
Location: Germany
Post
by mk-soft » Sun Sep 03, 2017 10:55 am
Information
I have once again occupied with ASM and the call convention.
Because 'Fred' is our great purebasic developer, he keeps himself as a professional programmer, to the call convention and uses the rbp-register as a pointer to the current record (frame pointer).
This allows the pointer to access the current structure (record) from the caller.
Of course, this only works so long if the compiler does not use any other method. For example, a processor-independent compiler (LLVM compiler)
P.S. Added CompilerError (Warning) for future Version of PB-Compiler
Last edited by
mk-soft on Sun Sep 03, 2017 9:03 pm, edited 2 times in total.
uweb
User
Posts: 98 Joined: Wed Mar 15, 2006 9:40 am
Location: Germany
Post
by uweb » Sun Sep 03, 2017 11:20 am
Yes, it is a greate trick.
I forgot to say : Thank you!
Please pardon my English, my native tongue is German.
mk-soft
Always Here
Posts: 6250 Joined: Fri May 12, 2006 6:51 pm
Location: Germany
Post
by mk-soft » Sun Sep 03, 2017 12:41 pm
Thanks
New example
Code: Select all
;-TOP
; -----------------------------------------------------------------------------
CompilerIf #PB_Compiler_Version > 561
CompilerError "Warning: Check ASM-Compiler for valid RBP-Register!"
CompilerEndIf
Macro GetCaller(self) ; Get frame pointer from caller
CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
EnableASM
mov self, ebp
DisableASM
CompilerElse
EnableASM
mov self, rbp
DisableASM
CompilerEndIf
EndMacro
; -----------------------------------------------------------------------------
Prototype protoInvoke()
Structure sBox
width.i
height.i
depth.i
volume.protoInvoke
sureface.protoInvoke
EndStructure
Procedure Volume()
Protected *self.sBox, result.i
GetCaller(*self)
With *self
result = \width * \height * \depth
EndWith
ProcedureReturn result
EndProcedure
Procedure Sureface()
Protected *self.sBox, result.i
GetCaller(*self)
With *self
result = \width * \height * 2 + \width * \depth * 2 + \height * \depth * 2
EndWith
ProcedureReturn result
EndProcedure
Procedure New()
Protected *self.sbox
*self = AllocateStructure(sBox)
If *self
*self\volume = @Volume()
*self\sureface = @Sureface()
EndIf
ProcedureReturn *self
EndProcedure
*box1.sbox = New()
*box1\width = 20
*box1\height = 40
*box1\depth = 100
Debug "Volume = " + *box1\volume()
Debug "Sureface = " + *box1\sureface()
wilbert
PureBasic Expert
Posts: 3942 Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands
Post
by wilbert » Sun Sep 03, 2017 4:37 pm
Nice example
Here a modified version of you example with a clone() procedure and corrected spelling for surface.
Code: Select all
;-TOP
; -----------------------------------------------------------------------------
CompilerIf #PB_Compiler_Version > 561
CompilerError "Warning: Check ASM-Compiler for valid RBP-Register!"
CompilerEndIf
Macro GetCaller(self) ; Get frame pointer from caller
CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
!mov [p.p_self], ebp
CompilerElse
!mov [p.p_self], rbp
CompilerEndIf
EndMacro
; -----------------------------------------------------------------------------
Prototype protoInvoke()
Structure sBox
width.i
height.i
depth.i
volume.protoInvoke
surface.protoInvoke
clone.protoInvoke
EndStructure
Procedure Volume()
Protected *self.sBox, result.i
GetCaller(*self)
With *self
result = \width * \height * \depth
EndWith
ProcedureReturn result
EndProcedure
Procedure Surface()
Protected *self.sBox, result.i
GetCaller(*self)
With *self
result = \width * \height * 2 + \width * \depth * 2 + \height * \depth * 2
EndWith
ProcedureReturn result
EndProcedure
Procedure Clone()
Protected *self.sBox, *clone.sBox
GetCaller(*self)
*clone = AllocateStructure(sBox)
If *clone
CopyStructure(*self, *clone, sBox)
EndIf
ProcedureReturn *clone
EndProcedure
Procedure New()
Protected *self.sBox
*self = AllocateStructure(sBox)
If *self
*self\volume = @Volume()
*self\surface = @Surface()
*self\clone = @Clone()
EndIf
ProcedureReturn *self
EndProcedure
*box1.sBox = New()
*box1\width = 20
*box1\height = 40
*box1\depth = 100
Debug "Volume = " + *box1\volume()
Debug "Surface = " + *box1\surface()
*box2.sBox = *box1\clone()
*box2\depth = 30
Debug "Volume = " + *box2\volume()
Debug "Surface = " + *box2\surface()
Windows (x64)
Raspberry Pi OS (Arm64)
Lunasole
Addict
Posts: 1091 Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:
Post
by Lunasole » Sun Sep 03, 2017 5:23 pm
Interesting that macro, but looks like I've lost interest to "true POO" after sitting long enough mostly with PB and C ^^
Now it looks simpler and clearer to use things like this
Code: Select all
EnableExplicit
; some pseudocode using map for simplicity
Structure WHATEVER
Data1$
EndStructure
Global NewMap Objects.WHATEVER()
Procedure$ SetData(obj$, value$)
Objects(obj$)\Data1$ = value$
EndProcedure
Procedure$ GetData (obj$)
ProcedureReturn Objects(obj$)\Data1$
EndProcedure
Procedure Destroy(obj$)
DeleteMapElement(Objects(), obj$)
EndProcedure
;;;;;;;;;;;;;;;;;;;;;;;
SetData("objectid1", "123")
SetData("objectid2", "456")
Debug GetData("objectid1") + GetData("objectid2")
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
skywalk
Addict
Posts: 4219 Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA
Post
by skywalk » Sun Sep 03, 2017 8:16 pm
Cool code mk-soft. Very similar to
OOP without interfaces .
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum