Program Listing for File common.h#
↰ Return to documentation for file (src/generated/ifgen/common.h)
#pragma once
#ifndef SAMPLE3_IFGEN_COMMON_H
#define SAMPLE3_IFGEN_COMMON_H
#include <bit>
#include <concepts>
#include <cstdint>
#include <istream>
#include <ostream>
#include <spanstream>
#include <streambuf>
#include <utility>
namespace Sample3
{
/* Enforce that this isn't a mixed-endian system. */
static_assert(std::endian::native == std::endian::big or
std::endian::native == std::endian::little);
/* Default endianness configured. */
static constexpr auto default_endian = std::endian::little;
/* Detect primitives that don't need byte swapping. */
template <typename T>
concept byte_size = sizeof(T) == 1;
/* No action for byte-sized primitives. */
template <std::endian endianness, byte_size T> inline void handle_endian_p(T *)
{
}
template <std::endian endianness, byte_size T> inline T handle_endian(T elem)
{
return elem;
}
/* No action if endianness is native. */
template <std::endian endianness, std::integral T>
inline void handle_endian_p(T *)
requires(not byte_size<T>) && (endianness == std::endian::native)
{
}
template <std::endian endianness, std::integral T>
inline T handle_endian(T elem)
requires(not byte_size<T>) && (endianness == std::endian::native)
{
return elem;
}
/* Swap any integral type. */
template <std::endian endianness, std::integral T>
inline T handle_endian(T elem)
requires(not byte_size<T>) && (endianness != std::endian::native)
{
return std::byteswap(elem);
}
template <std::endian endianness, std::integral T>
inline void handle_endian_p(T *elem)
requires(not byte_size<T>) && (endianness != std::endian::native)
{
*elem = std::byteswap(*elem);
}
/* Handler for 32-bit float. */
template <std::endian endianness, std::floating_point T>
inline void handle_endian_p(T *elem)
requires(sizeof(T) == sizeof(uint32_t))
{
handle_endian_p<endianness>(reinterpret_cast<uint32_t *>(elem));
}
template <std::endian endianness, std::floating_point T>
inline T handle_endian(T elem)
requires(sizeof(T) == sizeof(uint32_t))
{
return std::bit_cast<T>(
handle_endian<endianness>(std::bit_cast<uint32_t>(elem)));
}
/* Handler for 64-bit float. */
template <std::endian endianness, std::floating_point T>
inline void handle_endian_p(T *elem)
requires(sizeof(T) == sizeof(uint64_t))
{
handle_endian_p<endianness>(reinterpret_cast<uint64_t *>(elem));
}
template <std::endian endianness, std::floating_point T>
inline T handle_endian(T elem)
requires(sizeof(T) == sizeof(uint64_t))
{
return std::bit_cast<T>(
handle_endian<endianness>(std::bit_cast<uint64_t>(elem)));
}
/* Handler for enum class types. */
template <std::endian endianness, typename T>
inline void handle_endian_p(T *elem)
requires(std::is_enum_v<T>)
{
using underlying = std::underlying_type_t<T>;
handle_endian_p<endianness>(reinterpret_cast<underlying *>(elem));
}
template <std::endian endianness, typename T>
inline T handle_endian(T elem)
requires(std::is_enum_v<T>)
{
return static_cast<T>(handle_endian<endianness>(std::to_underlying(elem)));
}
/* Configured primitives for identifiers. */
using struct_id_t = uint8_t;
using enum_id_t = uint8_t;
/* Create useful aliases for bytes. */
template <std::size_t Extent = std::dynamic_extent>
using byte_span = std::span<std::byte, Extent>;
template <std::size_t size> using byte_array = std::array<std::byte, size>;
/* Abstract byte-stream interfaces. */
using byte_istream = std::basic_istream<std::byte>;
using byte_ostream = std::basic_ostream<std::byte>;
/* Concrete byte-stream interfaces (based on span). */
using byte_spanbuf = std::basic_spanbuf<std::byte>;
using byte_spanstream = std::basic_spanstream<std::byte>;
/* Constraint for generated structs. */
template <typename T>
concept ifgen_struct = requires {
std::is_integral_v<decltype(T::id)>;
std::is_same_v<decltype(T::size), std::size_t>;
};
}; // namespace Sample3
#endif