Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Changeset 2927

Show
Ignore:
Timestamp:
11/25/07 02:08:49 (1 year ago)
Author:
kris
Message:

* fixes [124] E,e format specifier is not supported
* resolves [753] Layout format strings
* fixes [780] Problem in tango.text.convert.Integer.format

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/tango/text/convert/Float.d

    r2913 r2927  
    108108        to the output. 
    109109 
    110 ******************************************************************************/ 
    111  
    112 T[] format(T, D=double, U=uint) (T[] dst, D x, U decimals = 2, bool scientific = false) 
    113 {return format!(T)(dst, x, decimals, scientific);} 
    114  
    115 T[] format(T) (T[] dst, NumType x, uint decimals = 2, bool scientific = false) 
     110        TODO: this should be replaced, as it is not sufficiently accurate  
     111 
     112******************************************************************************/ 
     113 
     114T[] format(T, D=double, U=uint) (T[] dst, D x, U decimals = 2, bool e = false) 
     115{return format!(T)(dst, x, decimals, e);} 
     116 
     117T[] format(T) (T[] dst, NumType x, uint decimals = 2, bool e = false) 
    116118{ 
    117119        static T[] inf = "-inf"; 
     
    140142                // Don't exceed max digits storable in a real 
    141143                // (-1 because the last digit is not always storable) 
    142                 if (++count > NumType.dig-1
     144                if (--count <= 0
    143145                    digit = 0; 
    144146                else 
     
    171173        if (x > 0.0) 
    172174           { 
    173            // round up a bit (should do even/odd test?) 
    174            x += 0.5 / pow10 (decimals); 
     175           // round up a bit 
     176           if (e is false) 
     177               x += 0.5 / pow10 (decimals); 
    175178 
    176179           // extract base10 exponent 
     
    186189           // switch to short display if not enough space 
    187190           if (len + 32 > dst.length) 
    188                scientific = true; 
     191               e = true;  
    189192           } 
    190193 
    191194        T* p = dst.ptr; 
    192         int count = 0
     195        int count = NumType.dig
    193196 
    194197        // emit sign 
     
    197200 
    198201        // are we doing +/-exp format? 
    199         if (scientific
     202        if (e
    200203           { 
    201204           // emit first digit, and decimal point 
    202205           *p++ = toDigit (x, count); 
    203            *p++ = '.'; 
     206           if (decimals) 
     207              { 
     208              *p++ = '.'; 
     209              if (exp < 0) 
     210                  count += exp; 
     211              } 
    204212 
    205213           // emit rest of mantissa 
     
    236244 
    237245           // emit point 
    238            *p++ = '.'; 
     246           if (decimals) 
     247               *p++ = '.'; 
    239248 
    240249           // emit leading fractional zeros? 
     
    389398debug (UnitTest) 
    390399{ 
    391         // void main() {} 
    392  
    393400        unittest 
    394401        { 
     
    412419 
    413420 
     421debug (Float) 
     422{ 
     423        void main() {} 
     424} 
  • trunk/tango/text/convert/Integer.d

    r2913 r2927  
    191191        T[]     prefix; 
    192192        auto    len = dst.length; 
     193         
     194        static T[] error (T[] msg) 
     195        { 
     196                if (1 & Flags.Throw) 
     197                    throw new IllegalArgumentException ("Integer.format :: invalid arguments"); 
     198                 return msg; 
     199        } 
    193200 
    194201        // must have some buffer space to operate within!  
     
    201208           switch (cast(byte) fmt) 
    202209                  { 
    203                   default: 
    204210                  case 'd': 
    205211                  case 'D': 
     
    247253                           prefix = "0X"; 
    248254                       break; 
     255 
     256                  default: 
     257                        return error (cast(T[])"{unknown format '"~cast(T)fmt~"'}"); 
    249258                  } 
    250259 
     
    283292           } 
    284293        else 
    285            if (flags & Flags.Throw) 
    286                throw new IllegalArgumentException ("Integer.format :: output truncated"); 
     294           return error ("{output width too small}"); 
    287295 
    288296        // return slice of provided output buffer 
     
    581589        assert (format (tmp[0..8], 0x5L, Style.Binary, Flags.Prefix | Flags.Zero) == "0b000101"); 
    582590 
    583         assert (format (tmp[0..8], -1, Style.Binary, Flags.Prefix | Flags.Zero) == "11111111"); 
     591        assert (format (tmp[0..8], -1, Style.Binary, Flags.Prefix | Flags.Zero) == "{output width too small}"); 
    584592        assert (format (tmp[0..2], 0x3, Style.Binary, Flags.Throw) == "11"); 
    585593        assert (format (tmp[0..4], 0x3, Style.Binary, Flags.Prefix | Flags.Zero | Flags.Throw) == "0b11"); 
  • trunk/tango/text/convert/Layout.d

    r2913 r2927  
    373373                      fragment = ++s; 
    374374 
    375                       void process( T[] str ){ 
    376                         int padding = width - str.length; 
    377  
    378                         // if not left aligned, pad out with spaces 
    379                         if (! leftAlign && padding > 0) 
    380                                 length += spaces (sink, padding); 
    381  
    382                         // emit formatted argument 
    383                         length += sink (str); 
    384  
    385                         // finally, pad out on right 
    386                         if (leftAlign && padding > 0) 
    387                             length += spaces (sink, padding); 
    388  
     375                      // handle alignment 
     376                      void process (T[] str) 
     377                      { 
     378                                int padding = width - str.length; 
     379 
     380                                // if not left aligned, pad out with spaces 
     381                                if (! leftAlign && padding > 0) 
     382                                      length += spaces (sink, padding); 
     383 
     384                                // emit formatted argument 
     385                                length += sink (str); 
     386 
     387                                // finally, pad out on right 
     388                                if (leftAlign && padding > 0) 
     389                                    length += spaces (sink, padding); 
    389390                      } 
    390391 
    391                       void processElement( TypeInfo _ti, Arg _arg ){ 
    392                             if( _ti.classinfo.name.length == 20 && _ti.classinfo.name[9..$] == "StaticArray" ) 
    393                             { 
    394                                 auto tiStat = cast(TypeInfo_StaticArray)_ti; 
    395                                 auto p = _arg; 
    396                                 length += sink ("[ "); 
    397                                 for( int i = 0; i < tiStat.len; i++ ){ 
    398                                     if( p !is _arg ){ 
    399                                         length += sink (", "); 
    400                                     } 
    401                                     processElement( tiStat.value, p ); 
    402  
    403                                     p += tiStat.tsize; 
    404                                 } 
    405                                 length += sink (" ]"); 
    406                             } 
    407                             else if( _ti.classinfo.name.length == 25 && _ti.classinfo.name[9..$] == "AssociativeArray" ) 
    408                             { 
    409                                 auto tiAsso = cast(TypeInfo_AssociativeArray)_ti; 
    410                                 TypeInfo tiKey = tiAsso.key; 
    411                                 TypeInfo tiVal = tiAsso.next(); 
    412                                 // the knowledge of the internal k/v storage is used 
    413                                 // so this might break if, that internal storage changes 
    414                                 alias ubyte AV; // any type for key, value might be ok, the sizes are corrected later 
    415                                 alias ubyte AK; 
    416                                 AV[AK] aa = *cast(AV[AK]*) _arg; 
    417  
    418                                 length += sink ("{ "); 
    419                                 bool first = true; 
    420                                 foreach( inout v; aa ) 
    421                                 { 
    422                                     int roundUp (int sz) 
    423                                     { 
    424                                         return ( sz + (void*).sizeof -1 ) & ~((void*).sizeof - 1); 
    425                                     } 
    426  
    427                                     // the key is befor the value, so substrace with fixed key size from above 
    428                                     Arg pk = cast(Arg)( &v - roundUp(AK.sizeof)); 
    429                                     // now the real value pos is plus the real key size 
    430                                     Arg pv = cast(Arg)(pk + roundUp(tiKey.tsize())); 
    431  
    432                                     if( !first ) 
    433                                     { 
    434                                         length += sink (", "); 
    435                                     } 
    436  
    437                                     processElement (tiKey, pk); 
    438                                     length += sink ("=>"); 
    439                                     processElement (tiVal, pv); 
    440                                     first = false; 
    441                                 } 
    442                                 length += sink (" }"); 
    443                             } 
    444                             else if( _ti.classinfo.name[9] == TypeCode.ARRAY 
    445                                 && (_ti !is typeid( char[])) 
    446                                 && (_ti !is typeid(wchar[])) 
    447                                 && (_ti !is typeid(dchar[])) ) 
    448                             { 
    449                                 // for all non string array types (including char[][]) 
    450                                 void[] arr = *cast(void[]*)_arg; 
    451                                 int len = arr.length; 
    452                                 Arg ptr = cast(Arg) arr.ptr; 
    453                                 TypeInfo elTi = _ti.next(); 
    454                                 int size = elTi.tsize(); 
    455                                 length += sink ("[ "); 
    456                                 while (len > 0) 
    457                                 { 
    458                                     if (ptr !is arr.ptr) 
    459                                     { 
    460                                         length += sink (", "); 
    461                                     } 
    462                                     processElement (elTi, ptr); 
    463  
    464                                     len -= 1; 
    465                                     ptr += size; 
    466                                 } 
    467                                 length += sink (" ]"); 
    468                            } 
    469                            else 
    470                            { 
    471                               // the standard processing 
    472                               process( munge (result, format, _ti, _arg ) ); 
    473                            } 
    474                         } 
    475  
    476                         if( index >= ti.length ) 
    477                         { 
    478                             process( "{invalid index}" ); 
    479                         } 
    480                         else 
    481                         { 
    482                           processElement( ti[index], args[index] ); 
    483                         } 
    484  
    485                 } 
     392                      // an astonishing number of typehacks needed to handle arrays :( 
     393                      void processElement (TypeInfo _ti, Arg _arg) 
     394                      { 
     395                                if (_ti.classinfo.name.length is 20 && _ti.classinfo.name[9..$] == "StaticArray" ) 
     396                                   { 
     397                                   auto tiStat = cast(TypeInfo_StaticArray)_ti; 
     398                                   auto p = _arg; 
     399                                   length += sink ("[ "); 
     400                                   for (int i = 0; i < tiStat.len; i++) 
     401                                       { 
     402                                       if (p !is _arg ) 
     403                                           length += sink (", "); 
     404                                       processElement (tiStat.value, p); 
     405                                       p += tiStat.tsize; 
     406                                       } 
     407                                   length += sink (" ]"); 
     408                                   } 
     409                                else  
     410                                if (_ti.classinfo.name.length is 25 && _ti.classinfo.name[9..$] == "AssociativeArray") 
     411                                   { 
     412                                   auto tiAsso = cast(TypeInfo_AssociativeArray)_ti; 
     413                                   auto tiKey = tiAsso.key; 
     414                                   auto tiVal = tiAsso.next(); 
     415                                   // the knowledge of the internal k/v storage is used 
     416                                   // so this might break if, that internal storage changes 
     417                                   alias ubyte AV; // any type for key, value might be ok, the sizes are corrected later 
     418                                   alias ubyte AK; 
     419                                   auto aa = *cast(AV[AK]*) _arg; 
     420 
     421                                   length += sink ("{ "); 
     422                                   bool first = true; 
     423                                   
     424                                   int roundUp (int sz) 
     425                                   { 
     426                                        return (sz + (void*).sizeof -1) & ~((void*).sizeof - 1); 
     427                                   } 
     428 
     429                                   foreach (inout v; aa) 
     430                                           { 
     431                                           // the key is befor the value, so substrace with fixed key size from above 
     432                                           auto pk = cast(Arg)( &v - roundUp(AK.sizeof)); 
     433                                           // now the real value pos is plus the real key size 
     434                                           auto pv = cast(Arg)(pk + roundUp(tiKey.tsize())); 
     435 
     436                                           if (!first) 
     437                                                length += sink (", "); 
     438                                           processElement (tiKey, pk); 
     439                                           length += sink ("=>"); 
     440                                           processElement (tiVal, pv); 
     441                                           first = false; 
     442                                           } 
     443                                   length += sink (" }"); 
     444                                   } 
     445                                else  
     446                                if (_ti.classinfo.name[9] is TypeCode.ARRAY && 
     447                                   (_ti !is typeid(char[]))  && 
     448                                   (_ti !is typeid(wchar[])) && 
     449                                   (_ti !is typeid(dchar[]))) 
     450                                   { 
     451                                   // for all non string array types (including char[][]) 
     452                                   auto arr = *cast(void[]*)_arg; 
     453                                   auto len = arr.length; 
     454                                   auto ptr = cast(Arg) arr.ptr; 
     455                                   auto elTi = _ti.next(); 
     456                                   auto size = elTi.tsize(); 
     457                                   length += sink ("[ "); 
     458                                   while (len > 0) 
     459                                         { 
     460                                         if (ptr !is arr.ptr) 
     461                                             length += sink (", "); 
     462                                         processElement (elTi, ptr); 
     463                                         len -= 1; 
     464                                         ptr += size; 
     465                                         } 
     466                                   length += sink (" ]"); 
     467                                   } 
     468                                else 
     469                                   // the standard processing 
     470                                   process (munge(result, format, _ti, _arg)); 
     471                      } 
     472 
     473                       
     474                      // process this argument 
     475                      if (index >= ti.length) 
     476                          process ("{invalid index}"); 
     477                      else 
     478                         processElement (ti[index], args[index]); 
     479                      } 
    486480                return length; 
    487481        } 
     
    531525                                return fromUtf32 (*cast(dchar[]*) p, result); 
    532526 
    533                             // Currently we only format d/w/char[] arrays. 
    534527                            return fromUtf8 (type.toString, result); 
    535528 
     
    606599                       } 
    607600 
    608                 static T[] Null = "{null}"; 
    609                 return Null; 
     601                return cast(T[]) "{null}"; 
    610602        } 
    611603 
     
    623615        **********************************************************************/ 
    624616 
    625         protected T[] integer (T[] output, long v, T[] alt, T format = 'd') 
    626         { 
    627                 uint width; 
    628                 auto style = cast(Integer.Style) parse2 (alt, width, format); 
    629  
     617        protected T[] integer (T[] output, long v, T[] format, T style = 'd') 
     618        { 
    630619                Integer.Flags flags; 
    631                 if (width) 
     620                uint          width = output.length; 
     621 
     622                if (parseGeneric (format, width, style)) 
     623                    if (width <= output.length) 
     624                       { 
     625                       output = output [0 .. width]; 
     626                       flags |= flags.Zero; 
     627                       } 
     628                return Integer.format (output, v, cast(Integer.Style) style, flags); 
     629        } 
     630 
     631        /********************************************************************** 
     632 
     633        **********************************************************************/ 
     634 
     635        protected T[] floater (T[] output, real v, T[] format) 
     636        { 
     637                T    style = 'f'; 
     638                uint places = 2; 
     639 
     640                parseGeneric (format, places, style); 
     641                return Float.format (output, v, places, (style is 'e' || style is 'E')); 
     642        } 
     643 
     644        /********************************************************************** 
     645 
     646        **********************************************************************/ 
     647 
     648        private bool parseGeneric (T[] format, ref uint width, ref T style) 
     649        { 
     650                if (format.length) 
    632651                   { 
    633                    output = output [0 .. width]; 
    634                    flags = flags.Zero; 
     652                   uint number; 
     653                   auto p = format.ptr; 
     654                   auto e = p + format.length; 
     655                   style = *p; 
     656                   while (++p < e) 
     657                          if (*p >= '0' && *p <= '9') 
     658                              number = number * 10 + *p - '0'; 
     659                          else 
     660                             break; 
     661 
     662                   if (p - format.ptr > 1) 
     663                      { 
     664                      width = number; 
     665                      return true; 
     666                      } 
    635667                   } 
    636  
    637                 return Integer.format (output, v, style, flags); 
    638         } 
    639  
    640         /********************************************************************** 
    641  
    642         **********************************************************************/ 
    643  
    644         protected T[] floater (T[] output, real v, T[] format) 
    645         { 
    646                 uint places; 
    647                 bool scientific; 
    648  
    649                 if (parse2(format, places) is 'e') 
    650                     scientific = true; 
    651  
    652                 if (places is 0) 
    653                     places = 2; 
    654  
    655                 return Float.format (output, v, places, scientific); 
    656         } 
    657  
    658         /********************************************************************** 
    659  
    660         **********************************************************************/ 
    661  
    662         private T parse2 (T[] format, inout uint width, T def=T.init) 
    663         { 
    664                 uint number; 
    665                 foreach (c; format) 
    666                          if (c >= '0' && c <= '9') 
    667                              number = number * 10 + c - '0'; 
    668  
    669                 width = number; 
    670                 return format.length > 0 ? format[0] : def; 
     668                return false; 
    671669        } 
    672670 
     
    858856 
    859857        assert( Formatter( "{0:f}", 1.23f ) == "1.23" ,  Formatter( "{0:f}", 1.23f )); 
    860         assert( Formatter( "{0:f4}", 1.23456789L ) == "1.2346" ); 
     858        assert( Formatter( "{0:f4}", 1.23456789L ) == "1.2345" ); 
     859        assert( Formatter( "{0:e4}", 0.0001) == "", Formatter( "{0:e4}", 0.0001) ); 
    861860 
    862861        int[] a = [ 51, 52, 53, 54, 55 ]; 
     
    874873        d[234] = 2; 
    875874        d[345] = 3; 
    876         Stdout.formatln( "{}", d ); 
    877875        assert( Formatter( "{}", d ) == "{ 234=>2, 345=>3 }" ); 
    878876 
     
    895893        import tango.io.Console; 
    896894 
    897         interface foo {} 
    898  
    899         class X : foo {char[] toString() {return "hello";}} 
    900  
    901895        void main () 
    902896        { 
    903                 int i = int.max; 
    904                 auto Formatter = new Layout!(char); 
    905  
    906                 auto x = new X; 
    907                 foo f = x; 
    908                 Cout (Formatter ("{:x8} {} {} bottles", -1, f, x)); 
     897                auto layout = new Layout!(char); 
     898 
     899                Cout (layout ("{:d2}", 56)).newline; 
     900                Cout (layout ("{:f4}", 0.001)).newline; 
     901                Cout (layout ("{:f8}", 3.14159)).newline; 
     902                Cout (layout ("{:e20}", 0.001)).newline; 
     903                Cout (layout ("{:e4}", 0.0000001)).newline; 
    909904        } 
    910905}