Note: This website is archived. For up-to-date information about D projects and development, please visit wiki.dlang.org.

Changeset 1717

Show
Ignore:
Timestamp:
07/04/10 21:39:09 (14 years ago)
Author:
andrei
Message:

Changed parse for integrals to accept input ranges; adapted Walter's strtold implementation to input ranges.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/phobos/std/conv.d

    r1646 r1717  
    1212           Shin Fujishiro, 
    1313           Adam D. Ruppe 
    1414 
    1515         Copyright Digital Mars 2007 - 2009. 
    1616Distributed under the Boost Software License, Version 1.0. 
    1717   (See accompanying file LICENSE_1_0.txt or copy at 
    1818         http://www.boost.org/LICENSE_1_0.txt) 
    1919*/ 
    2020module std.conv; 
    2121 
    22 import core.memory, core.stdc.errno, core.stdc.string, core.stdc.stdlib, 
    23     std.array, std.contracts
    24     std.ctype, std.math, std.range, std.stdio, 
    25     std.string, std.traits, std.typecons, std.typetuple
    26     std.utf; 
     22import core.stdc.math : ldexpl; 
     23import core.memory, core.stdc.errno, core.stdc.string
     24    core.stdc.stdlib; 
     25import std.array, std.ctype, std.exception, std.math, std.range, std.stdio
     26    std.string, std.traits, std.typecons, std.typetuple, std.utf; 
    2727import std.metastrings; 
    2828 
    2929//debug=conv;           // uncomment to turn on debugging printf's 
    3030 
    3131/* ************* Exceptions *************** */ 
    3232 
    3333/** 
    3434 * Thrown on conversion errors. 
    3535 */ 
    3636class ConvError : Error 
     
    951951assert(test == " \t  76.14"); // parse bumps string 
    952952munch(test, " \t\n\r"); // skip ws 
    953953assert(test == "76.14"); 
    954954auto b = parse!(double)(test); 
    955955assert(b == 76.14); 
    956956assert(test == ""); 
    957957-------------- 
    958958 */ 
    959959 
    960960Target parse(Target, Source)(ref Source s) 
    961 if (isSomeString!Source && isIntegral!Target) 
     961if (isSomeChar!(ElementType!Source) && isIntegral!Target) 
    962962{ 
    963963    static if (Target.sizeof < int.sizeof) 
    964964    { 
    965965        // smaller types are handled like integers 
    966966        auto v = parse!(Select!(Target.min < 0, int, uint), Source)(s); 
    967967        auto result = cast(Target) v; 
    968968        if (result != v) 
    969969        { 
    970970            conv_error!(Source, Target)(s); 
    971971        } 
    972972        return result; 
    973973    } 
    974974    else 
    975975    { 
    976976        // Larger than int types 
    977         immutable length = s.length; 
    978         if (!length) 
    979             goto Lerr; 
     977        // immutable length = s.length; 
     978        // if (!length) 
     979        //     goto Lerr; 
     980        if (s.empty) goto Lerr; 
    980981 
    981982        static if (Target.min < 0) 
    982983            int sign = 0; 
    983984        else 
    984985            static const int sign = 0; 
    985986        Target v = 0; 
    986987        size_t i = 0; 
    987988        enum char maxLastDigit = Target.min < 0 ? '7' : '5'; 
    988         for (; i < length; i++) 
    989         { 
    990             immutable c = s[i]; 
     989        //for (; i < length; i++) 
     990        for (; !s.empty; ++i) 
     991        { 
     992            //immutable c = s[i]; 
     993            immutable c = s.front; 
    991994            if (c >= '0' && c <= '9') 
    992995            { 
    993996                if (v >= Target.max/10 && 
    994997                        (v != Target.max/10|| c + sign > maxLastDigit)) 
    995998                    goto Loverflow; 
    996999                v = cast(Target) (v * 10 + (c - '0')); 
     1000                s.popFront(); 
    9971001            } 
    9981002            else static if (Target.min < 0) 
    9991003            { 
    10001004                if (c == '-' && i == 0) 
    10011005                { 
    1002                     if (length == 1) 
     1006                    s.popFront(); 
     1007                    if (s.empty) 
    10031008                        goto Lerr; 
    10041009                    sign = -1; 
    10051010                } 
    10061011                else if (c == '+' && i == 0) 
    10071012                { 
    1008                     if (length == 1) 
     1013                    s.popFront(); 
     1014                    if (s.empty) 
    10091015                        goto Lerr; 
    10101016                } 
    10111017                else 
    10121018                    break; 
    10131019            } 
    10141020            else 
    10151021                break; 
    10161022        } 
    10171023        if (i == 0) goto Lerr; 
    1018         s = s[i .. $]; 
     1024        //s = s[i .. $]; 
    10191025        static if (Target.min < 0) 
    10201026        { 
    10211027            if (sign == -1) 
    10221028            { 
    10231029                v = -v; 
    10241030            } 
    10251031        } 
    10261032        return v; 
    10271033      Loverflow: 
    10281034        ConvOverflowError.raise("Overflow in integral conversion"); 
     
    10761082    try 
    10771083    { 
    10781084        to!E("d"); 
    10791085        assert(0); 
    10801086    } 
    10811087    catch (ConvError e) 
    10821088    { 
    10831089    } 
    10841090} 
    10851091 
    1086 Target parse(Target, Source)(ref Source s) 
    1087     if (!isSomeString!Source && isSomeChar!(ElementType!Source) 
    1088         && isIntegral!Target) 
    1089 
    1090     char[] accum; 
    1091     foreach (c; s) 
    1092     { 
    1093         writeln(c); 
    1094         if ("0123456789-+".indexOf(c) < 0) 
    1095         { 
    1096             static if (is(typeof(s.unget(c)))) s.unget(c); 
    1097             break; 
    1098         } 
    1099         accum ~= c; 
    1100     } 
    1101     return parse!Target(accum); 
    1102 
    1103  
    1104 Target parse(Target, Source)(ref Source s) 
    1105 if (!isSomeString!Source && isFloatingPoint!Target) 
    1106 
    1107     static assert(0); 
    1108 
    1109  
    1110 Target parse(Target, Source)(ref Source s) 
    1111 if (isSomeString!Source && isFloatingPoint!Target) 
    1112 
    1113     // issue 1589 
    1114     //version (Windows) 
    1115     { 
    1116         if (icmp(s, "nan") == 0) 
    1117         { 
    1118             s = s[3 .. $]; 
    1119             return Target.nan; 
    1120         } 
    1121     } 
    1122  
    1123     auto t = s; 
    1124     if (t.startsWith('+', '-')) t.popFront(); 
    1125     munch(t, "0-9"); // integral part 
    1126     if (t.startsWith('.')) 
    1127     { 
    1128         t.popFront(); // decimal point 
    1129         munch(t, "0-9"); // fractionary part 
    1130     } 
    1131     if (t.startsWith('E', 'e')) 
    1132     { 
    1133         t.popFront(); 
    1134         if (t.startsWith('+', '-')) t.popFront(); 
    1135         munch(t, "0-9"); // exponent 
    1136     } 
    1137     auto len = s.length - t.length; 
    1138     char sz[80] = void; 
    1139     enforce(len < sz.length); 
    1140     foreach (i; 0 .. len) sz[i] = s[i]; 
    1141     sz[len] = 0; 
    1142  
    1143 //     //writefln("toFloat('%s')", s); 
    1144 //     auto sz = toStringz(to!(const char[])(s)); 
    1145 //     if (std.ctype.isspace(*sz)) 
    1146 //         goto Lerr; 
    1147  
    1148 //     // BUG: should set __locale_decpoint to "." for DMC 
    1149  
    1150     setErrno(0); 
    1151     char* endptr; 
    1152     static if (is(Target == float)) 
    1153         auto f = strtof(sz.ptr, &endptr); 
    1154     else static if (is(Target == double)) 
    1155         auto f = strtod(sz.ptr, &endptr); 
    1156     else static if (is(Target == real)) 
    1157         auto f = strtold(sz.ptr, &endptr); 
    1158     else 
    1159         static assert(false); 
    1160     if (getErrno() == ERANGE) 
    1161     { 
    1162         goto Lerr; 
    1163     } 
    1164     assert(endptr); 
    1165     if (endptr == sz.ptr) 
    1166     { 
    1167         // no progress 
    1168         goto Lerr; 
    1169     } 
    1170     s = s[endptr - sz.ptr .. $]; 
    1171     return f; 
    1172   Lerr: 
    1173     conv_error!(Source, Target)(s); 
    1174     assert(0); 
    1175 
    1176  
    1177 // Target parse(Target, Source)(ref Source s) 
    1178 // if (isSomeString!Source && isSomeString!Target) 
    1179 // { 
    1180  
    1181 // } 
     1092Target parse(Target, Source)(ref Source p) 
     1093if (isInputRange!Source && /*!isSomeString!Source && */isFloatingPoint!Target) 
     1094
     1095    static immutable real negtab[] = 
     1096        [ 1e-4096L,1e-2048L,1e-1024L,1e-512L,1e-256L,1e-128L,1e-64L,1e-32L, 
     1097                1e-16L,1e-8L,1e-4L,1e-2L,1e-1L,1.0L ]; 
     1098    static immutable real postab[] = 
     1099        [ 1e+4096L,1e+2048L,1e+1024L,1e+512L,1e+256L,1e+128L,1e+64L,1e+32L, 
     1100                1e+16L,1e+8L,1e+4L,1e+2L,1e+1L ]; 
     1101    // static immutable string infinity = "infinity"; 
     1102    // static immutable string nans = "nans"; 
     1103 
     1104    while (enforce(!p.empty), isspace(p.front)) 
     1105    { 
     1106        p.popFront(); 
     1107    } 
     1108    char sign = 0;                       /* indicating +                 */ 
     1109    switch (p.front) 
     1110    { 
     1111        case '-': sign++; goto case '+'; 
     1112        case '+': p.popFront(); enforce(!p.empty); 
     1113        default: {} 
     1114    } 
     1115 
     1116    const bool isHex = p.front == '0' 
     1117        && (p.popFront(), p.front == 'x' || p.front == 'X'); 
     1118 
     1119    real ldval = 0.0; 
     1120    char dot = 0;                        /* if decimal point has been seen */ 
     1121    int exp = 0; 
     1122    long msdec = 0, lsdec = 0; 
     1123    ulong msscale = 1; 
     1124 
     1125    if (isHex) 
     1126    { 
     1127        int guard = 0; 
     1128        int anydigits = 0; 
     1129        uint ndigits = 0; 
     1130 
     1131        p.popFront(); 
     1132        while (!p.empty) 
     1133        { 
     1134            int i = p.front; 
     1135            while (isxdigit(i)) 
     1136            { 
     1137                anydigits = 1; 
     1138                i = isalpha(i) ? ((i & ~0x20) - ('A' - 10)) : i - '0'; 
     1139                if (ndigits < 16) 
     1140                { 
     1141                    msdec = msdec * 16 + i; 
     1142                    if (msdec) 
     1143                        ndigits++; 
     1144                } 
     1145                else if (ndigits == 16) 
     1146                { 
     1147                    while (msdec >= 0) 
     1148                    { 
     1149                        exp--; 
     1150                        msdec <<= 1; 
     1151                        i <<= 1; 
     1152                        if (i & 0x10) 
     1153                            msdec |= 1; 
     1154                    } 
     1155                    guard = i << 4; 
     1156                    ndigits++; 
     1157                    exp += 4; 
     1158                } 
     1159                else 
     1160                { 
     1161                    guard |= i; 
     1162                    exp += 4; 
     1163                } 
     1164                exp -= dot; 
     1165                p.popFront(); 
     1166                if (p.empty) break; 
     1167                i = p.front; 
     1168            } 
     1169            if (i == '.' && !dot) 
     1170            {       p.popFront(); 
     1171                dot = 4; 
     1172            } 
     1173            else 
     1174                break; 
     1175        } 
     1176 
     1177        // Round up if (guard && (sticky || odd)) 
     1178        if (guard & 0x80 && (guard & 0x7F || msdec & 1)) 
     1179        { 
     1180            msdec++; 
     1181            if (msdec == 0)                 // overflow 
     1182            {   msdec = 0x8000000000000000L; 
     1183                exp++; 
     1184            } 
     1185        } 
     1186 
     1187        enforce(anydigits);         // if error (no digits seen) 
     1188        enforce(!p.empty && (p.front == 'p' || p.front == 'P'), 
     1189                "Floating point parsing: exponent is required"); 
     1190        char sexp; 
     1191        int e; 
     1192 
     1193        sexp = 0; 
     1194        p.popFront(); 
     1195        if (!p.empty) 
     1196        { 
     1197            switch (p.front) 
     1198            {   case '-':    sexp++; 
     1199                case '+':    p.popFront(); enforce(!p.empty); 
     1200                default: {} 
     1201            } 
     1202        } 
     1203        ndigits = 0; 
     1204        e = 0; 
     1205        while (!p.empty && isdigit(p.front)) 
     1206        { 
     1207            if (e < 0x7FFFFFFF / 10 - 10) // prevent integer overflow 
     1208            { 
     1209                e = e * 10 + p.front - '0'; 
     1210            } 
     1211            p.popFront(); 
     1212            ndigits = 1; 
     1213        } 
     1214        exp += (sexp) ? -e : e; 
     1215        enforce(ndigits);           // if no digits in exponent 
     1216 
     1217        if (msdec) 
     1218        { 
     1219            int e2 = 0x3FFF + 63; 
     1220 
     1221            // left justify mantissa 
     1222            while (msdec >= 0) 
     1223            {   msdec <<= 1; 
     1224                e2--; 
     1225            } 
     1226 
     1227            // Stuff mantissa directly into real 
     1228            *cast(long *)&ldval = msdec; 
     1229            (cast(ushort *)&ldval)[4] = cast(ushort) e2; 
     1230 
     1231            // Exponent is power of 2, not power of 10 
     1232            ldval = ldexpl(ldval,exp); 
     1233        } 
     1234        goto L6; 
     1235    } 
     1236    else // not hex 
     1237    { 
     1238        if (toupper(p.front) == 'N') 
     1239        { 
     1240            // nan 
     1241            enforce((p.popFront(), !p.empty && toupper(p.front) == 'A') 
     1242                    && (p.popFront(), !p.empty && toupper(p.front) == 'N')); 
     1243            // skip past the last 'n' 
     1244            p.popFront(); 
     1245            return typeof(return).nan; 
     1246        } 
     1247 
     1248        bool sawDigits = false; 
     1249 
     1250        while (!p.empty) 
     1251        { 
     1252            int i = p.front; 
     1253            while (isdigit(i)) 
     1254            { 
     1255                sawDigits = true;        /* must have at least 1 digit   */ 
     1256                if (msdec < (0x7FFFFFFFFFFFL-10)/10) 
     1257                    msdec = msdec * 10 + (i - '0'); 
     1258                else if (msscale < (0xFFFFFFFF-10)/10) 
     1259                {   lsdec = lsdec * 10 + (i - '0'); 
     1260                    msscale *= 10; 
     1261                } 
     1262                else 
     1263                { 
     1264                    exp++; 
     1265                } 
     1266                exp -= dot; 
     1267                p.popFront(); 
     1268                if (p.empty) break; 
     1269                i = p.front; 
     1270            } 
     1271            if (i == '.' && !dot) 
     1272            { 
     1273                p.popFront(); 
     1274                dot++; 
     1275            } 
     1276            else 
     1277            { 
     1278                break; 
     1279            } 
     1280        } 
     1281        enforce(sawDigits);               // if error (no digits seen) 
     1282    } 
     1283    if (!p.empty && (p.front == 'e' || p.front == 'E')) 
     1284    { 
     1285        char sexp; 
     1286        int e; 
     1287 
     1288        sexp = 0; 
     1289        p.popFront(); 
     1290        enforce(!p.empty); 
     1291        switch (p.front) 
     1292        {   case '-':    sexp++; 
     1293            case '+':    p.popFront(); 
     1294            default: {} 
     1295        } 
     1296        bool sawDigits = 0; 
     1297        e = 0; 
     1298        while (!p.empty && isdigit(p.front)) 
     1299        { 
     1300            if (e < 0x7FFFFFFF / 10 - 10)   // prevent integer overflow 
     1301            { 
     1302                e = e * 10 + p.front - '0'; 
     1303            } 
     1304            p.popFront(); 
     1305            sawDigits = 1; 
     1306        } 
     1307        exp += (sexp) ? -e : e; 
     1308        enforce(sawDigits);               // if no digits in exponent 
     1309    } 
     1310 
     1311    ldval = msdec; 
     1312    if (msscale != 1)               /* if stuff was accumulated in lsdec */ 
     1313        ldval = ldval * msscale + lsdec; 
     1314    if (ldval) 
     1315    { 
     1316        uint u = 0; 
     1317        int pow = 4096; 
     1318 
     1319        while (exp > 0) 
     1320        { 
     1321            while (exp >= pow) 
     1322            { 
     1323                ldval *= postab[u]; 
     1324                exp -= pow; 
     1325            } 
     1326            pow >>= 1; 
     1327            u++; 
     1328        } 
     1329        while (exp < 0) 
     1330        { 
     1331            while (exp <= -pow) 
     1332            { 
     1333                ldval *= negtab[u]; 
     1334                enforce(ldval != 0); // errno = ERANGE; 
     1335                exp += pow; 
     1336            } 
     1337            pow >>= 1; 
     1338            u++; 
     1339        } 
     1340    } 
     1341  L6: // if overflow occurred 
     1342    enforce(ldval != core.stdc.math.HUGE_VAL); // errno = ERANGE; 
     1343 
     1344  L1: 
     1345    return (sign) ? -ldval : ldval; 
     1346
     1347 
     1348unittest 
     1349
     1350    struct longdouble 
     1351    { 
     1352        ushort value[5]; 
     1353    } 
     1354 
     1355    real ld; 
     1356    longdouble x; 
     1357    real ld1; 
     1358    longdouble x1; 
     1359    int i; 
     1360 
     1361    string s = "0x1.FFFFFFFFFFFFFFFEp-16382"; 
     1362    ld = parse!real(s); 
     1363    assert(s.empty); 
     1364    x = *cast(longdouble *)&ld; 
     1365    ld1 = strtold("0x1.FFFFFFFFFFFFFFFEp-16382", null); 
     1366    x1 = *cast(longdouble *)&ld1; 
     1367    assert(x1 == x && ld1 == ld); 
     1368 
     1369    // for (i = 4; i >= 0; i--) 
     1370    // { 
     1371    //     printf("%04x ", x.value[i]); 
     1372    // } 
     1373    // printf("\n"); 
     1374    assert(!errno); 
     1375 
     1376    s = "1.0e5"; 
     1377    ld = parse!real(s); 
     1378    assert(s.empty); 
     1379    x = *cast(longdouble *)&ld; 
     1380    ld1 = strtold("1.0e5", null); 
     1381    x1 = *cast(longdouble *)&ld1; 
     1382 
     1383    // for (i = 4; i >= 0; i--) 
     1384    // { 
     1385    //     printf("%04x ", x.value[i]); 
     1386    // } 
     1387    // printf("\n"); 
     1388
    11821389 
    11831390unittest 
    11841391{ 
    11851392    string s = "123"; 
    11861393    auto a = parse!int(s); 
    11871394} 
    11881395 
    11891396 
    11901397// string to bool conversions 
    11911398Target parse(Target, Source)(ref Source s) 
     
    26132820 
    26142821/// Small signed integers to strings. 
    26152822T to(T, S)(S value) if (isIntegral!S && S.min < 0 
    26162823        && S.sizeof < int.sizeof && isSomeString!T) 
    26172824{ 
    26182825    return to!T(cast(int) value); 
    26192826} 
    26202827 
    26212828/// Unsigned integers (uint and ulong) to string. 
    26222829T to(T, S)(S input) 
    2623 if (std.typetuple.staticIndexOf!(Unqual!S, uint, ulong) >= 0 && isSomeString!T) 
     2830if (staticIndexOf!(Unqual!S, uint, ulong) >= 0 && isSomeString!T) 
    26242831{ 
    26252832    Unqual!S value = input; 
    26262833    alias Unqual!(typeof(T.init[0])) Char; 
    26272834    static if (is(typeof(T.init[0]) == const) || 
    26282835            is(typeof(T.init[0]) == immutable)) 
    26292836    { 
    26302837        if (value < 10) 
    26312838        { 
    26322839            static immutable Char[10] digits = "0123456789"; 
    26332840            // Avoid storage allocation for simple stuff 
     
    26352842        } 
    26362843    } 
    26372844 
    26382845    static if (S.sizeof == uint.sizeof) 
    26392846        enum maxlength = S.sizeof * 3; 
    26402847    else 
    26412848        auto maxlength = (value > uint.max ? S.sizeof : uint.sizeof) * 3; 
    26422849 
    26432850    Char[] result; 
    26442851    if (__ctfe) 
     2852    { 
    26452853        result = new Char[maxlength]; 
     2854    } 
    26462855    else 
     2856    { 
    26472857        result = cast(Char[]) 
    26482858            GC.malloc(Char.sizeof * maxlength, GC.BlkAttr.NO_SCAN) 
    26492859            [0 .. Char.sizeof * maxlength]; 
     2860    } 
    26502861 
    26512862    uint ndigits = 0; 
    26522863    do 
    26532864    { 
    2654         const c = cast(Char) ((value % 10) + '0'); 
    2655         value /= 10; 
    2656         ndigits++; 
     2865        auto div = value / 10; 
     2866        auto rem = value % 10; 
     2867        const c = cast(Char) (rem + '0'); 
     2868        value = div; 
     2869        ++ndigits; 
    26572870        result[$ - ndigits] = c; 
    26582871    } 
    26592872    while (value); 
    26602873    return cast(T) result[$ - ndigits .. $]; 
    26612874} 
    26622875 
    26632876unittest 
    26642877{ 
    26652878    assert(wtext(int.max) == "2147483647"w); 
    26662879    assert(wtext(int.min) == "-2147483648"w); 
     
    28523065 
    28533066/****************************************** 
    28543067 * Convert value to string in _radix radix. 
    28553068 * 
    28563069 * radix must be a value from 2 to 36. 
    28573070 * value is treated as a signed value only if radix is 10. 
    28583071 * The characters A through Z are used to represent values 10 through 36. 
    28593072 */ 
    28603073T to(T, S)(S value, uint radix) 
    28613074if (isIntegral!(Unqual!S) && !is(Unqual!S == ulong) && isSomeString!(T)) 
    2862 in 
    2863 
    2864     assert(radix >= 2 && radix <= 36); 
    2865 
    2866 body 
    2867 
     3075
     3076    enforce(radix >= 2 && radix <= 36); 
    28683077    if (radix == 10) 
    28693078        return to!string(value);     // handle signed cases only for radix 10 
    28703079    return to!string(cast(ulong) value, radix); 
    28713080} 
    28723081 
    28733082/// ditto 
    28743083T to(T, S)(S value, uint radix) 
    28753084if (is(Unqual!S == ulong) && isSomeString!(T)) 
    28763085in 
    28773086{