csutil/csendian.h Source File (Crystal Space 2.0 Public API Reference)

| ## Public API Reference

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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__