2026-04-19 17:28:44 -07:00
|
|
|
#pragma once
|
|
|
|
|
#include <cstddef>
|
|
|
|
|
#include <cstdint>
|
|
|
|
|
#include <cstring>
|
|
|
|
|
#include <span>
|
|
|
|
|
|
2026-05-01 10:47:08 -07:00
|
|
|
// Buffer that grows in both directions from a midpoint. Payload is appended at
|
|
|
|
|
// the back; each protocol layer then prepends its header in reverse order
|
|
|
|
|
// (UDP, then IPv4, then Ethernet) without moving payload bytes. Lets the
|
|
|
|
|
// network stack build outbound frames bottom-up with no copies or scratch.
|
2026-04-19 17:28:44 -07:00
|
|
|
template <size_t N>
|
|
|
|
|
class prepend_buffer {
|
|
|
|
|
uint8_t m_buf[N];
|
|
|
|
|
size_t m_start = N / 2;
|
|
|
|
|
size_t m_end = N / 2;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
template <typename T>
|
|
|
|
|
T* prepend() {
|
|
|
|
|
m_start -= sizeof(T);
|
|
|
|
|
return reinterpret_cast<T*>(m_buf + m_start);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t* append(size_t len) {
|
|
|
|
|
uint8_t* p = m_buf + m_end;
|
|
|
|
|
m_end += len;
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void append_copy(std::span<const uint8_t> data) {
|
|
|
|
|
memcpy(append(data.size()), data.data(), data.size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t* payload_ptr() { return m_buf + m_end; }
|
|
|
|
|
|
|
|
|
|
uint8_t* data() { return m_buf + m_start; }
|
|
|
|
|
const uint8_t* data() const { return m_buf + m_start; }
|
|
|
|
|
size_t size() const { return m_end - m_start; }
|
|
|
|
|
|
|
|
|
|
std::span<const uint8_t> span() const { return {data(), size()}; }
|
|
|
|
|
};
|