diff --git a/include/duckhandy/ducktypes.hpp b/include/duckhandy/ducktypes.hpp new file mode 100644 index 0000000..6336258 --- /dev/null +++ b/include/duckhandy/ducktypes.hpp @@ -0,0 +1,64 @@ +/* Copyright 2016, 2017 Michele Santullo + * This file is part of "duckhandy". + * + * "duckhandy" is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * "duckhandy" is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with "duckhandy". If not, see . + */ + +#ifndef MY_INCL_DUCKTYPES_H +#define MY_INCL_DUCKTYPES_H + +#include +#include + +namespace dhandy { + namespace internal { + class ERROR_inttype_not_available { + ERROR_inttype_not_available(); + }; + } // namespace internal + + // Retrieves a signed/unsigned integer type with sizeof( T ) == BYTES + template + struct int_t { + typedef typename std::conditional< sizeof( signed char ) * CHAR_BIT == CHAR_BIT * BYTES, signed char, + typename std::conditional< sizeof( signed short ) * CHAR_BIT == CHAR_BIT * BYTES, signed short, + typename std::conditional< sizeof( signed int ) * CHAR_BIT == CHAR_BIT * BYTES, signed int, + typename std::conditional< sizeof( signed long ) * CHAR_BIT == CHAR_BIT * BYTES, signed long, + typename std::conditional< sizeof( signed long long ) * CHAR_BIT == CHAR_BIT * BYTES, signed long long, + internal::ERROR_inttype_not_available >::type >::type >::type >::type >::type type; + }; + + template + struct int_t { + typedef typename std::conditional< sizeof( unsigned char ) * CHAR_BIT == CHAR_BIT * BYTES, unsigned char, + typename std::conditional< sizeof( unsigned short ) * CHAR_BIT == CHAR_BIT * BYTES, unsigned short, + typename std::conditional< sizeof( unsigned int ) * CHAR_BIT == CHAR_BIT * BYTES, unsigned int, + typename std::conditional< sizeof( unsigned long ) * CHAR_BIT == CHAR_BIT * BYTES, unsigned long, + typename std::conditional< sizeof( unsigned long long ) * CHAR_BIT == CHAR_BIT * BYTES, unsigned long long, + internal::ERROR_inttype_not_available >::type >::type >::type >::type >::type type; + }; + + // Retrieves the smallest unsigned integer type with sizeof( T ) >= BYTES + template + struct uint_t_min { + typedef typename std::conditional< sizeof( unsigned char ) * CHAR_BIT >= CHAR_BIT * BYTES, unsigned char, + typename std::conditional< sizeof( unsigned short ) * CHAR_BIT >= CHAR_BIT * BYTES, unsigned short, + typename std::conditional< sizeof( unsigned int ) * CHAR_BIT >= CHAR_BIT * BYTES, unsigned int, + typename std::conditional< sizeof( unsigned long ) * CHAR_BIT >= CHAR_BIT * BYTES, unsigned long, + typename std::conditional< sizeof( unsigned long long ) * CHAR_BIT >= CHAR_BIT * BYTES, unsigned long long, + internal::ERROR_inttype_not_available >::type >::type >::type >::type >::type type; + }; +} //namespace dhandy + +#endif // MY_INCL_DUCKTYPES_H diff --git a/include/duckhandy/endianness.hpp b/include/duckhandy/endianness.hpp index 4e704a9..cc7cb08 100644 --- a/include/duckhandy/endianness.hpp +++ b/include/duckhandy/endianness.hpp @@ -18,190 +18,56 @@ #ifndef id1A975372553B45BC8C4E42CDBDD97497 #define id1A975372553B45BC8C4E42CDBDD97497 +#include "ducktypes.hpp" +#include "int_types.hpp" #include #include +#include namespace dhandy { - template constexpr T htobe (T parV); - template constexpr T htole (T parV); + template constexpr typename std::enable_if::value, T>::type htobe (T parV); + template constexpr typename std::enable_if::value, T>::type htole (T parV); template constexpr T betoh (T parV); template constexpr T letoh (T parV); - template <> - [[gnu::pure]] inline constexpr uint8_t htobe (uint8_t parV) { - return parV; - } - template <> - [[gnu::pure]] inline constexpr uint16_t htobe (uint16_t parV) { + namespace implem { + template constexpr + typename int_t::type bswap (typename int_t::type parV); + + template <> + [[gnu::pure]] inline constexpr + u8 bswap<1> (u8 parV) { return parV; } + + template <> + [[gnu::pure]] inline constexpr + u16 bswap<2> (u16 parV) { return __builtin_bswap16(parV); } + + template <> + [[gnu::pure]] inline constexpr + u32 bswap<4> (u32 parV) { return __builtin_bswap32(parV); } + + template <> + [[gnu::pure]] inline constexpr + u64 bswap<8> (u64 parV) { return __builtin_bswap64(parV); } + } //namespace implem + + template + [[gnu::pure]] inline constexpr + auto htobe (T parV) -> typename std::enable_if::value, T>::type { #if __BYTE_ORDER == __BIG_ENDIAN return parV; #elif __BYTE_ORDER == __LITTLE_ENDIAN - return __builtin_bswap16(parV); -#else -# error "Unsupported endianness" -#endif - } - template <> - [[gnu::pure]] inline constexpr uint32_t htobe (uint32_t parV) { -#if __BYTE_ORDER == __BIG_ENDIAN - return parV; -#elif __BYTE_ORDER == __LITTLE_ENDIAN - return __builtin_bswap32(parV); -#else -# error "Unsupported endianness" -#endif - } - template <> - [[gnu::pure]] inline constexpr uint64_t htobe (uint64_t parV) { -#if __BYTE_ORDER == __BIG_ENDIAN - return parV; -#elif __BYTE_ORDER == __LITTLE_ENDIAN - return __builtin_bswap64(parV); -#else -# error "Unsupported endianness" -#endif - } - template <> - [[gnu::pure]] inline constexpr int8_t htobe (int8_t parV) { - return parV; - } - template <> - [[gnu::pure]] inline constexpr int16_t htobe (int16_t parV) { -#if __BYTE_ORDER == __BIG_ENDIAN - return parV; -#elif __BYTE_ORDER == __LITTLE_ENDIAN - return static_cast(__builtin_bswap16(static_cast(parV))); -#else -# error "Unsupported endianness" -#endif - } - template <> - [[gnu::pure]] inline constexpr int32_t htobe (int32_t parV) { -#if __BYTE_ORDER == __BIG_ENDIAN - return parV; -#elif __BYTE_ORDER == __LITTLE_ENDIAN - return static_cast(__builtin_bswap32(static_cast(parV))); -#else -# error "Unsupported endianness" -#endif - } - template <> - [[gnu::pure]] inline constexpr int64_t htobe (int64_t parV) { -#if __BYTE_ORDER == __BIG_ENDIAN - return parV; -#elif __BYTE_ORDER == __LITTLE_ENDIAN - return static_cast(__builtin_bswap64(static_cast(parV))); -#else -# error "Unsupported endianness" -#endif - } - template <> - [[gnu::pure]] inline constexpr long long int htobe (long long int parV) { - static_assert(sizeof(long long int) == sizeof(uint64_t), "Size mismatch"); -#if __BYTE_ORDER == __BIG_ENDIAN - return parV; -#elif __BYTE_ORDER == __LITTLE_ENDIAN - return static_cast(__builtin_bswap64(static_cast(parV))); -#else -# error "Unsupported endianness" -#endif - } - template <> - [[gnu::pure]] inline constexpr unsigned long long int htobe (unsigned long long int parV) { - static_assert(sizeof(unsigned long long int) == sizeof(uint64_t), "Size mismatch"); -#if __BYTE_ORDER == __BIG_ENDIAN - return parV; -#elif __BYTE_ORDER == __LITTLE_ENDIAN - return static_cast(__builtin_bswap64(static_cast(parV))); + return static_cast(implem::bswap(static_cast::type>(parV))); #else # error "Unsupported endianness" #endif } - template <> - [[gnu::pure]] inline constexpr uint8_t htole (uint8_t parV) { - return parV; - } - template <> - [[gnu::pure]] inline constexpr uint16_t htole (uint16_t parV) { + template + [[gnu::pure]] inline constexpr + auto htole (T parV) -> typename std::enable_if::value, T>::type { #if __BYTE_ORDER == __BIG_ENDIAN - return __builtin_bswap16(parV); -#elif __BYTE_ORDER == __LITTLE_ENDIAN - return parV; -#else -# error "Unsupported endianness" -#endif - } - template <> - [[gnu::pure]] inline constexpr uint32_t htole (uint32_t parV) { -#if __BYTE_ORDER == __BIG_ENDIAN - return __builtin_bswap32(parV); -#elif __BYTE_ORDER == __LITTLE_ENDIAN - return parV; -#else -# error "Unsupported endianness" -#endif - } - template <> - [[gnu::pure]] inline constexpr uint64_t htole (uint64_t parV) { -#if __BYTE_ORDER == __BIG_ENDIAN - return __builtin_bswap64(parV); -#elif __BYTE_ORDER == __LITTLE_ENDIAN - return parV; -#else -# error "Unsupported endianness" -#endif - } - template <> - [[gnu::pure]] inline constexpr int8_t htole (int8_t parV) { - return parV; - } - template <> - [[gnu::pure]] inline constexpr int16_t htole (int16_t parV) { -#if __BYTE_ORDER == __BIG_ENDIAN - return static_cast(__builtin_bswap16(static_cast(parV))); -#elif __BYTE_ORDER == __LITTLE_ENDIAN - return parV; -#else -# error "Unsupported endianness" -#endif - } - template <> - [[gnu::pure]] inline constexpr int32_t htole (int32_t parV) { -#if __BYTE_ORDER == __BIG_ENDIAN - return static_cast(__builtin_bswap32(static_cast(parV))); -#elif __BYTE_ORDER == __LITTLE_ENDIAN - return parV; -#else -# error "Unsupported endianness" -#endif - } - template <> - [[gnu::pure]] inline constexpr int64_t htole (int64_t parV) { -#if __BYTE_ORDER == __BIG_ENDIAN - return static_cast(__builtin_bswap64(static_cast(parV))); -#elif __BYTE_ORDER == __LITTLE_ENDIAN - return parV; -#else -# error "Unsupported endianness" -#endif - } - template <> - [[gnu::pure]] inline constexpr long long int htole (long long int parV) { - static_assert(sizeof(long long int) == sizeof(uint64_t), "Size mismatch"); -#if __BYTE_ORDER == __BIG_ENDIAN - return static_cast(__builtin_bswap64(static_cast(parV))); -#elif __BYTE_ORDER == __LITTLE_ENDIAN - return parV; -#else -# error "Unsupported endianness" -#endif - } - template <> - [[gnu::pure]] inline constexpr unsigned long long int htole (unsigned long long int parV) { - static_assert(sizeof(unsigned long long int) == sizeof(uint64_t), "Size mismatch"); -#if __BYTE_ORDER == __BIG_ENDIAN - return static_cast(__builtin_bswap64(static_cast(parV))); + return static_cast(implem::bswap(static_cast::type>(parV))); #elif __BYTE_ORDER == __LITTLE_ENDIAN return parV; #else diff --git a/include/duckhandy/int_types.hpp b/include/duckhandy/int_types.hpp new file mode 100644 index 0000000..290bb95 --- /dev/null +++ b/include/duckhandy/int_types.hpp @@ -0,0 +1,35 @@ +/* Copyright 2016, 2017 Michele Santullo + * This file is part of "duckhandy". + * + * "duckhandy" is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * "duckhandy" is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with "duckhandy". If not, see . + */ + +#ifndef idC1B85F801982440AB8C66070635BEE17 +#define idC1B85F801982440AB8C66070635BEE17 + +#include "ducktypes.hpp" + +namespace dhandy { + // Machine independent definition of sized integer types + typedef int_t<1, true>::type i8; + typedef int_t<2, true>::type i16; + typedef int_t<4, true>::type i32; + typedef int_t<8, true>::type i64; + typedef int_t<1, false>::type u8; + typedef int_t<2, false>::type u16; + typedef int_t<4, false>::type u32; + typedef int_t<8, false>::type u64; +} //namespace dhandy + +#endif