Skip to content

Instantly share code, notes, and snippets.

@zpalmtree
Created July 10, 2018 02:13
Show Gist options
  • Save zpalmtree/bcc7800c249cf3dca5b0f9cad4687586 to your computer and use it in GitHub Desktop.
Save zpalmtree/bcc7800c249cf3dca5b0f9cad4687586 to your computer and use it in GitHub Desktop.
#include <iostream>
#include <vector>
const uint8_t PORTABLE_RAW_SIZE_MARK_MASK = 0x03;
const uint8_t PORTABLE_RAW_SIZE_MARK_BYTE = 0;
const uint8_t PORTABLE_RAW_SIZE_MARK_WORD = 1;
const uint8_t PORTABLE_RAW_SIZE_MARK_DWORD = 2;
const uint8_t PORTABLE_RAW_SIZE_MARK_INT64 = 3;
template<class T>
std::vector<uint8_t> packVarint(uint8_t type_or, size_t pv) {
T v = static_cast<T>(pv << 2);
v |= type_or;
std::vector<uint8_t> ret;
void * mem;
mem = &v;
for (int i = 0; i < sizeof(T); i++)
{
ret.emplace_back(((char*)mem)[i]);
}
return ret;
}
std::vector<uint8_t> writeArraySize(size_t val) {
if (val <= 63) {
return packVarint<uint8_t>(PORTABLE_RAW_SIZE_MARK_BYTE, val);
} else if (val <= 16383) {
return packVarint<uint16_t>(PORTABLE_RAW_SIZE_MARK_WORD, val);
} else if (val <= 1073741823) {
return packVarint<uint32_t>(PORTABLE_RAW_SIZE_MARK_DWORD, val);
} else {
if (val > 4611686018427387903) {
throw std::runtime_error("failed to pack varint - too big amount");
}
return packVarint<uint64_t>(PORTABLE_RAW_SIZE_MARK_INT64, val);
}
}
size_t readVarint(std::vector<uint8_t> input) {
int vecPos = 0;
uint8_t b = input[vecPos];
vecPos++;
uint8_t size_mask = b & PORTABLE_RAW_SIZE_MARK_MASK;
size_t bytesLeft = 0;
switch (size_mask){
case PORTABLE_RAW_SIZE_MARK_BYTE:
bytesLeft = 0;
break;
case PORTABLE_RAW_SIZE_MARK_WORD:
bytesLeft = 1;
break;
case PORTABLE_RAW_SIZE_MARK_DWORD:
bytesLeft = 3;
break;
case PORTABLE_RAW_SIZE_MARK_INT64:
bytesLeft = 7;
break;
}
size_t value = b;
std::cout << "Bytes left: " << bytesLeft << std::endl;
for (size_t i = 1; i <= bytesLeft; ++i) {
size_t n = input[vecPos];
vecPos++;
value |= n << (i * 8);
}
value >>= 2;
return value;
}
std::string uint8_vector_to_hex_string(const std::vector<uint8_t>& v)
{
std::string result;
result.reserve(v.size() * 2); // two digits per character
static constexpr char hex[] = "0123456789ABCDEF";
for (uint8_t c : v)
{
result.push_back(hex[c / 16]);
result.push_back(hex[c % 16]);
}
return result;
}
int main()
{
while (true)
{
std::cout << "Enter int: " << std::flush;
std::string input;
std::getline(std::cin, input);
if (input == "exit")
{
return 0;
}
try
{
size_t val = static_cast<size_t>(std::stol(input));
std::vector<uint8_t> result = writeArraySize(val);
std::string encoded = uint8_vector_to_hex_string(result);
size_t decoded = readVarint(result);
std::cout << "Input: " << std::to_string(val) << std::endl;
std::cout << "Encoded: " << encoded << std::endl;
std::cout << "Decoded: " << std::to_string(decoded) << std::endl;
if (val != decoded)
{
std::cout << "ayo hol up" << std::endl;
}
std::cout << std::endl;
}
catch (const std::invalid_argument &)
{
std::cout << "fuck off mate" << std::endl;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment