diff --git a/src/tl/tl/tl.pro b/src/tl/tl/tl.pro index b0ab6a2f7..de941a2af 100644 --- a/src/tl/tl/tl.pro +++ b/src/tl/tl/tl.pro @@ -51,7 +51,8 @@ SOURCES = \ tlUnitTest.cc \ tlInt128Support.cc \ tlHttpStreamCurl.cc \ - tlHttpStreamQt.cc + tlHttpStreamQt.cc \ + tlLongInt.cc HEADERS = \ tlAlgorithm.h \ @@ -102,7 +103,8 @@ HEADERS = \ tlUnitTest.h \ tlInt128Support.h \ tlHttpStreamCurl.h \ - tlHttpStreamQt.h + tlHttpStreamQt.h \ + tlLongInt.h INCLUDEPATH = DEPENDPATH = diff --git a/src/tl/tl/tlLongInt.cc b/src/tl/tl/tlLongInt.cc new file mode 100644 index 000000000..ac0f4bbe7 --- /dev/null +++ b/src/tl/tl/tlLongInt.cc @@ -0,0 +1,29 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "tlLongInt.h" + +namespace tl +{ + // .. nothing yet .. +} diff --git a/src/tl/tl/tlLongInt.h b/src/tl/tl/tlLongInt.h new file mode 100644 index 000000000..9035bedc8 --- /dev/null +++ b/src/tl/tl/tlLongInt.h @@ -0,0 +1,1261 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#ifndef HDR_tlLongInt +#define HDR_tlLongInt + +#include "tlCommon.h" + +#include + +namespace tl +{ + +/** + * @brief A universal long unsigned int + * + * The long unsigned int is composed of N chunks of B type. + * B can be any unsigned int type. BI is the working type + * which must be twice the size of B. + * + * Specifically, this universal int is intended to emulate + * __uint128 by using: + * + * typedef long_uint<4, uint32_t, uint64_t> __uint128; + */ +template +class long_uint +{ +public: + enum { bits = sizeof (B) * 8 }; + + typedef B basic_type; + + /** + * @brief Default constructor + * This will initialize the value to 0. + */ + long_uint () + { + for (unsigned int i = 0; i < N; ++i) { + b[i] = 0; + } + } + + /** + * @brief Initialize the universal unsigned int with a POD type + * If T is a signed type, the upper bit won't be sign-extended. + */ + template + long_uint (T t) + { + unsigned int i = 0; + unsigned int tbits = sizeof (T) * 8; + + while (tbits > 0) { + b[i] = B (t); + if (tbits > bits) { + t >>= bits; + } + tbits -= bits; + ++i; + } + for ( ; i < N; ++i) { + b[i] = 0; + } + } + + /** + * @brief Convert the universal long int to the given type + * Casting will potentially reduce the number of significant + * bits of the value. + */ + template + operator T () const + { + T t = 0; + unsigned int tbits = sizeof (T) * 8; + + for (int i = N; i > 0 && tbits > 0; ) { + --i; + t <<= bits; + t |= b[i]; + tbits -= bits; + } + + return t; + } + + /** + * @brief Initialize the universal unsigned int from another one with a different width + */ + template + long_uint (const long_uint &o) + { + for (unsigned int i = 0; i < N; ++i) { + b[i] = i < N2 ? o.b[i] : 0; + } + } + + /** + * @brief zero predicate + * This method returns true, if the value is 0. + */ + bool is_zero () const + { + for (unsigned int i = 0; i < N; ++i) { + if (b[i]) { + return false; + } + } + return true; + } + + /** + * @brief Equality + */ + bool operator== (const long_uint &o) const + { + for (unsigned int i = 0; i < N; ++i) { + if (b[i] != o.b[i]) { + return false; + } + } + return true; + } + + /** + * @brief Inequality + */ + bool operator!= (const long_uint &b) const + { + return !operator== (b); + } + + /** + * @brief Less operator + */ + bool operator< (const long_uint &o) const + { + for (unsigned int i = N; i > 0; ) { + --i; + if (b[i] != o.b[i]) { + return b[i] < o.b[i]; + } + } + return false; + } + + /** + * @brief Greater or equal + */ + bool operator>= (const long_uint &b) const + { + return !operator< (b); + } + + /** + * @brief Less or equal + */ + bool operator<= (const long_uint &b) const + { + return b >= *this; + } + + /** + * @brief Greater + */ + bool operator> (const long_uint &b) const + { + return b < *this; + } + + /** + * @brief Multiplication + */ + template + long_uint operator* (const long_uint &o) const + { + long_uint res; + + for (unsigned int i = 0; i < N; ++i) { + for (unsigned int j = 0; j < N2; ++j) { + BI p = BI (b[i]) * BI (o.b[j]); + unsigned int n = i + j; + while (p > 0) { + B &r = res.b[n]; + B rold = r; + r += B (p); + p >>= bits; + if (r < rold) { + p += 1; + } + ++n; + } + } + } + + return long_uint (res); + } + + /** + * @brief In-place multiplication + */ + template + long_uint &operator*= (const long_uint &o) + { + *this = *this * o; + return *this; + } + + /** + * @brief Bitwise inversion + */ + long_uint operator~ () const + { + long_uint res = *this; + for (unsigned int i = 0; i < N; ++i) { + res.b[i] = ~res.b[i]; + } + return res; + } + + /** + * @brief Boolean and operator + */ + long_uint operator& (const long_uint &o) const + { + long_uint res = *this; + res &= o; + return res; + } + + /** + * @brief In-place boolean and operator + */ + long_uint &operator&= (const long_uint &o) + { + for (unsigned int i = 0; i < N; ++i) { + b[i] &= o.b[i]; + } + return *this; + } + + /** + * @brief Boolean xor operator + */ + long_uint operator^ (const long_uint &o) const + { + long_uint res = *this; + res ^= o; + return res; + } + + /** + * @brief In-place boolean xor operator + */ + long_uint &operator^= (const long_uint &o) + { + for (unsigned int i = 0; i < N; ++i) { + b[i] ^= o.b[i]; + } + return *this; + } + + /** + * @brief Boolean or operator + */ + long_uint operator| (const long_uint &o) const + { + long_uint res = *this; + res |= o; + return res; + } + + /** + * @brief In-place boolean or operator + */ + long_uint &operator|= (const long_uint &o) + { + for (unsigned int i = 0; i < N; ++i) { + b[i] |= o.b[i]; + } + return *this; + } + + /** + * @brief Left-shift operator + */ + long_uint operator<< (unsigned int n) const + { + long_uint res = *this; + res.lshift (n); + return res; + } + + /** + * @brief In-place left-shift operator + */ + long_uint &operator<<= (unsigned int n) + { + lshift (n); + return *this; + } + + /** + * @brief Bitwise left-shift + * This method will left-shift the value by the given number of bits + */ + void lshift (unsigned int n) + { + unsigned int w = n / bits; + if (w > 0) { + n -= w * bits; + for (unsigned int i = N - w; i > 0; ) { + --i; + b[i + w] = b[i]; + } + for (unsigned int i = 0; i < w; ++i) { + b[i] = 0; + } + } + + B carry = 0; + for (unsigned int i = 0; i < N; ++i) { + BI p = b[i]; + p <<= n; + p |= carry; + carry = B (p >> bits); + b[i] = B (p); + } + } + + /** + * @brief right-shift operator + */ + long_uint operator>> (unsigned int n) const + { + long_uint res = *this; + res.rshift (n); + return res; + } + + /** + * @brief In-place right-shift operator + */ + long_uint &operator>>= (unsigned int n) + { + rshift (n); + return *this; + } + + /** + * @brief Bitwise right-shift + * This method will right-shift the value by the given number of bits. + * The sign flag will be used to fill the upper bits. + */ + void rshift (unsigned int n, bool sign = false) + { + unsigned int w = n / bits; + if (w > 0) { + n -= w * bits; + for (unsigned int i = 0; i < N - w; ++i) { + b[i] = b[i + w]; + } + for (unsigned int i = N - w; i < N; ++i) { + b[i] = sign ? ~B (0) : B (0); + } + } + + if (n > 0) { + B carry = sign ? (~B (0) << (bits - n)) : 0; + for (unsigned int i = N; i > 0; ) { + --i; + BI p = BI (b[i]) << bits; + p >>= n; + p |= (BI (carry) << bits); + carry = B (p); + b[i] = B (p >> bits); + } + } + } + + /** + * @brief Sets the given bit in the universal long int + * Bit 0 is the rightmost (LSB) one. + */ + void set_bit (unsigned int n) + { + unsigned int i = n / bits; + n -= i * bits; + if (i < N) { + b[i] |= (1 << n); + } + } + + /** + * @brief Gets the number of zero bits counted from the MSB to the right + */ + unsigned int zero_bits_from_msb () const + { + unsigned int zb = 0; + for (unsigned int i = N; i > 0; ) { + --i; + if (!b[i]) { + zb += bits; + } else { + B m = 1 << (bits - 1); + B n = b[i]; + while (! (n & m)) { + ++zb; + n <<= 1; + } + break; + } + } + return zb; + } + + /** + * @brief Division and modulo operation + * This method returns the division of *this and d (the divider) in the first + * element of the returned pair and the modulo value (remainder) in the second. + */ + std::pair, long_uint > divmod (const long_uint &d) const + { + long_uint rem = *this; + long_uint div; + + if (d.is_zero ()) { + // should assert? + return std::make_pair (div, rem); + } + + unsigned int bd = d.zero_bits_from_msb (); + + while (rem >= d) { + + unsigned int brem = rem.zero_bits_from_msb (); + unsigned int shift = bd - brem; + + if (shift == 0) { + rem -= d; + div.set_bit (0); + } else { + long_uint sub = d; + sub.lshift (shift); + if (sub > rem) { + shift -= 1; + sub.rshift (1); + } + div.set_bit (shift); + rem -= sub; + } + + } + + return std::make_pair (div, rem); + } + + /** + * @brief Division operator + */ + long_uint operator/ (const long_uint &b) const + { + return divmod (b).first; + } + + /** + * @brief In-place division operator + */ + long_uint &operator/= (const long_uint &b) + { + *this = divmod (b).first; + return *this; + } + + /** + * @brief Modulo operator + */ + long_uint operator% (const long_uint &b) const + { + return divmod (b).second; + } + + /** + * @brief In-place modulo operator + */ + long_uint &operator%= (const long_uint &b) + { + *this = divmod (b).second; + return *this; + } + + /** + * @brief Addition with the basic type + */ + long_uint operator+ (B o) const + { + long_uint res; + + B carry = o; + for (unsigned int i = 0; i < N; ++i) { + B &r = res.b[i]; + r = b[i]; + B rold = r; + r += carry; + carry = 0; + if (r < rold) { + carry = 1; + } + } + + return res; + } + + /** + * @brief In-place addition with the basic type + */ + long_uint &operator+= (B o) + { + B carry = o; + for (unsigned int i = 0; i < N; ++i) { + B &r = b[i]; + B rold = r; + r += carry; + carry = 0; + if (r < rold) { + carry = 1; + } + } + + return *this; + } + + /** + * @brief Addition + */ + long_uint operator+ (const long_uint &o) const + { + long_uint res; + + B carry = 0; + for (unsigned int i = 0; i < N; ++i) { + B &r = res.b[i]; + r = b[i]; + B rold = r; + r += carry; + carry = 0; + if (r < rold) { + carry = 1; + } + rold = r; + r += o.b[i]; + if (r < rold) { + carry = 1; + } + } + + return res; + } + + /** + * @brief In-place addition + */ + long_uint &operator+= (const long_uint &o) + { + B carry = 0; + for (unsigned int i = 0; i < N; ++i) { + B &r = b[i]; + B rold = r; + r += carry; + carry = 0; + if (r < rold) { + carry = 1; + } + rold = r; + r += o.b[i]; + if (r < rold) { + carry = 1; + } + } + + return *this; + } + + /** + * @brief Subtraction + */ + long_uint operator- (const long_uint &o) const + { + long_uint res; + + B carry = 0; + for (unsigned int i = 0; i < N; ++i) { + B &r = res.b[i]; + r = b[i]; + B rold = r; + r -= carry; + carry = 0; + if (r > rold) { + carry = 1; + } + rold = r; + r -= o.b[i]; + if (r > rold) { + carry = 1; + } + } + + return res; + } + + /** + * @brief In-place subtraction + */ + long_uint &operator-= (const long_uint &o) + { + B carry = 0; + for (unsigned int i = 0; i < N; ++i) { + B &r = b[i]; + B rold = r; + r -= carry; + carry = 0; + if (r > rold) { + carry = 1; + } + rold = r; + r -= o.b[i]; + if (r > rold) { + carry = 1; + } + } + + return *this; + } + + /** + * @brief Subtraction with the basic type + */ + long_uint operator- (B o) const + { + long_uint res; + + B carry = o; + for (unsigned int i = 0; i < N; ++i) { + B &r = res.b[i]; + r = b[i]; + B rold = r; + r -= carry; + carry = 0; + if (r > rold) { + carry = 1; + } + } + + return res; + } + + /** + * @brief In-place subtraction with the basic type + */ + long_uint &operator-= (B o) + { + B carry = o; + for (unsigned int i = 0; i < N; ++i) { + B &r = b[i]; + B rold = r; + r -= carry; + carry = 0; + if (r > rold) { + carry = 1; + } + } + + return *this; + } + + B b[N]; +}; + +/** + * @brief A universal long signed int + * + * The long unsigned int is composed of N chunks of B type. + * B can be any unsigned int type. BI is the working type + * which must be twice the size of B. + * + * B and BI must be unsigned types. + * + * Specifically, this universal int is intended to emulate + * __int128 by using: + * + * typedef long_int<4, uint32_t, uint64_t> __int128; + */ +template +class long_int + : public long_uint +{ +public: + /** + * @brief Default constructor + * This will initialize the value to 0. + */ + long_int () + : long_uint () + { + // .. nothing yet .. + } + + /** + * @brief Initialize the universal int with a POD type + * If T is a signed type, the upper bit will be sign-extended. + */ + template + long_int (T t) + { + for (unsigned int i = 0; i < N; ++i) { + long_uint::b[i] = B (t); + t >>= long_uint::bits; + } + } + + /** + * @brief Convert the universal long int to the given type + * Casting will potentially reduce the number of significant + * bits of the value. + */ + template + operator T () const + { + T t = is_neg () ? -1 : 0; + unsigned int tbits = sizeof (T) * 8; + + for (int i = N; i > 0 && tbits > 0; ) { + --i; + t <<= long_uint::bits; + t |= long_uint::b[i]; + tbits -= long_uint::bits; + } + + return t; + } + + /** + * @brief Initialize the universal unsigned int from an unsigned one with a different width + * Sign inversion will happen, if the unsigned int is bigger than the maximum value + * representable by our type. + */ + template + long_int (const long_uint &o) + : long_uint (o) + { + // .. nothing yet .. + } + + /** + * @brief Initialize the universal int from another one with a different width + */ + template + long_int (const long_int &o) + : long_uint (o) + { + // .. nothing yet .. + } + + /** + * @brief negative predicate + * This method returns true, if the value is negative. + */ + bool is_neg () const + { + return (long_uint::b[N - 1] & (1 << (long_uint::bits - 1))) != 0; + } + + /** + * @brief zero predicate + * This method returns true, if the value is 0. + */ + bool is_zero () const + { + for (unsigned int i = 0; i < N; ++i) { + if (long_uint::b[i]) { + return false; + } + } + return true; + } + + /** + * @brief Less operator + */ + bool operator< (const long_uint &o) const + { + // we cast both arguments to unsigned as C++ does + return long_uint::operator< (o); + } + + /** + * @brief Less operator + */ + bool operator< (const long_int &o) const + { + if (is_neg () != o.is_neg ()) { + return is_neg () > o.is_neg (); + } else { + return long_uint::operator< (o); + } + } + + /** + * @brief Greater or equal + */ + bool operator>= (const long_uint &b) const + { + return !operator< (b); + } + + /** + * @brief Greater or equal + */ + bool operator>= (const long_int &b) const + { + return !operator< (b); + } + + /** + * @brief Less or equal + */ + bool operator<= (const long_uint &b) const + { + return b >= *this; + } + + /** + * @brief Less or equal + */ + bool operator<= (const long_int &b) const + { + return b >= *this; + } + + /** + * @brief Greater + */ + bool operator> (const long_uint &b) const + { + return b < *this; + } + + /** + * @brief Greater + */ + bool operator> (const long_int &b) const + { + return b < *this; + } + + /** + * @brief Sign inversion (two's complement) + */ + long_int operator- () const + { + long_uint res = ~*this; + res += B (1); + return long_int (res); + } + + /** + * @brief Multiplication with unsigned + */ + template + long_uint operator* (const long_uint &o) const + { + return long_uint::operator* (o); + } + + /** + * @brief Multiplication with signed + */ + template + long_int operator* (const long_int &o) const + { + if (is_neg () && ! o.is_neg ()) { + return -long_int ((-*this).long_uint::operator* (o)); + } else if (! is_neg () && o.is_neg ()) { + return -long_int (long_uint::operator* (-o)); + } else if (is_neg () && o.is_neg ()) { + return long_int ((-*this).long_uint::operator* (-o)); + } else { + return long_int (long_uint::operator* (o)); + } + } + + /** + * @brief In-place multiplication with unsigned + */ + template + long_int &operator*= (const long_uint &o) + { + long_uint::operator= (*this * o); + return *this; + } + + /** + * @brief In-place multiplication with signed + */ + template + long_int &operator*= (const long_int &o) + { + *this = *this * o; + return *this; + } + + /** + * @brief Left-shift operator + */ + long_int operator<< (unsigned int n) const + { + long_int res = *this; + res.lshift (n); + return res; + } + + /** + * @brief In-place left-shift operator + */ + long_int &operator<<= (unsigned int n) + { + long_uint::lshift (n); + return *this; + } + + /** + * @brief right-shift operator + */ + long_int operator>> (unsigned int n) const + { + long_uint res = *this; + res.rshift (n, is_neg ()); + return res; + } + + /** + * @brief In-place right-shift operator + */ + long_int &operator>>= (unsigned int n) + { + long_uint::rshift (n, is_neg ()); + return *this; + } + + /** + * @brief Division and modulo operation with unsigned type + * This method returns the division of *this and d (the divider) in the first + * element of the returned pair and the modulo value (remainder) in the second. + */ + std::pair, long_uint > divmod (const long_uint &d) const + { + return long_uint::divmod (d); + } + + /** + * @brief Division operator with unsigned + */ + long_uint operator/ (const long_uint &b) const + { + return divmod (b).first; + } + + /** + * @brief In-place division operator with unsigned + */ + long_int &operator/= (const long_uint &b) + { + long_uint::operator= (divmod (b).first); + return *this; + } + + /** + * @brief Modulo operator with unsigned + */ + long_uint operator% (const long_uint &b) const + { + return divmod (b).second; + } + + /** + * @brief In-place modulo operator with unsigned + */ + long_int &operator%= (const long_uint &b) + { + long_uint::operator= (divmod (b).second); + return *this; + } + + /** + * @brief Division and modulo operation + * This method returns the division of *this and d (the divider) in the first + * element of the returned pair and the modulo value (remainder) in the second. + */ + std::pair, long_int > divmod (const long_int &d) const + { + if (is_neg () && !d.is_neg ()) { + std::pair, long_uint > res = (-*this).long_uint::divmod (d); + return std::make_pair (-long_int (res.first), -long_int (res.second)); + } else if (! is_neg () && d.is_neg ()) { + std::pair, long_uint > res = long_uint::divmod (-d); + // The definition of the modulo sign is consistent with int arithmetics + return std::make_pair (-long_int (res.first), long_int (res.second)); + } else if (is_neg () && d.is_neg ()) { + std::pair, long_uint > res = (-*this).long_uint::divmod (-d); + // The definition of the modulo sign is consistent with int arithmetics + return std::make_pair (res.first, -long_int (res.second)); + } else { + std::pair, long_uint > res = long_uint::divmod (d); + return std::make_pair (res.first, res.second); + } + } + + /** + * @brief Division operator + */ + long_int operator/ (const long_int &b) const + { + return divmod (b).first; + } + + /** + * @brief In-place division operator + */ + long_int &operator/= (const long_int &b) + { + *this = divmod (b).first; + return *this; + } + + /** + * @brief Modulo operator + */ + long_int operator% (const long_int &b) const + { + return divmod (b).second; + } + + /** + * @brief In-place modulo operator + */ + long_int &operator%= (const long_int &b) + { + *this = divmod (b).second; + return *this; + } + + /** + * @brief Addition with basic type + */ + long_int operator+ (B o) const + { + return long_int (long_uint::operator+ (o)); + } + + /** + * @brief Addition with unsigned + */ + long_uint operator+ (const long_uint &o) const + { + return long_uint::operator+ (o); + } + + /** + * @brief Addition + */ + long_int operator+ (const long_int &o) const + { + return long_int (long_uint::operator+ (o)); + } + + /** + * @brief In-place addition with basic_type + */ + long_int &operator+= (B o) + { + long_uint::operator+= (o); + return *this; + } + + /** + * @brief In-place addition + */ + long_int &operator+= (const long_int &o) + { + long_uint::operator+= (o); + return *this; + } + + /** + * @brief In-place addition with unsigned + */ + long_int &operator+= (const long_uint &o) + { + long_uint::operator+= (o); + return *this; + } + + /** + * @brief Subtraction with basic_type + */ + long_int operator- (B o) const + { + return long_int (long_uint::operator- (o)); + } + + /** + * @brief Subtraction with unsigned + */ + long_uint operator- (const long_uint &o) const + { + return long_uint::operator- (o); + } + + /** + * @brief Subtraction + */ + long_int operator- (const long_int &o) const + { + return long_int (long_uint::operator- (o)); + } + + /** + * @brief In-place subtraction with basic_type + */ + long_int &operator-= (B o) + { + long_uint::operator-= (o); + return *this; + } + + /** + * @brief In-place subtraction with unsigned + */ + long_int &operator-= (const long_uint &o) + { + long_uint::operator-= (o); + return *this; + } + + /** + * @brief In-place subtraction + */ + long_int &operator-= (const long_int &o) + { + long_uint::operator-= (o); + return *this; + } +}; + +/** + * @brief Less operator with unsigned and signed + */ +template +bool operator< (const long_uint &a, const long_int &b) +{ + // we cast both arguments to unsigned (as C++ does) + return a.operator< (b); +} + +/** + * @brief Less or equal operator with unsigned and signed + */ +template +bool operator<= (const long_uint &a, const long_int &b) +{ + return !(b < a); +} + +/** + * @brief Greater operator with unsigned and signed + */ +template +bool operator> (const long_uint &a, const long_int &b) +{ + return b < a; +} + +/** + * @brief Greater or equal operator with unsigned and signed + */ +template +bool operator>= (const long_uint &a, const long_int &b) +{ + return !(a < b); +} + +/** + * @brief Multiplication with unsigned and signed + */ +template +long_uint operator* (const long_uint &a, const long_int &b) +{ + return a.operator* (b); +} + +/** + * @brief Division with unsigned and signed + */ +template +long_uint operator/ (const long_uint &a, const long_int &b) +{ + return a.operator/ (b); +} + +/** + * @brief Modulo with unsigned and signed + */ +template +long_uint operator% (const long_uint &a, const long_int &b) +{ + return a.operator% (b); +} + +/** + * @brief Addition with unsigned and signed + */ +template +long_uint operator+ (const long_uint &a, const long_int &b) +{ + return a.operator+ (b); +} + +/** + * @brief Subtraction with unsigned and signed + */ +template +long_uint operator- (const long_uint &a, const long_int &b) +{ + return a.operator- (b); +} + +} + +#endif diff --git a/src/tl/unit_tests/tlLongInt.cc b/src/tl/unit_tests/tlLongInt.cc new file mode 100644 index 000000000..3620e68e9 --- /dev/null +++ b/src/tl/unit_tests/tlLongInt.cc @@ -0,0 +1,178 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include +#include +#include + +#include "tlLongInt.h" +#include "tlUnitTest.h" + +typedef tl::long_int<4, uint8_t, uint16_t> li_type; +typedef int32_t i_type; + +typedef tl::long_uint<4, uint8_t, uint16_t> lui_type; +typedef uint32_t ui_type; + +i_type to_i (li_type x) +{ + return i_type (x); +} + +ui_type to_i (lui_type x) +{ + return ui_type (x); +} + +li_type to_e (i_type x) +{ + return li_type (x); +} + +lui_type to_e (ui_type x) +{ + return lui_type (x); +} + +template +static void run_test_int (tl::TestBase *_this, I1 a, I2 b) +{ + typedef typename LI1::basic_type basic_type; + if (tl::verbose ()) { + printf("Long int test with pair (%ld,%ld)\n", long (a), long (b)); + } + + LI1 ae = to_e (a); + LI2 be = to_e (b); + LI1 r; + + EXPECT_EQ (to_i (ae), a); + EXPECT_EQ (to_i (be), b); + + EXPECT_EQ (to_i (ae + be), a + b); + r = ae; + r += be; + EXPECT_EQ (to_i (r), a + b); + EXPECT_EQ (to_i (ae + basic_type (2)), a + basic_type (2)); + r = ae; + r += basic_type (2); + EXPECT_EQ (to_i (r), a + basic_type (2)); + + EXPECT_EQ (to_i (ae - be), a - b); + r = ae; + r -= be; + EXPECT_EQ (to_i (r), a - b); + EXPECT_EQ (to_i (ae - basic_type (2)), a - basic_type (2)); + r = ae; + r -= basic_type (2); + EXPECT_EQ (to_i (r), a - basic_type (2)); + + EXPECT_EQ (ae == be, a == b); + EXPECT_EQ (ae != be, a != b); + EXPECT_EQ (ae < be, a < b); + EXPECT_EQ (ae <= be, a <= b); + EXPECT_EQ (ae > be, a > b); + EXPECT_EQ (ae >= be, a >= b); + EXPECT_EQ (ae.is_zero (), a == 0); + + EXPECT_EQ (to_i (ae * be), a * b); + r = ae; + r *= be; + EXPECT_EQ (to_i (r), a * b); + + if (b != 0) { + EXPECT_EQ (to_i (ae / be), a / b); + r = ae; + r /= be; + EXPECT_EQ (to_i (r), a / b); + EXPECT_EQ (to_i (ae % be), a % b); + r = ae; + r %= be; + EXPECT_EQ (to_i (r), a % b); + } +} + +template +static void run_test (tl::TestBase *_this, I1 a, I2 b) +{ + run_test_int (_this, a, b); + run_test_int (_this, a, a); + run_test_int (_this, b, b); + run_test_int (_this, b, a); +} + +TEST(1) +{ + run_test (_this, 0, 1); + run_test (_this, 256, 257); + run_test (_this, 256, 2); + run_test (_this, 65535, 65536); + run_test (_this, 65535, 2); + run_test (_this, 0xfffffffe, 0xffffffff); + run_test (_this, 0xfffffffe, 2); + for (unsigned int i = 0; i < 100000; ++i) { + run_test (_this, rand () * rand (), rand () * rand ()); + } +} + +TEST(2) +{ + run_test (_this, 0, 1); + run_test (_this, 256, 257); + run_test (_this, 256, 2); + run_test (_this, 65535, 65536); + run_test (_this, 65535, 2); + run_test (_this, 0xfffffffe, 0xffffffff); + run_test (_this, 0xfffffffe, 2); + for (unsigned int i = 0; i < 100000; ++i) { + run_test (_this, rand () * rand (), rand () * rand ()); + } +} + +TEST(3) +{ + run_test (_this, 0, 1); + run_test (_this, 256, 257); + run_test (_this, 256, 2); + run_test (_this, 65535, 65536); + run_test (_this, 65535, 2); + run_test (_this, 0xfffffffe, 0xffffffff); + run_test (_this, 0xfffffffe, 2); + for (unsigned int i = 0; i < 100000; ++i) { + run_test (_this, rand () * rand (), rand () * rand ()); + } +} + +TEST(4) +{ + run_test (_this, 0, 1); + run_test (_this, 256, 257); + run_test (_this, 256, 2); + run_test (_this, 65535, 65536); + run_test (_this, 65535, 2); + run_test (_this, 0xfffffffe, 0xffffffff); + run_test (_this, 0xfffffffe, 2); + for (unsigned int i = 0; i < 100000; ++i) { + run_test (_this, rand () * rand (), rand () * rand ()); + } +} diff --git a/src/tl/unit_tests/unit_tests.pro b/src/tl/unit_tests/unit_tests.pro index 1984e3fa0..ddbb50ba3 100644 --- a/src/tl/unit_tests/unit_tests.pro +++ b/src/tl/unit_tests/unit_tests.pro @@ -32,7 +32,8 @@ SOURCES = \ tlVariant.cc \ tlWebDAV.cc \ tlXMLParser.cc \ - tlInt128Support.cc + tlInt128Support.cc \ + tlLongInt.cc INCLUDEPATH += $$TL_INC DEPENDPATH += $$TL_INC