xref: /aosp_15_r20/external/pdfium/third_party/bigint/BigUnsignedInABase.cc (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2014 The PDFium Authors
2*3ac0a46fSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*3ac0a46fSAndroid Build Coastguard Worker // found in the LICENSE file.
4*3ac0a46fSAndroid Build Coastguard Worker 
5*3ac0a46fSAndroid Build Coastguard Worker // Original code by Matt McCutchen, see the LICENSE file.
6*3ac0a46fSAndroid Build Coastguard Worker 
7*3ac0a46fSAndroid Build Coastguard Worker #include "BigUnsignedInABase.hh"
8*3ac0a46fSAndroid Build Coastguard Worker 
BigUnsignedInABase(const Digit * d,Index l,Base base)9*3ac0a46fSAndroid Build Coastguard Worker BigUnsignedInABase::BigUnsignedInABase(const Digit *d, Index l, Base base)
10*3ac0a46fSAndroid Build Coastguard Worker 	: NumberlikeArray<Digit>(d, l), base(base) {
11*3ac0a46fSAndroid Build Coastguard Worker 	// Check the base
12*3ac0a46fSAndroid Build Coastguard Worker 	if (base < 2)
13*3ac0a46fSAndroid Build Coastguard Worker         abort();
14*3ac0a46fSAndroid Build Coastguard Worker 
15*3ac0a46fSAndroid Build Coastguard Worker 	// Validate the digits.
16*3ac0a46fSAndroid Build Coastguard Worker 	for (Index i = 0; i < l; i++)
17*3ac0a46fSAndroid Build Coastguard Worker 		if (blk[i] >= base)
18*3ac0a46fSAndroid Build Coastguard Worker             abort();
19*3ac0a46fSAndroid Build Coastguard Worker 
20*3ac0a46fSAndroid Build Coastguard Worker 	// Eliminate any leading zeros we may have been passed.
21*3ac0a46fSAndroid Build Coastguard Worker 	zapLeadingZeros();
22*3ac0a46fSAndroid Build Coastguard Worker }
23*3ac0a46fSAndroid Build Coastguard Worker 
24*3ac0a46fSAndroid Build Coastguard Worker namespace {
bitLen(unsigned int x)25*3ac0a46fSAndroid Build Coastguard Worker 	unsigned int bitLen(unsigned int x) {
26*3ac0a46fSAndroid Build Coastguard Worker 		unsigned int len = 0;
27*3ac0a46fSAndroid Build Coastguard Worker 		while (x > 0) {
28*3ac0a46fSAndroid Build Coastguard Worker 			x >>= 1;
29*3ac0a46fSAndroid Build Coastguard Worker 			len++;
30*3ac0a46fSAndroid Build Coastguard Worker 		}
31*3ac0a46fSAndroid Build Coastguard Worker 		return len;
32*3ac0a46fSAndroid Build Coastguard Worker 	}
ceilingDiv(unsigned int a,unsigned int b)33*3ac0a46fSAndroid Build Coastguard Worker 	unsigned int ceilingDiv(unsigned int a, unsigned int b) {
34*3ac0a46fSAndroid Build Coastguard Worker 		return (a + b - 1) / b;
35*3ac0a46fSAndroid Build Coastguard Worker 	}
36*3ac0a46fSAndroid Build Coastguard Worker }
37*3ac0a46fSAndroid Build Coastguard Worker 
BigUnsignedInABase(const BigUnsigned & x,Base base)38*3ac0a46fSAndroid Build Coastguard Worker BigUnsignedInABase::BigUnsignedInABase(const BigUnsigned &x, Base base) {
39*3ac0a46fSAndroid Build Coastguard Worker 	// Check the base
40*3ac0a46fSAndroid Build Coastguard Worker 	if (base < 2)
41*3ac0a46fSAndroid Build Coastguard Worker         abort();
42*3ac0a46fSAndroid Build Coastguard Worker 	this->base = base;
43*3ac0a46fSAndroid Build Coastguard Worker 
44*3ac0a46fSAndroid Build Coastguard Worker 	// Get an upper bound on how much space we need
45*3ac0a46fSAndroid Build Coastguard Worker 	int maxBitLenOfX = x.getLength() * BigUnsigned::N;
46*3ac0a46fSAndroid Build Coastguard Worker 	int minBitsPerDigit = bitLen(base) - 1;
47*3ac0a46fSAndroid Build Coastguard Worker 	int maxDigitLenOfX = ceilingDiv(maxBitLenOfX, minBitsPerDigit);
48*3ac0a46fSAndroid Build Coastguard Worker 	len = maxDigitLenOfX; // Another change to comply with `staying in bounds'.
49*3ac0a46fSAndroid Build Coastguard Worker 	allocate(len); // Get the space
50*3ac0a46fSAndroid Build Coastguard Worker 
51*3ac0a46fSAndroid Build Coastguard Worker 	BigUnsigned x2(x), buBase(base);
52*3ac0a46fSAndroid Build Coastguard Worker 	Index digitNum = 0;
53*3ac0a46fSAndroid Build Coastguard Worker 
54*3ac0a46fSAndroid Build Coastguard Worker 	while (!x2.isZero()) {
55*3ac0a46fSAndroid Build Coastguard Worker 		// Get last digit.  This is like `lastDigit = x2 % buBase, x2 /= buBase'.
56*3ac0a46fSAndroid Build Coastguard Worker 		BigUnsigned lastDigit(x2);
57*3ac0a46fSAndroid Build Coastguard Worker 		lastDigit.divideWithRemainder(buBase, x2);
58*3ac0a46fSAndroid Build Coastguard Worker 		// Save the digit.
59*3ac0a46fSAndroid Build Coastguard Worker 		blk[digitNum] = lastDigit.toUnsignedShort();
60*3ac0a46fSAndroid Build Coastguard Worker 		// Move on.  We can't run out of room: we figured it out above.
61*3ac0a46fSAndroid Build Coastguard Worker 		digitNum++;
62*3ac0a46fSAndroid Build Coastguard Worker 	}
63*3ac0a46fSAndroid Build Coastguard Worker 
64*3ac0a46fSAndroid Build Coastguard Worker 	// Save the actual length.
65*3ac0a46fSAndroid Build Coastguard Worker 	len = digitNum;
66*3ac0a46fSAndroid Build Coastguard Worker }
67*3ac0a46fSAndroid Build Coastguard Worker 
operator BigUnsigned() const68*3ac0a46fSAndroid Build Coastguard Worker BigUnsignedInABase::operator BigUnsigned() const {
69*3ac0a46fSAndroid Build Coastguard Worker 	BigUnsigned ans(0), buBase(base), temp;
70*3ac0a46fSAndroid Build Coastguard Worker 	Index digitNum = len;
71*3ac0a46fSAndroid Build Coastguard Worker 	while (digitNum > 0) {
72*3ac0a46fSAndroid Build Coastguard Worker 		digitNum--;
73*3ac0a46fSAndroid Build Coastguard Worker 		temp.multiply(ans, buBase);
74*3ac0a46fSAndroid Build Coastguard Worker 		ans.add(temp, BigUnsigned(blk[digitNum]));
75*3ac0a46fSAndroid Build Coastguard Worker 	}
76*3ac0a46fSAndroid Build Coastguard Worker 	return ans;
77*3ac0a46fSAndroid Build Coastguard Worker }
78*3ac0a46fSAndroid Build Coastguard Worker 
BigUnsignedInABase(const std::string & s,Base base)79*3ac0a46fSAndroid Build Coastguard Worker BigUnsignedInABase::BigUnsignedInABase(const std::string &s, Base base) {
80*3ac0a46fSAndroid Build Coastguard Worker 	// Check the base.
81*3ac0a46fSAndroid Build Coastguard Worker 	if (base > 36)
82*3ac0a46fSAndroid Build Coastguard Worker         abort();
83*3ac0a46fSAndroid Build Coastguard Worker 	// Save the base.
84*3ac0a46fSAndroid Build Coastguard Worker 	// This pattern is seldom seen in C++, but the analogous ``this.'' is common in Java.
85*3ac0a46fSAndroid Build Coastguard Worker 	this->base = base;
86*3ac0a46fSAndroid Build Coastguard Worker 
87*3ac0a46fSAndroid Build Coastguard Worker 	// `s.length()' is a `size_t', while `len' is a `NumberlikeArray::Index',
88*3ac0a46fSAndroid Build Coastguard Worker 	// also known as an `unsigned int'.  Some compilers warn without this cast.
89*3ac0a46fSAndroid Build Coastguard Worker 	len = Index(s.length());
90*3ac0a46fSAndroid Build Coastguard Worker 	allocate(len);
91*3ac0a46fSAndroid Build Coastguard Worker 
92*3ac0a46fSAndroid Build Coastguard Worker 	Index digitNum, symbolNumInString;
93*3ac0a46fSAndroid Build Coastguard Worker 	for (digitNum = 0; digitNum < len; digitNum++) {
94*3ac0a46fSAndroid Build Coastguard Worker 		symbolNumInString = len - 1 - digitNum;
95*3ac0a46fSAndroid Build Coastguard Worker 		char theSymbol = s[symbolNumInString];
96*3ac0a46fSAndroid Build Coastguard Worker 		if (theSymbol >= '0' && theSymbol <= '9')
97*3ac0a46fSAndroid Build Coastguard Worker 			blk[digitNum] = theSymbol - '0';
98*3ac0a46fSAndroid Build Coastguard Worker 		else if (theSymbol >= 'A' && theSymbol <= 'Z')
99*3ac0a46fSAndroid Build Coastguard Worker 			blk[digitNum] = theSymbol - 'A' + 10;
100*3ac0a46fSAndroid Build Coastguard Worker 		else if (theSymbol >= 'a' && theSymbol <= 'z')
101*3ac0a46fSAndroid Build Coastguard Worker 			blk[digitNum] = theSymbol - 'a' + 10;
102*3ac0a46fSAndroid Build Coastguard Worker 		else
103*3ac0a46fSAndroid Build Coastguard Worker             abort();
104*3ac0a46fSAndroid Build Coastguard Worker 
105*3ac0a46fSAndroid Build Coastguard Worker 		if (blk[digitNum] >= base)
106*3ac0a46fSAndroid Build Coastguard Worker             abort();
107*3ac0a46fSAndroid Build Coastguard Worker 	}
108*3ac0a46fSAndroid Build Coastguard Worker 	zapLeadingZeros();
109*3ac0a46fSAndroid Build Coastguard Worker }
110*3ac0a46fSAndroid Build Coastguard Worker 
operator std::string() const111*3ac0a46fSAndroid Build Coastguard Worker BigUnsignedInABase::operator std::string() const {
112*3ac0a46fSAndroid Build Coastguard Worker 	if (base > 36)
113*3ac0a46fSAndroid Build Coastguard Worker         abort();
114*3ac0a46fSAndroid Build Coastguard Worker 	if (len == 0)
115*3ac0a46fSAndroid Build Coastguard Worker 		return std::string("0");
116*3ac0a46fSAndroid Build Coastguard Worker 	// Some compilers don't have push_back, so use a char * buffer instead.
117*3ac0a46fSAndroid Build Coastguard Worker 	char *s = new char[len + 1];
118*3ac0a46fSAndroid Build Coastguard Worker 	s[len] = '\0';
119*3ac0a46fSAndroid Build Coastguard Worker 	Index digitNum, symbolNumInString;
120*3ac0a46fSAndroid Build Coastguard Worker 	for (symbolNumInString = 0; symbolNumInString < len; symbolNumInString++) {
121*3ac0a46fSAndroid Build Coastguard Worker 		digitNum = len - 1 - symbolNumInString;
122*3ac0a46fSAndroid Build Coastguard Worker 		Digit theDigit = blk[digitNum];
123*3ac0a46fSAndroid Build Coastguard Worker 		if (theDigit < 10)
124*3ac0a46fSAndroid Build Coastguard Worker 			s[symbolNumInString] = char('0' + theDigit);
125*3ac0a46fSAndroid Build Coastguard Worker 		else
126*3ac0a46fSAndroid Build Coastguard Worker 			s[symbolNumInString] = char('A' + theDigit - 10);
127*3ac0a46fSAndroid Build Coastguard Worker 	}
128*3ac0a46fSAndroid Build Coastguard Worker 	std::string s2(s);
129*3ac0a46fSAndroid Build Coastguard Worker 	delete [] s;
130*3ac0a46fSAndroid Build Coastguard Worker 	return s2;
131*3ac0a46fSAndroid Build Coastguard Worker }
132