Last active
November 8, 2019 13:08
-
-
Save matovitch/757c29082c3b69f378c0e99f5b9609a1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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