1
0
Fork 0
Univerxel/src/core/net/io.hpp

175 lines
4.7 KiB
C++

#pragma once
#include "data.hpp"
#include "../data/mem.hpp"
namespace net {
//TODO: preallocate static data pool
/// Helper to write allocated packets
class PacketWriter final {
public:
PacketWriter(size_t size): buffer((uint8_t*)malloc(size), size), visible_size(size) { }
PacketWriter(uint8_t type, size_t data_size): PacketWriter(sizeof(type) + data_size) {
write(type);
}
PacketWriter(net::client_packet_type type, size_t data_size): PacketWriter((uint8_t)type, data_size) { }
PacketWriter(net::server_packet_type type, size_t data_size): PacketWriter((uint8_t)type, data_size) { }
~PacketWriter() {
if (buffer.ptr != nullptr)
free(buffer.ptr);
}
void write(const void* data, size_t len) {
buffer.write((uint8_t*)data, len);
}
template<typename D>
void write(const D& d) {
write(&d, sizeof(d));
}
constexpr size_t getCursor() const { return buffer.cur; }
void writeAt(size_t pos, const void* data, size_t len) {
assert(pos + len <= buffer.siz);
memcpy(buffer.ptr + pos, data, len);
}
template<typename D>
void writeAt(size_t pos, const D& d) {
writeAt(pos, &d, sizeof(d));
}
void reserve(size_t target) {
if (target >= buffer.siz - buffer.cur) {
const auto size = target + buffer.cur;
buffer.ptr = (uint8_t *)realloc(buffer.ptr, size);
buffer.siz = size;
}
}
void resize(size_t target) {
reserve(target);
visible_size = target;
}
void writePush(const void* data, size_t len) {
if (buffer.cur + len > buffer.siz)
resize(buffer.cur + len);
write(data, len);
}
template<typename D>
void writePush(const D& d) {
writePush(&d, sizeof(d));
}
struct varying_part {
varying_part(data::in_view &buffer, size_t& p_size): buffer(buffer), parent_size(p_size), visible_size(0) { }
~varying_part() {
buffer.cur += visible_size;
parent_size += visible_size;
}
data::in_view &buffer;
size_t &parent_size;
size_t visible_size;
constexpr size_t size() const { return visible_size; }
void* data() { return buffer.writeTo(0); }
void reserve(size_t target) {
if (target >= buffer.siz - buffer.cur) {
const auto size = target + buffer.cur;
buffer.ptr = (uint8_t *)realloc(buffer.ptr, size);
buffer.siz = size;
}
}
void resize(size_t target) {
reserve(target);
visible_size = target;
}
};
/// Only from resize, write, resize down
varying_part varying() {
return varying_part(buffer, visible_size);
}
bool isFull() const {
return buffer.cur >= visible_size;
}
[[nodiscard]]
data::out_buffer finish() {
assert(isFull());
data::out_buffer cpy(buffer.ptr, visible_size);
buffer.ptr = nullptr;
buffer.siz = 0;
return cpy;
}
[[nodiscard]]
static data::out_buffer Of(net::client_packet_type type, const void* data, size_t size) {
auto packet = PacketWriter(type, size);
packet.write(data, size);
return packet.finish();
}
[[nodiscard]]
static data::out_buffer Of(net::server_packet_type type, const void* data, size_t size) {
auto packet = PacketWriter(type, size);
packet.write(data, size);
return packet.finish();
}
template<typename D>
[[nodiscard]]
static data::out_buffer Of(net::client_packet_type type, const D& data) {
return Of(type, &data, sizeof(data));
}
template<typename D>
[[nodiscard]]
static data::out_buffer Of(net::server_packet_type type, const D& data) {
return Of(type, &data, sizeof(data));
}
private:
data::in_view buffer;
size_t visible_size;
};
/// Helper to read out_view
class PacketReader final {
public:
PacketReader(const data::out_view& buf): buffer(buf) { }
template<typename D>
const D* read() {
return buffer.cur + sizeof(D) <= buffer.size() ?
(const D*)buffer.readFrom(sizeof(D)) : nullptr;
}
template<typename D>
bool read(D& out) {
const auto ptr = read<D>();
if (ptr == nullptr)
return false;
out = *ptr;
return true;
}
bool skip(size_t size) {
buffer.readFrom(size);
return !isFull();
}
data::out_view readPart(size_t size) {
return data::out_view(buffer.readFrom(size), size);
}
data::out_view readAll() {
return readPart(buffer.size() - buffer.cur);
}
bool isFull() const {
return buffer.isDone();
}
private:
data::out_view buffer;
};
}