CrystalSpace

Public API Reference

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.1 by doxygen 1.5.3