1 /* This file is part of Shapes.
3 * Shapes is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
8 * Shapes is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright 2008 Henrik Tidefelt
21 #include "/home/rt/tidefelt/include/refcount.h"
30 /* The closest to the one level recursion needed is to start from two sets of symmetric macros.
31 * One set ends in "1", the other ends in "2".
34 /* Define the class heierarcy in macros:
36 #define CLASSTREE1_A( Ma, S, Mb ) Ma( S, Mb, A )
37 #define CLASSTREE1_B( Ma, S, Mb ) Ma( S, Mb, B ) CLASSTREE1_C( Ma, S, Mb )
38 #define CLASSTREE1_C( Ma, S, Mb ) Ma( S, Mb, C )
39 #define CLASSTREE1_ROOT( Ma, S, Mb ) \
40 CLASSTREE1_A( Ma, S, Mb )\
41 CLASSTREE1_B( Ma, S, Mb )
43 #define CLASSTREE2_A( Ma, S, Mb ) Ma( S, Mb, A )
44 #define CLASSTREE2_B( Ma, S, Mb ) Ma( S, Mb, B ) CLASSTREE2_C( Ma, S, Mb )
45 #define CLASSTREE2_C( Ma, S, Mb ) Ma( S, Mb, C )
46 #define CLASSTREE2_ROOT( Ma, S, Mb ) \
47 CLASSTREE2_A( Ma, S, Mb )\
48 CLASSTREE2_B( Ma, S, Mb )
52 /* Define convenient macros for looping.
54 #define SINGLELOOP1_( Sb, M, T ) M( T )
55 #define SINGLELOOP1( Sa, M ) Sa( SINGLELOOP1_,, M )
56 #define DOUBLELOOP1__( M, Ta, Tb ) M( Ta, Tb )
57 #define DOUBLELOOP1_( Sb, M, Ta ) Sb( DOUBLELOOP1__, M, Ta )
58 #define DOUBLELOOP1( Sa, Sb, M ) Sa( DOUBLELOOP1_, Sb, M )
60 #define SINGLELOOP2_( Sb, M, T ) M( T )
61 #define SINGLELOOP2( Sa, M ) Sa( SINGLELOOP2_,, M )
62 #define DOUBLELOOP2__( M, Ta, Tb ) M( Ta, Tb )
63 #define DOUBLELOOP2_( Sb, M, Ta ) Sb( DOUBLELOOP2__, M, Ta )
64 #define DOUBLELOOP2( Sa, Sb, M ) Sa( DOUBLELOOP2_, Sb, M )
66 /* Define a macro that only uses the first argument,
67 * resulting in a macro that calls another macro for each class.
69 #define FORALLCLASSESM( M ) SINGLELOOP1( CLASSTREE1_ROOT, M )
71 /* Define a macro that calls another macro with a given first argument,
72 * varying the second argument over all classes.
74 #define FORALLCLASSESMT( M, T ) CLASSTREE2_ROOT( DOUBLELOOP2__, M, T )
76 /* Use the two looping macros above in a nested manner to produce a default method
77 * for each pair combination of classes.
79 #define DEFAULTOP__( Ta, Tb ) virtual int op( RefCountPtr< const Ta > x1, RefCountPtr< const Tb > x2 ) const { return 0; }
80 #define DEFAULTOP_( Ta ) FORALLCLASSESMT( DEFAULTOP__, Ta )
81 #define DEFAULTOP FORALLCLASSESM( DEFAULTOP_ )
83 /* Define a macro for hiding the default method for a set of classes:
85 #define HIDEDEFAULT_( Ta, Tb ) virtual int op( Ta * v1, Tb * v2 ) const { return 0; }
86 #define HIDEDEFAULT( Sa, Sb ) DOUBLELOOP2( Sa, Sb, HIDEDEFAULT_ )
88 /* Define a macro for hiding the default method for a set of classes:
90 #define CALLIMPL_( Ta, Tb ) virtual int op( RefCountPtr< const Ta > x1, RefCountPtr< const Tb > x2 ) const { return impl( x1.getPtr( ), x1, x2.getPtr( ), x2 ); }
91 #define CALLIMPL( Sa, Sb ) DOUBLELOOP2( Sa, Sb, CALLIMPL_ )
96 int call( RefCountPtr
< const Value
> v1
, RefCountPtr
< const Value
> v2
) const;
100 #define DISPATCH1NULLDECL_ virtual int dispatch1( RefCountPtr< const Value > self, RefCountPtr< const Value > other, const BinOp * op ) const = 0;
101 #define DISPATCH2NULLDECL_( Ts, To ) virtual int dispatch2( RefCountPtr< const To > other, RefCountPtr< const Value > self, const BinOp * op ) const = 0;
103 #define DISPATCHCASE_LEVEL2( T2 )\
104 case TYPEID_ ## T2 : \
106 RefCountPtr< const T2 > arg2 = other.down_cast< const T2 >( ); \
107 if( arg2 == NullPtr< const T2 >( ) ) \
109 throw Exceptions::InternalError( "Downcast in dispatch level 2 failed, " #T2 ); \
111 return op->op( arg1, arg2 ); \
115 #define DISPATCHCASE_LEVEL1( T1 )\
116 case TYPEID_ ## T1 : \
118 RefCountPtr< const T1 > arg1 = self.down_cast< const T1 >( ); \
119 if( arg1 == NullPtr< const T1 >( ) ) \
121 throw Exceptions::InternalError( "Downcast in dispatch level 1 failed, " #T1 ); \
123 switch( other->getTypeID( ) ) \
125 SINGLELOOP2( CLASSTREE2_ROOT, DISPATCHCASE_LEVEL2 ); \
127 throw Exceptions::InternalError( "QuickTypeID out of range in dispatch level 2" ); \
132 #define DISPATCHCASEDECL static int dispatch1( RefCountPtr< const Value > self, RefCountPtr< const Value > other, const BinOp * op )
133 #define DISPATCHCASEIMPL \
134 int Value::dispatch1( RefCountPtr< const Value > self, RefCountPtr< const Value > other, const BinOp * op )\
136 switch( self->getTypeID( ) )\
138 SINGLELOOP1( CLASSTREE1_ROOT, DISPATCHCASE_LEVEL1 ); \
140 throw Exceptions::InternalError( "QuickTypeID out of range in dispatch level 1" ); \
144 #define DISPATCHNULLDECL DISPATCHCASEDECL
145 /*DISPATCH1NULLDECL_ FORALLCLASSESMT( DISPATCH2NULLDECL_, )*/
147 #define MAKE_TYPEID( T ) TYPEID_ ## T ,
149 { SINGLELOOP1( CLASSTREE1_ROOT
, MAKE_TYPEID
)
155 virtual QuickTypeID
getTypeID( ) const = 0;
162 BinOp::call( RefCountPtr
< const Value
> v1
, RefCountPtr
< const Value
> v2
) const
164 return v1
->dispatch1( v1
, v2
, this );
167 #define DISPATCH1DECL_ virtual int dispatch1( RefCountPtr< const Value > self, RefCountPtr< const Value > other, const BinOp * op ) const;
168 #define DISPATCH1IMPL_( Ts ) \
169 int Ts::dispatch1( RefCountPtr< const Value > self, RefCountPtr< const Value > other, const BinOp * op ) const \
171 RefCountPtr< const Ts > typedSelf = self.down_cast< const Ts >( ); \
172 if( typedSelf == NullPtr< const Ts >( ) ) \
174 cerr << "Downcast in dispatch1 failed" << endl ;\
176 return other->dispatch2( typedSelf, other, op );\
179 #define DISPATCH2DECL_( Ts, To ) virtual int dispatch2( RefCountPtr< const To > other, RefCountPtr< const Value > self, const BinOp * op ) const;
180 #define DISPATCH2IMPL_( Ts, To ) \
181 int Ts::dispatch2( RefCountPtr< const To > other, RefCountPtr< const Value > self, const BinOp * op ) const\
183 RefCountPtr< const Ts > typedSelf = self.down_cast< const Ts >( ); \
184 if( typedSelf == NullPtr< const Ts >( ) ) \
186 cerr << "Downcast in dispatch1 failed" << endl ;\
188 return op->op( other, typedSelf );\
191 #define GETTYPEIDDECL virtual QuickTypeID getTypeID( ) const;
193 #define DISPATCHDECL GETTYPEIDDECL
194 /* DISPATCH1DECL_ FORALLCLASSESMT( DISPATCH2DECL_, )*/
195 #define DISPATCHIMPL( Ts )
196 /* DISPATCH1IMPL_( Ts ) FORALLCLASSESMT( DISPATCH2IMPL_, Ts )*/
198 class A
: public Value
204 class B
: public Value
220 #define DUMMYANDREF( T ) T *, RefCountPtr< T >
222 class Plus
: public BinOp
225 CALLIMPL( CLASSTREE1_B
, CLASSTREE2_A
)
227 int impl( DUMMYANDREF( const B
) v1
, DUMMYANDREF( const A
) v2
) const { return 1; }
228 int impl( DUMMYANDREF( const C
) v1
, DUMMYANDREF( const A
) v2
) const { return 2; }
231 class Star
: public BinOp
234 CALLIMPL( CLASSTREE1_B
, CLASSTREE2_B
)
235 CALLIMPL( CLASSTREE1_A
, CLASSTREE2_B
)
237 int impl( DUMMYANDREF( const B
) v1
, DUMMYANDREF( const B
) v2
) const { return 1; }
238 int impl( DUMMYANDREF( const A
) v1
, DUMMYANDREF( const B
) v2
) const { return 7; }
241 #define GETTYPEID_MAKER( T ) \
243 T::getTypeID( ) const \
245 return TYPEID_ ## T; \
248 SINGLELOOP1( CLASSTREE1_ROOT
, GETTYPEID_MAKER
)
258 const char opstr
[] = "+";
259 cout
<< "A" << opstr
<< "A => " << op
.call( a
, a
) << endl
;
260 cout
<< "A" << opstr
<< "B => " << op
.call( a
, b
) << endl
;
261 cout
<< "A" << opstr
<< "C => " << op
.call( a
, c
) << endl
;
262 cout
<< "B" << opstr
<< "A => " << op
.call( b
, a
) << endl
;
263 cout
<< "B" << opstr
<< "B => " << op
.call( b
, b
) << endl
;
264 cout
<< "B" << opstr
<< "C => " << op
.call( b
, c
) << endl
;
265 cout
<< "C" << opstr
<< "A => " << op
.call( c
, a
) << endl
;
266 cout
<< "C" << opstr
<< "B => " << op
.call( c
, b
) << endl
;
267 cout
<< "C" << opstr
<< "C => " << op
.call( c
, c
) << endl
;
272 const char opstr
[] = "*";
273 cout
<< "A" << opstr
<< "A => " << op
.call( a
, a
) << endl
;
274 cout
<< "A" << opstr
<< "B => " << op
.call( a
, b
) << endl
;
275 cout
<< "A" << opstr
<< "C => " << op
.call( a
, c
) << endl
;
276 cout
<< "B" << opstr
<< "A => " << op
.call( b
, a
) << endl
;
277 cout
<< "B" << opstr
<< "B => " << op
.call( b
, b
) << endl
;
278 cout
<< "B" << opstr
<< "C => " << op
.call( b
, c
) << endl
;
279 cout
<< "C" << opstr
<< "A => " << op
.call( c
, a
) << endl
;
280 cout
<< "C" << opstr
<< "B => " << op
.call( c
, b
) << endl
;
281 cout
<< "C" << opstr
<< "C => " << op
.call( c
, c
) << endl
;