- Move the BigUnsigned conversion templates to fix a build error.
authorMatt McCutchen <matt@mattmccutchen.net>
Wed, 16 Jul 2008 18:59:10 +0000 (14:59 -0400)
committerMatt McCutchen <matt@mattmccutchen.net>
Wed, 16 Jul 2008 18:59:10 +0000 (14:59 -0400)
- Format conversion code more nicely.

BigInteger.cc
BigUnsigned.cc
BigUnsigned.hh

index 2651ab7..56f30ab 100644 (file)
@@ -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<long, unsigned long>(x)) {}
-BigInteger::BigInteger(int x) : sign(signOf(x)),
-       mag(magOf<int, unsigned int>(x)) {}
-BigInteger::BigInteger(short x) : sign(signOf(x)),
-       mag(magOf<short, unsigned short>(x)) {}
+BigInteger::BigInteger(long  x) : sign(signOf(x)), mag(magOf<long , unsigned long >(x)) {}
+BigInteger::BigInteger(int   x) : sign(signOf(x)), mag(magOf<int  , unsigned int  >(x)) {}
+BigInteger::BigInteger(short x) : sign(signOf(x)), mag(magOf<short, unsigned short>(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 long>();
-}
-unsigned int BigInteger::toUnsignedInt() const {
-       return convertToUnsignedPrimitive<unsigned int>();
-}
-unsigned short BigInteger::toUnsignedShort() const {
-       return convertToUnsignedPrimitive<unsigned short>();
-}
-long BigInteger::toLong() const {
-       return convertToSignedPrimitive<long, unsigned long>();
-}
-int BigInteger::toInt() const {
-       return convertToSignedPrimitive<int, unsigned int>();
-}
-short BigInteger::toShort() const {
-       return convertToSignedPrimitive<short, unsigned short>();
-}
+unsigned long  BigInteger::toUnsignedLong () const { return convertToUnsignedPrimitive<unsigned long >       (); }
+unsigned int   BigInteger::toUnsignedInt  () const { return convertToUnsignedPrimitive<unsigned int  >       (); }
+unsigned short BigInteger::toUnsignedShort() const { return convertToUnsignedPrimitive<unsigned short>       (); }
+long           BigInteger::toLong         () const { return convertToSignedPrimitive  <long , unsigned long> (); }
+int            BigInteger::toInt          () const { return convertToSignedPrimitive  <int  , unsigned int>  (); }
+short          BigInteger::toShort        () const { return convertToSignedPrimitive  <short, unsigned short>(); }
 
 // COMPARISON
 BigInteger::CmpRes BigInteger::compareTo(const BigInteger &x) const {
index 9e5a347..a4e6d9b 100644 (file)
@@ -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 <class X>
-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 <class X>
-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 <class X>
-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<Primitive>: "
-               "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 <class X>
-X BigUnsigned::convertToSignedPrimitive() const {
-       X x = convertToPrimitive<X>();
-       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 long>();
-}
-unsigned int BigUnsigned::toUnsignedInt() const {
-       return convertToPrimitive<unsigned int>();
-}
-unsigned short BigUnsigned::toUnsignedShort() const {
-       return convertToPrimitive<unsigned short>();
-}
-long BigUnsigned::toLong() const {
-       return convertToSignedPrimitive<long>();
-}
-int BigUnsigned::toInt() const {
-       return convertToSignedPrimitive<int>();
-}
-short BigUnsigned::toShort() const {
-       return convertToSignedPrimitive<short>();
-}
+unsigned long  BigUnsigned::toUnsignedLong () const { return convertToPrimitive      <unsigned long >(); }
+unsigned int   BigUnsigned::toUnsignedInt  () const { return convertToPrimitive      <unsigned int  >(); }
+unsigned short BigUnsigned::toUnsignedShort() const { return convertToPrimitive      <unsigned short>(); }
+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 {
index 12dc534..0813234 100644 (file)
@@ -62,7 +62,7 @@ public:
        BigUnsigned(         short x);
 protected:
        // Helpers
-       template <class X> void initFromPrimitive(X x);
+       template <class X> void initFromPrimitive      (X x);
        template <class X> void initFromSignedPrimitive(X x);
 public:
 
@@ -78,7 +78,7 @@ public:
 protected:
        // Helpers
        template <class X> X convertToSignedPrimitive() const;
-       template <class X> X convertToPrimitive() const;
+       template <class X> 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 <class X>
+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 <class X>
+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 <class X>
+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<Primitive>: "
+               "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 <class X>
+X BigUnsigned::convertToSignedPrimitive() const {
+       X x = convertToPrimitive<X>();
+       if (x >= 0)
+               return x;
+       else
+               throw "BigUnsigned::to(Primitive): "
+                       "Value is too big to fit in the requested type";
+}
+
 #endif