用处巨大,自行领悟。
#include <iostream>
#include <cstdint>
#include <string>
#include <vector>
#include <Windows.h>
using namespace std;
/* 96 printable characters(include tab) */
/* remove \ for compatibility */
/* remove tab for uniformity */
/* luckly, 11/9 > log(256)/log(94) */
enum
{
BASE94_SYMBOL_COUNT = 94,
BASE94_INPUT_BLOCK_SIZE = 9,
BASE94_OUTPUT_BLOCK_SIZE = 11,
};
static constexpr void base94_decimalToBase94(uint64_t num, uint64_t base94[10], int& base94_size)
{
uint64_t n = num;
base94_size = 0;
do {
n /= 94;
base94_size++;
} while (n > 0);
int k = 0;
n = num;
do {
uint64_t c = (n % 94) + 0x20;
n /= 94;
base94[base94_size - ++k] = c;
} while (n > 0);
}
static constexpr uint64_t base94_base94ToDecimal(uint8_t*& p, int size)
{
uint64_t n = 0;
for (uint8_t* k = p + size; p != k; )
{
uint8_t v = (*p++ - 0x20);
n = n * 94 + v;
}
return n;
}
template <typename T>
static constexpr void base94_decimalToBase94(std::vector<uint8_t>& bytes, uint8_t*& p, int mode)
{
uint64_t base94[BASE94_OUTPUT_BLOCK_SIZE];
int base94_size;
base94_decimalToBase94(*(T*)p, base94, base94_size);
p += sizeof(T);
uint8_t h = base94_size | mode << 4;
h += 0x20;
bytes.push_back(h);
for (int i = 0; i < base94_size; i++)
{
uint64_t v = base94[i];
bytes.push_back(v);
}
}
template <typename T>
static constexpr bool base94_base94ToDecimal(std::vector<uint8_t>& bytes, uint8_t*& p)
{
uint8_t n1 = (*p++) - 0x20;
if (n1 < 1)
{
return false;
}
uint8_t n2 = n1 >> 4;
if (n2 < 1 || n2 > 4)
{
return false;
}
else
{
n1 = n1 & 0x0f;
n2 = 1 << (n2 - 1);
}
if (n1 > BASE94_OUTPUT_BLOCK_SIZE)
{
return false;
}
T v = base94_base94ToDecimal(p, n1);
uint8_t* b = (uint8_t*)&v;
for (int k = 0; k < n2; k++)
{
uint8_t v = b[k];
bytes.push_back(v);
}
return true;
}
bool base94_encode(const void* data, int data_size, std::vector<uint8_t>& bytes, int& bytes_size)
{
uint8_t* stream = (uint8_t*)data;
bytes_size = data_size * ceil((double)BASE94_OUTPUT_BLOCK_SIZE / (double)BASE94_INPUT_BLOCK_SIZE) + 1;
bytes.reserve(bytes_size);
int stream_size = data_size >> 3;
data_size %= sizeof(uint64_t);
for (int i = 0; i < stream_size; i++)
{
base94_decimalToBase94<uint64_t>(bytes, stream, 4);
}
stream_size = data_size >> 2;
data_size %= sizeof(uint32_t);
for (int i = 0; i < stream_size; i++)
{
base94_decimalToBase94<uint32_t>(bytes, stream, 3);
}
stream_size = data_size >> 1;
data_size %= sizeof(uint16_t);
for (int i = 0; i < stream_size; i++)
{
base94_decimalToBase94<uint16_t>(bytes, stream, 2);
}
stream_size = data_size;
data_size = 0;
for (int i = 0; i < stream_size; i++)
{
base94_decimalToBase94<uint8_t>(bytes, stream, 1);
}
bytes_size = bytes.size();
return true;
}
bool base94_decode(const void* data, int data_size, std::vector<uint8_t>& bytes, int& bytes_size)
{
uint8_t* stream = (uint8_t*)data;
bytes_size = data_size * ceil((double)BASE94_INPUT_BLOCK_SIZE / (double)BASE94_OUTPUT_BLOCK_SIZE) + 1;
bytes.reserve(bytes_size);
int stream_size = data_size >> 3;
data_size %= sizeof(uint64_t);
for (int i = 0; i < stream_size; i++)
{
if (!base94_base94ToDecimal<uint64_t>(bytes, stream))
{
return false;
}
}
stream_size = data_size >> 2;
data_size %= sizeof(uint32_t);
for (int i = 0; i < stream_size; i++)
{
if (!base94_base94ToDecimal<uint32_t>(bytes, stream))
{
return false;
}
}
stream_size = data_size >> 1;
data_size %= sizeof(uint16_t);
for (int i = 0; i < stream_size; i++)
{
if (!base94_base94ToDecimal<uint16_t>(bytes, stream))
{
return false;
}
}
stream_size = data_size;
data_size = 0;
for (int i = 0; i < stream_size; i++)
{
if (!base94_base94ToDecimal<uint8_t>(bytes, stream))
{
return false;
}
}
bytes_size = bytes.size();
return true;
}
int main() {
uint8_t messages[] = "您好!";
uint64_t last = GetTickCount64();
for (int i = 0; i < 100000; i++)
{
int bytes_size;
std::vector<uint8_t> bytes;
base94_encode(messages, sizeof(messages), bytes, bytes_size);
int output_size;
std::vector<uint8_t> output;
base94_decode(bytes.data(), bytes_size, output, output_size);
}
uint64_t diff = GetTickCount64() - last;
printf("tick: %llu\n", diff);
system("pause");
return 0;
}