Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

/ray/src/lib/lex/fastval2str.cc

Go to the documentation of this file.
00001 /*
00002  * lib/lex/fastval2str.cc
00003  * 
00004  * Fast integer / floating point string writing routines. 
00005  * 
00006  * Copyright (c) 2004 by Wolfgang Wieser ] wwieser (a) gmx <*> de [ 
00007  * 
00008  * This file may be distributed and/or modified under the terms of the 
00009  * GNU General Public License version 2 as published by the Free Software 
00010  * Foundation. (See COPYING.GPL for details.)
00011  * 
00012  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00013  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00014  * 
00015  */
00016 
00017 #include "fastval2str.h"
00018 #include <lib/numerics/num_math.h>
00019 
00020 
00021 // These are the hex chars. I added 4 more to be on the safe side for 
00022 // strange things which are not supposed to happen...
00023 static const char *_hexdig="YZ0123456789abcdefGH";
00024 static const char *hexdig=_hexdig+2;
00025 
00026 
00027 // Used to format integer into string. 
00028 // Only base values 8, 10 and 16 are supported; base 8 gets 0 prefix and 
00029 // base 16 gets 0x prefix. 
00030 // Special value 0 is base 16 without prefix. 
00031 template<typename T>static char *_UInt2String(char *dest,T val,char base)
00032 {
00033     // These are optimized version for each supported base. 
00034     switch(base)
00035     {
00036         case 8:
00037         {
00038             *dest++='0';
00039             if(!val)  break;
00040             // Make sure shift is dividable by 3. 
00041             int shift = 
00042                 (sizeof(T)*8)%3==0 ? (sizeof(T)*8) : 
00043                 (sizeof(T)*8+1)%3==0 ? (sizeof(T)*8+1) : (sizeof(T)*8+2);
00044             Assert(!(shift%3));
00045             while(shift)
00046             {
00047                 shift-=3;
00048                 uchar c=(uchar)((val>>shift)&7U);  
00049                 if(c)
00050                 {  *dest++=(char)c+'0';  break;  }
00051             }
00052             while(shift)
00053             {
00054                 shift-=3;
00055                 *dest++=(char)((val>>shift)&0x7U)+'0';
00056             }
00057         }   break;
00058         case 10:
00059         {
00060             if(!val)
00061             {  *dest++='0';  break;  }
00062             static const T div0 = 
00063                 sizeof(T)==1 ? (T)100U : 
00064                 sizeof(T)==2 ? (T)10000U : 
00065                 sizeof(T)==4 ? (T)1000000000LU : 
00066                                (T)10000000000000000000LLU;
00067             T div=div0;
00068             uchar c;
00069             while(div)
00070             {
00071                 c=(uchar)(val/div);
00072                 if(c)  goto start;
00073                 div/=10;
00074             }
00075             while(div)
00076             {
00077                 c=(uchar)(val/div);
00078                 start:
00079                 *dest++=(char)c+'0';
00080                 val-=c*div;
00081                 div/=10;
00082             }
00083         }   break;
00084         case 16:
00085             *dest++='0';
00086             *dest++='x';
00087             // Fall through
00088         case 0:  // <-- special case: base 0 is base 16 without prefix
00089         {
00090             if(!val)
00091             {  *dest++='0';  break;  }
00092             int shift=sizeof(T)*8;
00093             while(shift)
00094             {
00095                 shift-=4;
00096                 uchar c=(uchar)((val>>shift)&0xfU);  
00097                 if(c)
00098                 {  *dest++=hexdig[c];  break;  }
00099             }
00100             while(shift)
00101             {
00102                 shift-=4;
00103                 *dest++=hexdig[(val>>shift)&0xfU];
00104             }
00105         }   break;
00106         default: Assert(0);
00107     }
00108     
00109     return(dest);
00110 }
00111 
00112 // Generate the exported instantiations. 
00113 char *FastInt2String(char *dest,uint8 val,char base)
00114     {  return(_UInt2String<uint8>(dest,val,base));  }
00115 char *FastInt2String(char *dest,uint16 val,char base)
00116     {  return(_UInt2String<uint16>(dest,val,base));  }
00117 char *FastInt2String(char *dest,uint32 val,char base)
00118     {  return(_UInt2String<uint32>(dest,val,base));  }
00119 char *FastInt2String(char *dest,uint64 val,char base)
00120     {  return(_UInt2String<uint64>(dest,val,base));  }
00121 
00122 
00123 template<typename T,typename UT>static inline char *_SInt2String(
00124     char *dest,T val,char base)
00125 {
00126     UT uval;
00127     
00128     if(val<0)
00129     {  *dest++='-';  uval=(UT)(-val);  }
00130     else
00131     {  uval=(UT)val;  }
00132     
00133     return(_UInt2String<UT>(dest,uval,base));
00134 }
00135 
00136 // Generate the exported instantiations. 
00137 char *FastInt2String(char *dest,int8 val,char base)
00138     {  return(_SInt2String<int8,uint8>(dest,val,base));  }
00139 char *FastInt2String(char *dest,int16 val,char base)
00140     {  return(_SInt2String<int16,uint16>(dest,val,base));  }
00141 char *FastInt2String(char *dest,int32 val,char base)
00142     {  return(_SInt2String<int32,uint32>(dest,val,base));  }
00143 char *FastInt2String(char *dest,int64 val,char base)
00144     {  return(_SInt2String<int64,uint64>(dest,val,base));  }
00145 
00146 
00147 template<typename T>static char *_Float2String(char *dest,T val)
00148 {
00149     if(val==0)
00150     {  *dest++='0';  }
00151     
00152     if(val<0)
00153     {  *dest++='-';  val=-val;  }
00154     *dest++='0';
00155     *dest++='x';
00156     *dest++='.';
00157     
00158     int exp=0;
00159     val=NUM::frexp(val,&exp);
00160     
00161     // This worls well for IEEE-754, IEEE-854. 
00162     // IEEE FP numbers: double: m=52 bits (13 hexdig), exp=11 bits (3 hexdig)
00163     // IEEE FP numbers: float:  m=23 bits (6 hexdig), exp=8 bits (2 hexdig)
00164     // The m_digs values have been verified to catch exactly the whole 
00165     // IEEE precision. Following digits are all 0. 
00166     static const int m_digs = 
00167         sizeof(T)==8 ? 13 : 
00168         sizeof(T)==4 ? 6 : 0;
00169     
00170     // This has been verified to work correctly with IEEE FP numbers. 
00171     for(int i=0; i<m_digs; i++)
00172     {
00173         val*=16.0;
00174         int iv=(int)val;
00175         *dest++=hexdig[iv];
00176         val-=(T)iv;
00177         if(val==0.0)  break;  // <-- Avoid trailing zeros. 
00178     }
00179     // Remove trailing zeros: 
00180     //while(*--dest=='0');
00181     //if(*++dest=='.')  ++dest;
00182     
00183     *dest++='p';
00184     
00185     dest=_SInt2String<int,uint>(dest,exp,10);
00186     
00187     return(dest);
00188 }
00189 
00190 char *FastFloat2String(char *dest,flt val)
00191     {  return(_Float2String<flt>(dest,val));  }
00192 char *FastFloat2String(char *dest,dbl val)
00193     {  return(_Float2String<dbl>(dest,val));  }
00194 
00195 
00196 #if 0   /* test program */
00197 // gcc fastval2str.o -o test -lm && ./test
00198 
00199 #include <stdio.h>
00200 
00201 int main()
00202 {
00203     char tmp[256];
00204     
00205     char *s=tmp;
00206     //s=FastInt2String(s,18446744073709551615LLU,16);
00207     //s=FastInt2String(s,(uint8)0xf,8);
00208     //s=FastFloat2String(s,0x.edcba987654321p-77);
00209     //s=FastFloat2String(s,0.1f);
00210     s=FastFloat2String(s,0x.81201p0);
00211     *s='\0';
00212     
00213     fprintf(stderr,"out=<%s>\n",tmp);
00214     
00215     return(0);
00216 }
00217 #endif

Generated on Sat Feb 19 22:33:45 2005 for Ray by doxygen 1.3.5