Tag: template

Average template

Posted by on August 5, 2009

A tiny template for averaging numbers.
I needed this for a prototype and I didn’t want to “wing it” anymore.

I think there should be a package with similar templates that people could download to enhance the language, I’m just saying… It takes little to come up with this kind of code and in the end it’s always useful to have it around.

Macro Average_Register( _type )
	
	Structure AVERAGE#_type
		sum._type
		average._type
		count.i
	EndStructure
	
	Procedure.i Average#_type#_Create()
		Define.AVERAGE#_type *this = AllocateMemory( SizeOf( AVERAGE#_type ) )
		ProcedureReturn *this
	EndProcedure
	
	Procedure.i Average#_type#_Destroy( *this.AVERAGE#_type )
		FreeMemory( *this )
		*this = #Null
	EndProcedure
	
	Procedure._type Average#_type#_Calculate( *this.AVERAGE#_type )
		If *this\count And *this\sum
			*this\average = ( *this\sum / *this\count )
			ProcedureReturn	*this\average
		EndIf
	EndProcedure
	
	Procedure.i Average#_type#_Reset( *this.AVERAGE#_type )
		*this\sum 	= 0.0
		*this\average 	= 0.0
		*this\count 	= 0
	EndProcedure
	
	Procedure.i Average#_type#_Add( *this.AVERAGE#_type, sample.f )
		*this\sum 	+ sample
		*this\count 	+ 1
	EndProcedure
	
	Procedure.i Average#_type#_Count( *this.AVERAGE#_type )
		ProcedureReturn *this\count
	EndProcedure
	
	Procedure._type Average#_type#_Sum( *this.AVERAGE#_type )
		ProcedureReturn *this\sum
	EndProcedure
	
	Procedure._type Average#_type#_Get( *this.AVERAGE#_type )
		ProcedureReturn *this\average
	EndProcedure
	
EndMacro

You may register it as any numerical type.
Usage example:

Average_Register( f ) ; register with floats.
Define.AVERAGEf test

Averagef_Add( test, 1.0 )
Averagef_Add( test, 2.0 )
Averagef_Add( test, 3.0 )
Averagef_Add( test, 4.0 )
Averagef_Add( test, 5.0 )

Debug Averagef_Calculate( test )
Debug Averagef_Count( test )
Debug Averagef_Sum( test )

Averagef_Reset( test )

Debug Averagef_Calculate( test )
Debug Averagef_Count( test )
Debug Averagef_Sum( test )

You can allocate an instance of the structure with the Create function.
For example, if you registered the template as float, then you may create a dynamic “object” in this way:

Define.AVERAGEf *test = Averagef_Create() ; the *test variable holds an instance of the AVERAGEf structure

Likewise, you should call the Destroy() function to get rid of it.

Averagef_Destroy( *test ) 

Trivial but useful. I’m not particularly happy with the naming convention though. But, let’s not forget that this is not an attempt at emulating OOP at all; it’s just a way of giving flexibility to an encapsulated piece of code. For OOP there are proper languages and there is no point whatsoever in trying to emulate it.

Cheers

Macro Templates, by example.

Posted by on July 13, 2009

Heres an example of what I call “macro templates” in PureBasic. A template encapsulates certain functionality, allowing you to dynamically generate the code in a flexible manner.

This example implements a bare-bones n-vector library using a structure and a static array:

Macro Vector_Register( _n, _type )
	
	Structure VECTOR#_n#_type
		vector._type[_n]
	EndStructure
	
	Procedure._type Vector#_n#_type#_Add( *r.VECTOR#_n#_type, *a.VECTOR#_n#_type, *b.VECTOR#_n#_type )
		Define.i i
		For i=0 To _n - 1
			*r\vector[i] = *a\vector[i] + *b\vector[i]
		Next
	EndProcedure
	
	Procedure._type Vector#_n#_type#_Subtract( *r.VECTOR#_n#_type, *a.VECTOR#_n#_type, *b.VECTOR#_n#_type )
		Define.i i
		For i=0 To _n - 1
			*r\vector[i] = *a\vector[i] - *b\vector[i]
		Next
	EndProcedure
	
	Procedure._type Vector#_n#_type#_Divide( *r.VECTOR#_n#_type, *a.VECTOR#_n#_type, *b.VECTOR#_n#_type )
		Define.i i
		For i=0 To _n - 1
			If *b\vector[i] <> 0.0 And *a\vector[i] <> 0.0
				*r\vector[i] = *a\vector[i] / *b\vector[i]
			EndIf
		Next
	EndProcedure
	
	Procedure._type Vector#_n#_type#_Multiply( *r.VECTOR#_n#_type, *a.VECTOR#_n#_type, *b.VECTOR#_n#_type )
		Define.i i
		For i=0 To _n - 1
			*r\vector[i] = *a\vector[i] * *b\vector[i]
		Next
	EndProcedure
	
	Procedure._type Vector#_n#_type#_DotProduct( *a.VECTOR#_n#_type, *b.VECTOR#_n#_type )
		Define.i i
		Define._type result
		For i=0 To _n - 1
			result + ( *a\vector[i] * *b\vector[i] )
		Next
		ProcedureReturn result
	EndProcedure
	
	Procedure._type Vector#_n#_type#_Length( *v.VECTOR#_n#_type )
		ProcedureReturn Sqr( Vector#_n#_type#_DotProduct( *v, *v ) )
	EndProcedure
	
	Procedure._type Vector#_n#_type#_Distance( *a.VECTOR#_n#_type, *b.VECTOR#_n#_type )
		Define.VECTOR#_n#_type temp
		Vector#_n#_type#_Subtract( temp, *a, *b )
		ProcedureReturn Vector#_n#_type#_Length( temp )
	EndProcedure
	
	Procedure.s Vector#_n#_type#_Debug( *v.VECTOR#_n#_type, Decimals.i=#PB_Default )
		Define.i i
		Define.s tmp = "["
		For i=0 To _n-1
			tmp + StrF( *v\vector[i], Decimals.i )
			If i <> _n-1
				tmp + ", "
			EndIf
		Next
		tmp + "]"
		Debug tmp
		ProcedureReturn tmp
	EndProcedure
	
EndMacro

It might look strange/complicated at first, but once you read it you’ll realize it’s fairly simple.

Let’s see the usage of this particular template:

Vector_Register(3, f )	; Register a float "vec3".
Define.VECTOR3f a,b,c	; Define a few vectors with the new structure.

a\vector[0] = 10.0
a\vector[1] = 20.0
a\vector[2] = 30.0

b\vector[0] = 100.0
b\vector[1] = 200.0
b\vector[2] = 300.0

Vector3f_Add(c, a, b)	; c = a + b
Vector3f_Debug(c)	; show each element using the debug output.

Debug Vector3f_DotProduct( a, b )
Debug Vector3f_Length( a )
Debug Vector3f_Distance( a, b )

Cool, huh?. And you can define any amount of elements with any basic type.

Of course we sacrificed speed for flexibility. In those cases where we have to define n-vectors, this would be an ideal solution. For everything else, I suggest a specific library, such as my vec3 macro lib.

Using this principle you can abstract almost anything, within reason. One good example is my object factory template. ¬†Ideally one would have arrays, lists, etc. Implemented in this very same way, in such case the possibilities would be endless and you’d be able to define dynamic lists/arrays inside structures, etc.

I strongly advice you to implement at least one of those templates, even if it’s just for an exercise.

Having the extra tools can’t hurt!

Cheers.