Skip to content

Instantly share code, notes, and snippets.

@matovitch
Last active November 8, 2019 13:08
Show Gist options
  • Save matovitch/757c29082c3b69f378c0e99f5b9609a1 to your computer and use it in GitHub Desktop.
Save matovitch/757c29082c3b69f378c0e99f5b9609a1 to your computer and use it in GitHub Desktop.
#include <algorithm>
#include <iostream>
#include <cstdint>
#include <vector>
#include <array>
constexpr int log2(int x)
{
return x < 2 ? x : 1 + log2(x >> 1);
}
enum class Endianness
{
LITTLE,
BIG
};
template <Endianness ENDIANNESS,
class TypeSize,
class TypeTag>
class TNode
{
public:
TNode(const TypeTag tag,
uint8_t* head,
const uint8_t* const tail) :
_head{head},
_tail{tail}
{
write(tag);
write(static_cast<TypeSize>(_head - tail - sizeof(TypeSize) + 1));
}
template <class Type>
void write(const Type value)
{
if constexpr (sizeof(Type) == 1)
{
put(*(reinterpret_cast<const uint8_t*>(&value)));
}
if constexpr (sizeof(Type) == 2)
{
put(*(reinterpret_cast<const uint16_t*>(&value)));
}
if constexpr (sizeof(Type) == 4)
{
put(*(reinterpret_cast<const uint32_t*>(&value)));
}
if constexpr (sizeof(Type) == 8)
{
put(*(reinterpret_cast<const uint64_t*>(&value)));
}
}
void put(const uint8_t u8)
{
*_head = u8;
advance();
}
void put(const uint16_t u16)
{
if constexpr (ENDIANNESS == Endianness::LITTLE)
{
*_head = ((u16 << 8) >> 8);
advance();
*_head = (u16 >> 8);
advance();
}
if constexpr (ENDIANNESS == Endianness::BIG)
{
*_head = (u16 >> 8);
advance();
*_head = ((u16 << 8) >> 8);
advance();
}
}
void put(const uint32_t u32)
{
if constexpr (ENDIANNESS == Endianness::LITTLE)
{
*_head = ((u32 & (static_cast<uint32_t>(0xff) << 0)) >> 0);
advance();
*_head = ((u32 & (static_cast<uint32_t>(0xff) << 8)) >> 8);
advance();
*_head = ((u32 & (static_cast<uint32_t>(0xff) << 16)) >> 16);
advance();
*_head = ((u32 & (static_cast<uint32_t>(0xff) << 24)) >> 24);
advance();
}
if constexpr (ENDIANNESS == Endianness::BIG)
{
*_head = ((u32 & (static_cast<uint32_t>(0xff) << 24)) >> 24);
advance();
*_head = ((u32 & (static_cast<uint32_t>(0xff) << 16)) >> 16);
advance();
*_head = ((u32 & (static_cast<uint32_t>(0xff) << 8)) >> 8);
advance();
*_head = ((u32 & (static_cast<uint32_t>(0xff) << 0)) >> 0);
advance();
}
}
void put(const uint64_t u64)
{
if constexpr (ENDIANNESS == Endianness::LITTLE)
{
*_head = ((u64 & (static_cast<uint64_t>(0xff) << 0)) >> 0);
advance();
*_head = ((u64 & (static_cast<uint64_t>(0xff) << 8)) >> 8);
advance();
*_head = ((u64 & (static_cast<uint64_t>(0xff) << 16)) >> 16);
advance();
*_head = ((u64 & (static_cast<uint64_t>(0xff) << 24)) >> 24);
advance();
*_head = ((u64 & (static_cast<uint64_t>(0xff) << 32)) >> 32);
advance();
*_head = ((u64 & (static_cast<uint64_t>(0xff) << 40)) >> 40);
advance();
*_head = ((u64 & (static_cast<uint64_t>(0xff) << 48)) >> 48);
advance();
*_head = ((u64 & (static_cast<uint64_t>(0xff) << 56)) >> 56);
advance();
}
if constexpr (ENDIANNESS == Endianness::BIG)
{
*_head = ((u64 & (static_cast<uint64_t>(0xff) << 56)) >> 56);
advance();
*_head = ((u64 & (static_cast<uint64_t>(0xff) << 48)) >> 48);
advance();
*_head = ((u64 & (static_cast<uint64_t>(0xff) << 40)) >> 40);
advance();
*_head = ((u64 & (static_cast<uint64_t>(0xff) << 32)) >> 32);
advance();
*_head = ((u64 & (static_cast<uint64_t>(0xff) << 24)) >> 24);
advance();
*_head = ((u64 & (static_cast<uint64_t>(0xff) << 16)) >> 16);
advance();
*_head = ((u64 & (static_cast<uint64_t>(0xff) << 8)) >> 8);
advance();
*_head = ((u64 & (static_cast<uint64_t>(0xff) << 0)) >> 0);
advance();
}
}
private:
void advance()
{
if (_head > _tail)
{
_head--;
}
}
uint8_t* _head;
const uint8_t* const _tail;
};
template <Endianness ENDIANNESS,
class TypeTag,
class TypeSize>
class TTree
{
using Node = TNode<ENDIANNESS, TypeSize,
TypeTag>;
public:
static constexpr auto HEADER_SIZE = sizeof(TypeSize) +
sizeof(TypeTag);
TTree(std::vector<uint8_t>& buffer) : _buffer{buffer} {}
uint64_t size() const
{
return _buffer.size();
}
Node makeLeaf(const TypeTag tag, const uint64_t size)
{
_buffer.resize(_buffer.size() + size + HEADER_SIZE);
return Node{tag,
_buffer.data() + _buffer.size() - 1,
_buffer.data() + _buffer.size() - size - HEADER_SIZE};
}
void makeNode(const TypeTag tag, const uint64_t size)
{
makeLeaf(tag, 0);
TypeSize* head = reinterpret_cast<TypeSize*>(_buffer.data() +
_buffer.size() - HEADER_SIZE);
*head = this->size() - size - HEADER_SIZE;
}
void close(const TypeTag tag, const uint64_t size)
{
makeNode(tag, size);
_buffer.push_back(((size == 0 ) << 5) |
(static_cast<int>(ENDIANNESS ) << 4) |
(log2(sizeof(TypeSize) ) << 2) |
(log2(sizeof(TypeTag) ) << 0));
}
void write(uint8_t* dest) const
{
std::reverse_copy(_buffer.data(),
_buffer.data() + _buffer.size(),
dest);
}
private:
std::vector<uint8_t>& _buffer;
};
template <class Tree>
void write(const Tree& tree, uint8_t* dest)
{
std::reverse_copy(tree.buffer().data(),
tree.buffer().data() + tree.buffer().size(),
dest);
}
int main()
{
using Tree1 = TTree<Endianness::BIG, uint8_t , uint8_t >;
using Tree2 = TTree<Endianness::BIG, uint16_t , uint16_t >;
std::vector<uint8_t> srce;
std::vector<uint8_t> dest;
Tree1 tree1{srce};
auto size1 = tree1.size();
auto node1 = tree1.makeLeaf(0xbb, 6);
node1.write(0.5f);
//node1.write<uint32_t>(0xcececece);
node1.write<uint16_t>(0xafaf);
auto node2 = tree1.makeLeaf(0xdd, 6);
node2.write<uint32_t>(0xdbdbdbdb);
node2.write<uint16_t>(0xeded);
//tree1.makeNode(0xff, 2);
tree1.close(0xff, size1);
Tree2 tree2{srce};
auto size2 = tree2.size();
auto node3 = tree2.makeLeaf(0xdd, 6);
node3.write<uint32_t>(0xdbdbdbdb);
node3.write<uint16_t>(0xeded);
tree2.close(0xff, size2);
dest.resize(tree2.size());
tree2.write(dest.data());
for (const auto byte : dest)
{
std::cout << byte;
}
/*std::array<uint8_t, 8> memory;
TNode<Endianness::LITTLE, uint8_t, uint8_t> node{0xbe, memory.data() + memory.size() - 1,
memory.data()};
node.write<uint32_t>(0x12abcdef);
node.write<uint16_t>(0x4321);
for (const auto byte : memory)
{
std::cout << byte;
}
return 0;*/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment