view include/core/endian.h @ 364:99c961c91809

core: refactor out byte stream into its own file easy dubs
author Paper <paper@paper.us.eu.org>
date Tue, 16 Jul 2024 21:15:59 -0400
parents 9aaf1e788896
children
line wrap: on
line source

#ifndef MINORI_CORE_ENDIAN_H_
#define MINORI_CORE_ENDIAN_H_

/* definition of endian-related stuff. primarily used for x11
 * binary structures */

#include "core/bit_cast.h"
#include <cstdint>
#include <type_traits>

class Endian {
private:
	/* check for compiler builtins for byteswapping */
#ifdef __has_builtin
#	if __has_builtin(__builtin_bswap16)
#		define COMPILER_BUILTIN_BSWAP16(x) __builtin_bswap16(x)
#	endif
#	if __has_builtin(__builtin_bswap32)
#		define COMPILER_BUILTIN_BSWAP32(x) __builtin_bswap32(x)
#	endif
#	if __has_builtin(__builtin_bswap64)
#		define COMPILER_BUILTIN_BSWAP64(x) __builtin_bswap64(x)
#	endif
#endif

	static constexpr uint16_t byteswap_16(uint16_t x) {
#ifdef COMPILER_BUILTIN_BSWAP16
		return COMPILER_BUILTIN_BSWAP16(x);
#else
		return (
			  ((x & UINT16_C(0x00FF)) << 8)
			| ((x & UINT16_C(0xFF00)) >> 8)
		);
#endif
	}

	static constexpr uint32_t byteswap_32(uint32_t x) {
#ifdef COMPILER_BUILTIN_BSWAP32
		return COMPILER_BUILTIN_BSWAP32(x);
#else
		return (
			  ((x & UINT32_C(0x000000FF)) << 24)
			| ((x & UINT32_C(0x0000FF00)) << 8)
			| ((x & UINT32_C(0x00FF0000)) >> 8)
			| ((x & UINT32_C(0xFF000000)) >> 24)
		);
#endif
	}

	static constexpr uint64_t byteswap_64(uint64_t x) {
#ifdef COMPILER_BUILTIN_BSWAP64
		return COMPILER_BUILTIN_BSWAP64(x);
#else
		return (
			  ((x & UINT64_C(0x00000000000000FF)) << 56)
			| ((x & UINT64_C(0x000000000000FF00)) << 40)
			| ((x & UINT64_C(0x0000000000FF0000)) << 24)
			| ((x & UINT64_C(0x00000000FF000000)) << 8)
			| ((x & UINT64_C(0x000000FF00000000)) >> 8)
			| ((x & UINT64_C(0x0000FF0000000000)) >> 24)
			| ((x & UINT64_C(0x00FF000000000000)) >> 40)
			| ((x & UINT64_C(0xFF00000000000000)) >> 56)
		);
#endif
	}

#ifdef COMPILER_BUILTIN_BSWAP16
#	undef COMPILER_BUILTIN_BSWAP16
#endif
#ifdef COMPILER_BUILTIN_BSWAP32
#	undef COMPILER_BUILTIN_BSWAP32
#endif
#ifdef COMPILER_BUILTIN_BSWAP64
#	undef COMPILER_BUILTIN_BSWAP64
#endif
public:
#if defined(BYTE_ORDER_BIG)
	static constexpr bool big = true;
	static constexpr bool little = false;
#elif defined(BYTE_ORDER_LITTLE)
	static constexpr bool big = false;
	static constexpr bool little = true;
#else
#error "unsupported endianness"
#endif

	template<typename T>
	static constexpr T byteswap(T x) {
		static_assert(std::is_integral<T>::value);
		static_assert(std::is_unsigned<T>::value, "use signed_byteswap");

		if constexpr (std::is_same<T, uint8_t>::value) {
			return x;
		} else if constexpr (std::is_same<T, uint16_t>::value) {
			return byteswap_16(x);
		} else if constexpr (std::is_same<T, uint32_t>::value) {
			return byteswap_32(x);
		} else if constexpr (std::is_same<T, uint64_t>::value) {
			return byteswap_64(x);
		} else {
			static_assert(!sizeof(T), "invalid integer type given to byteswap");
		}
	}

	/* this can't be constexpr */
	template<typename T>
	static T signed_byteswap(T x) {
		static_assert(std::is_integral<T>::value);
		static_assert(std::is_signed<T>::value, "use regular byteswap");

		using uT = typename std::make_unsigned<T>::type;
		return minori::BitCast<T, uT>(byteswap<uT>(minori::BitCast<uT, T>(x)));
	}

	template<typename T>
	static constexpr T byteswap_little_to_host(T x) {
		if constexpr (little) {
			return x;
		} else if constexpr (big) {
			return byteswap(x);
		}
	}

	template<typename T>
	static constexpr T byteswap_big_to_host(T x) {
		if constexpr (big) {
			return x;
		} else if constexpr (little) {
			return byteswap(x);
		}
	}

	template<typename T>
	static T signed_byteswap_little_to_host(T x) {
		if constexpr (little) {
			return x;
		} else if constexpr (big) {
			return signed_byteswap(x);
		}
	}

	template<typename T>
	static T signed_byteswap_big_to_host(T x) {
		if constexpr (big) {
			return x;
		} else if constexpr (little) {
			return signed_byteswap(x);
		}
	}
private:
	Endian() = delete;
};

#endif /* MINORI_CORE_ENDIAN_H_ */