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 CS::Utility::BitOps::ScanBitReverse (mantissa, index); 00262 00263 exponent -= (index - 9); 00264 mantissa <<= (index - 8); 00265 mantissa &= 0x007FFFFF; 00266 } 00267 00268 // Convert the exponent... 00269 exponent += 112; 00270 exponent <<= 23; 00271 00272 // And create the float... 00273 u2f.u = sign | exponent | mantissa; 00274 00275 return u2f.f; 00276 } 00277 00282 static CS_FORCEINLINE uint16 FromNativeRTZ (float f) 00283 { 00284 union 00285 { 00286 float f; 00287 unsigned int u; 00288 } f2u; 00289 00290 f2u.f = f; 00291 unsigned short sign = 0x8000 & (f2u.u >> 16); 00292 00293 // Get the absolute value. 00294 f2u.u &= 0x7FFFFFFF; 00295 00296 // Check for a NaN 00297 if(CS::IsNaN (f2u.f)) 00298 { 00299 // Construct a silent NaN. 00300 f2u.u >>= 13; 00301 f2u.u &= 0x7fff; 00302 f2u.u |= 0x0200; 00303 return sign | f2u.u; 00304 } 00305 00306 // Check for overflow. 00307 if(f2u.u >= 0x47800000) 00308 { 00309 // Check for INF. 00310 if(f2u.u == 0x7F800000) 00311 return sign | 0x7C00; 00312 00313 return sign | 0x7BFF; 00314 } 00315 00316 // Check for underflow and denorms (flush to zero). 00317 if(f2u.u < 0x38800000) 00318 return sign; 00319 00320 // Convert the float to a half (rounding to zero). 00321 f2u.u &= 0xFFFFE000U; 00322 f2u.u -= 0x38000000U; 00323 return sign | (f2u.u >> 13); 00324 } 00325 }; 00326 00335 struct csGetFromAddress 00336 { 00338 00339 static CS_FORCEINLINE uint16 UInt16 (const void *buff) 00340 { 00341 #ifdef CS_STRICT_ALIGNMENT 00342 uint16 s; memcpy (&s, buff, sizeof (s)); 00343 return s; 00344 #else 00345 return *(uint16 *)buff; 00346 #endif 00347 } 00348 static CS_FORCEINLINE int16 Int16 (const void *buff) 00349 { return (int16)UInt16 (buff); } 00350 static CS_FORCEINLINE uint32 UInt32 (const void *buff) 00351 { 00352 #ifdef CS_STRICT_ALIGNMENT 00353 uint32 s; memcpy (&s, buff, sizeof (s)); 00354 return s; 00355 #else 00356 return *(uint32 *)buff; 00357 #endif 00358 } 00359 static CS_FORCEINLINE int32 Int32 (const void *buff) 00360 { return (int32)UInt32 (buff); } 00361 static CS_FORCEINLINE uint64 UInt64 (const void *buff) 00362 { 00363 #ifdef CS_STRICT_ALIGNMENT 00364 uint64 s; memcpy (&s, buff, sizeof (s)); 00365 return s; 00366 #else 00367 return *(uint64 *)buff; 00368 #endif 00369 } 00370 static CS_FORCEINLINE int64 Int64 (const void *buff) 00371 { return (int64)UInt64 (buff); } 00373 }; 00374 00383 struct csSetToAddress 00384 { 00386 00387 static CS_FORCEINLINE void UInt16 (void *buff, uint16 s) 00388 { 00389 #ifdef CS_STRICT_ALIGNMENT 00390 memcpy (buff, &s, sizeof (s)); 00391 #else 00392 *((uint16 *)buff) = s; 00393 #endif 00394 } 00395 static CS_FORCEINLINE void Int16 (void *buff, int16 s) 00396 { UInt16 (buff, (uint16)s); } 00397 static CS_FORCEINLINE void UInt32 (void *buff, uint32 s) 00398 { 00399 #ifdef CS_STRICT_ALIGNMENT 00400 memcpy (buff, &s, sizeof (s)); 00401 #else 00402 *((uint32 *)buff) = s; 00403 #endif 00404 } 00405 static CS_FORCEINLINE void Int32 (void *buff, int32 s) 00406 { UInt32 (buff, (uint32)s); } 00407 static CS_FORCEINLINE void UInt64 (void *buff, uint64 s) 00408 { 00409 #ifdef CS_STRICT_ALIGNMENT 00410 memcpy (buff, &s, sizeof (s)); 00411 #else 00412 *((uint64 *)buff) = s; 00413 #endif 00414 } 00415 static CS_FORCEINLINE void Int64 (void *buff, int64 s) 00416 { UInt64 (buff, (uint64)s); } 00418 }; 00419 00420 00421 /* 00422 To be able to painlessly transfer files betwen platforms, we should 00423 avoid using native floating-point format. Here are a couple of routines 00424 that are guaranteed to work on all platforms. 00425 00426 The floating point is converted to a fixed 1.7.25 bits format 00427 (one bit sign, 7 bits exponent, 25 bits mantissa) and back, 00428 so that we can binary store floating-point number without 00429 cross-platform problems. If you wonder why 1+7+25 = 33 while we 00430 only have 32 bits, we'll ommit the most significant bit of mantissa 00431 since it is always 1 (we use normalized numbers). This increases the 00432 precision twice. 00433 00434 For double, we use one bit sign, 15 bits exponent, 49 bits mantissa. 00435 */ 00436 00442 CS_DEPRECATED_METHOD_MSG("Use csIEEEfloat methods instead") 00443 static inline int32 csFloatToLong (float f) 00444 { 00445 int exp; 00446 int32 mant = csQroundSure (frexp (f, &exp) * 0x1000000); 00447 int32 sign = mant & 0x80000000; 00448 if (mant < 0) mant = -mant; 00449 if (exp > 63) exp = 63; else if (exp < -64) exp = -64; 00450 return sign | ((exp & 0x7f) << 24) | (mant & 0xffffff); 00451 } 00452 00458 CS_DEPRECATED_METHOD_MSG("Use csIEEEfloat methods instead") 00459 static inline float csLongToFloat (int32 l) 00460 { 00461 int exp = (l >> 24) & 0x7f; 00462 if (exp & 0x40) exp = exp | ~0x7f; 00463 float mant = float (l & 0x00ffffff) / 0x1000000; 00464 if (l & 0x80000000) mant = -mant; 00465 return (float) ldexp (mant, exp); 00466 } 00467 00468 /* Implementation note: csDoubleToLongLong() and csLongLongToDouble() 00469 * 00470 * We avoid use of CONST_INT64() because 64-bit constants are illegal with g++ 00471 * under -ansi -pedantic, and we want this header to be useful to external 00472 * projects which use -ansi -pedantic. Instead, we use bit shifts, such as (1 00473 * << 59), and construct `mask' manually. 00474 */ 00475 00481 CS_DEPRECATED_METHOD_MSG("Use csIEEEfloat methods instead") 00482 static inline int64 csDoubleToLongLong (double d) 00483 { 00484 int exp; 00485 int64 mant = (int64) (frexp (d, &exp) * ((int64)1 << 48)); 00486 int64 sign = mant & ((int64)1 << 59); 00487 if (mant < 0) mant = -mant; 00488 if (exp > 32767) exp = 32767; else if (exp < -32768) exp = -32768; 00489 int64 const mask = ((uint64)0xffff << 32) | (uint64)0xffffffff; 00490 return sign | ((int64 (exp) & 0x7fff) << 48) | (mant & mask); 00491 } 00492 00498 CS_DEPRECATED_METHOD_MSG("Use csIEEEfloat methods instead") 00499 static inline double csLongLongToDouble (int64 i) 00500 { 00501 int exp = (i >> 48) & 0x7fff; 00502 if (exp & 0x4000) exp = exp | ~0x7fff; 00503 int64 const mask = ((uint64)0xffff << 32) | (uint64)0xffffffff; 00504 double mant = double (i & mask) / ((int64)1 << 48); 00505 if (i & ((int64)1 << 59)) mant = -mant; 00506 return ldexp (mant, exp); 00507 } 00508 00509 /* *\name Floating point conversions 00510 * These routines are used for converting floating-point numbers 00511 * into 16-bit shorts and back. This is useful for low-precision data. 00512 * They use the 1.4.12 format. The range of numbers that can be represented 00513 * in this format is from 2^-8 to 2^7. The precision for numbers near to 00514 * 2^-8 (0.00390625) is near 0.000001, for numbers near 2^7 (128) is near 0.03. 00515 * @{ */ 00516 00522 CS_DEPRECATED_METHOD_MSG("Use csIEEEfloat methods instead") 00523 static inline short csFloatToShort (float f) 00524 { 00525 int exp; 00526 long mant = csQroundSure (frexp (f, &exp) * 0x1000); 00527 long sign = mant & 0x8000; 00528 if (mant < 0) mant = -mant; 00529 if (exp > 7) mant = 0x7ff, exp = 7; else if (exp < -8) mant = 0, exp = -8; 00530 return short(sign | ((exp & 0xf) << 11) | (mant & 0x7ff)); 00531 } 00532 00538 CS_DEPRECATED_METHOD_MSG("Use csIEEEfloat methods instead") 00539 static inline float csShortToFloat (short s) 00540 { 00541 int exp = (s >> 11) & 0xf; 00542 if (exp & 0x8) exp = exp | ~0xf; 00543 float mant = float ((s & 0x07ff) | 0x0800) / 0x1000; 00544 if (s & 0x8000) mant = -mant; 00545 return (float) ldexp (mant, exp); 00546 } 00547 00555 #endif // __CS_CSENDIAN_H__
Generated for Crystal Space 2.0 by doxygen 1.6.1