Wolfgang Thallergcc 15.1.0ada185d1 year agoHistory
394 lines · 11.7 KB · D
RawDownload
// Written in the D programming language. /*   Copyright: Copyright The D Language Foundation 2000-2013.    License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).    Authors: $(HTTP walterbright.com, Walter Bright), $(HTTP erdani.com,   Andrei Alexandrescu), and Kenji Hara    Source: $(PHOBOSSRC std/format/internal/read.d) */module std.format.internal.read; import std.range.primitives : ElementEncodingType, ElementType, isInputRange; import std.traits : isAggregateType, isArray, isAssociativeArray,    isDynamicArray, isFloatingPoint, isIntegral, isSomeChar, isSomeString,    isStaticArray, StringTypeOf; import std.format.spec : FormatSpec; package(std.format): void skipData(Range, Char)(ref Range input, scope const ref FormatSpec!Char spec){    import std.ascii : isDigit, isWhite;    import std.range.primitives : empty, front, popFront;     switch (spec.spec)    {        case 'c': input.popFront(); break;        case 'd':            if (input.front == '+' || input.front == '-') input.popFront();            goto case 'u';        case 's':            while (!input.empty && !isWhite(input.front)) input.popFront();            break;        case 'u':            while (!input.empty && isDigit(input.front)) input.popFront();            break;        default:            assert(0, "Format specifier not understood: %" ~ spec.spec);    }} private template acceptedSpecs(T){    static if (isIntegral!T)        enum acceptedSpecs = "bdosuxX";    else static if (isFloatingPoint!T)        enum acceptedSpecs = "seEfgG";    else static if (isSomeChar!T)        enum acceptedSpecs = "bcdosuxX";    // integral + 'c'    else        enum acceptedSpecs = "";} T unformatValueImpl(T, Range, Char)(ref Range input, scope const ref FormatSpec!Char spec)if (isInputRange!Range && is(immutable T == immutable bool)){    import std.algorithm.searching : find;    import std.conv : parse, text;    import std.format : enforceFmt, unformatValue;     if (spec.spec == 's') return parse!T(input);     enforceFmt(find(acceptedSpecs!long, spec.spec).length,               text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof));     return unformatValue!long(input, spec) != 0;} T unformatValueImpl(T, Range, Char)(ref Range input, scope const ref FormatSpec!Char spec)if (isInputRange!Range && is(T == typeof(null))){    import std.conv : parse, text;    import std.format : enforceFmt;     enforceFmt(spec.spec == 's',               text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof));     return parse!T(input);} T unformatValueImpl(T, Range, Char)(ref Range input, scope const ref FormatSpec!Char spec)if (isInputRange!Range && isIntegral!T && !is(T == enum) && isSomeChar!(ElementType!Range)){    import std.algorithm.searching : find;    import std.conv : parse, text;    import std.format : enforceFmt, FormatException;     if (spec.spec == 'r')    {        static if (is(immutable ElementEncodingType!Range == immutable char)                || is(immutable ElementEncodingType!Range == immutable byte)                || is(immutable ElementEncodingType!Range == immutable ubyte))            return rawRead!T(input);        else            throw new FormatException(                "The raw read specifier %r may only be used with narrow strings and ranges of bytes."            );    }     enforceFmt(find(acceptedSpecs!T, spec.spec).length,               text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof));     enforceFmt(spec.width == 0, "Parsing integers with a width specification is not implemented");   // TODO     immutable uint base =        spec.spec == 'x' || spec.spec == 'X' ? 16 :        spec.spec == 'o' ? 8 :        spec.spec == 'b' ? 2 :        spec.spec == 's' || spec.spec == 'd' || spec.spec == 'u' ? 10 : 0;    assert(base != 0, "base must be not equal to zero");     return parse!T(input, base); } T unformatValueImpl(T, Range, Char)(ref Range input, scope const ref FormatSpec!Char spec)if (isFloatingPoint!T && !is(T == enum) && isInputRange!Range    && isSomeChar!(ElementType!Range)&& !is(Range == enum)){    import std.algorithm.searching : find;    import std.conv : parse, text;    import std.format : enforceFmt, FormatException;     if (spec.spec == 'r')    {        static if (is(immutable ElementEncodingType!Range == immutable char)                || is(immutable ElementEncodingType!Range == immutable byte)                || is(immutable ElementEncodingType!Range == immutable ubyte))            return rawRead!T(input);        else            throw new FormatException(                "The raw read specifier %r may only be used with narrow strings and ranges of bytes."            );    }     enforceFmt(find(acceptedSpecs!T, spec.spec).length,               text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof));     return parse!T(input);} T unformatValueImpl(T, Range, Char)(ref Range input, scope const ref FormatSpec!Char spec)if (isInputRange!Range && isSomeChar!T && !is(T == enum) && isSomeChar!(ElementType!Range)){    import std.algorithm.searching : find;    import std.conv : to, text;    import std.range.primitives : empty, front, popFront;    import std.format : enforceFmt, unformatValue;     if (spec.spec == 's' || spec.spec == 'c')    {        auto result = to!T(input.front);        input.popFront();        return result;    }     enforceFmt(find(acceptedSpecs!T, spec.spec).length,               text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof));     enum int size = T.sizeof;    static if (size == 1)        return unformatValue!ubyte(input, spec);    else static if (size == 2)        return unformatValue!ushort(input, spec);    else static if (size == 4)        return unformatValue!uint(input, spec);    else        static assert(false, T.stringof ~ ".sizeof must be 1, 2, or 4 not " ~                      size.stringof);} T unformatValueImpl(T, Range, Char)(ref Range input, scope const ref FormatSpec!Char fmt)if (isInputRange!Range && is(StringTypeOf!T) && !isAggregateType!T && !is(T == enum)){    import std.conv : text;    import std.range.primitives : empty, front, popFront, put;    import std.format : enforceFmt;     const spec = fmt.spec;    if (spec == '(')    {        return unformatRange!T(input, fmt);    }    enforceFmt(spec == 's',               text("Wrong unformat specifier '%", spec , "' for ", T.stringof));     static if (isStaticArray!T)    {        T result;        auto app = result[];    }    else    {        import std.array : appender;        auto app = appender!T();    }    if (fmt.trailing.empty)    {        for (; !input.empty; input.popFront())        {            static if (isStaticArray!T)                if (app.empty)                    break;            app.put(input.front);        }    }    else    {        immutable end = fmt.trailing.front;        for (; !input.empty && input.front != end; input.popFront())        {            static if (isStaticArray!T)                if (app.empty)                    break;            app.put(input.front);        }    }    static if (isStaticArray!T)    {        enforceFmt(app.empty, "need more input");        return result;    }    else        return app.data;} T unformatValueImpl(T, Range, Char)(ref Range input, scope const ref FormatSpec!Char fmt)if (isInputRange!Range && !is(StringTypeOf!T) && !isAggregateType!T    && (isArray!T || isAssociativeArray!T || is(T == enum))){    import std.conv : parse, text;    import std.format : enforceFmt;     const spec = fmt.spec;    if (spec == '(')    {        return unformatRange!T(input, fmt);    }     enforceFmt(spec == 's',               text("Wrong unformat specifier '%", spec , "' for ", T.stringof));     return parse!T(input);} /* * Function that performs raw reading. Used by unformatValue * for integral and float types. */private T rawRead(T, Range)(ref Range input)if (is(immutable ElementEncodingType!Range == immutable char)    || is(immutable ElementEncodingType!Range == immutable byte)    || is(immutable ElementEncodingType!Range == immutable ubyte)){    import std.range.primitives : popFront;     union X    {        ubyte[T.sizeof] raw;        T typed;    }    X x;    foreach (i; 0 .. T.sizeof)    {        static if (isSomeString!Range)        {            x.raw[i] = input[0];            input = input[1 .. $];        }        else        {            // TODO: recheck this            x.raw[i] = input.front;            input.popFront();        }    }    return x.typed;} private T unformatRange(T, Range, Char)(ref Range input, scope const ref FormatSpec!Char spec)in (spec.spec == '(', "spec.spec must be '(' not " ~ spec.spec){    import std.range.primitives : empty, front, popFront;    import std.format : enforceFmt, format;     T result;    static if (isStaticArray!T)    {        size_t i;    }     const(Char)[] cont = spec.trailing;    for (size_t j = 0; j < spec.trailing.length; ++j)    {        if (spec.trailing[j] == '%')        {            cont = spec.trailing[0 .. j];            break;        }    }     bool checkEnd()    {        return input.empty || !cont.empty && input.front == cont.front;    }     if (!checkEnd())    {        for (;;)        {            auto fmt = FormatSpec!Char(spec.nested);            fmt.readUpToNextSpec(input);            enforceFmt(!input.empty, "Unexpected end of input when parsing range");             static if (isStaticArray!T)            {                result[i++] = unformatElement!(typeof(T.init[0]))(input, fmt);            }            else static if (isDynamicArray!T)            {                import std.conv : WideElementType;                result ~= unformatElement!(WideElementType!T)(input, fmt);            }            else static if (isAssociativeArray!T)            {                auto key = unformatElement!(typeof(T.init.keys[0]))(input, fmt);                fmt.readUpToNextSpec(input);        // eat key separator                 result[key] = unformatElement!(typeof(T.init.values[0]))(input, fmt);            }             static if (isStaticArray!T)            {                enforceFmt(i <= T.length,                           "Too many format specifiers for static array of length %d".format(T.length));            }             if (spec.sep !is null)                fmt.readUpToNextSpec(input);            auto sep = spec.sep !is null ? spec.sep : fmt.trailing;             if (checkEnd())                break;             if (!sep.empty && input.front == sep.front)            {                while (!sep.empty)                {                    enforceFmt(!input.empty,                               "Unexpected end of input when parsing range separator");                    enforceFmt(input.front == sep.front,                               "Unexpected character when parsing range separator");                    input.popFront();                    sep.popFront();                }            }        }    }    static if (isStaticArray!T)    {        enforceFmt(i == T.length,                   "Too few (%d) format specifiers for static array of length %d".format(i, T.length));    }    return result;} T unformatElement(T, Range, Char)(ref Range input, scope const ref FormatSpec!Char spec)if (isInputRange!Range){    import std.conv : parseElement;    import std.format.read : unformatValue;     static if (isSomeString!T)    {        if (spec.spec == 's')        {            return parseElement!T(input);        }    }    else static if (isSomeChar!T)    {        if (spec.spec == 's')        {            return parseElement!T(input);        }    }     return unformatValue!T(input, spec);}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t