// // Copyright (c) 2003 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. // // N-ary typeint implementation // // Described in CUJ online experts column, June 2003 // #ifndef TYPEINT_NARY_H #define TYPEINT_NARY_H #include "utils.h" // // Basic Parameterization // // The value L is the number of bits used to represent each // fragment of the extended precision integer. The larger L is, // the faster compile time will be and the larger integers can be. // // L must be chosen carefully to satisfy your compiler. // Remember that Annex B suggests an implementation support // object sizes of only 256*1024==2**18, so the array bound // should in the representation should be <= 2**18/sizeof(pointer) // probably == 2**16. Since stored array bounds are incremented // by 1, a safer value would be 2**15 (or 2**1, for that matter). const int L = 15; // number of bits in representation #define MASK( n ) ((1<<(n))-1) #define BOUND( b ) ((b)&MASK(L)) #define END( b, n ) ((b) & (MASK(n)<<(L-(n)))) //#define LSLOST( bits, n ) ((bits)&(((1<<(n))-1)<<(L-(n))))>>(L-(n)) #define LSLOST( b, n ) (END(b,n)>>(L-(n))) // // Left Shift // template struct LShiftShort { typedef T R; }; template struct LShiftShort { enum { mylostbits = LSLOST(bound-1,n), newb = (BOUND((bound-1)<::R Temp; typedef Temp (*RR)[newb]; typedef typename Select< (mylostbits && (IsAry::R>::bound==0)), RR (*)[mylostbits+1], RR >::R R; }; template struct LShift { typedef typename LShiftShort::R Temp; typedef typename AddPtrAryN::R R; }; // // Right Shift // template struct RShiftShort { typedef T R; }; template struct RShiftShort { enum { pb = IsAry::bound, // previous bound fixedpb = pb ? pb-1 : 0, // if prev not array, bound==0, else remove 1 added to avoid 0 bound lostbits = fixedpb & ((1<>n) | (lostbits<<(L-n))) + 1 // add 1 to fix up }; typedef typename RShiftShort::R Temp; // if the previous bound is 0, then this is lowest level array mod. // if bound is 0, then trim the useless modifier (it's a leading zero, essentially). typedef typename Select< newb==1 && pb==0, Temp, Temp(*)[newb] >::R R; }; template struct RShift { typedef typename DePtrAryN::R Temp; typedef typename RShiftShort::R R; }; // // Bitwise Or // template struct Or; template <> struct Or { typedef char R; }; template struct Or { typedef T1 (*R)[b1]; }; template struct Or { typedef T2 (*R)[b2]; }; template struct Or { typedef typename Or::R Temp; enum { newbound = ((b1-1) | (b2-1)) + 1 }; typedef Temp (*R)[newbound]; }; // // Bitwise And // template struct And; template <> struct And { typedef char R; }; template struct And { typedef typename And::R Temp; enum { newbound = ((b1-1) & (b2-1)) + 1 }; // if this is the high-order digit, and it's zero, clip it. typedef typename Select< (newbound==1) && IsSame::r, char, Temp (*) [newbound] >::R R; }; template struct And { typedef char R; }; template struct And { typedef char R; }; // // Bitwise Xor // template struct Xor; template <> struct Xor { typedef char R; }; template struct Xor { typedef typename Xor::R Temp; enum { newbound = ((b1-1) ^ (b2-1)) + 1 }; typedef Temp (*R)[newbound]; }; template struct Xor { typedef T1 (*R)[b1]; }; template struct Xor { typedef T2 (*R)[b2]; }; // // Addition // template struct Add; template struct Add { // neither A nor B is 0 // Approach: find the sum of more significant bits // then modify to take into account least significant bit pos typedef typename Add::R Temp; typedef typename Select< ((b1-1+b2-1)>BOUND(b1-1+b2-1)), // if there's overflow typename Add::R, // add one to Temp Temp // otherwise not >::R (*R)[BOUND(b1-1+b2-1)+1]; }; template struct Add { typedef T1 (*R)[b1]; // A+0=A }; template struct Add { typedef T2 (*R)[b2]; // 0+B=B }; template <> struct Add { typedef char R; // 0+0=0 }; // // Comparison // template struct Comp { enum { ls = false, eql = true, gtr = false }; }; template struct Comp { enum { pls = Comp::ls, peql = Comp::eql, pgtr = Comp::gtr, ls = pls || (peql && b1b2) }; }; template struct Comp { // T1 longer than T2, T1 is greater enum { ls = false, eql = false, gtr = true }; }; template struct Comp { // T2 longer than T1, T1 is less enum { ls = true, eql = false, gtr = false }; }; template struct Less { enum { r = Comp::ls }; }; template struct LessEqual { typedef Comp C; enum { r = C::ls || C::eql }; }; template struct Equal { enum { r = Comp::eql }; }; template struct NotEqual { enum { r = !Comp::eql }; }; template struct GreaterEqual { typedef Comp C; enum { r = C::gtr || C::eql }; }; template struct Greater { enum { r = Comp::gtr }; }; // // Converting small integers to and from types. // template struct Value { enum { r = 0 }; }; template struct Value { enum { r = (Value::r << L) + bound-1 }; }; template struct TypeInt { typedef typename TypeInt<(n>>L)>::R (*R) [(n&MASK(L))+1]; // add 1 to avoid zero bound }; template <> struct TypeInt<0> { typedef char R; }; // // Printing big typeints // // Just a handy utility for debugging, and is not more generally useful. // Prints a binary representation. template struct PrintTypeint; template <> struct PrintTypeint { static void print() { std::cout << "==>"; } }; template struct PrintTypeint { static void print(); }; //#define METROWERKS template void PrintTypeint::print() { PrintTypeint::print(); for( int i = L-1; i >= 0; --i ) { #ifdef METROWERKS // can't seem to reference bound without core dump!?! std::cout << 'x'; #else const char c = (((bound-1)&(1<