Wolfgang Thallergcc16 merge934c3885 months agoHistory
6420 lines · 181.7 KB · D
RawDownload
// Written in the D programming language. /**A one-stop shop for converting values from one type to another. $(SCRIPT inhibitQuickIndex = 1;)$(DIVC quickindex,$(BOOKTABLE,$(TR $(TH Category) $(TH Functions))$(TR $(TD Generic) $(TD        $(LREF asOriginalType)        $(LREF castFrom)        $(LREF parse)        $(LREF to)        $(LREF toChars)        $(LREF bitCast)))$(TR $(TD Strings) $(TD        $(LREF text)        $(LREF wtext)        $(LREF dtext)        $(LREF writeText)        $(LREF writeWText)        $(LREF writeDText)        $(LREF hexString)))$(TR $(TD Numeric) $(TD        $(LREF octal)        $(LREF roundTo)        $(LREF signed)        $(LREF unsigned)))$(TR $(TD Exceptions) $(TD        $(LREF ConvException)        $(LREF ConvOverflowException))))) Copyright: Copyright The D Language Foundation 2007-. License:   $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors:   $(HTTP digitalmars.com, Walter Bright),           $(HTTP erdani.org, Andrei Alexandrescu),           Shin Fujishiro,           Adam D. Ruppe,           Kenji Hara Source:    $(PHOBOSSRC std/conv.d) */module std.conv; public import std.ascii : LetterCase; import std.meta;import std.range;import std.traits;import std.typecons : Flag, Yes, No, tuple, isTuple; // Same as std.string.format, but "self-importing".// Helps reduce code and imports, particularly in static asserts.// Also helps with missing imports errors.package template convFormat(){    import std.format : format;    alias convFormat = format;} /* ************* Exceptions *************** */ /** * Thrown on conversion errors. */class ConvException : Exception{    import std.exception : basicExceptionCtors;    ///    mixin basicExceptionCtors;} ///@safe unittest{    import std.exception : assertThrown;    assertThrown!ConvException(to!int("abc"));} private auto convError(S, T)(S source, string fn = __FILE__, size_t ln = __LINE__){    string msg;     if (source.empty)        msg = "Unexpected end of input when converting from type " ~ S.stringof ~ " to type " ~ T.stringof;    else    {        ElementType!S el = source.front;         if (el == '\n')            msg = text("Unexpected '\\n' when converting from type " ~ S.stringof ~ " to type " ~ T.stringof);        else            msg =  text("Unexpected '", el,                 "' when converting from type " ~ S.stringof ~ " to type " ~ T.stringof);    }     return new ConvException(msg, fn, ln);} @safe pure/* nothrow*/  // lazy parameter bugprivate auto parseError(lazy string msg, string fn = __FILE__, size_t ln = __LINE__){    return new ConvException(text("Can't parse string: ", msg), fn, ln);} private void parseCheck(alias source)(dchar c, string fn = __FILE__, size_t ln = __LINE__){    if (source.empty)        throw parseError(text("unexpected end of input when expecting \"", c, "\""));    if (source.front != c)        throw parseError(text("\"", c, "\" is missing"), fn, ln);    source.popFront();} private{    T toStr(T, S)(S src)    if (isSomeString!T)    {        // workaround for https://issues.dlang.org/show_bug.cgi?id=14198        static if (is(S == bool) && is(typeof({ T s = "string"; })))        {            return src ? "true" : "false";        }        else        {            import std.array : appender;            import std.format.spec : FormatSpec;            import std.format.write : formatValue;             auto w = appender!T();            FormatSpec!(ElementEncodingType!T) f;            formatValue(w, src, f);            return w.data;        }    }     template isExactSomeString(T)    {        enum isExactSomeString = isSomeString!T && !is(T == enum);    }     template isEnumStrToStr(S, T)    {        enum isEnumStrToStr = is(S : T) &&                              is(S == enum) && isExactSomeString!T;    }    template isNullToStr(S, T)    {        enum isNullToStr = is(S : T) &&                           (is(immutable S == immutable typeof(null))) && isExactSomeString!T;    }} /** * Thrown on conversion overflow errors. */class ConvOverflowException : ConvException{    @safe pure nothrow    this(string s, string fn = __FILE__, size_t ln = __LINE__)    {        super(s, fn, ln);    }} ///@safe unittest{    import std.exception : assertThrown;    assertThrown!ConvOverflowException(to!ubyte(1_000_000));} /**The `to` template converts a value from one type _to another.The source type is deduced and the target type must be specified, for example theexpression `to!int(42.0)` converts the number 42 from`double` _to `int`. The conversion is "safe", i.e.,it checks for overflow; `to!int(4.2e10)` would throw the`ConvOverflowException` exception. Overflow checks are onlyinserted when necessary, e.g., `to!double(42)` does not doany checking because any `int` fits in a `double`. Conversions from string _to numeric types differ from the C equivalents`atoi()` and `atol()` by checking for overflow and not allowing whitespace. For conversion of strings _to signed types, the grammar recognized is:$(PRE $(I Integer):    $(I Sign UnsignedInteger)    $(I UnsignedInteger)$(I Sign):    $(B +)    $(B -)) For conversion _to unsigned types, the grammar recognized is:$(PRE $(I UnsignedInteger):    $(I DecimalDigit)    $(I DecimalDigit) $(I UnsignedInteger)) */template to(T){    T to(A...)(A args)    if (A.length > 0)    {        return toImpl!T(args);    }     // Fix https://issues.dlang.org/show_bug.cgi?id=6175    T to(S)(ref S arg)    if (isStaticArray!S)    {        return toImpl!T(arg);    }     // Fix https://issues.dlang.org/show_bug.cgi?id=16108    T to(S)(ref S arg)    if (isAggregateType!S && !isCopyable!S)    {        return toImpl!T(arg);    }} /** * Converting a value _to its own type (useful mostly for generic code) * simply returns its argument. */@safe pure unittest{    int a = 42;    int b = to!int(a);    double c = to!double(3.14); // c is double with value 3.14} /** * Converting among numeric types is a safe way _to cast them around. * * Conversions from floating-point types _to integral types allow loss of * precision (the fractional part of a floating-point number). The * conversion is truncating towards zero, the same way a cast would * truncate. (_To round a floating point value when casting _to an * integral, use `roundTo`.) */@safe pure unittest{    import std.exception : assertThrown;     int a = 420;    assert(to!long(a) == a);    assertThrown!ConvOverflowException(to!byte(a));     assert(to!int(4.2e6) == 4200000);    assertThrown!ConvOverflowException(to!uint(-3.14));    assert(to!uint(3.14) == 3);    assert(to!uint(3.99) == 3);    assert(to!int(-3.99) == -3);} /** * When converting strings _to numeric types, note that D hexadecimal and binary * literals are not handled. Neither the prefixes that indicate the base, nor the * horizontal bar used _to separate groups of digits are recognized. This also * applies to the suffixes that indicate the type. * * _To work around this, you can specify a radix for conversions involving numbers. */@safe pure unittest{    auto str = to!string(42, 16);    assert(str == "2A");    auto i = to!int(str, 16);    assert(i == 42);} /** * Conversions from integral types _to floating-point types always * succeed, but might lose accuracy. The largest integers with a * predecessor representable in floating-point format are `2^24-1` for * `float`, `2^53-1` for `double`, and `2^64-1` for `real` (when * `real` is 80-bit, e.g. on Intel machines). */@safe pure unittest{    // 2^24 - 1, largest proper integer representable as float    int a = 16_777_215;    assert(to!int(to!float(a)) == a);    assert(to!int(to!float(-a)) == -a);} /**   Conversion from string types to char types enforces the input   to consist of a single code point, and said code point must   fit in the target type. Otherwise, $(LREF ConvException) is thrown. */@safe pure unittest{    import std.exception : assertThrown;     assert(to!char("a") == 'a');    assertThrown(to!char("ñ")); // 'ñ' does not fit into a char    assert(to!wchar("ñ") == 'ñ');    assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar    assert(to!dchar("😃") == '😃');     // Using wstring or dstring as source type does not affect the result    assert(to!char("a"w) == 'a');    assert(to!char("a"d) == 'a');     // Two code points cannot be converted to a single one    assertThrown(to!char("ab"));} /** * Converting an array _to another array type works by converting each * element in turn. Associative arrays can be converted _to associative * arrays as long as keys and values can in turn be converted. */@safe pure unittest{    import std.string : split;     int[] a = [1, 2, 3];    auto b = to!(float[])(a);    assert(b == [1.0f, 2, 3]);    string str = "1 2 3 4 5 6";    auto numbers = to!(double[])(split(str));    assert(numbers == [1.0, 2, 3, 4, 5, 6]);    int[string] c;    c["a"] = 1;    c["b"] = 2;    auto d = to!(double[wstring])(c);    assert(d["a"w] == 1 && d["b"w] == 2);} /** * Conversions operate transitively, meaning that they work on arrays and * associative arrays of any complexity. * * This conversion works because `to!short` applies _to an `int`, `to!wstring` * applies _to a `string`, `to!string` applies _to a `double`, and * `to!(double[])` applies _to an `int[]`. The conversion might throw an * exception because `to!short` might fail the range check. */@safe unittest{    int[string][double[int[]]] a;    auto b = to!(short[wstring][string[double[]]])(a);} /** * Object-to-object conversions by dynamic casting throw exception when * the source is non-null and the target is null. */@safe pure unittest{    import std.exception : assertThrown;    // Testing object conversions    class A {}    class B : A {}    class C : A {}    A a1 = new A, a2 = new B, a3 = new C;    assert(to!B(a2) is a2);    assert(to!C(a3) is a3);    assertThrown!ConvException(to!B(a3));} /** * Stringize conversion from all types is supported. * $(UL *   $(LI String _to string conversion works for any two string types having *        (`char`, `wchar`, `dchar`) character widths and any *        combination of qualifiers (mutable, `const`, or `immutable`).) *   $(LI Converts array (other than strings) _to string. *        Each element is converted by calling `to!T`.) *   $(LI Associative array _to string conversion. *        Each element is converted by calling `to!T`.) *   $(LI Object _to string conversion calls `toString` against the object or *        returns `"null"` if the object is null.) *   $(LI Struct _to string conversion calls `toString` against the struct if *        it is defined.) *   $(LI For structs that do not define `toString`, the conversion _to string *        produces the list of fields.) *   $(LI Enumerated types are converted _to strings as their symbolic names.) *   $(LI Boolean values are converted to `"true"` or `"false"`.) *   $(LI `char`, `wchar`, `dchar` _to a string type.) *   $(LI Unsigned or signed integers _to strings. *        $(DL $(DT [special case]) *             $(DD Convert integral value _to string in $(D_PARAM radix) radix. *             radix must be a value from 2 to 36. *             value is treated as a signed value only if radix is 10. *             The characters A through Z are used to represent values 10 through 36 *             and their case is determined by the $(D_PARAM letterCase) parameter.))) *   $(LI All floating point types _to all string types.) *   $(LI Pointer to string conversions convert the pointer to a `size_t` value. *        If pointer is `char*`, treat it as C-style strings. *        In that case, this function is `@system`.)) * See $(REF formatValue, std,format) on how `toString` should be defined. */@system pure unittest // @system due to cast and ptr{    // Conversion representing dynamic/static array with string    long[] a = [ 1, 3, 5 ];    assert(to!string(a) == "[1, 3, 5]");     // Conversion representing associative array with string    int[string] associativeArray = ["0":1, "1":2];    assert(to!string(associativeArray) == `["0":1, "1":2]` ||           to!string(associativeArray) == `["1":2, "0":1]`);     // char* to string conversion    assert(to!string(cast(char*) null) == "");    assert(to!string("foo\0".ptr) == "foo");     // Conversion reinterpreting void array to string    auto w = "abcx"w;    const(void)[] b = w;    assert(b.length == 8);     auto c = to!(wchar[])(b);    assert(c == "abcx");} /** * Strings can be converted to enum types. The enum member with the same name as the * input string is returned. The comparison is case-sensitive. * * A $(LREF ConvException) is thrown if the enum does not have the specified member. */@safe pure unittest{    import std.exception : assertThrown;     enum E { a, b, c }    assert(to!E("a") == E.a);    assert(to!E("b") == E.b);    assertThrown!ConvException(to!E("A"));} // Tests for https://issues.dlang.org/show_bug.cgi?id=6175@safe pure nothrow unittest{    char[9] sarr = "blablabla";    auto darr = to!(char[])(sarr);    assert(sarr.ptr == darr.ptr);    assert(sarr.length == darr.length);} // Tests for https://issues.dlang.org/show_bug.cgi?id=7348@safe pure /+nothrow+/ unittest{    assert(to!string(null) == "null");    assert(text(null) == "null");} // Test `scope` inference of parameters of `text`@safe unittest{    static struct S    {        int* x; // make S a type with pointers        string toString() const scope        {            return "S";        }    }    scope S s;    assert(text("a", s) == "aS");} // Tests for https://issues.dlang.org/show_bug.cgi?id=11390@safe pure /+nothrow+/ unittest{    const(typeof(null)) ctn;    immutable(typeof(null)) itn;    assert(to!string(ctn) == "null");    assert(to!string(itn) == "null");} // Tests for https://issues.dlang.org/show_bug.cgi?id=8729: do NOT skip leading WS@safe pure unittest{    import std.exception;    static foreach (T; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong))    {        assertThrown!ConvException(to!T(" 0"));        assertThrown!ConvException(to!T(" 0", 8));    }    static foreach (T; AliasSeq!(float, double, real))    {        assertThrown!ConvException(to!T(" 0"));    } 

Lines 1–500 of 6420.

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