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 #include "csgeom/math.h" 00032 #include "csutil/bitops.h" 00033 #if defined(CS_HAVE_BYTESWAP_H) 00034 #include <byteswap.h> 00035 #endif 00036 00037 #define csQroundSure(x) (int ((x) + ((x < 0) ? -0.5 : +0.5))) 00038 00042 struct csSwapBytes 00043 { 00044 public: 00046 00047 static CS_FORCEINLINE uint16 Swap (uint16 s) 00048 { 00049 #if defined(CS_COMPILER_MSVC) && (_MSC_VER >= 1300) 00050 return _byteswap_ushort (s); 00051 #elif defined(CS_HAVE_BYTESWAP_H) 00052 return bswap_16 (s); 00053 #else 00054 return (s >> 8) | (s << 8); 00055 #endif 00056 } 00057 static CS_FORCEINLINE int16 Swap (int16 s) 00058 { return (int16)Swap ((uint16)s); } 00059 static CS_FORCEINLINE uint32 Swap (uint32 l) 00060 { 00061 #if defined(CS_COMPILER_MSVC) && (_MSC_VER >= 1300) 00062 return _byteswap_ulong (l); 00063 #elif defined(CS_HAVE_BYTESWAP_H) 00064 return bswap_32 (l); 00065 #else 00066 return (l >> 24) | ((l >> 8) & 0xff00) | ((l << 8) & 0xff0000) | (l << 24); 00067 #endif 00068 } 00069 static CS_FORCEINLINE int32 Swap (int32 l) 00070 { return (int32)Swap ((uint32)l); } 00071 static CS_FORCEINLINE uint64 Swap (uint64 l) 00072 { 00073 #if defined(CS_COMPILER_MSVC) && (_MSC_VER >= 1300) 00074 return _byteswap_uint64 (l); 00075 #elif defined(CS_HAVE_BYTESWAP_H) && !defined(__STRICT_ANSI__) 00076 return bswap_64 (l); 00077 #else 00078 union 00079 { 00080 uint64 ui64; 00081 uint32 ui32[2]; 00082 } u1, u2; 00083 u1.ui64 = l; 00084 u2.ui32[0] = Swap (u1.ui32[1]); 00085 u2.ui32[1] = Swap (u1.ui32[0]); 00086 return u2.ui64; 00087 #endif 00088 } 00089 static CS_FORCEINLINE int64 Swap (int64 l) 00090 { return (int64)Swap ((uint64)l); } 00091 00092 static CS_FORCEINLINE uint16 UInt16 (uint16 x) { return Swap (x); } 00093 static CS_FORCEINLINE int16 Int16 (int16 x) { return Swap (x); } 00094 static CS_FORCEINLINE uint32 UInt32 (uint32 x) { return Swap (x); } 00095 static CS_FORCEINLINE int32 Int32 (int32 x) { return Swap (x); } 00096 static CS_FORCEINLINE uint64 UInt64 (uint64 x) { return Swap (x); } 00097 static CS_FORCEINLINE int64 Int64 (int64 x) { return Swap (x); } 00099 }; 00100 00101 #ifdef CS_BIG_ENDIAN 00102 struct csBigEndian 00103 #else 00109 struct csLittleEndian 00110 #endif 00111 { 00113 00114 static CS_FORCEINLINE uint16 Convert (uint16 x) { return x; } 00115 static CS_FORCEINLINE int16 Convert (int16 x) { return x; } 00116 static CS_FORCEINLINE uint32 Convert (uint32 x) { return x; } 00117 static CS_FORCEINLINE int32 Convert (int32 x) { return x; } 00118 static CS_FORCEINLINE uint64 Convert (uint64 x) { return x; } 00119 static CS_FORCEINLINE int64 Convert (int64 x) { return x; } 00120 00121 static CS_FORCEINLINE uint16 UInt16 (uint16 x) { return Convert (x); } 00122 static CS_FORCEINLINE int16 Int16 (int16 x) { return Convert (x); } 00123 static CS_FORCEINLINE uint32 UInt32 (uint32 x) { return Convert (x); } 00124 static CS_FORCEINLINE int32 Int32 (int32 x) { return Convert (x); } 00125 static CS_FORCEINLINE uint64 UInt64 (uint64 x) { return Convert (x); } 00126 static CS_FORCEINLINE int64 Int64 (int64 x) { return Convert (x); } 00128 }; 00129 00130 #ifdef CS_LITTLE_ENDIAN 00131 00136 struct csBigEndian 00137 #else 00138 struct csLittleEndian 00139 #endif 00140 { 00141 public: 00143 00144 static CS_FORCEINLINE uint16 Convert (uint16 s) 00145 { return csSwapBytes::Swap (s); } 00146 static CS_FORCEINLINE int16 Convert (int16 s) 00147 { return csSwapBytes::Swap (s); } 00148 static CS_FORCEINLINE uint32 Convert (uint32 l) 00149 { return csSwapBytes::Swap (l); } 00150 static CS_FORCEINLINE int32 Convert (int32 l) 00151 { return csSwapBytes::Swap (l); } 00152 static CS_FORCEINLINE uint64 Convert (uint64 l) 00153 { return csSwapBytes::Swap (l); } 00154 static CS_FORCEINLINE int64 Convert (int64 l) 00155 { return csSwapBytes::Swap (l); } 00156 00157 static CS_FORCEINLINE uint16 UInt16 (uint16 x) { return Convert (x); } 00158 static CS_FORCEINLINE int16 Int16 (int16 x) { return Convert (x); } 00159 static CS_FORCEINLINE uint32 UInt32 (uint32 x) { return Convert (x); } 00160 static CS_FORCEINLINE int32 Int32 (int32 x) { return Convert (x); } 00161 static CS_FORCEINLINE uint64 UInt64 (uint64 x) { return Convert (x); } 00162 static CS_FORCEINLINE int64 Int64 (int64 x) { return Convert (x); } 00164 }; 00165 00169 struct csIEEEfloat 00170 { 00171 /* \todo It would be even better if we also check for sizeof (float) 00172 * in configure or so. */ 00173 #ifdef CS_IEEE_DOUBLE_FORMAT 00174 00175 00176 static CS_FORCEINLINE uint32 FromNative (float f) 00177 { 00178 union 00179 { 00180 float f; 00181 uint32 ui32; 00182 } u; 00183 u.f = f; 00184 return u.ui32; 00185 } 00186 static CS_FORCEINLINE uint64 FromNative (double f) 00187 { 00188 union 00189 { 00190 double f; 00191 uint64 ui64; 00192 } u; 00193 u.f = f; 00194 return u.ui64; 00195 } 00197 00199 00200 static CS_FORCEINLINE float ToNative (uint32 f) 00201 { 00202 union 00203 { 00204 float f; 00205 uint32 ui32; 00206 } u; 00207 u.ui32 = f; 00208 return u.f; 00209 } 00210 static CS_FORCEINLINE double ToNative (uint64 f) 00211 { 00212 union 00213 { 00214 double f; 00215 uint64 ui64; 00216 } u; 00217 u.ui64 = f; 00218 return u.f; 00219 } 00221 #else 00222 #error Do not know how to convert to IEEE floats 00223 #endif 00224 00226 static CS_FORCEINLINE float ToNative (uint16 half) 00227 { 00228 union 00229 { 00230 uint32 u; 00231 float f; 00232 } u2f; 00233 00234 uint32 sign = (half & 0x8000) << 16; 00235 int32 exponent = (half & 0x7C00) >> 10; 00236 uint32 mantissa = (half & 0x03ff) << 13; 00237 00238 // Check for INF or NaN. 00239 if (exponent == 0x1F) 00240 { 00241 u2f.u = sign | mantissa; 00242 00243 if (mantissa != 0) 00244 { 00245 // NaN 00246 u2f.u |= 0x7FC00000; 00247 } 00248 else 00249 { 00250 // INF 00251 u2f.u |= 0x7f800000; 00252 } 00253 00254 return u2f.f; 00255 } 00256 00257 // Check for a denorm. 00258 if(exponent == 0) 00259 { 00260 unsigned long index; 00261 if (CS::Utility::BitOps::ScanBitReverse (mantissa, index)) 00262 { 00263 exponent -= (index - 9); 00264 mantissa <<= (index - 8); 00265 mantissa &= 0x007FFFFF; 00266 } 00267 else 00268 { 00269 // 0 mantissa -> force float to be 0 00270 return (sign != 0) ? -0.0f : 0.0f; 00271 } 00272 } 00273 00274 // Convert the exponent... 00275 exponent += 112; 00276 exponent <<= 23; 00277 00278 // And create the float... 00279 u2f.u = sign | exponent | mantissa; 00280 00281 return u2f.f; 00282 } 00283 00288 static CS_FORCEINLINE uint16 FromNativeRTZ (float f) 00289 { 00290 union 00291 { 00292 float f; 00293 unsigned int u; 00294 } f2u; 00295 00296 f2u.f = f; 00297 unsigned short sign = 0x8000 & (f2u.u >> 16); 00298 00299 // Get the absolute value. 00300 f2u.u &= 0x7FFFFFFF; 00301 00302 // Check for a NaN 00303 if(CS::IsNaN (f2u.f)) 00304 { 00305 // Construct a silent NaN. 00306 f2u.u >>= 13; 00307 f2u.u &= 0x7fff; 00308 f2u.u |= 0x0200; 00309 return sign | f2u.u; 00310 } 00311 00312 // Check for overflow. 00313 if(f2u.u >= 0x47800000) 00314 { 00315 // Check for INF. 00316 if(f2u.u == 0x7F800000) 00317 return sign | 0x7C00; 00318 00319 return sign | 0x7BFF; 00320 } 00321 00322 // Check for underflow and denorms (flush to zero). 00323 if(f2u.u < 0x38800000) 00324 return sign; 00325 00326 // Convert the float to a half (rounding to zero). 00327 f2u.u &= 0xFFFFE000U; 00328 f2u.u -= 0x38000000U; 00329 return sign | (f2u.u >> 13); 00330 } 00331 }; 00332 00341 struct csGetFromAddress 00342 { 00344 00345 static CS_FORCEINLINE uint16 UInt16 (const void *buff) 00346 { 00347 #ifdef CS_STRICT_ALIGNMENT 00348 uint16 s; memcpy (&s, buff, sizeof (s)); 00349 return s; 00350 #else 00351 return *(uint16 *)buff; 00352 #endif 00353 } 00354 static CS_FORCEINLINE int16 Int16 (const void *buff) 00355 { return (int16)UInt16 (buff); } 00356 static CS_FORCEINLINE uint32 UInt32 (const void *buff) 00357 { 00358 #ifdef CS_STRICT_ALIGNMENT 00359 uint32 s; memcpy (&s, buff, sizeof (s)); 00360 return s; 00361 #else 00362 return *(uint32 *)buff; 00363 #endif 00364 } 00365 static CS_FORCEINLINE int32 Int32 (const void *buff) 00366 { return (int32)UInt32 (buff); } 00367 static CS_FORCEINLINE uint64 UInt64 (const void *buff) 00368 { 00369 #ifdef CS_STRICT_ALIGNMENT 00370 uint64 s; memcpy (&s, buff, sizeof (s)); 00371 return s; 00372 #else 00373 return *(uint64 *)buff; 00374 #endif 00375 } 00376 static CS_FORCEINLINE int64 Int64 (const void *buff) 00377 { return (int64)UInt64 (buff); } 00379 }; 00380 00389 struct csSetToAddress 00390 { 00392 00393 static CS_FORCEINLINE void UInt16 (void *buff, uint16 s) 00394 { 00395 #ifdef CS_STRICT_ALIGNMENT 00396 memcpy (buff, &s, sizeof (s)); 00397 #else 00398 *((uint16 *)buff) = s; 00399 #endif 00400 } 00401 static CS_FORCEINLINE void Int16 (void *buff, int16 s) 00402 { UInt16 (buff, (uint16)s); } 00403 static CS_FORCEINLINE void UInt32 (void *buff, uint32 s) 00404 { 00405 #ifdef CS_STRICT_ALIGNMENT 00406 memcpy (buff, &s, sizeof (s)); 00407 #else 00408 *((uint32 *)buff) = s; 00409 #endif 00410 } 00411 static CS_FORCEINLINE void Int32 (void *buff, int32 s) 00412 { UInt32 (buff, (uint32)s); } 00413 static CS_FORCEINLINE void UInt64 (void *buff, uint64 s) 00414 { 00415 #ifdef CS_STRICT_ALIGNMENT 00416 memcpy (buff, &s, sizeof (s)); 00417 #else 00418 *((uint64 *)buff) = s; 00419 #endif 00420 } 00421 static CS_FORCEINLINE void Int64 (void *buff, int64 s) 00422 { UInt64 (buff, (uint64)s); } 00424 }; 00425 00426 00427 /* 00428 To be able to painlessly transfer files betwen platforms, we should 00429 avoid using native floating-point format. Here are a couple of routines 00430 that are guaranteed to work on all platforms. 00431 00432 The floating point is converted to a fixed 1.7.25 bits format 00433 (one bit sign, 7 bits exponent, 25 bits mantissa) and back, 00434 so that we can binary store floating-point number without 00435 cross-platform problems. If you wonder why 1+7+25 = 33 while we 00436 only have 32 bits, we'll ommit the most significant bit of mantissa 00437 since it is always 1 (we use normalized numbers). This increases the 00438 precision twice. 00439 00440 For double, we use one bit sign, 15 bits exponent, 49 bits mantissa. 00441 */ 00442 00448 CS_DEPRECATED_METHOD_MSG("Use csIEEEfloat methods instead") 00449 static inline int32 csFloatToLong (float f) 00450 { 00451 int exp; 00452 int32 mant = csQroundSure (frexp (f, &exp) * 0x1000000); 00453 int32 sign = mant & 0x80000000; 00454 if (mant < 0) mant = -mant; 00455 if (exp > 63) exp = 63; else if (exp < -64) exp = -64; 00456 return sign | ((exp & 0x7f) << 24) | (mant & 0xffffff); 00457 } 00458 00464 CS_DEPRECATED_METHOD_MSG("Use csIEEEfloat methods instead") 00465 static inline float csLongToFloat (int32 l) 00466 { 00467 int exp = (l >> 24) & 0x7f; 00468 if (exp & 0x40) exp = exp | ~0x7f; 00469 float mant = float (l & 0x00ffffff) / 0x1000000; 00470 if (l & 0x80000000) mant = -mant; 00471 return (float) ldexp (mant, exp); 00472 } 00473 00474 /* Implementation note: csDoubleToLongLong() and csLongLongToDouble() 00475 * 00476 * We avoid use of CONST_INT64() because 64-bit constants are illegal with g++ 00477 * under -ansi -pedantic, and we want this header to be useful to external 00478 * projects which use -ansi -pedantic. Instead, we use bit shifts, such as (1 00479 * << 59), and construct `mask' manually. 00480 */ 00481 00487 CS_DEPRECATED_METHOD_MSG("Use csIEEEfloat methods instead") 00488 static inline int64 csDoubleToLongLong (double d) 00489 { 00490 int exp; 00491 int64 mant = (int64) (frexp (d, &exp) * ((int64)1 << 48)); 00492 int64 sign = mant & ((int64)1 << 59); 00493 if (mant < 0) mant = -mant; 00494 if (exp > 32767) exp = 32767; else if (exp < -32768) exp = -32768; 00495 int64 const mask = ((uint64)0xffff << 32) | (uint64)0xffffffff; 00496 return sign | ((int64 (exp) & 0x7fff) << 48) | (mant & mask); 00497 } 00498 00504 CS_DEPRECATED_METHOD_MSG("Use csIEEEfloat methods instead") 00505 static inline double csLongLongToDouble (int64 i) 00506 { 00507 int exp = (i >> 48) & 0x7fff; 00508 if (exp & 0x4000) exp = exp | ~0x7fff; 00509 int64 const mask = ((uint64)0xffff << 32) | (uint64)0xffffffff; 00510 double mant = double (i & mask) / ((int64)1 << 48); 00511 if (i & ((int64)1 << 59)) mant = -mant; 00512 return ldexp (mant, exp); 00513 } 00514 00515 /* *\name Floating point conversions 00516 * These routines are used for converting floating-point numbers 00517 * into 16-bit shorts and back. This is useful for low-precision data. 00518 * They use the 1.4.12 format. The range of numbers that can be represented 00519 * in this format is from 2^-8 to 2^7. The precision for numbers near to 00520 * 2^-8 (0.00390625) is near 0.000001, for numbers near 2^7 (128) is near 0.03. 00521 * @{ */ 00522 00528 CS_DEPRECATED_METHOD_MSG("Use csIEEEfloat methods instead") 00529 static inline short csFloatToShort (float f) 00530 { 00531 int exp; 00532 long mant = csQroundSure (frexp (f, &exp) * 0x1000); 00533 long sign = mant & 0x8000; 00534 if (mant < 0) mant = -mant; 00535 if (exp > 7) mant = 0x7ff, exp = 7; else if (exp < -8) mant = 0, exp = -8; 00536 return short(sign | ((exp & 0xf) << 11) | (mant & 0x7ff)); 00537 } 00538 00544 CS_DEPRECATED_METHOD_MSG("Use csIEEEfloat methods instead") 00545 static inline float csShortToFloat (short s) 00546 { 00547 int exp = (s >> 11) & 0xf; 00548 if (exp & 0x8) exp = exp | ~0xf; 00549 float mant = float ((s & 0x07ff) | 0x0800) / 0x1000; 00550 if (s & 0x8000) mant = -mant; 00551 return (float) ldexp (mant, exp); 00552 } 00553 00561 #endif // __CS_CSENDIAN_H__
Generated for Crystal Space 2.1 by doxygen 1.6.1
