#pragma once
#include <cassert>
#include <cstdint>
#include <memory>
#include <utility>
#include <vector>
namespace pdl::packet {
class slice {
public:
slice() = default;
slice(slice const&) = default;
slice(std::shared_ptr<const std::vector<uint8_t>> packet)
: packet_(std::move(packet)), offset_(0), size_(packet_->size()) {}
slice(std::shared_ptr<const std::vector<uint8_t>> packet, size_t offset,
size_t size)
: packet_(std::move(packet)), offset_(offset), size_(size) {}
slice subrange(size_t offset, size_t size) const {
assert((offset + size) <= size_);
return slice(packet_, offset_ + offset, size);
}
template <typename T, size_t N = sizeof(T)>
T read_le() {
static_assert(N <= sizeof(T));
assert(N <= size_);
T value = 0;
for (size_t n = 0; n < N; n++) {
value |= (T)at(n) << (8 * n);
}
skip(N);
return value;
}
template <typename T, size_t N = sizeof(T)>
T read_be() {
static_assert(N <= sizeof(T));
assert(N <= size_);
T value = 0;
for (size_t n = 0; n < N; n++) {
value = (value << 8) | (T)at(n);
}
skip(N);
return value;
}
uint8_t at(size_t offset) const {
assert(offset <= size_);
return packet_->at(offset_ + offset);
}
void skip(size_t size) {
assert(size <= size_);
offset_ += size;
size_ -= size;
}
void clear() { size_ = 0; }
size_t size() const { return size_; }
std::vector<uint8_t> bytes() const {
return std::vector<uint8_t>(packet_->cbegin() + offset_,
packet_->cbegin() + offset_ + size_);
}
bool operator==(slice const& other) const {
return size_ == other.size_ &&
std::equal(packet_->begin() + offset_,
packet_->begin() + offset_ + size_,
other.packet_->begin());
}
private:
std::shared_ptr<const std::vector<uint8_t>> packet_;
size_t offset_{0};
size_t size_{0};
};
class Builder {
public:
virtual ~Builder() = default;
virtual void Serialize(std::vector<uint8_t>&) const {}
virtual size_t GetSize() const { return 0; }
template <typename T, size_t N = sizeof(T)>
static void write_le(std::vector<uint8_t>& output, T value) {
static_assert(N <= sizeof(T));
for (size_t n = 0; n < N; n++) {
output.push_back(value >> (8 * n));
}
}
template <typename T, size_t N = sizeof(T)>
static void write_be(std::vector<uint8_t>& output, T value) {
static_assert(N <= sizeof(T));
for (size_t n = 0; n < N; n++) {
output.push_back(value >> (8 * (N - 1 - n)));
}
}
virtual std::vector<uint8_t> SerializeToBytes() const {
std::vector<uint8_t> output;
Serialize(output);
return output;
}
};
}