blob: b3c38f372ec787593ad88057a8e1a618abf26c2b [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.phoenix.util;
/**
* Utility for converting a base 10 number to string that represents a base 62 number
*/
public class Base62Encoder {
// All possible chars for representing a number as a base 62 encoded String
public static final char[] digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
private static final char[] DigitTens = new char[3844];
private static final char[] DigitOnes = new char[3844];
static {
for (byte i = 0; i < 62; ++i) {
for (byte j = 0; j < 62; ++j) {
DigitTens[i * 62 + j] = digits[i];
DigitOnes[i * 62 + j] = digits[j];
}
}
}
final static long[] pow62 = { 62, 3844, 238328, 14776336, 916132832, 56800235584L, 3521614606208L,
218340105584896L, 13537086546263552L, 839299365868340224L };
/**
* Returns the length of the base 62 encoded string required to represent num
*
* @param num
* must be a positive number
*/
static int stringSize(long num) {
for (int i = 0; i < 10; i++) {
if (num < pow62[i])
return i + 1;
}
return 11;
}
/**
* Fills the given buffer with a string representing the given number in base 62. The characters are placed into the
* buffer backwards starting with the least significant digit and working backwards from there.
*
* @param num
* number to convert, should be > Long.MIN_VALUE
* @param size
* size of the buffer
* @param buf
* buffer to place encoded string
*/
static void getChars(long num, int size, char[] buf) {
long q;
int r;
int charPos = size;
char sign = 0;
if (num < 0) {
sign = '-';
num = -num;
}
// Get 2 digits per iteration using longs until quotient fits into an int
while (num > Integer.MAX_VALUE) {
q = num / 3844;
r = (int) (num - (q * 3844));
num = q;
buf[--charPos] = DigitOnes[r];
buf[--charPos] = DigitTens[r];
}
// Get 2 digits per iteration using ints
int q2;
int i2 = (int) num;
while (i2 >= 65536) {
q2 = i2 / 3844;
r = i2 - (q2 * 3844);
i2 = q2;
buf[--charPos] = DigitOnes[r];
buf[--charPos] = DigitTens[r];
}
// Fall through to fast mode for smaller numbers
// assert(i2 <= 65536, i2);
for (;;) {
// this evaluates to i2/62
// see "How to optimize for the Pentium family of microprocessors", Agner Fog, section 18.7
q2 = ((i2 + 1) * 33825) >>> (16 + 5);
r = i2 - (q2 * 62);
buf[--charPos] = digits[r];
i2 = q2;
if (i2 == 0)
break;
}
if (sign != 0) {
buf[--charPos] = sign;
}
}
/**
* Returns a String object representing the specified long encoded in base 62.
*
* @param num
* number to be converted
* @return a string representation of the number encoded in base 62
*/
public static String toString(long num) {
if (num == Long.MIN_VALUE)
return "-AzL8n0Y58m8";
int size = (num < 0) ? stringSize(-num) + 1 : stringSize(num);
char[] buf = new char[size];
getChars(num, size, buf);
return new String(buf);
}
}