12-19-2005, 12:23 PM
Here is a question I've been pondering while I work on a project of mine, something of a generic library akin to C++'s STL: How many people would use a generic MACRO library? While implementing it is rather tedious without the support of classes, it's not impossible, and not too far from being quite practical.
Currently, I have implemented a vector and stack containers, and I've started working on generic binary comparison functions. I'll present some code at the end of the post.
Now, mind you, I have not yet implemented custom allocators (seems silly to do so without classes), nor iterators (so I have yet to begin any generic algorithm functions dealing with iterators such as find() or copy()), so use of these containers is pretty raw. My goal is to implement vector and stack iterators sometime before Christmas. That will at least give me an opportunity to start coding the generic algorithms.
As a demonstration as to how something like this would look, here is code for some generic comparison functions:
As you can see, these function MACROs compare two values of like types, and are instantiated (expanded) for integral and string types by default. The file macros.bi contains the space-saving MACRO INST_MACRO_FOR_INTTYPES(...), and is defined below:
Moving on, another part of the library that makes use of the above comparison functions is the always useful max(...) and min(...) generic functions. For space reasons, I'll just post the max(...) definition, min(...) being similar:
This function MACRO uses the generic comparison function less_than(...) to determine the maximum of two values. It is also specialized for references as well. To use this function with a type of your own, your type must be less than comparable, that is, you must overload the global less_than(...) function for your type. As an example, I have done just that with a simple Rational number type:
This code simply defines a custom type, makes it less than and greater than comparable by overloading the less_than(...) and greater_than(...) functions, and finally instantiates Rational versions of the max(...) and min(...) function MACROs. This would be what end-user code might look like.
You'll note that I haven't taken into account floating-point types, or zstrings for the generic comparison functions - yet. That is also planned this week, as well as a gigantic Christmas dinner I will be having when I go home this weekend.
If you care to share, I've filled out a poll - I don't know if it will work or not - and I'd like to get some feedback on this idea. Thanks for your time.
Currently, I have implemented a vector and stack containers, and I've started working on generic binary comparison functions. I'll present some code at the end of the post.
Now, mind you, I have not yet implemented custom allocators (seems silly to do so without classes), nor iterators (so I have yet to begin any generic algorithm functions dealing with iterators such as find() or copy()), so use of these containers is pretty raw. My goal is to implement vector and stack iterators sometime before Christmas. That will at least give me an opportunity to start coding the generic algorithms.
As a demonstration as to how something like this would look, here is code for some generic comparison functions:
Code:
'' -----------------------------------------------------------------------------
'' - sml/comparison.bi -
'' -----------------------------------------------------------------------------
'' contains binary function MACROs for global comparisons
#ifndef COMPARISON_BI
#define COMPARISON_BI
option explicit
option byval
#include "utility/macros.bi" '' for INST_MACRO_FOR_INTTYPES(...)
enum boolean : false = 0 : true = not false : end enum
declare function not_equal overload () as boolean
declare function less_than overload () as boolean
declare function less_than_or_equal overload () as boolean
declare function equal overload () as boolean
declare function greater_than overload () as boolean
declare function greater_than_or_equal overload () as boolean
'' not_equal( lhs as T, rhs as T ) as boolean
'' -----------------------------------------------------------------------------
'' returns true if lhs is not equal to rhs
#define INST_NOT_EQUAL( T ) _
function not_equal( lhs as T, rhs as T ) as boolean :_
return lhs <> rhs :_
end function
'' less_than( lhs as T, rhs as T ) as boolean
'' -----------------------------------------------------------------------------
'' returns true if lhs is less than rhs
#define INST_LESS_THAN( T ) _
function less_than( lhs as T, rhs as T ) as boolean :_
return lhs < rhs :_
end function
'' less_than_or_equal( lhs as T, rhs as T ) as boolean
'' -----------------------------------------------------------------------------
'' returns true if lhs is less than or equal to rhs
#define INST_LESS_THAN_OR_EQUAL( T ) _
function less_than_or_equal( lhs as T, rhs as T ) as boolean :_
return lhs <= rhs :_
end function
'' equal( lhs as T, rhs as T ) as boolean
'' -----------------------------------------------------------------------------
'' returns true if lhs is equal to rhs
#define INST_EQUAL( T ) _
function equal( lhs as T, rhs as T ) as boolean :_
return lhs = rhs :_
end function
'' greater_than( lhs as T, rhs as T ) as boolean
'' -----------------------------------------------------------------------------
'' returns true if lhs is greater than rhs
#define INST_GREATER_THAN( T ) _
function greater_than( lhs as T, rhs as T ) as boolean :_
return lhs > rhs :_
end function
'' greater_than_or_equal( lhs as T, rhs as T ) as boolean
'' -----------------------------------------------------------------------------
'' returns true if lhs is greater than or equal to rhs
#define INST_GREATER_THAN_OR_EQUAL( T ) _
function greater_than_or_equal( lhs as T, rhs as T ) as boolean :_
return lhs >= rhs :_
end function
'' - instantiate comparison function MACROs for integral and string types ------
INST_MACRO_FOR_INTTYPES( NOT_EQUAL ) : INST_NOT_EQUAL( string )
INST_MACRO_FOR_INTTYPES( LESS_THAN ) : INST_LESS_THAN( string )
INST_MACRO_FOR_INTTYPES( LESS_THAN_OR_EQUAL ) : INST_LESS_THAN_OR_EQUAL( string )
INST_MACRO_FOR_INTTYPES( EQUAL ) : INST_EQUAL( string )
INST_MACRO_FOR_INTTYPES( GREATER_THAN ) : INST_GREATER_THAN( string )
INST_MACRO_FOR_INTTYPES( GREATER_THAN_OR_EQUAL ) : INST_GREATER_THAN_OR_EQUAL( string )
#endif '' COMPARISON_BI
Code:
'' -----------------------------------------------------------------------------
'' - sml/utility/macros.bi -
'' -----------------------------------------------------------------------------
'' - defines useful macros for instantiating function MACROs
'' -
'' - function MACRO declaration conventions:
'' - unary function MACROs =
:_ - #define INST_UFM_templatename( type ) _
:_ - function templatename overload ( ... ) ...
'' - binary function MACROs =
:_ - #define INST_BFM_templatename( type1, type2 ) _
:_ - function templatename overload ( ... ) ...
#ifndef MACROS_BI
#define MACROS_BI
'' MACRO for instantiating unary MACROs for all integral types
#define INST_MACRO_FOR_INTTYPES( macro ) _
INST_##macro##( byte ) :_
INST_##macro##( ubyte ) :_
INST_##macro##( short ) :_
INST_##macro##( ushort ) :_
INST_##macro##( integer ) :_
INST_##macro##( uinteger ) :_
INST_##macro##( longint ) :_
INST_##macro##( ulongint )
'' MACRO for instantiating unary MACROs for floating-point types
#define INST_MACRO_FOR_FLOATTYPES( macro ) _
INST_##macro##( single ) :_
INST_##macro##( double ) :_
'' MACRO for instantiating unary MACROs for all standard types
#define INST_MACRO_FOR_STDTYPES( macro ) _
INST_##macro##( byte ) :_
INST_##macro##( ubyte ) :_
INST_##macro##( short ) :_
INST_##macro##( ushort ) :_
INST_##macro##( integer ) :_
INST_##macro##( uinteger ) :_
INST_##macro##( longint ) :_
INST_##macro##( ulongint ) :_
INST_##macro##( single ) :_
INST_##macro##( double ) :_
INST_##macro##( string ) :_
INST_##macro##( zstring ptr )
#endif '' MACROS_BI
Moving on, another part of the library that makes use of the above comparison functions is the always useful max(...) and min(...) generic functions. For space reasons, I'll just post the max(...) definition, min(...) being similar:
Code:
'' -----------------------------------------------------------------------------
'' - sml/utility/max.bi -
'' -----------------------------------------------------------------------------
'' defines a function MACRO that returns the greater of two objects
#ifndef MAX_BI
#define MAX_BI
option explicit
option byval
#include "../comparison.bi" '' for less_than(...)
#include "macros.bi" '' for INST_MACRO_FOR_INTTYPES(...)
declare function max overload()
'' - max( T,T ) as T -----------------------------------------------------------
'' returns the greater of two objects. objects must be less_than comparable
#define INST_MAX( T ) _
:_ '' returns the value of the greater of two objects
function max( a as T, b as T ) as T :_
if( less_than( a,b ) ) then return b : end if :_
return a :_
end function :_
:_
:_ '' returns a reference to the greater of two objects
function max( a as T ptr, b as T ptr ) as T ptr :_
if( less_than( *a,*b ) ) then return b : end if :_
return a :_
end function
INST_MACRO_FOR_INTTYPES( MAX )
#endif '' MAX_BI
Code:
'' -----------------------------------------------------------------------------
'' - sml/smlTest.bas -
'' -----------------------------------------------------------------------------
'' demonstrates two generic comparison functions, and how to use max(...) and
'' min(...) with UDTs
#include "comparison.bi"
#include "utility/max.bi"
#include "utility/min.bi"
option explicit
option byval
'' define a Rational number type
type Rational
numerator as integer
denominator as integer
end type
'' overload less_than(...) function for Rational types [used by max(...)]
function less_than( lhs as Rational, rhs as Rational ) as boolean
return ( lhs.numerator/lhs.denominator ) < ( rhs.numerator/rhs.denominator )
end function
'' overload greater_than(...) function for Rational types [used by min(...)]
function greater_than( lhs as Rational, rhs as Rational ) as boolean
return ( lhs.numerator/lhs.denominator ) > ( rhs.numerator/rhs.denominator )
end function
'' instantiate max(...) and min(...) function MACROs for Rational types
INST_MAX( Rational )
INST_MIN( Rational )
dim as Rational r1 => ( 1,2 )
dim as Rational r2 => ( 1,3 )
assert( less_than( r2, max( r1,r2 ) ) ) '' test max(...)
assert( less_than( r2, *max( @r1,@r2 ) ) )
assert( greater_than( r1, min( r1,r2 ) ) ) '' test min(...)
assert( greater_than( r1, *min( @r1,@r2 ) ) )
sleep : end 0
You'll note that I haven't taken into account floating-point types, or zstrings for the generic comparison functions - yet. That is also planned this week, as well as a gigantic Christmas dinner I will be having when I go home this weekend.
If you care to share, I've filled out a poll - I don't know if it will work or not - and I'd like to get some feedback on this idea. Thanks for your time.
stylin: