#include <cstring>
#include <cstdint>
#include <vector>
namespace bond
{
template<typename STRLEN_TYPE = std::uint32_t>
class reader
{
unsigned char const * first;
unsigned char const * last;
unsigned char const * it;
public:
reader() noexcept
{
first = nullptr;
last = nullptr;
it = nullptr;
}
reader(void const * data, std::size_t len) noexcept
{
set(data, len);
}
void set(void const * data, std::size_t len) noexcept
{
first = static_cast<unsigned char const *>(data);
last = static_cast<unsigned char const *>(data) + len;
it = static_cast<unsigned char const *>(data);
}
std::size_t remain() noexcept
{
return static_cast<std::size_t>(last - it);
}
template<typename T>
bool read(T * output) noexcept
{
if (remain() < sizeof(*output))
return false;
std::memcpy(output, it, sizeof(*output));
it += sizeof(*output);
return true;
}
bool read(void * output, std::size_t len) noexcept
{
if (remain() < len)
return false;
std::memcpy(output, it, len);
it += len;
return true;
}
bool next_strlen(STRLEN_TYPE * output) noexcept
{
STRLEN_TYPE len;
std::size_t remain_size = remain();
if (remain_size < sizeof(len))
return false;
std::memcpy(&len, it, sizeof(len));
if (remain_size < sizeof(len) + len)
return false;
*output = len;
return true;
}
bool read_str(char * output, STRLEN_TYPE len) noexcept
{
STRLEN_TYPE slen;
if (!next_strlen(&slen))
return false;
if (len <= slen)
return false;
unsigned char const * data = it + sizeof(slen);
std::memcpy(output, data, slen);
output[slen] = '\0';
it = data + slen;
return true;
}
};
template<typename STRLEN_TYPE = std::uint32_t>
class writer
{
unsigned char * first;
unsigned char * last;
unsigned char * it;
public:
writer() noexcept
{
first = nullptr;
last = nullptr;
it = nullptr;
}
writer(void * data, std::size_t len) noexcept
{
set(data, len);
}
void set(void * data, std::size_t len) noexcept
{
first = static_cast<unsigned char *>(data);
last = static_cast<unsigned char *>(data) + len;
it = static_cast<unsigned char *>(data);
}
void * data() noexcept
{
return first;
}
std::size_t size() noexcept
{
return static_cast<std::size_t>(it - first);
}
std::size_t remain() noexcept
{
return static_cast<std::size_t>(last - it);
}
template<typename T>
bool write(T const & input) noexcept
{
if (remain() < sizeof(input))
return false;
unsigned char * data = it;
std::memcpy(data, &input, sizeof(input));
it = data + sizeof(input);
return true;
}
bool write(void const * input, std::size_t len) noexcept
{
if (remain() < len)
return false;
unsigned char * data = it;
std::memcpy(data, input, len);
it = data + len;
return true;
}
bool write_str(char const * input) noexcept
{
STRLEN_TYPE slen = static_cast<STRLEN_TYPE>(std::strlen(input));
std::size_t len = sizeof(slen) + slen;
if (remain() < len)
return false;
unsigned char * data = it;
std::memcpy(&data[0], &slen, sizeof(slen));
std::memcpy(&data[sizeof(slen)], input, slen);
it = data + len;
return true;
}
};
template<typename STRLEN_TYPE = std::uint32_t>
class dynamic_writer
{
std::vector<unsigned char> block;
public:
dynamic_writer()
{
}
dynamic_writer(std::size_t capacity)
{
block.reserve(capacity);
}
void * data() noexcept
{
return block.data();
}
std::size_t size() noexcept
{
return block.size();
}
std::size_t remain() noexcept
{
return block.capacity() - block.size();
}
template<typename T>
void write(T const & input)
{
block.insert(block.end(),
reinterpret_cast<unsigned char const *>(&input),
reinterpret_cast<unsigned char const *>(&input) + sizeof(input));
}
void write(void const * input, std::size_t len)
{
block.insert(block.end(),
reinterpret_cast<unsigned char const *>(input),
reinterpret_cast<unsigned char const *>(input) + len);
}
void write_str(char const * input)
{
STRLEN_TYPE slen = static_cast<STRLEN_TYPE>(std::strlen(input));
block.insert(block.end(),
reinterpret_cast<unsigned char const *>(&slen),
reinterpret_cast<unsigned char const *>(&slen) + sizeof(slen));
block.insert(block.end(),
reinterpret_cast<unsigned char const *>(input),
reinterpret_cast<unsigned char const *>(input) + slen);
}
};
}