Introduction
I often have to encode positive integer IDs into text to send over a socket, and like to keep the messages as short as possible and the encoding / decoding as fast as possible. Using C#, it's easy to send your integer ID as base 10 or base 16 strings, but using base 64 or base 62 or base 36 or base 32 encoded strings saves a lot of space. There is another article on this site encoding and decoding base 36 integers, but it uses Math.Pow
, which is very slow.
By choosing Base 64 (made from 0-9, A-Z, a-z, +, -) which fits perfectly into 6 bits, I can encode and decode very quickly. I can also fit a nine or ten digit base 10 Int32
into a five character base 64 string.
In fact, this app shows that C#'s Convert.ToInt32
followed by Convert.ToString
is 5½ times slower than using my base 64 encoding functions!
The code is very simple, and easily modified to Int64
or passing a char[]
with offset, which is useful for socket stuff. For the encode, you choose the number of characters to encode into. One character gives you 0-63, of course, two is 4096, three 262,144 etc.
It would be easy to translate to C or C++ as well. If you download the app, you can see some demonstrations and a speed test using the high performance timer. But otherwise, all the code you need is here:
using System;
using System.Collections.Generic;
using System.Text;
class Base64
{
static char[] b64e = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z',
'+', '/'};
static int[] b64d = new int[] { 000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,
000,000,000,062,000,000,000,063,000,001,
002,003,004,005,006,007,008,009,000,000,
000,000,000,000,000,010,011,012,013,014,
015,016,017,018,019,020,021,022,023,024,
025,026,027,028,029,030,031,032,033,034,
035,000,000,000,000,000,000,036,037,038,
039,040,041,042,043,044,045,046,047,048,
049,050,051,052,053,054,055,056,057,058,
059,060,061,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000};
public static string b64ConvertInt(int value, int length)
{
if (length == 5)
{
char[] c = new char[5];
c[0] = b64e[(value & 1056964608) >> 24];
c[1] = b64e[(value & 16515072) >> 18];
c[2] = b64e[(value & 258048) >> 12];
c[3] = b64e[(value & 4032) >> 06];
c[4] = b64e[(value & 63)];
return new string(c);
}
else if (length == 4)
{
char[] c = new char[4];
c[0] = b64e[(value & 16515072) >> 18];
c[1] = b64e[(value & 258048) >> 12];
c[2] = b64e[(value & 4032) >> 06];
c[3] = b64e[(value & 63)];
return new string(c);
}
else if (length == 3)
{
char[] c = new char[3];
c[0] = b64e[(value & 258048) >> 12];
c[1] = b64e[(value & 4032) >> 06];
c[2] = b64e[(value & 63)];
return new string(c);
}
else if (length == 2)
{
char[] c = new char[2];
c[0] = b64e[(value & 4032) >> 06];
c[1] = b64e[(value & 63)];
return new string(c);
}
else
{
return Convert.ToString(b64e[(value & 63)]);
}
}
public static int b64ConvertString(string s)
{
int n = s.Length;
char[] c = s.ToCharArray();
if (n == 5)
{
return (b64d[c[0]] << 24) + (b64d[c[1]] << 18) +
(b64d[c[2]] << 12) + (b64d[c[3]] << 6) + b64d[c[4]];
}
else if (n == 4)
{
return (b64d[c[0]] << 18) + (b64d[c[1]] << 12) +
(b64d[c[2]] << 6) + b64d[c[3]];
}
else if (n == 3)
{
return (b64d[c[0]] << 12) + (b64d[c[1]] << 6) + b64d[c[2]];
}
else if (n == 2)
{
return (b64d[c[0]] << 6) + b64d[c[1]];
}
else if (n == 1)
{
return b64d[c[0]];
}
return 0;
}
}