//----------------------------------------------------------------------------// // // // ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation // // and distributed under the MIT License (MIT). // // // // Copyright (c) Guillaume Blanc // // // // Permission is hereby granted, free of charge, to any person obtaining a // // copy of this software and associated documentation files (the "Software"), // // to deal in the Software without restriction, including without limitation // // the rights to use, copy, modify, merge, publish, distribute, sublicense, // // and/or sell copies of the Software, and to permit persons to whom the // // Software is furnished to do so, subject to the following conditions: // // // // The above copyright notice and this permission notice shall be included in // // all copies or substantial portions of the Software. // // // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // // DEALINGS IN THE SOFTWARE. // // // //----------------------------------------------------------------------------// #ifndef OZZ_OZZ_BASE_ENDIANNESS_H_ #define OZZ_OZZ_BASE_ENDIANNESS_H_ // Declares endianness modes and functions to swap data from a mode to another. #include #include "ozz/base/platform.h" namespace ozz { // Declares supported endianness. enum Endianness { kBigEndian, kLittleEndian, }; // Get the native endianness of the targeted processor. // This function does not rely on a pre-processor definition as no standard // definition exists. It is rather implemented as a portable runtime function. inline Endianness GetNativeEndianness() { const union { uint16_t s; uint8_t c[2]; } u = {1}; // Initializes u.s -> then read u.c. return Endianness(u.c[0]); } // Declare the endian swapper struct that is aimed to be specialized (template // meaning) for every type sizes. // The swapper provides two functions: // - void Swap(_Ty* _ty, size_t _count) swaps the array _ty of _count // elements in-place. // - _Ty Swap(_Ty _ty) returns a swapped copy of _ty. // It can be used directly if _Ty is known or through EndianSwap function. // The default value of template attribute _size enables automatic // specialization selection. template struct EndianSwapper; // Internal macro used to swap two bytes. #define OZZ_BYTE_SWAP(_a, _b) \ do { \ const char temp = _a; \ _a = _b; \ _b = temp; \ } while (0) // EndianSwapper specialization for 1 byte types. template struct EndianSwapper<_Ty, 1> { OZZ_INLINE static void Swap(_Ty* _ty, size_t _count) { (void)_ty; (void)_count; } OZZ_INLINE static _Ty Swap(_Ty _ty) { return _ty; } }; // EndianSwapper specialization for 2 bytes types. template struct EndianSwapper<_Ty, 2> { OZZ_INLINE static void Swap(_Ty* _ty, size_t _count) { char* alias = reinterpret_cast(_ty); for (size_t i = 0; i < _count * 2; i += 2) { OZZ_BYTE_SWAP(alias[i + 0], alias[i + 1]); } } OZZ_INLINE static _Ty Swap(_Ty _ty) { // Pass by copy to swap _ty in-place. char* alias = reinterpret_cast(&_ty); OZZ_BYTE_SWAP(alias[0], alias[1]); return _ty; } }; // EndianSwapper specialization for 4 bytes types. template struct EndianSwapper<_Ty, 4> { OZZ_INLINE static void Swap(_Ty* _ty, size_t _count) { char* alias = reinterpret_cast(_ty); for (size_t i = 0; i < _count * 4; i += 4) { OZZ_BYTE_SWAP(alias[i + 0], alias[i + 3]); OZZ_BYTE_SWAP(alias[i + 1], alias[i + 2]); } } OZZ_INLINE static _Ty Swap(_Ty _ty) { // Pass by copy to swap _ty in-place. char* alias = reinterpret_cast(&_ty); OZZ_BYTE_SWAP(alias[0], alias[3]); OZZ_BYTE_SWAP(alias[1], alias[2]); return _ty; } }; // EndianSwapper specialization for 8 bytes types. template struct EndianSwapper<_Ty, 8> { OZZ_INLINE static void Swap(_Ty* _ty, size_t _count) { char* alias = reinterpret_cast(_ty); for (size_t i = 0; i < _count * 8; i += 8) { OZZ_BYTE_SWAP(alias[i + 0], alias[i + 7]); OZZ_BYTE_SWAP(alias[i + 1], alias[i + 6]); OZZ_BYTE_SWAP(alias[i + 2], alias[i + 5]); OZZ_BYTE_SWAP(alias[i + 3], alias[i + 4]); } } OZZ_INLINE static _Ty Swap(_Ty _ty) { // Pass by copy to swap _ty in-place. char* alias = reinterpret_cast(&_ty); OZZ_BYTE_SWAP(alias[0], alias[7]); OZZ_BYTE_SWAP(alias[1], alias[6]); OZZ_BYTE_SWAP(alias[2], alias[5]); OZZ_BYTE_SWAP(alias[3], alias[4]); return _ty; } }; // OZZ_BYTE_SWAP is not useful anymore. #undef OZZ_BYTE_SWAP // Helper function that swaps _count elements of the array _ty in place. template OZZ_INLINE void EndianSwap(_Ty* _ty, size_t _count) { EndianSwapper<_Ty>::Swap(_ty, _count); } // Helper function that swaps _ty in place. template OZZ_INLINE _Ty EndianSwap(_Ty _ty) { return EndianSwapper<_Ty>::Swap(_ty); } } // namespace ozz #endif // OZZ_OZZ_BASE_ENDIANNESS_H_