// Copyright (C) 2026 Kiyotsugu Arai // SPDX-License-Identifier: LGPL-3.0-or-later // endian_utils.hpp // エンディアン変換ユーティリティ // // このファイルでは、異なるエンディアンの環境間でのデータ交換を // サポートするためのユーティリティ関数を提供します。 // // 主な機能: // - エンディアン検出 // - バイトスワップ関数 // - プラットフォーム間の変換ヘルパー #ifndef CALX_ENDIAN_UTILS_HPP #define CALX_ENDIAN_UTILS_HPP #include #include #include // コンパイラ依存のエンディアン検出 #if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #define CALX_LITTLE_ENDIAN 1 #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ #define CALX_BIG_ENDIAN 1 #else #error "Unknown endianness" #endif #elif defined(_MSC_VER) // Microsoft Visual C++の場合は常にリトルエンディアン #define CALX_LITTLE_ENDIAN 1 #else // 実行時検出フォールバック #warning "Compile-time endianness detection not available, using runtime detection" #define CALX_RUNTIME_ENDIAN_DETECTION 1 #endif namespace calx { namespace endian { /** * @brief エンディアン型の列挙型 */ enum class Endianness { Little, ///< リトルエンディアン(下位バイトが先) Big ///< ビッグエンディアン(上位バイトが先) }; /** * @brief 現在のプラットフォームのエンディアン形式 */ #if defined(CALX_LITTLE_ENDIAN) constexpr Endianness platform_endianness = Endianness::Little; #elif defined(CALX_BIG_ENDIAN) constexpr Endianness platform_endianness = Endianness::Big; #else // 実行時検出が必要 inline Endianness detect_platform_endianness() { const uint16_t test = 0x0102; const uint8_t* ptr = reinterpret_cast(&test); return (ptr[0] == 0x02) ? Endianness::Little : Endianness::Big; } const Endianness platform_endianness = detect_platform_endianness(); #endif /** * @brief 16ビット整数のバイト順を反転 * @param value 反転する値 * @return バイト順を反転した値 */ inline uint16_t byte_swap(uint16_t value) { return ((value & 0x00FF) << 8) | ((value & 0xFF00) >> 8); } /** * @brief 32ビット整数のバイト順を反転 * @param value 反転する値 * @return バイト順を反転した値 */ inline uint32_t byte_swap(uint32_t value) { return ((value & 0x000000FF) << 24) | ((value & 0x0000FF00) << 8) | ((value & 0x00FF0000) >> 8) | ((value & 0xFF000000) >> 24); } /** * @brief 64ビット整数のバイト順を反転 * @param value 反転する値 * @return バイト順を反転した値 */ inline uint64_t byte_swap(uint64_t value) { return ((value & 0x00000000000000FFULL) << 56) | ((value & 0x000000000000FF00ULL) << 40) | ((value & 0x0000000000FF0000ULL) << 24) | ((value & 0x00000000FF000000ULL) << 8) | ((value & 0x000000FF00000000ULL) >> 8) | ((value & 0x0000FF0000000000ULL) >> 24) | ((value & 0x00FF000000000000ULL) >> 40) | ((value & 0xFF00000000000000ULL) >> 56); } /** * @brief 符号付き整数のバイト順を反転(符号なし版を利用) * @param value 反転する値 * @return バイト順を反転した値 */ template requires std::is_signed_v inline T byte_swap(T value) { using UT = typename std::make_unsigned::type; return static_cast(byte_swap(static_cast(value))); } /** * @brief 特定のエンディアンから現在のプラットフォームのエンディアンに変換 * @param value 変換する値 * @param from 元のエンディアン形式 * @return 変換後の値 */ template inline T to_native(T value, Endianness from) { if (from == platform_endianness) { return value; } return byte_swap(value); } /** * @brief 現在のプラットフォームのエンディアンから特定のエンディアンに変換 * @param value 変換する値 * @param to 変換先のエンディアン形式 * @return 変換後の値 */ template inline T from_native(T value, Endianness to) { if (to == platform_endianness) { return value; } return byte_swap(value); } /** * @brief リトルエンディアンから現在のプラットフォームのエンディアンに変換 * @param value 変換する値 * @return 変換後の値 */ template inline T from_little_endian(T value) { return to_native(value, Endianness::Little); } /** * @brief ビッグエンディアンから現在のプラットフォームのエンディアンに変換 * @param value 変換する値 * @return 変換後の値 */ template inline T from_big_endian(T value) { return to_native(value, Endianness::Big); } /** * @brief 現在のプラットフォームのエンディアンからリトルエンディアンに変換 * @param value 変換する値 * @return 変換後の値 */ template inline T to_little_endian(T value) { return from_native(value, Endianness::Little); } /** * @brief 現在のプラットフォームのエンディアンからビッグエンディアンに変換 * @param value 変換する値 * @return 変換後の値 */ template inline T to_big_endian(T value) { return from_native(value, Endianness::Big); } /** * @brief バッファのバイト順を反転 * @param buffer 反転するバッファ * @param size バッファのサイズ(バイト単位) * @param element_size 各要素のサイズ(バイト単位) */ inline void byte_swap_buffer(void* buffer, size_t size, size_t element_size) { if (buffer == nullptr || size == 0 || element_size <= 1) { return; } uint8_t* bytes = static_cast(buffer); for (size_t i = 0; i < size; i += element_size) { for (size_t j = 0; j < element_size / 2; ++j) { std::swap(bytes[i + j], bytes[i + element_size - 1 - j]); } } } } // namespace endian } // namespace calx #endif // CALX_ENDIAN_UTILS_HPP