csutil/csendian.h
Go to the documentation of this file.00001 /* 00002 Copyright (C) 1998 by Jorrit Tyberghein 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public 00015 License along with this library; if not, write to the Free 00016 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00017 */ 00018 00019 #ifndef __CS_CSENDIAN_H__ 00020 #define __CS_CSENDIAN_H__ 00021 00029 #include <math.h> 00030 #include "cstypes.h" 00031 #if defined(CS_HAVE_BYTESWAP_H) 00032 #include <byteswap.h> 00033 #endif 00034 00035 #define csQroundSure(x) (int ((x) + ((x < 0) ? -0.5 : +0.5))) 00036 00040 struct csSwapBytes 00041 { 00042 public: 00044 00045 static CS_FORCEINLINE uint16 Swap (uint16 s) 00046 { 00047 #if defined(CS_COMPILER_MSVC) && (_MSC_VER >= 1300) 00048 return _byteswap_ushort (s); 00049 #elif defined(CS_HAVE_BYTESWAP_H) 00050 return bswap_16 (s); 00051 #else 00052 return (s >> 8) | (s << 8); 00053 #endif 00054 } 00055 static CS_FORCEINLINE int16 Swap (int16 s) 00056 { return (int16)Swap ((uint16)s); } 00057 static CS_FORCEINLINE uint32 Swap (uint32 l) 00058 { 00059 #if defined(CS_COMPILER_MSVC) && (_MSC_VER >= 1300) 00060 return _byteswap_ulong (l); 00061 #elif defined(CS_HAVE_BYTESWAP_H) 00062 return bswap_32 (l); 00063 #else 00064 return (l >> 24) | ((l >> 8) & 0xff00) | ((l << 8) & 0xff0000) | (l << 24); 00065 #endif 00066 } 00067 static CS_FORCEINLINE int32 Swap (int32 l) 00068 { return (int32)Swap ((uint32)l); } 00069 static CS_FORCEINLINE uint64 Swap (uint64 l) 00070 { 00071 #if defined(CS_COMPILER_MSVC) && (_MSC_VER >= 1300) 00072 return _byteswap_uint64 (l); 00073 #elif defined(CS_HAVE_BYTESWAP_H) && !defined(__STRICT_ANSI__) 00074 return bswap_64 (l); 00075 #else 00076 union 00077 { 00078 uint64 ui64; 00079 uint32 ui32[2]; 00080 } u1, u2; 00081 u1.ui64 = l; 00082 u2.ui32[0] = Swap (u1.ui32[1]); 00083 u2.ui32[1] = Swap (u1.ui32[0]); 00084 return u2.ui64; 00085 #endif 00086 } 00087 static CS_FORCEINLINE int64 Swap (int64 l) 00088 { return (int64)Swap ((uint64)l); } 00089 00090 static CS_FORCEINLINE uint16 UInt16 (uint16 x) { return Swap (x); } 00091 static CS_FORCEINLINE int16 Int16 (int16 x) { return Swap (x); } 00092 static CS_FORCEINLINE uint32 UInt32 (uint32 x) { return Swap (x); } 00093 static CS_FORCEINLINE int32 Int32 (int32 x) { return Swap (x); } 00094 static CS_FORCEINLINE uint64 UInt64 (uint64 x) { return Swap (x); } 00095 static CS_FORCEINLINE int64 Int64 (int64 x) { return Swap (x); } 00097 }; 00098 00099 #ifdef CS_BIG_ENDIAN 00100 struct csBigEndian 00101 #else 00107 struct csLittleEndian 00108 #endif 00109 { 00111 00112 static CS_FORCEINLINE uint16 Convert (uint16 x) { return x; } 00113 static CS_FORCEINLINE int16 Convert (int16 x) { return x; } 00114 static CS_FORCEINLINE uint32 Convert (uint32 x) { return x; } 00115 static CS_FORCEINLINE int32 Convert (int32 x) { return x; } 00116 static CS_FORCEINLINE uint64 Convert (uint64 x) { return x; } 00117 static CS_FORCEINLINE int64 Convert (int64 x) { return x; } 00118 00119 static CS_FORCEINLINE uint16 UInt16 (uint16 x) { return Convert (x); } 00120 static CS_FORCEINLINE int16 Int16 (int16 x) { return Convert (x); } 00121 static CS_FORCEINLINE uint32 UInt32 (uint32 x) { return Convert (x); } 00122 static CS_FORCEINLINE int32 Int32 (int32 x) { return Convert (x); } 00123 static CS_FORCEINLINE uint64 UInt64 (uint64 x) { return Convert (x); } 00124 static CS_FORCEINLINE int64 Int64 (int64 x) { return Convert (x); } 00126 }; 00127 00128 #ifdef CS_LITTLE_ENDIAN 00129 00134 struct csBigEndian 00135 #else 00136 struct csLittleEndian 00137 #endif 00138 { 00139 public: 00141 00142 static CS_FORCEINLINE uint16 Convert (uint16 s) 00143 { return csSwapBytes::Swap (s); } 00144 static CS_FORCEINLINE int16 Convert (int16 s) 00145 { return csSwapBytes::Swap (s); } 00146 static CS_FORCEINLINE uint32 Convert (uint32 l) 00147 { return csSwapBytes::Swap (l); } 00148 static CS_FORCEINLINE int32 Convert (int32 l) 00149 { return csSwapBytes::Swap (l); } 00150 static CS_FORCEINLINE uint64 Convert (uint64 l) 00151 { return csSwapBytes::Swap (l); } 00152 static CS_FORCEINLINE int64 Convert (int64 l) 00153 { return csSwapBytes::Swap (l); } 00154 00155 static CS_FORCEINLINE uint16 UInt16 (uint16 x) { return Convert (x); } 00156 static CS_FORCEINLINE int16 Int16 (int16 x) { return Convert (x); } 00157 static CS_FORCEINLINE uint32 UInt32 (uint32 x) { return Convert (x); } 00158 static CS_FORCEINLINE int32 Int32 (int32 x) { return Convert (x); } 00159 static CS_FORCEINLINE uint64 UInt64 (uint64 x) { return Convert (x); } 00160 static CS_FORCEINLINE int64 Int64 (int64 x) { return Convert (x); } 00162 }; 00163 00167 struct csIEEEfloat 00168 { 00169 /* \todo It would be even better if we also check for sizeof (float) 00170 * in configure or so. */ 00171 #ifdef CS_IEEE_DOUBLE_FORMAT 00172 00173 00174 static CS_FORCEINLINE uint32 FromNative (float f) 00175 { 00176 union 00177 { 00178 float f; 00179 uint32 ui32; 00180 } u; 00181 u.f = f; 00182 return u.ui32; 00183 } 00184 static CS_FORCEINLINE uint64 FromNative (double f) 00185 { 00186 union 00187 { 00188 double f; 00189 uint64 ui64; 00190 } u; 00191 u.f = f; 00192 return u.ui64; 00193 } 00195 00197 00198 static CS_FORCEINLINE float ToNative (uint32 f) 00199 { 00200 union 00201 { 00202 float f; 00203 uint32 ui32; 00204 } u; 00205 u.ui32 = f; 00206 return u.f; 00207 } 00208 static CS_FORCEINLINE double ToNative (uint64 f) 00209 { 00210 union 00211 { 00212 double f; 00213 uint64 ui64; 00214 } u; 00215 u.ui64 = f; 00216 return u.f; 00217 } 00219 #else 00220 #error Do not know how to convert to IEEE floats 00221 #endif 00222 }; 00223 00232 struct csGetFromAddress 00233 { 00235 00236 static CS_FORCEINLINE uint16 UInt16 (const void *buff) 00237 { 00238 #ifdef CS_STRICT_ALIGNMENT 00239 uint16 s; memcpy (&s, buff, sizeof (s)); 00240 return s; 00241 #else 00242 return *(uint16 *)buff; 00243 #endif 00244 } 00245 static CS_FORCEINLINE int16 Int16 (const void *buff) 00246 { return (int16)UInt16 (buff); } 00247 static CS_FORCEINLINE uint32 UInt32 (const void *buff) 00248 { 00249 #ifdef CS_STRICT_ALIGNMENT 00250 uint32 s; memcpy (&s, buff, sizeof (s)); 00251 return s; 00252 #else 00253 return *(uint32 *)buff; 00254 #endif 00255 } 00256 static CS_FORCEINLINE int32 Int32 (const void *buff) 00257 { return (int32)UInt32 (buff); } 00258 static CS_FORCEINLINE uint64 UInt64 (const void *buff) 00259 { 00260 #ifdef CS_STRICT_ALIGNMENT 00261 uint64 s; memcpy (&s, buff, sizeof (s)); 00262 return s; 00263 #else 00264 return *(uint64 *)buff; 00265 #endif 00266 } 00267 static CS_FORCEINLINE int64 Int64 (const void *buff) 00268 { return (int64)UInt64 (buff); } 00270 }; 00271 00280 struct csSetToAddress 00281 { 00283 00284 static CS_FORCEINLINE void UInt16 (void *buff, uint16 s) 00285 { 00286 #ifdef CS_STRICT_ALIGNMENT 00287 memcpy (buff, &s, sizeof (s)); 00288 #else 00289 *((uint16 *)buff) = s; 00290 #endif 00291 } 00292 static CS_FORCEINLINE void Int16 (void *buff, int16 s) 00293 { UInt16 (buff, (uint16)s); } 00294 static CS_FORCEINLINE void UInt32 (void *buff, uint32 s) 00295 { 00296 #ifdef CS_STRICT_ALIGNMENT 00297 memcpy (buff, &s, sizeof (s)); 00298 #else 00299 *((uint32 *)buff) = s; 00300 #endif 00301 } 00302 static CS_FORCEINLINE void Int32 (void *buff, int32 s) 00303 { UInt32 (buff, (uint32)s); } 00304 static CS_FORCEINLINE void UInt64 (void *buff, uint64 s) 00305 { 00306 #ifdef CS_STRICT_ALIGNMENT 00307 memcpy (buff, &s, sizeof (s)); 00308 #else 00309 *((uint64 *)buff) = s; 00310 #endif 00311 } 00312 static CS_FORCEINLINE void Int64 (void *buff, int64 s) 00313 { UInt64 (buff, (uint64)s); } 00315 }; 00316 00317 00318 /* 00319 To be able to painlessly transfer files betwen platforms, we should 00320 avoid using native floating-point format. Here are a couple of routines 00321 that are guaranteed to work on all platforms. 00322 00323 The floating point is converted to a fixed 1.7.25 bits format 00324 (one bit sign, 7 bits exponent, 25 bits mantissa) and back, 00325 so that we can binary store floating-point number without 00326 cross-platform problems. If you wonder why 1+7+25 = 33 while we 00327 only have 32 bits, we'll ommit the most significant bit of mantissa 00328 since it is always 1 (we use normalized numbers). This increases the 00329 precision twice. 00330 00331 For double, we use one bit sign, 15 bits exponent, 49 bits mantissa. 00332 */ 00333 00338 /*CS_DEPRECATED_METHOD*/ static inline int32 csFloatToLong (float f) 00339 { 00340 int exp; 00341 int32 mant = csQroundSure (frexp (f, &exp) * 0x1000000); 00342 int32 sign = mant & 0x80000000; 00343 if (mant < 0) mant = -mant; 00344 if (exp > 63) exp = 63; else if (exp < -64) exp = -64; 00345 return sign | ((exp & 0x7f) << 24) | (mant & 0xffffff); 00346 } 00347 00352 /*CS_DEPRECATED_METHOD*/ static inline float csLongToFloat (int32 l) 00353 { 00354 int exp = (l >> 24) & 0x7f; 00355 if (exp & 0x40) exp = exp | ~0x7f; 00356 float mant = float (l & 0x00ffffff) / 0x1000000; 00357 if (l & 0x80000000) mant = -mant; 00358 return (float) ldexp (mant, exp); 00359 } 00360 00361 /* Implementation note: csDoubleToLongLong() and csLongLongToDouble() 00362 * 00363 * We avoid use of CONST_INT64() because 64-bit constants are illegal with g++ 00364 * under -ansi -pedantic, and we want this header to be useful to external 00365 * projects which use -ansi -pedantic. Instead, we use bit shifts, such as (1 00366 * << 59), and construct `mask' manually. 00367 */ 00368 00373 /*CS_DEPRECATED_METHOD*/ static inline int64 csDoubleToLongLong (double d) 00374 { 00375 int exp; 00376 int64 mant = (int64) (frexp (d, &exp) * ((int64)1 << 48)); 00377 int64 sign = mant & ((int64)1 << 59); 00378 if (mant < 0) mant = -mant; 00379 if (exp > 32767) exp = 32767; else if (exp < -32768) exp = -32768; 00380 int64 const mask = ((uint64)0xffff << 32) | (uint64)0xffffffff; 00381 return sign | ((int64 (exp) & 0x7fff) << 48) | (mant & mask); 00382 } 00383 00388 /*CS_DEPRECATED_METHOD*/ static inline double csLongLongToDouble (int64 i) 00389 { 00390 int exp = (i >> 48) & 0x7fff; 00391 if (exp & 0x4000) exp = exp | ~0x7fff; 00392 int64 const mask = ((uint64)0xffff << 32) | (uint64)0xffffffff; 00393 double mant = double (i & mask) / ((int64)1 << 48); 00394 if (i & ((int64)1 << 59)) mant = -mant; 00395 return ldexp (mant, exp); 00396 } 00397 00398 /* *\name Floating point conversions 00399 * These routines are used for converting floating-point numbers 00400 * into 16-bit shorts and back. This is useful for low-precision data. 00401 * They use the 1.4.12 format. The range of numbers that can be represented 00402 * in this format is from 2^-8 to 2^7. The precision for numbers near to 00403 * 2^-8 (0.00390625) is near 0.000001, for numbers near 2^7 (128) is near 0.03. 00404 * @{ */ 00405 00410 /*CS_DEPRECATED_METHOD*/ static inline short csFloatToShort (float f) 00411 { 00412 int exp; 00413 long mant = csQroundSure (frexp (f, &exp) * 0x1000); 00414 long sign = mant & 0x8000; 00415 if (mant < 0) mant = -mant; 00416 if (exp > 7) mant = 0x7ff, exp = 7; else if (exp < -8) mant = 0, exp = -8; 00417 return short(sign | ((exp & 0xf) << 11) | (mant & 0x7ff)); 00418 } 00419 00424 /*CS_DEPRECATED_METHOD*/ static inline float csShortToFloat (short s) 00425 { 00426 int exp = (s >> 11) & 0xf; 00427 if (exp & 0x8) exp = exp | ~0xf; 00428 float mant = float ((s & 0x07ff) | 0x0800) / 0x1000; 00429 if (s & 0x8000) mant = -mant; 00430 return (float) ldexp (mant, exp); 00431 } 00432 00440 #endif // __CS_CSENDIAN_H__
Generated for Crystal Space 1.2 by doxygen 1.4.7