From 83a639e66e094c683b48215a895f6d35e9d60d32 Mon Sep 17 00:00:00 2001 From: Matt McCutchen Date: Wed, 16 Jul 2008 14:59:10 -0400 Subject: [PATCH] - Move the BigUnsigned conversion templates to fix a build error. - Format conversion code more nicely. --- BigInteger.cc | 45 +++++++----------------- BigUnsigned.cc | 95 +++++--------------------------------------------- BigUnsigned.hh | 80 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 98 insertions(+), 122 deletions(-) diff --git a/BigInteger.cc b/BigInteger.cc index 2651ab7..56f30ab 100644 --- a/BigInteger.cc +++ b/BigInteger.cc @@ -39,15 +39,9 @@ BigInteger::BigInteger(const BigUnsigned &x, Sign s) : mag(x) { * negative BigInteger instead of an exception. */ // Done longhand to let us use initialization. -BigInteger::BigInteger(unsigned long x) : mag(x) { - sign = mag.isZero() ? zero : positive; -} -BigInteger::BigInteger(unsigned int x) : mag(x) { - sign = mag.isZero() ? zero : positive; -} -BigInteger::BigInteger(unsigned short x) : mag(x) { - sign = mag.isZero() ? zero : positive; -} +BigInteger::BigInteger(unsigned long x) : mag(x) { sign = mag.isZero() ? zero : positive; } +BigInteger::BigInteger(unsigned int x) : mag(x) { sign = mag.isZero() ? zero : positive; } +BigInteger::BigInteger(unsigned short x) : mag(x) { sign = mag.isZero() ? zero : positive; } // For signed input, determine the desired magnitude and sign separately. @@ -66,12 +60,9 @@ namespace { } } -BigInteger::BigInteger(long x) : sign(signOf(x)), - mag(magOf(x)) {} -BigInteger::BigInteger(int x) : sign(signOf(x)), - mag(magOf(x)) {} -BigInteger::BigInteger(short x) : sign(signOf(x)), - mag(magOf(x)) {} +BigInteger::BigInteger(long x) : sign(signOf(x)), mag(magOf(x)) {} +BigInteger::BigInteger(int x) : sign(signOf(x)), mag(magOf(x)) {} +BigInteger::BigInteger(short x) : sign(signOf(x)), mag(magOf(x)) {} // CONVERSION TO PRIMITIVE INTEGERS @@ -119,24 +110,12 @@ X BigInteger::convertToSignedPrimitive() const { "Value is too big to fit in the requested type"; } -unsigned long BigInteger::toUnsignedLong() const { - return convertToUnsignedPrimitive(); -} -unsigned int BigInteger::toUnsignedInt() const { - return convertToUnsignedPrimitive(); -} -unsigned short BigInteger::toUnsignedShort() const { - return convertToUnsignedPrimitive(); -} -long BigInteger::toLong() const { - return convertToSignedPrimitive(); -} -int BigInteger::toInt() const { - return convertToSignedPrimitive(); -} -short BigInteger::toShort() const { - return convertToSignedPrimitive(); -} +unsigned long BigInteger::toUnsignedLong () const { return convertToUnsignedPrimitive (); } +unsigned int BigInteger::toUnsignedInt () const { return convertToUnsignedPrimitive (); } +unsigned short BigInteger::toUnsignedShort() const { return convertToUnsignedPrimitive (); } +long BigInteger::toLong () const { return convertToSignedPrimitive (); } +int BigInteger::toInt () const { return convertToSignedPrimitive (); } +short BigInteger::toShort () const { return convertToSignedPrimitive (); } // COMPARISON BigInteger::CmpRes BigInteger::compareTo(const BigInteger &x) const { diff --git a/BigUnsigned.cc b/BigUnsigned.cc index 9e5a347..a4e6d9b 100644 --- a/BigUnsigned.cc +++ b/BigUnsigned.cc @@ -2,38 +2,8 @@ // Memory management definitions have moved to the bottom of NumberlikeArray.hh. -// CONSTRUCTION FROM PRIMITIVE INTEGERS - -/* Initialize this BigUnsigned from the given primitive integer. The same - * pattern works for all primitive integer types, so I put it into a template to - * reduce code duplication. (Don't worry: this is protected and we instantiate - * it only with primitive integer types.) Type X could be signed, but x is - * known to be nonnegative. */ -template -void BigUnsigned::initFromPrimitive(X x) { - if (x == 0) - ; // NumberlikeArray already initialized us to zero. - else { - // Create a single block. blk is NULL; no need to delete it. - cap = 1; - blk = new Blk[1]; - len = 1; - blk[0] = Blk(x); - } -} - -/* Ditto, but first check that x is nonnegative. I could have put the check in - * initFromPrimitive and let the compiler optimize it out for unsigned-type - * instantiations, but I wanted to avoid the warning stupidly issued by g++ for - * a condition that is constant in *any* instantiation, even if not in all. */ -template -void BigUnsigned::initFromSignedPrimitive(X x) { - if (x < 0) - throw "BigUnsigned constructor: " - "Cannot construct a BigUnsigned from a negative number"; - else - initFromPrimitive(x); -} +// The templates used by these constructors and converters are at the bottom of +// BigUnsigned.hh. BigUnsigned::BigUnsigned(unsigned long x) { initFromPrimitive (x); } BigUnsigned::BigUnsigned(unsigned int x) { initFromPrimitive (x); } @@ -42,61 +12,12 @@ BigUnsigned::BigUnsigned( long x) { initFromSignedPrimitive(x); } BigUnsigned::BigUnsigned( int x) { initFromSignedPrimitive(x); } BigUnsigned::BigUnsigned( short x) { initFromSignedPrimitive(x); } -// CONVERSION TO PRIMITIVE INTEGERS - -/* Template with the same idea as initFromPrimitive. This might be slightly - * slower than the previous version with the masks, but it's much shorter and - * clearer, which is the library's stated goal. */ -template -X BigUnsigned::convertToPrimitive() const { - if (len == 0) - // The number is zero; return zero. - return 0; - else if (len == 1) { - // The single block might fit in an X. Try the conversion. - X x = X(blk[0]); - // Make sure the result accurately represents the block. - if (Blk(x) == blk[0]) - // Successful conversion. - return x; - // Otherwise fall through. - } - throw "BigUnsigned::to: " - "Value is too big to fit in the requested type"; -} - -/* Wrap the above in an x >= 0 test to make sure we got a nonnegative result, - * not a negative one that happened to convert back into the correct nonnegative - * one. (E.g., catch incorrect conversion of 2^31 to the long -2^31.) Again, - * separated to avoid a g++ warning. */ -template -X BigUnsigned::convertToSignedPrimitive() const { - X x = convertToPrimitive(); - if (x >= 0) - return x; - else - throw "BigUnsigned::to(Primitive): " - "Value is too big to fit in the requested type"; -} - -unsigned long BigUnsigned::toUnsignedLong() const { - return convertToPrimitive(); -} -unsigned int BigUnsigned::toUnsignedInt() const { - return convertToPrimitive(); -} -unsigned short BigUnsigned::toUnsignedShort() const { - return convertToPrimitive(); -} -long BigUnsigned::toLong() const { - return convertToSignedPrimitive(); -} -int BigUnsigned::toInt() const { - return convertToSignedPrimitive(); -} -short BigUnsigned::toShort() const { - return convertToSignedPrimitive(); -} +unsigned long BigUnsigned::toUnsignedLong () const { return convertToPrimitive (); } +unsigned int BigUnsigned::toUnsignedInt () const { return convertToPrimitive (); } +unsigned short BigUnsigned::toUnsignedShort() const { return convertToPrimitive (); } +long BigUnsigned::toLong () const { return convertToSignedPrimitive< long >(); } +int BigUnsigned::toInt () const { return convertToSignedPrimitive< int >(); } +short BigUnsigned::toShort () const { return convertToSignedPrimitive< short>(); } // COMPARISON BigUnsigned::CmpRes BigUnsigned::compareTo(const BigUnsigned &x) const { diff --git a/BigUnsigned.hh b/BigUnsigned.hh index 12dc534..0813234 100644 --- a/BigUnsigned.hh +++ b/BigUnsigned.hh @@ -62,7 +62,7 @@ public: BigUnsigned( short x); protected: // Helpers - template void initFromPrimitive(X x); + template void initFromPrimitive (X x); template void initFromSignedPrimitive(X x); public: @@ -78,7 +78,7 @@ public: protected: // Helpers template X convertToSignedPrimitive() const; - template X convertToPrimitive() const; + template X convertToPrimitive () const; public: // ACCESSORS @@ -324,4 +324,80 @@ inline void BigUnsigned::operator >>=(int b) { bitShiftRight(*this, b); } +/* Templates for conversions of BigUnsigned to and from primitive integers. + * BigInteger.cc needs to instantiate convertToPrimitive, and the uses in + * BigUnsigned.cc didn't do the trick; I think gcc inlined convertToPrimitive + * instead of generating linkable instantiations. So for consistency, I put + * all the templates here. */ + +// CONSTRUCTION FROM PRIMITIVE INTEGERS + +/* Initialize this BigUnsigned from the given primitive integer. The same + * pattern works for all primitive integer types, so I put it into a template to + * reduce code duplication. (Don't worry: this is protected and we instantiate + * it only with primitive integer types.) Type X could be signed, but x is + * known to be nonnegative. */ +template +void BigUnsigned::initFromPrimitive(X x) { + if (x == 0) + ; // NumberlikeArray already initialized us to zero. + else { + // Create a single block. blk is NULL; no need to delete it. + cap = 1; + blk = new Blk[1]; + len = 1; + blk[0] = Blk(x); + } +} + +/* Ditto, but first check that x is nonnegative. I could have put the check in + * initFromPrimitive and let the compiler optimize it out for unsigned-type + * instantiations, but I wanted to avoid the warning stupidly issued by g++ for + * a condition that is constant in *any* instantiation, even if not in all. */ +template +void BigUnsigned::initFromSignedPrimitive(X x) { + if (x < 0) + throw "BigUnsigned constructor: " + "Cannot construct a BigUnsigned from a negative number"; + else + initFromPrimitive(x); +} + +// CONVERSION TO PRIMITIVE INTEGERS + +/* Template with the same idea as initFromPrimitive. This might be slightly + * slower than the previous version with the masks, but it's much shorter and + * clearer, which is the library's stated goal. */ +template +X BigUnsigned::convertToPrimitive() const { + if (len == 0) + // The number is zero; return zero. + return 0; + else if (len == 1) { + // The single block might fit in an X. Try the conversion. + X x = X(blk[0]); + // Make sure the result accurately represents the block. + if (Blk(x) == blk[0]) + // Successful conversion. + return x; + // Otherwise fall through. + } + throw "BigUnsigned::to: " + "Value is too big to fit in the requested type"; +} + +/* Wrap the above in an x >= 0 test to make sure we got a nonnegative result, + * not a negative one that happened to convert back into the correct nonnegative + * one. (E.g., catch incorrect conversion of 2^31 to the long -2^31.) Again, + * separated to avoid a g++ warning. */ +template +X BigUnsigned::convertToSignedPrimitive() const { + X x = convertToPrimitive(); + if (x >= 0) + return x; + else + throw "BigUnsigned::to(Primitive): " + "Value is too big to fit in the requested type"; +} + #endif -- 2.34.1