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

Number.d

Go to the documentation of this file.
00001 /*******************************************************************************
00002 
00003         @file Number.d
00004         
00005         Copyright (c) 2004 Kris Bell
00006         
00007         This software is provided 'as-is', without any express or implied
00008         warranty. In no event will the authors be held liable for damages
00009         of any kind arising from the use of this software.
00010         
00011         Permission is hereby granted to anyone to use this software for any 
00012         purpose, including commercial applications, and to alter it and/or 
00013         redistribute it freely, subject to the following restrictions:
00014         
00015         1. The origin of this software must not be misrepresented; you must 
00016            not claim that you wrote the original software. If you use this 
00017            software in a product, an acknowledgment within documentation of 
00018            said product would be appreciated but is not required.
00019 
00020         2. Altered source versions must be plainly marked as such, and must 
00021            not be misrepresented as being the original software.
00022 
00023         3. This notice may not be removed or altered from any distribution
00024            of the source.
00025 
00026         4. Derivative works are permitted, but they must carry this notice
00027            in full and credit the original source.
00028 
00029 
00030                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00031 
00032         
00033         @version        Initial version; Feb 2005
00034 
00035         @author         Kris
00036 
00037 
00038 *******************************************************************************/
00039 
00040 module mango.format.Number;
00041 
00042 private import  mango.format.Styled;
00043 
00044 /******************************************************************************
00045 
00046         Utility functions for integer conversion.
00047 
00048         While these functions are all static, they are encapsulated within 
00049         a class inheritance to preserve some namespace cohesion. One might 
00050         use structs for encapsualtion instead, but then inheritance would 
00051         be lost. Note that the root class, Styled, is abstract to prevent 
00052         accidental instantiation of these classes.
00053 
00054 ******************************************************************************/
00055 
00056 class Number : Styled
00057 {
00058         enum NFormat:ubyte {Binary='b', Octal='o', Hex='x', HexUpper='X', Decimal='d', Unsigned='u'};
00059 
00060         /***********************************************************************
00061         
00062                 Format numeric values into the provided output buffer. The
00063                 traditional printf() conversion specifiers are adhered to,
00064                 and the following types are supported:
00065 
00066                 u - unsigned decimal
00067                 d - signed decimal
00068                 o - octal
00069                 x - lowercase hexadecimal
00070                 X - uppercase hexadecimal
00071                 b - binary
00072 
00073                 Modifiers supported include:
00074 
00075                 #      : prefix the conversion with a type identifier
00076                 +      : prefix positive decimals with a '+'
00077                 space  : prefix positive decimals with one space
00078                 0      : left-pad the number with zeros
00079 
00080                 These modifiers are specifed via the 'flags' provided, 
00081                 and are represented via these identifiers:
00082 
00083                 #     : Flags.Hash
00084                 +     : Flags.Plus
00085                 space : Flags.Space
00086                 0     : Flags.Zero
00087 
00088         ***********************************************************************/
00089 
00090         final static char[] format (char[] dst, long i, NFormat fmt = NFormat.Decimal, Flags flags = 0)
00091         {
00092                 char[]  prefix;
00093                 int     len = dst.length;
00094                    
00095                 // must have some buffer space to operate within! 
00096                 if (len)
00097                    {
00098                    uint    radix;
00099                    char[]  numbers = "0123456789abcdef";
00100 
00101                    // pre-conversion setup
00102                    switch (fmt)
00103                           {
00104                           default:
00105                           case NFormat.Decimal:
00106                                if (i < 0)
00107                                   {
00108                                   prefix = "-";
00109                                   i = -i;
00110                                   }
00111                                else
00112                                   if (flags & Flags.Space)
00113                                       prefix = " ";
00114                                   else
00115                                      if (flags & Flags.Plus)
00116                                          prefix = "+";
00117                                // fall through!
00118                           case NFormat.Unsigned:
00119                                radix = 10;
00120                                break;
00121 
00122                           case NFormat.Binary:
00123                                radix = 2;
00124                                if (flags & Flags.Hash)
00125                                    prefix = "0b";
00126                                break;
00127 
00128                           case NFormat.Octal:
00129                                radix = 8;
00130                                if (flags & Flags.Hash)
00131                                    prefix = "0o";
00132                                break;
00133 
00134                           case NFormat.Hex:
00135                                radix = 16;
00136                                if (flags & Flags.Hash)
00137                                    prefix = "0x";
00138                                break;
00139 
00140                           case NFormat.HexUpper:
00141                                radix = 16;
00142                                numbers = "0123456789ABCDEF";
00143                                if (flags & Flags.Hash)
00144                                    prefix = "0X";
00145                                break;
00146                           }
00147         
00148                    // convert number to text
00149                    char* p = dst.ptr + len;
00150                    if (i <= uint.max)
00151                       {
00152                       uint v = i;
00153                       do {
00154                          *--p = numbers[v % radix];
00155                          } while ((v /= radix) && --len);
00156                       }
00157                    else
00158                       {
00159                       ulong v = i;
00160                       do {
00161                          *--p = numbers[v % radix];
00162                          } while ((v /= radix) && --len);
00163                       }
00164                    }
00165 
00166                 // are we about to overflow?
00167                 if (--len < 0 || 0 > (len -= prefix.length))
00168                     error ("output buffer too small in Number.format()");
00169 
00170                 // prefix number with zeros? 
00171                 if (flags & Flags.Zero)
00172                    {
00173                    dst [prefix.length .. len + prefix.length] = '0';
00174                    len = 0;
00175                    }
00176                 
00177                 // write optional prefix string ...
00178                 dst [len .. len + prefix.length] = prefix[];
00179 
00180                 // return slice of provided output buffer
00181                 return dst [len .. dst.length];                               
00182         } 
00183 
00184 
00185         /**********************************************************************
00186         
00187                 Strip leading whitespace, extract an optional numeric sign,
00188                 and optionally strip and return a possible radix prefix.
00189 
00190                 This can be used as a precursor to the conversion of digits
00191                 into a number.
00192 
00193                 Returns the number of matching characters.
00194 
00195         **********************************************************************/
00196 
00197         package static uint trim (char[] digits, inout bool sign, uint* radix=null)
00198         {
00199                 char   c;
00200                 char*  p = digits;
00201                 int    len = digits.length;
00202 
00203                 // strip off whitespace and sign characters
00204                 for (c = *p; len; c = *++p, --len)
00205                      if (c == ' ' || c == '\t')
00206                         {}
00207                      else
00208                         if (c == '-')
00209                             sign = true;
00210                         else
00211                            if (c == '+')
00212                                sign = false;
00213                            else
00214                               break;
00215 
00216                 // strip off a radix specifier also?
00217                 if (radix && *radix == 0)
00218                     if (c == '0' && len)
00219                         switch (*++p)
00220                                {
00221                                case 'x':
00222                                case 'X':
00223                                     ++p;
00224                                     *radix = 16;
00225                                     break;
00226 
00227                                case 'b':
00228                                case 'B':
00229                                     ++p;
00230                                     *radix = 2;
00231                                     break;
00232 
00233                                case 'o':
00234                                case 'O':
00235                                     ++p;
00236                                default:
00237                                     *radix = 8;
00238                                     break;
00239                                } 
00240                     else
00241                        *radix = 10;
00242 
00243                 // return number of characters eaten
00244                 return p - digits.ptr;
00245         }
00246 }
00247 
00248 

Generated on Mon Nov 14 10:59:39 2005 for Mango by  doxygen 1.4.0