mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			125 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			125 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "BigUnsignedInABase.hh"
 | |
| 
 | |
| BigUnsignedInABase::BigUnsignedInABase(const Digit *d, Index l, Base base)
 | |
| 	: NumberlikeArray<Digit>(d, l), base(base) {
 | |
| 	// Check the base
 | |
| 	if (base < 2)
 | |
| 		throw "BigUnsignedInABase::BigUnsignedInABase(const Digit *, Index, Base): The base must be at least 2";
 | |
| 
 | |
| 	// Validate the digits.
 | |
| 	for (Index i = 0; i < l; i++)
 | |
| 		if (blk[i] >= base)
 | |
| 			throw "BigUnsignedInABase::BigUnsignedInABase(const Digit *, Index, Base): A digit is too large for the specified base";
 | |
| 
 | |
| 	// Eliminate any leading zeros we may have been passed.
 | |
| 	zapLeadingZeros();
 | |
| }
 | |
| 
 | |
| namespace {
 | |
| 	unsigned int bitLen(unsigned int x) {
 | |
| 		unsigned int len = 0;
 | |
| 		while (x > 0) {
 | |
| 			x >>= 1;
 | |
| 			len++;
 | |
| 		}
 | |
| 		return len;
 | |
| 	}
 | |
| 	unsigned int ceilingDiv(unsigned int a, unsigned int b) {
 | |
| 		return (a + b - 1) / b;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| BigUnsignedInABase::BigUnsignedInABase(const BigUnsigned &x, Base base) {
 | |
| 	// Check the base
 | |
| 	if (base < 2)
 | |
| 		throw "BigUnsignedInABase(BigUnsigned, Base): The base must be at least 2";
 | |
| 	this->base = base;
 | |
| 
 | |
| 	// Get an upper bound on how much space we need
 | |
| 	int maxBitLenOfX = x.getLength() * BigUnsigned::N;
 | |
| 	int minBitsPerDigit = bitLen(base) - 1;
 | |
| 	int maxDigitLenOfX = ceilingDiv(maxBitLenOfX, minBitsPerDigit);
 | |
| 	len = maxDigitLenOfX; // Another change to comply with `staying in bounds'.
 | |
| 	allocate(len); // Get the space
 | |
| 
 | |
| 	BigUnsigned x2(x), buBase(base);
 | |
| 	Index digitNum = 0;
 | |
| 
 | |
| 	while (!x2.isZero()) {
 | |
| 		// Get last digit.  This is like `lastDigit = x2 % buBase, x2 /= buBase'.
 | |
| 		BigUnsigned lastDigit(x2);
 | |
| 		lastDigit.divideWithRemainder(buBase, x2);
 | |
| 		// Save the digit.
 | |
| 		blk[digitNum] = lastDigit.toUnsignedShort();
 | |
| 		// Move on.  We can't run out of room: we figured it out above.
 | |
| 		digitNum++;
 | |
| 	}
 | |
| 
 | |
| 	// Save the actual length.
 | |
| 	len = digitNum;
 | |
| }
 | |
| 
 | |
| BigUnsignedInABase::operator BigUnsigned() const {
 | |
| 	BigUnsigned ans(0), buBase(base), temp;
 | |
| 	Index digitNum = len;
 | |
| 	while (digitNum > 0) {
 | |
| 		digitNum--;
 | |
| 		temp.multiply(ans, buBase);
 | |
| 		ans.add(temp, BigUnsigned(blk[digitNum]));
 | |
| 	}
 | |
| 	return ans;
 | |
| }
 | |
| 
 | |
| BigUnsignedInABase::BigUnsignedInABase(const std::string &s, Base base) {
 | |
| 	// Check the base.
 | |
| 	if (base > 36)
 | |
| 		throw "BigUnsignedInABase(std::string, Base): The default string conversion routines use the symbol set 0-9, A-Z and therefore support only up to base 36.  You tried a conversion with a base over 36; write your own string conversion routine.";
 | |
| 	// Save the base.
 | |
| 	// This pattern is seldom seen in C++, but the analogous ``this.'' is common in Java.
 | |
| 	this->base = base;
 | |
| 
 | |
| 	// `s.length()' is a `size_t', while `len' is a `NumberlikeArray::Index',
 | |
| 	// also known as an `unsigned int'.  Some compilers warn without this cast.
 | |
| 	len = Index(s.length());
 | |
| 	allocate(len);
 | |
| 
 | |
| 	Index digitNum, symbolNumInString;
 | |
| 	for (digitNum = 0; digitNum < len; digitNum++) {
 | |
| 		symbolNumInString = len - 1 - digitNum;
 | |
| 		char theSymbol = s[symbolNumInString];
 | |
| 		if (theSymbol >= '0' && theSymbol <= '9')
 | |
| 			blk[digitNum] = theSymbol - '0';
 | |
| 		else if (theSymbol >= 'A' && theSymbol <= 'Z')
 | |
| 			blk[digitNum] = theSymbol - 'A' + 10;
 | |
| 		else if (theSymbol >= 'a' && theSymbol <= 'z')
 | |
| 			blk[digitNum] = theSymbol - 'a' + 10;
 | |
| 		else
 | |
| 			throw "BigUnsignedInABase(std::string, Base): Bad symbol in input.  Only 0-9, A-Z, a-z are accepted.";
 | |
| 
 | |
| 		if (blk[digitNum] >= base)
 | |
| 			throw "BigUnsignedInABase::BigUnsignedInABase(const Digit *, Index, Base): A digit is too large for the specified base";
 | |
| 	}
 | |
| 	zapLeadingZeros();
 | |
| }
 | |
| 
 | |
| BigUnsignedInABase::operator std::string() const {
 | |
| 	if (base > 36)
 | |
| 		throw "BigUnsignedInABase ==> std::string: The default string conversion routines use the symbol set 0-9, A-Z and therefore support only up to base 36.  You tried a conversion with a base over 36; write your own string conversion routine.";
 | |
| 	if (len == 0)
 | |
| 		return std::string("0");
 | |
| 	// Some compilers don't have push_back, so use a char * buffer instead.
 | |
| 	char *s = new char[len + 1];
 | |
| 	s[len] = '\0';
 | |
| 	Index digitNum, symbolNumInString;
 | |
| 	for (symbolNumInString = 0; symbolNumInString < len; symbolNumInString++) {
 | |
| 		digitNum = len - 1 - symbolNumInString;
 | |
| 		Digit theDigit = blk[digitNum];
 | |
| 		if (theDigit < 10)
 | |
| 			s[symbolNumInString] = char('0' + theDigit);
 | |
| 		else
 | |
| 			s[symbolNumInString] = char('A' + theDigit - 10);
 | |
| 	}
 | |
| 	std::string s2(s);
 | |
| 	delete [] s;
 | |
| 	return s2;
 | |
| }
 |