// // Copyright (c) 2002 by Stephen C. Dewhurst // Permission to use, copy, modify, distribute and sell this software for any purpose is // hereby granted without fee, provided that the above copyright notice appears in all copies // and that both that copyright notice and this permission notice appear in supporting documentation. // The author makes no representations about the suitability of this software for any purpose. // It is provided "as is" without express or implied warranty. // // "typeof" operator implementation // // Described in CUJ 20(8, 10, and 12), August, October, and December 2002: "A Bit-Wise Typeof" // This version is a re-write of the original implementation that employs the typeint implementation // of extended precision compile time arithmetic. Typeints are described in CUJ online experts // column, February 2003. // #ifndef GENGN_H #define GENGN_H #include "utils.h" #include "typeint.h" #include typedef unsigned short Code; const Code CodeLen = std::numeric_limits::digits; #define MASK( n ) (((1<<((n)-1))-1)|(1<<((n)-1))) const Code NumCodes = 4; const Code CodeMax = MASK(CodeLen); const Code CodeMask = CodeMax; // // Godel numbering approximation // const Code BaseLen = 6; const Code BaseMax = (1<::R BaseMaskT; const Code QualBaseLen = BaseLen+2; #define ISBASECODE( n ) ((n)<(1<::R ConstBaseQualT; const Code VolBasePos = ConstBasePos+1; const Code VolBaseQual = 1 << VolBasePos; typedef TypeInt::R VolBaseQualT; const Code ModLen = 8; const Code ModMask = MASK(ModLen); typedef TypeInt::R ModMaskT; const Code ArrayboundLen = 8; const Code ArrayboundMask = MASK(ArrayboundLen); typedef TypeInt::R ArrayboundMaskT; const Code ArgcountLen = 2; const Code MaxArgs = 1; const Code ArglenLen = 6; enum BaseTypeCodes { BoolVal = 1, CharVal, UCharVal, SCharVal, ShortVal, UShortVal, IntVal, UIntVal, LongVal, ULongVal, FloatVal, DoubleVal, LDoubleVal, VoidVal, FirstUnreservedTypeVal }; enum ModifierCodes { Ptr = 0x01, Ref = 0x02, Ary = 0x03, Pcm = 0x04, Fun = 0x05, PcmFun0 = 0x06, PcmFun0C = 0x07, PcmFun0V = 0x09, PcmFun0CV = 0x0A, PcmFun1 = 0x0B, PcmFun1C = 0x0C, PcmFun1V = 0x0D, PcmFun1CV = 0x0E, Const = 0x40, Vol = 0x80 }; // TypeInt versions of modifier codes typedef TypeInt::R PtrT; typedef TypeInt::R CPtrT; typedef TypeInt::R VPtrT; typedef TypeInt::R CVPtrT; typedef TypeInt::R RefT; typedef TypeInt::R AryT; typedef TypeInt::R PcmT; typedef TypeInt::R CPcmT; typedef TypeInt::R VPcmT; typedef TypeInt::R CVPcmT; typedef TypeInt::R FunT; typedef TypeInt::R PcmFun0T; typedef TypeInt::R PcmFun0CT; typedef TypeInt::R PcmFun0VT; typedef TypeInt::R PcmFun0CVT; typedef TypeInt::R PcmFun1T; typedef TypeInt::R PcmFun1CT; typedef TypeInt::R PcmFun1VT; typedef TypeInt::R PcmFun1CVT; typedef TypeInt::R ConstT; typedef TypeInt::R VolT; const Code QualMask = Const+Vol; // // "Round trip" generation of registered base types. // TypeCode turns type into integer, DeCode turns integer back into type. // template struct TypeCode; template struct DeCode; // Special handling for void, due to inability to declare void &. Int2Int typeCode( void ); template <> struct TypeCode { enum { value = VoidVal }; }; template <> struct DeCode { typedef void R; }; #define REGISTER( T, N )\ Int2Int\ typeCode(T &);\ template <>\ struct TypeCode {\ enum { value = N };\ };\ template <>\ struct DeCode {\ typedef T R;\ } // Pre-registration of built-in types. // Users are responsible for registering user-defined types. REGISTER( bool, BoolVal ); REGISTER( char, CharVal ); REGISTER( unsigned char, UCharVal ); REGISTER( signed char, SCharVal ); REGISTER( short, ShortVal ); REGISTER( unsigned short, UShortVal ); REGISTER( int, IntVal ); REGISTER( unsigned int, UIntVal ); REGISTER( long, LongVal ); REGISTER( unsigned long, ULongVal ); REGISTER( float, FloatVal ); REGISTER( double, DoubleVal ); REGISTER( long double, LDoubleVal ); template struct BaseType { typedef typename DeQual::R S; enum { base = TypeCode::value, code = base | (IsConst::r << ConstBasePos) | (IsVol::r << VolBasePos), len = QualBaseLen }; typedef typename TypeInt::R Code; }; template struct GN { enum { len = BaseType::len }; typedef typename BaseType::Code Code; }; template struct GN { enum { len = GN::len+ModLen }; typedef typename Or::Code,ModLen>::R,PtrT>::R Code; }; template struct GN { enum { len = GN::len+ModLen }; typedef typename GN::Code T1; typedef typename LShift::R T2; typedef typename Or::R Code; }; template struct GN { enum { len = GN::len+ModLen }; typedef typename GN::Code T1; typedef typename LShift::R T2; typedef typename Or::R Code; }; template struct GN { enum { len = GN::len+ModLen }; typedef typename GN::Code T1; typedef typename LShift::R T2; typedef typename Or::R Code; }; template struct GN { enum { len = GN::len+ModLen }; typedef typename GN::Code T1; typedef typename LShift::R T2; typedef typename Or::R Code; }; template struct GN { enum { len = GN::len+ArrayboundLen+ModLen }; typedef typename GN::Code T1; typedef typename LShift::R T2; typedef typename TypeInt<((ArrayboundMask&N)<::R T3; typedef typename Or::R Code; }; template struct GN { enum { len = GN::len+ArgcountLen+ModLen }; typedef typename GN::Code T1; typedef typename LShift::R T2; typedef typename Or::R Code; }; template struct GN { typedef R RetType; typedef A ArgType; typedef R FuncType( A ); enum { // calculate lengths and shift amounts argshift = ArglenLen+ArgcountLen+ModLen, arglen = GN::len, retshift = arglen+argshift, retlen = GN::len, len = retlen+arglen+ArglenLen+ArgcountLen+ModLen }; //typedef typename GN::Code Ret; // GN for return type //typedef typename GN::Code Arg; // GN for argument type //typedef typename LShift::R SA; // shift arg to proper position //typedef typename LShift::R SR; // shift ret to proper position //typedef typename Or::R T1; // or them together //typedef typename TypeInt<(arglen<<(ArgcountLen+ModLen)) | (1<::R T2; // gen code for function modifier, etc. //typedef typename Or::R Code; // or modifier into previous result typedef typename Or::Code,retshift>::R,typename LShift::Code,argshift>::R>::R,typename TypeInt<(arglen<<(ArgcountLen+ModLen)) | (1<::R>::R Code; }; template struct GN { enum { // Note class type is not qualified: BaseLen, not QualBaseLen, TypeCode, not GN or BaseType. len = GN::len+BaseLen+ModLen }; typedef typename GN::Code T1; typedef typename LShift::R T2; typedef typename Or::value<::R>::R T3; typedef typename Or::R Code; }; //====== COMMENT OUT THIS BLOCK FOR METROWERKS template struct GN { enum { len = GN::len+BaseLen+ModLen }; typedef typename GN::Code T1; typedef typename LShift::R T2; typedef typename Or::value<::R>::R T3; typedef typename Or::R Code; }; template struct GN { enum { len = GN::len+BaseLen+ModLen }; typedef typename GN::Code T1; typedef typename LShift::R T2; typedef typename Or::value<::R>::R T3; typedef typename Or::R Code; }; template struct GN { enum { len = GN::len+BaseLen+ModLen }; typedef typename GN::Code T1; typedef typename LShift::R T2; typedef typename Or::value<::R>::R T3; typedef typename Or::R Code; }; // Note that a member function is a very different beast from // a non-member function, so we have to special-case for them. // However, we can leverage much of our implementation of non-member // functions if we're careful. // Note also that (for pedegogic reasons?) we've taken a different tack // with the implementation of pointers to member functions. We're being // more "combinatorial" here, with different modifier codes for each number // of arguments and each cv-qualifer combination. This does cause // something of a "combinatorial explosion" when combined with the possible // cv-qualifiers of the pointer to member itself (4*4*(max_#_args+1)). // This can be improved by factoring the templates, which I'll get around to some day... // Laziness compelled me to permit only unqualified pointers to member // function below, though the member functions themselves may be qualified. template struct GN { typedef R M(); typedef GN GNM; typedef typename GNM::Code T1; typedef typename LShift::R T2; typedef typename Or::r<::R>::R T3; typedef typename Or::R Code; enum { len = GNM::len+BaseLen+ModLen }; }; template struct GN { typedef GN GNMF; typedef typename GNMF::Code T1; enum { len = GNMF::len }; typedef typename Xor::R T2; typedef typename Or::R Code; }; template struct GN { typedef GN GNMF; typedef typename GNMF::Code T1; enum { len = GNMF::len }; typedef typename Xor::R T2; typedef typename Or::R Code; }; template struct GN { typedef GN GNMF; typedef typename GNMF::Code T1; enum { len = GNMF::len }; typedef typename Xor::R T2; typedef typename Or::R Code; }; template struct GN { typedef R Ret; typedef A Arg; typedef R M(A); typedef typename GN::Code T1; typedef typename LShift::R T2; typedef typename Or::r<::R>::R T3; typedef typename Or::R Code; enum { len = T1::len+BaseLen+ModLen }; }; template struct GN { typedef GN GNMF; typedef typename GNMF::Code T1; typedef typename Xor::R T2; typedef typename Or::R Code; enum { len = GNMF::len }; }; template struct GN { typedef GN GNMF; typedef typename GNMF::Code T1; typedef typename Xor::R T2; typedef typename Or::R Code; enum { len = GNMF::len }; }; template struct GN { typedef GN GNMF; typedef typename GNMF::Code T1; typedef typename Xor::R T2; typedef typename Or::R Code; enum { len = GNMF::len }; }; //=================== END OF METROWERKS COMMENT OUT const int nb = CodeLen; typedef TypeInt<(1<::R Mask; #define V( T, n ) (Value::Code,(n)*nb>::R,Mask>::R>::r) #define Vv( n ) (Value::Code,(n)*nb>::R,Mask>::R>::r) char (*genGN1( void ))[Vv(0)+1]; // no definition char (*genGN2( void ))[Vv(1)+1]; char (*genGN3( void ))[Vv(2)+1]; char (*genGN4( void ))[Vv(3)+1]; template char (*genGN1( T & ))[V(T,0)+1]; // no definition template char (*genGN2( T & ))[V(T,1)+1]; template char (*genGN3( T & ))[V(T,2)+1]; template char (*genGN4( T & ))[V(T,3)+1]; #endif