#pragma once #include <algorithm> #include <array> #include <ostream> #include <sstream> namespace rmrf::net { template<std::size_t pkg_size = 1024> class udp_packet { typedef const uint8_t& const_reference; typedef uint8_t* iterator; private: std::array<uint8_t, pkg_size> arr; size_t actual_length; public: udp_packet() : arr{}, actual_length(0) { } inline constexpr size_t max_size() const { return arr.max_size(); } inline size_t size() const { return actual_length; } inline size_t length() const { return actual_length; } inline constexpr uint8_t at(size_t pos) const { return arr.at(pos); } inline constexpr const_reference operator[](size_t pos) const noexcept { return arr.operator[](pos); } inline uint8_t& operator[](size_t pos) noexcept { return arr.operator[](pos); } inline bool advance(size_t i) { if (this->actual_length + i > this->max_size()) { return false; } this->actual_length += i; return true; } inline size_t append(const iterator begin, const iterator end) { const auto remaining_length = pkg_size - this->length(); size_t i = 0; for (; i < remaining_length && begin + i < end; i++) { this->arr[this->length() + i] = begin[i]; } this->advance(i); return i; } constexpr const uint8_t* raw() const noexcept { return this->arr.data(); } constexpr uint8_t* raw() noexcept { return this->arr.data(); } constexpr std::array<uint8_t, pkg_size>::iterator begin() noexcept { return this->arr.begin(); } constexpr std::array<uint8_t, pkg_size>::iterator end() noexcept { return this->arr.end(); } constexpr std::array<uint8_t, pkg_size>::const_iterator cbegin() const noexcept { return this->arr.cbegin(); } constexpr std::array<uint8_t, pkg_size>::const_iterator cend() const noexcept { return this->arr.cend(); } udp_packet<pkg_size>& operator<<(const std::string& obj) { const auto max_space = pkg_size - this->length(); const auto str_length = obj.length(); strncpy((char*) (this->raw() + this->length()), obj.c_str(), max_space); this->advance(std::min(str_length, max_space)); return *this; } template<class T> udp_packet<pkg_size>& operator<<(const T& obj) { const auto size_to_copy = obj.end() - obj.begin(); if (auto error = memcpy_s(this->raw() + this->length(), pkg_size - this->length(), obj.begin(), size_to_copy); error != 0) { std::stringstream ss; ss << "Unable to concat object. Errorcode: " << error << ". Is the memory structure too large for this packet?"; throw std::invalid_argument(ss.str()); } this->advance(size_to_copy); return *this; } }; } inline std::ostream& operator<<(std::ostream& os, const rmrf::net::udp_packet<>& obj) { return os << "[UDP-Packet with size " << obj.size() << ']'; }