You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
354 lines
12 KiB
354 lines
12 KiB
#ifndef MONOFORMAT_PARSEHELPERS_HPP
|
|
#define MONOFORMAT_PARSEHELPERS_HPP
|
|
|
|
#include <cstdint>
|
|
#include <cstddef>
|
|
#include <expected>
|
|
#include <span>
|
|
#include <tuple> // for std::ignore
|
|
|
|
namespace monoformat {
|
|
|
|
enum class ParseError {
|
|
BufferSizeMismatch = 1,
|
|
InvalidValue = 2,
|
|
};
|
|
|
|
inline std::expected<std::uint8_t, ParseError> peekU8LE(std::span<std::byte const> buffer) {
|
|
if (buffer.size() < 1) {
|
|
return std::unexpected(ParseError::BufferSizeMismatch);
|
|
}
|
|
return static_cast<std::uint8_t>(buffer[0]);
|
|
}
|
|
|
|
inline std::expected<std::uint8_t, ParseError> readU8LE(std::span<std::byte const>& buffer) {
|
|
auto result = peekU8LE(buffer);
|
|
if (result) {
|
|
buffer = buffer.subspan(1);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline std::expected<std::uint8_t, ParseError> peekU8BE(std::span<std::byte const> buffer) {
|
|
if (buffer.size() < 1) {
|
|
return std::unexpected(ParseError::BufferSizeMismatch);
|
|
}
|
|
return static_cast<std::uint8_t>(buffer[0]);
|
|
}
|
|
|
|
inline std::expected<std::uint8_t, ParseError> readU8BE(std::span<std::byte const>& buffer) {
|
|
auto result = peekU8BE(buffer);
|
|
if (result) {
|
|
buffer = buffer.subspan(1);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline std::expected<std::uint16_t, ParseError> peekU16LE(std::span<std::byte const> buffer) {
|
|
if (buffer.size() < 2) {
|
|
return std::unexpected(ParseError::BufferSizeMismatch);
|
|
}
|
|
return (static_cast<std::uint16_t>(buffer[0]) << 0u)
|
|
| (static_cast<std::uint16_t>(buffer[1]) << 8u);
|
|
}
|
|
|
|
inline std::expected<std::uint16_t, ParseError> readU16LE(std::span<std::byte const>& buffer) {
|
|
auto result = peekU16LE(buffer);
|
|
if (result) {
|
|
buffer = buffer.subspan(2);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline std::expected<std::uint16_t, ParseError> peekU16BE(std::span<std::byte const> buffer) {
|
|
if (buffer.size() < 2) {
|
|
return std::unexpected(ParseError::BufferSizeMismatch);
|
|
}
|
|
return (static_cast<std::uint16_t>(buffer[1]) << 0u)
|
|
| (static_cast<std::uint16_t>(buffer[0]) << 8u);
|
|
}
|
|
|
|
inline std::expected<std::uint16_t, ParseError> readU16BE(std::span<std::byte const>& buffer) {
|
|
auto result = peekU16BE(buffer);
|
|
if (result) {
|
|
buffer = buffer.subspan(2);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline std::expected<std::uint32_t, ParseError> peekU24LE(std::span<std::byte const> buffer) {
|
|
if (buffer.size() < 3) {
|
|
return std::unexpected(ParseError::BufferSizeMismatch);
|
|
}
|
|
return (static_cast<std::uint32_t>(buffer[0]) << 0u)
|
|
| (static_cast<std::uint32_t>(buffer[1]) << 8u)
|
|
| (static_cast<std::uint32_t>(buffer[2]) << 16u);
|
|
}
|
|
|
|
inline std::expected<std::uint32_t, ParseError> readU24LE(std::span<std::byte const>& buffer) {
|
|
auto result = peekU24LE(buffer);
|
|
if (result) {
|
|
buffer = buffer.subspan(3);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline std::expected<std::uint32_t, ParseError> peekU24BE(std::span<std::byte const> buffer) {
|
|
if (buffer.size() < 3) {
|
|
return std::unexpected(ParseError::BufferSizeMismatch);
|
|
}
|
|
return (static_cast<std::uint32_t>(buffer[2]) << 0u)
|
|
| (static_cast<std::uint32_t>(buffer[1]) << 8u)
|
|
| (static_cast<std::uint32_t>(buffer[0]) << 16u);
|
|
}
|
|
|
|
inline std::expected<std::uint32_t, ParseError> readU24BE(std::span<std::byte const>& buffer) {
|
|
auto result = peekU24BE(buffer);
|
|
if (result) {
|
|
buffer = buffer.subspan(3);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline std::expected<std::uint32_t, ParseError> peekU32LE(std::span<std::byte const> buffer) {
|
|
if (buffer.size() < 4) {
|
|
return std::unexpected(ParseError::BufferSizeMismatch);
|
|
}
|
|
return (static_cast<std::uint32_t>(buffer[0]) << 0u)
|
|
| (static_cast<std::uint32_t>(buffer[1]) << 8u)
|
|
| (static_cast<std::uint32_t>(buffer[2]) << 16u)
|
|
| (static_cast<std::uint32_t>(buffer[3]) << 24u);
|
|
}
|
|
|
|
inline std::expected<std::uint32_t, ParseError> readU32LE(std::span<std::byte const>& buffer) {
|
|
auto result = peekU32LE(buffer);
|
|
if (result) {
|
|
buffer = buffer.subspan(4);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline std::expected<std::uint32_t, ParseError> peekU32BE(std::span<std::byte const> buffer) {
|
|
if (buffer.size() < 4) {
|
|
return std::unexpected(ParseError::BufferSizeMismatch);
|
|
}
|
|
return (static_cast<std::uint32_t>(buffer[3]) << 0u)
|
|
| (static_cast<std::uint32_t>(buffer[2]) << 8u)
|
|
| (static_cast<std::uint32_t>(buffer[1]) << 16u)
|
|
| (static_cast<std::uint32_t>(buffer[0]) << 24u);
|
|
}
|
|
|
|
inline std::expected<std::uint32_t, ParseError> readU32BE(std::span<std::byte const>& buffer) {
|
|
auto result = peekU32BE(buffer);
|
|
if (result) {
|
|
buffer = buffer.subspan(8);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline std::expected<std::uint64_t, ParseError> peekU64LE(std::span<std::byte const> buffer) {
|
|
if (buffer.size() < 8) {
|
|
return std::unexpected(ParseError::BufferSizeMismatch);
|
|
}
|
|
return (static_cast<std::uint64_t>(buffer[0]) << 0u)
|
|
| (static_cast<std::uint64_t>(buffer[1]) << 8u)
|
|
| (static_cast<std::uint64_t>(buffer[2]) << 16u)
|
|
| (static_cast<std::uint64_t>(buffer[3]) << 24u)
|
|
| (static_cast<std::uint64_t>(buffer[4]) << 32u)
|
|
| (static_cast<std::uint64_t>(buffer[5]) << 40u)
|
|
| (static_cast<std::uint64_t>(buffer[6]) << 48u)
|
|
| (static_cast<std::uint64_t>(buffer[7]) << 56u);
|
|
}
|
|
|
|
inline std::expected<std::uint64_t, ParseError> readU64LE(std::span<std::byte const>& buffer) {
|
|
auto result = peekU64LE(buffer);
|
|
if (result) {
|
|
buffer = buffer.subspan(8);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline std::expected<std::uint64_t, ParseError> peekU64BE(std::span<std::byte const> buffer) {
|
|
if (buffer.size() < 8) {
|
|
return std::unexpected(ParseError::BufferSizeMismatch);
|
|
}
|
|
return (static_cast<std::uint64_t>(buffer[7]) << 0u)
|
|
| (static_cast<std::uint64_t>(buffer[6]) << 8u)
|
|
| (static_cast<std::uint64_t>(buffer[5]) << 16u)
|
|
| (static_cast<std::uint64_t>(buffer[4]) << 24u)
|
|
| (static_cast<std::uint64_t>(buffer[3]) << 32u)
|
|
| (static_cast<std::uint64_t>(buffer[2]) << 40u)
|
|
| (static_cast<std::uint64_t>(buffer[1]) << 48u)
|
|
| (static_cast<std::uint64_t>(buffer[0]) << 56u);
|
|
}
|
|
|
|
inline std::expected<std::uint64_t, ParseError> readU64BE(std::span<std::byte const>& buffer) {
|
|
auto result = peekU64BE(buffer);
|
|
if (result) {
|
|
buffer = buffer.subspan(8);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline std::expected<std::span<std::byte const>, ParseError> peekBuffer(std::span<std::byte const> buffer, std::size_t n) {
|
|
if (buffer.size() < n) {
|
|
return std::unexpected(ParseError::BufferSizeMismatch);
|
|
}
|
|
return buffer.subspan(0, n);
|
|
}
|
|
|
|
inline std::expected<std::span<std::byte const>, ParseError> readBuffer(std::span<std::byte const>& buffer, std::size_t n) {
|
|
auto result = peekBuffer(buffer, n);
|
|
if (result) {
|
|
buffer = buffer.subspan(n);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline std::expected<void, ParseError> expectEnd(std::span<std::byte const> buffer) {
|
|
if (buffer.size() > 0) {
|
|
return std::unexpected(ParseError::BufferSizeMismatch);
|
|
}
|
|
return {};
|
|
}
|
|
|
|
inline std::pair<std::uint8_t, bool> overflowingShr(std::uint8_t value, std::uint8_t bits) {
|
|
bool overflow = false;
|
|
if (bits >= 8) {
|
|
bits = bits & 0x07;
|
|
overflow = true;
|
|
}
|
|
return {value >> bits, overflow};
|
|
}
|
|
|
|
inline std::pair<std::uint8_t, bool> overflowingShl(std::uint8_t value, std::uint8_t bits) {
|
|
bool overflow = false;
|
|
if (bits >= 8) {
|
|
bits = bits & 0x07;
|
|
overflow = true;
|
|
}
|
|
return {value << bits, overflow};
|
|
}
|
|
|
|
inline std::size_t writeU8LE(std::span<std::byte>& target, std::size_t pos, std::uint8_t value) {
|
|
if (pos < target.size()) {
|
|
target[pos] = static_cast<std::byte>(value);
|
|
}
|
|
return pos + 1;
|
|
}
|
|
|
|
inline std::size_t writeU8BE(std::span<std::byte>& target, std::size_t pos, std::uint8_t value) {
|
|
if (pos < target.size()) {
|
|
target[pos] = static_cast<std::byte>(value);
|
|
}
|
|
return pos + 1;
|
|
}
|
|
|
|
inline std::size_t writeU16LE(std::span<std::byte>& target, std::size_t pos, std::uint16_t value) {
|
|
if ((pos + 1) < target.size()) {
|
|
target[pos + 0] = static_cast<std::byte>((value >> 0u) & 0xffu);
|
|
target[pos + 1] = static_cast<std::byte>((value >> 8u) & 0xffu);
|
|
}
|
|
return pos + 2;
|
|
}
|
|
|
|
inline std::size_t writeU16BE(std::span<std::byte>& target, std::size_t pos, std::uint16_t value) {
|
|
if ((pos + 1) < target.size()) {
|
|
target[pos + 0] = static_cast<std::byte>((value >> 8u) & 0xffu);
|
|
target[pos + 1] = static_cast<std::byte>((value >> 0u) & 0xffu);
|
|
}
|
|
return pos + 2;
|
|
}
|
|
|
|
inline std::size_t writeU24LE(std::span<std::byte>& target, std::size_t pos, std::uint32_t value) {
|
|
if ((pos + 2) < target.size()) {
|
|
target[pos + 0] = static_cast<std::byte>((value >> 0u) & 0xffu);
|
|
target[pos + 1] = static_cast<std::byte>((value >> 8u) & 0xffu);
|
|
target[pos + 2] = static_cast<std::byte>((value >> 16u) & 0xffu);
|
|
}
|
|
return pos + 3;
|
|
}
|
|
|
|
inline std::size_t writeU24BE(std::span<std::byte>& target, std::size_t pos, std::uint32_t value) {
|
|
if ((pos + 2) < target.size()) {
|
|
target[pos + 0] = static_cast<std::byte>((value >> 16u) & 0xffu);
|
|
target[pos + 1] = static_cast<std::byte>((value >> 8u) & 0xffu);
|
|
target[pos + 2] = static_cast<std::byte>((value >> 0u) & 0xffu);
|
|
}
|
|
return pos + 3;
|
|
}
|
|
|
|
inline std::size_t writeU32LE(std::span<std::byte>& target, std::size_t pos, std::uint32_t value) {
|
|
if ((pos + 3) < target.size()) {
|
|
target[pos + 0] = static_cast<std::byte>((value >> 0u) & 0xffu);
|
|
target[pos + 1] = static_cast<std::byte>((value >> 8u) & 0xffu);
|
|
target[pos + 2] = static_cast<std::byte>((value >> 16u) & 0xffu);
|
|
target[pos + 3] = static_cast<std::byte>((value >> 24u) & 0xffu);
|
|
}
|
|
return pos + 4;
|
|
}
|
|
|
|
inline std::size_t writeU32BE(std::span<std::byte>& target, std::size_t pos, std::uint32_t value) {
|
|
if ((pos + 3) < target.size()) {
|
|
target[pos + 0] = static_cast<std::byte>((value >> 24u) & 0xffu);
|
|
target[pos + 1] = static_cast<std::byte>((value >> 16u) & 0xffu);
|
|
target[pos + 2] = static_cast<std::byte>((value >> 8u) & 0xffu);
|
|
target[pos + 3] = static_cast<std::byte>((value >> 0u) & 0xffu);
|
|
}
|
|
return pos + 4;
|
|
}
|
|
|
|
inline std::size_t writeU64LE(std::span<std::byte>& target, std::size_t pos, std::uint64_t value) {
|
|
if ((pos + 7) < target.size()) {
|
|
target[pos + 0] = static_cast<std::byte>((value >> 0u) & 0xffu);
|
|
target[pos + 1] = static_cast<std::byte>((value >> 8u) & 0xffu);
|
|
target[pos + 2] = static_cast<std::byte>((value >> 16u) & 0xffu);
|
|
target[pos + 3] = static_cast<std::byte>((value >> 24u) & 0xffu);
|
|
target[pos + 4] = static_cast<std::byte>((value >> 32u) & 0xffu);
|
|
target[pos + 5] = static_cast<std::byte>((value >> 40u) & 0xffu);
|
|
target[pos + 6] = static_cast<std::byte>((value >> 48u) & 0xffu);
|
|
target[pos + 7] = static_cast<std::byte>((value >> 56u) & 0xffu);
|
|
}
|
|
return pos + 8;
|
|
}
|
|
|
|
inline std::size_t writeU64BE(std::span<std::byte>& target, std::size_t pos, std::uint64_t value) {
|
|
if ((pos + 3) < target.size()) {
|
|
target[pos + 0] = static_cast<std::byte>((value >> 56u) & 0xffu);
|
|
target[pos + 1] = static_cast<std::byte>((value >> 48u) & 0xffu);
|
|
target[pos + 2] = static_cast<std::byte>((value >> 40u) & 0xffu);
|
|
target[pos + 3] = static_cast<std::byte>((value >> 32u) & 0xffu);
|
|
target[pos + 4] = static_cast<std::byte>((value >> 24u) & 0xffu);
|
|
target[pos + 5] = static_cast<std::byte>((value >> 16u) & 0xffu);
|
|
target[pos + 6] = static_cast<std::byte>((value >> 8u) & 0xffu);
|
|
target[pos + 7] = static_cast<std::byte>((value >> 0u) & 0xffu);
|
|
}
|
|
return pos + 8;
|
|
}
|
|
|
|
inline std::size_t writeBuffer(std::span<std::byte>& target, std::size_t pos, std::span<std::byte const> value) {
|
|
if ((pos + value.size()) > target.size()) {
|
|
if (pos < target.size()) {
|
|
std::size_t const n = target.size() - pos;
|
|
std::copy(value.begin(), value.begin() + n, target.begin() + pos);
|
|
}
|
|
} else {
|
|
std::copy(value.begin(), value.end(), target.begin() + pos);
|
|
}
|
|
return pos + value.size();
|
|
}
|
|
|
|
inline std::size_t alignNextWrite(std::span<std::byte>& target, std::size_t pos, std::size_t alignment) {
|
|
std::ignore = target;
|
|
if (alignment <= 1) {
|
|
return pos;
|
|
}
|
|
if (pos % alignment == 0) {
|
|
return pos;
|
|
}
|
|
return ((pos + alignment - 1) / alignment) * alignment;
|
|
}
|
|
|
|
} // namespace monoformat
|
|
|
|
#endif // MONOFORMAT_PARSEHELPERS_HPP
|
|
|