diff lphobos/std/conv.d @ 131:5825d48b27d1 trunk

[svn r135] * Merged DMD 1.025 * * Fixed a minor linking order mishap * * Added an command line option -annotate * * Fixed some problems with running optimizations * * Added std.stdio and dependencies to lphobos (still not 100% working, but compiles and links) * * Fixed problems with passing aggregate types to variadic functions * * Added initial code towards full GC support, currently based on malloc and friends, not all the runtime calls the GC yet for memory * * Fixed problems with resolving nested function context pointers for some heavily nested cases * * Redid function argument passing + other minor code cleanups, still lots to do on this end... *
author lindquist
date Fri, 04 Jan 2008 01:38:42 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/std/conv.d	Fri Jan 04 01:38:42 2008 +0100
@@ -0,0 +1,1578 @@
+
+// Written in the D programming language.
+
+/*
+ *  Copyright (C) 2002-2006 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *  Some parts contributed by David L. Davis
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, subject to the following restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+/***********
+ * Conversion building blocks. These differ from the C equivalents
+ * <tt>atoi()</tt> and <tt>atol()</tt> by
+ * checking for overflow and not allowing whitespace.
+ *
+ * For conversion to signed types, the grammar recognized is:
+ * <pre>
+$(I Integer):
+    $(I Sign UnsignedInteger)
+    $(I UnsignedInteger)
+
+$(I Sign):
+    $(B +)
+    $(B -)
+ * </pre>
+ * For conversion to signed types, the grammar recognized is:
+ * <pre>
+$(I UnsignedInteger):
+    $(I DecimalDigit)
+    $(I DecimalDigit) $(I UnsignedInteger)
+ * </pre>
+ * Macros:
+ *	WIKI=Phobos/StdConv
+ */
+
+module std.conv;
+
+private import std.string;  // for atof(), toString()
+private import std.c.stdlib;
+private import std.math;  // for fabs(), isnan()
+private import std.stdio; // for writefln() and printf()
+
+
+//debug=conv;		// uncomment to turn on debugging printf's
+
+/* ************* Exceptions *************** */
+
+/**
+ * Thrown on conversion errors, which happens on deviation from the grammar.
+ */
+class ConvError : Error
+{
+    this(char[] s)
+    {
+	super("conversion " ~ s);
+    }
+}
+
+private void conv_error(char[] s)
+{
+    throw new ConvError(s);
+}
+
+/**
+ * Thrown on conversion overflow errors.
+ */
+class ConvOverflowError : Error
+{
+    this(char[] s)
+    {
+	super("Error: overflow " ~ s);
+    }
+}
+
+private void conv_overflow(char[] s)
+{
+    throw new ConvOverflowError(s);
+}
+
+/***************************************************************
+ * Convert character string to the return type.
+ */
+
+int toInt(char[] s)
+{
+    int length = s.length;
+
+    if (!length)
+	goto Lerr;
+
+    int sign = 0;
+    int v = 0;
+
+    for (int i = 0; i < length; i++)
+    {
+	char c = s[i];
+	if (c >= '0' && c <= '9')
+	{
+	    if (v < int.max/10 || (v == int.max/10 && c + sign <= '7'))
+		v = v * 10 + (c - '0');
+	    else
+		goto Loverflow;
+	}
+	else if (c == '-' && i == 0)
+	{
+	    sign = -1;
+	    if (length == 1)
+		goto Lerr;
+	}
+	else if (c == '+' && i == 0)
+	{
+	    if (length == 1)
+		goto Lerr;
+	}
+	else
+	    goto Lerr;
+    }
+    if (sign == -1)
+    {
+	if (cast(uint)v > 0x80000000)
+	    goto Loverflow;
+	v = -v;
+    }
+    else
+    {
+	if (cast(uint)v > 0x7FFFFFFF)
+	    goto Loverflow;
+    }
+    return v;
+
+Loverflow:
+    conv_overflow(s);
+
+Lerr:
+    conv_error(s);
+    return 0;
+}
+
+unittest
+{
+    debug(conv) printf("conv.toInt.unittest\n");
+
+    int i;
+
+    i = toInt("0");
+    assert(i == 0);
+
+    i = toInt("+0");
+    assert(i == 0);
+
+    i = toInt("-0");
+    assert(i == 0);
+
+    i = toInt("6");
+    assert(i == 6);
+
+    i = toInt("+23");
+    assert(i == 23);
+
+    i = toInt("-468");
+    assert(i == -468);
+
+    i = toInt("2147483647");
+    assert(i == 0x7FFFFFFF);
+
+    i = toInt("-2147483648");
+    assert(i == 0x80000000);
+
+    static char[][] errors =
+    [
+	"",
+	"-",
+	"+",
+	"-+",
+	" ",
+	" 0",
+	"0 ",
+	"- 0",
+	"1-",
+	"xx",
+	"123h",
+	"2147483648",
+	"-2147483649",
+	"5656566565",
+    ];
+
+    for (int j = 0; j < errors.length; j++)
+    {
+	i = 47;
+	try
+	{
+	    i = toInt(errors[j]);
+	    printf("i = %d\n", i);
+	}
+	catch (Error e)
+	{
+	    debug(conv) e.print();
+	    i = 3;
+	}
+	assert(i == 3);
+    }
+}
+
+
+/*******************************************************
+ * ditto
+ */
+
+uint toUint(char[] s)
+{
+    int length = s.length;
+
+    if (!length)
+	goto Lerr;
+
+    uint v = 0;
+
+    for (int i = 0; i < length; i++)
+    {
+	char c = s[i];
+	if (c >= '0' && c <= '9')
+	{
+	    if (v < uint.max/10 || (v == uint.max/10 && c <= '5'))
+		v = v * 10 + (c - '0');
+	    else
+		goto Loverflow;
+	}
+	else
+	    goto Lerr;
+    }
+    return v;
+
+Loverflow:
+    conv_overflow(s);
+
+Lerr:
+    conv_error(s);
+    return 0;
+}
+
+unittest
+{
+    debug(conv) printf("conv.toUint.unittest\n");
+
+    uint i;
+
+    i = toUint("0");
+    assert(i == 0);
+
+    i = toUint("6");
+    assert(i == 6);
+
+    i = toUint("23");
+    assert(i == 23);
+
+    i = toUint("468");
+    assert(i == 468);
+
+    i = toUint("2147483647");
+    assert(i == 0x7FFFFFFF);
+
+    i = toUint("4294967295");
+    assert(i == 0xFFFFFFFF);
+
+    static char[][] errors =
+    [
+	"",
+	"-",
+	"+",
+	"-+",
+	" ",
+	" 0",
+	"0 ",
+	"- 0",
+	"1-",
+	"+5",
+	"-78",
+	"xx",
+	"123h",
+	"4294967296",
+    ];
+
+    for (int j = 0; j < errors.length; j++)
+    {
+	i = 47;
+	try
+	{
+	    i = toUint(errors[j]);
+	    printf("i = %d\n", i);
+	}
+	catch (Error e)
+	{
+	    debug(conv) e.print();
+	    i = 3;
+	}
+	assert(i == 3);
+    }
+}
+
+/*******************************************************
+ * ditto
+ */
+
+long toLong(char[] s)
+{
+    int length = s.length;
+
+    if (!length)
+	goto Lerr;
+
+    int sign = 0;
+    long v = 0;
+
+    for (int i = 0; i < length; i++)
+    {
+	char c = s[i];
+	if (c >= '0' && c <= '9')
+	{
+	    if (v < long.max/10 || (v == long.max/10 && c + sign <= '7'))
+		v = v * 10 + (c - '0');
+	    else
+		goto Loverflow;
+	}
+	else if (c == '-' && i == 0)
+	{
+	    sign = -1;
+	    if (length == 1)
+		goto Lerr;
+	}
+	else if (c == '+' && i == 0)
+	{
+	    if (length == 1)
+		goto Lerr;
+	}
+	else
+	    goto Lerr;
+    }
+    if (sign == -1)
+    {
+	if (cast(ulong)v > 0x8000000000000000)
+	    goto Loverflow;
+	v = -v;
+    }
+    else
+    {
+	if (cast(ulong)v > 0x7FFFFFFFFFFFFFFF)
+	    goto Loverflow;
+    }
+    return v;
+
+Loverflow:
+    conv_overflow(s);
+
+Lerr:
+    conv_error(s);
+    return 0;
+}
+
+unittest
+{
+    debug(conv) printf("conv.toLong.unittest\n");
+
+    long i;
+
+    i = toLong("0");
+    assert(i == 0);
+
+    i = toLong("+0");
+    assert(i == 0);
+
+    i = toLong("-0");
+    assert(i == 0);
+
+    i = toLong("6");
+    assert(i == 6);
+
+    i = toLong("+23");
+    assert(i == 23);
+
+    i = toLong("-468");
+    assert(i == -468);
+
+    i = toLong("2147483647");
+    assert(i == 0x7FFFFFFF);
+
+    i = toLong("-2147483648");
+    assert(i == -0x80000000L);
+
+    i = toLong("9223372036854775807");
+    assert(i == 0x7FFFFFFFFFFFFFFF);
+
+    i = toLong("-9223372036854775808");
+    assert(i == 0x8000000000000000);
+
+    static char[][] errors =
+    [
+	"",
+	"-",
+	"+",
+	"-+",
+	" ",
+	" 0",
+	"0 ",
+	"- 0",
+	"1-",
+	"xx",
+	"123h",
+	"9223372036854775808",
+	"-9223372036854775809",
+    ];
+
+    for (int j = 0; j < errors.length; j++)
+    {
+	i = 47;
+	try
+	{
+	    i = toLong(errors[j]);
+	    printf("l = %d\n", i);
+	}
+	catch (Error e)
+	{
+	    debug(conv) e.print();
+	    i = 3;
+	}
+	assert(i == 3);
+    }
+}
+
+
+/*******************************************************
+ * ditto
+ */
+
+ulong toUlong(char[] s)
+{
+    int length = s.length;
+
+    if (!length)
+	goto Lerr;
+
+    ulong v = 0;
+
+    for (int i = 0; i < length; i++)
+    {
+	char c = s[i];
+	if (c >= '0' && c <= '9')
+	{
+	    if (v < ulong.max/10 || (v == ulong.max/10 && c <= '5'))
+		v = v * 10 + (c - '0');
+	    else
+		goto Loverflow;
+	}
+	else
+	    goto Lerr;
+    }
+    return v;
+
+Loverflow:
+    conv_overflow(s);
+
+Lerr:
+    conv_error(s);
+    return 0;
+}
+
+unittest
+{
+    debug(conv) printf("conv.toUlong.unittest\n");
+
+    ulong i;
+
+    i = toUlong("0");
+    assert(i == 0);
+
+    i = toUlong("6");
+    assert(i == 6);
+
+    i = toUlong("23");
+    assert(i == 23);
+
+    i = toUlong("468");
+    assert(i == 468);
+
+    i = toUlong("2147483647");
+    assert(i == 0x7FFFFFFF);
+
+    i = toUlong("4294967295");
+    assert(i == 0xFFFFFFFF);
+
+    i = toUlong("9223372036854775807");
+    assert(i == 0x7FFFFFFFFFFFFFFF);
+
+    i = toUlong("18446744073709551615");
+    assert(i == 0xFFFFFFFFFFFFFFFF);
+
+
+    static char[][] errors =
+    [
+	"",
+	"-",
+	"+",
+	"-+",
+	" ",
+	" 0",
+	"0 ",
+	"- 0",
+	"1-",
+	"+5",
+	"-78",
+	"xx",
+	"123h",
+	"18446744073709551616",
+    ];
+
+    for (int j = 0; j < errors.length; j++)
+    {
+	i = 47;
+	try
+	{
+	    i = toUlong(errors[j]);
+	    printf("i = %d\n", i);
+	}
+	catch (Error e)
+	{
+	    debug(conv) e.print();
+	    i = 3;
+	}
+	assert(i == 3);
+    }
+}
+
+
+/*******************************************************
+ * ditto
+ */
+
+short toShort(char[] s)
+{
+    int v = toInt(s);
+
+    if (v != cast(short)v)
+	goto Loverflow;
+
+    return cast(short)v;
+
+Loverflow:
+    conv_overflow(s);
+    return 0;
+}
+
+unittest
+{
+    debug(conv) printf("conv.toShort.unittest\n");
+
+    short i;
+
+    i = toShort("0");
+    assert(i == 0);
+
+    i = toShort("+0");
+    assert(i == 0);
+
+    i = toShort("-0");
+    assert(i == 0);
+
+    i = toShort("6");
+    assert(i == 6);
+
+    i = toShort("+23");
+    assert(i == 23);
+
+    i = toShort("-468");
+    assert(i == -468);
+
+    i = toShort("32767");
+    assert(i == 0x7FFF);
+
+    i = toShort("-32768");
+    assert(i == cast(short)0x8000);
+
+    static char[][] errors =
+    [
+	"",
+	"-",
+	"+",
+	"-+",
+	" ",
+	" 0",
+	"0 ",
+	"- 0",
+	"1-",
+	"xx",
+	"123h",
+	"32768",
+	"-32769",
+    ];
+
+    for (int j = 0; j < errors.length; j++)
+    {
+	i = 47;
+	try
+	{
+	    i = toShort(errors[j]);
+	    printf("i = %d\n", i);
+	}
+	catch (Error e)
+	{
+	    debug(conv) e.print();
+	    i = 3;
+	}
+	assert(i == 3);
+    }
+}
+
+
+/*******************************************************
+ * ditto
+ */
+
+ushort toUshort(char[] s)
+{
+    uint v = toUint(s);
+
+    if (v != cast(ushort)v)
+	goto Loverflow;
+
+    return cast(ushort)v;
+
+Loverflow:
+    conv_overflow(s);
+    return 0;
+}
+
+unittest
+{
+    debug(conv) printf("conv.toUshort.unittest\n");
+
+    ushort i;
+
+    i = toUshort("0");
+    assert(i == 0);
+
+    i = toUshort("6");
+    assert(i == 6);
+
+    i = toUshort("23");
+    assert(i == 23);
+
+    i = toUshort("468");
+    assert(i == 468);
+
+    i = toUshort("32767");
+    assert(i == 0x7FFF);
+
+    i = toUshort("65535");
+    assert(i == 0xFFFF);
+
+    static char[][] errors =
+    [
+	"",
+	"-",
+	"+",
+	"-+",
+	" ",
+	" 0",
+	"0 ",
+	"- 0",
+	"1-",
+	"+5",
+	"-78",
+	"xx",
+	"123h",
+	"65536",
+    ];
+
+    for (int j = 0; j < errors.length; j++)
+    {
+	i = 47;
+	try
+	{
+	    i = toUshort(errors[j]);
+	    printf("i = %d\n", i);
+	}
+	catch (Error e)
+	{
+	    debug(conv) e.print();
+	    i = 3;
+	}
+	assert(i == 3);
+    }
+}
+
+
+/*******************************************************
+ * ditto
+ */
+
+byte toByte(char[] s)
+{
+    int v = toInt(s);
+
+    if (v != cast(byte)v)
+	goto Loverflow;
+
+    return cast(byte)v;
+
+Loverflow:
+    conv_overflow(s);
+    return 0;
+}
+
+unittest
+{
+    debug(conv) printf("conv.toByte.unittest\n");
+
+    byte i;
+
+    i = toByte("0");
+    assert(i == 0);
+
+    i = toByte("+0");
+    assert(i == 0);
+
+    i = toByte("-0");
+    assert(i == 0);
+
+    i = toByte("6");
+    assert(i == 6);
+
+    i = toByte("+23");
+    assert(i == 23);
+
+    i = toByte("-68");
+    assert(i == -68);
+
+    i = toByte("127");
+    assert(i == 0x7F);
+
+    i = toByte("-128");
+    assert(i == cast(byte)0x80);
+
+    static char[][] errors =
+    [
+	"",
+	"-",
+	"+",
+	"-+",
+	" ",
+	" 0",
+	"0 ",
+	"- 0",
+	"1-",
+	"xx",
+	"123h",
+	"128",
+	"-129",
+    ];
+
+    for (int j = 0; j < errors.length; j++)
+    {
+	i = 47;
+	try
+	{
+	    i = toByte(errors[j]);
+	    printf("i = %d\n", i);
+	}
+	catch (Error e)
+	{
+	    debug(conv) e.print();
+	    i = 3;
+	}
+	assert(i == 3);
+    }
+}
+
+
+/*******************************************************
+ * ditto
+ */
+
+ubyte toUbyte(char[] s)
+{
+    uint v = toUint(s);
+
+    if (v != cast(ubyte)v)
+	goto Loverflow;
+
+    return cast(ubyte)v;
+
+Loverflow:
+    conv_overflow(s);
+    return 0;
+}
+
+unittest
+{
+    debug(conv) printf("conv.toUbyte.unittest\n");
+
+    ubyte i;
+
+    i = toUbyte("0");
+    assert(i == 0);
+
+    i = toUbyte("6");
+    assert(i == 6);
+
+    i = toUbyte("23");
+    assert(i == 23);
+
+    i = toUbyte("68");
+    assert(i == 68);
+
+    i = toUbyte("127");
+    assert(i == 0x7F);
+
+    i = toUbyte("255");
+    assert(i == 0xFF);
+
+    static char[][] errors =
+    [
+	"",
+	"-",
+	"+",
+	"-+",
+	" ",
+	" 0",
+	"0 ",
+	"- 0",
+	"1-",
+	"+5",
+	"-78",
+	"xx",
+	"123h",
+	"256",
+    ];
+
+    for (int j = 0; j < errors.length; j++)
+    {
+	i = 47;
+	try
+	{
+	    i = toUbyte(errors[j]);
+	    printf("i = %d\n", i);
+	}
+	catch (Error e)
+	{
+	    debug(conv) e.print();
+	    i = 3;
+	}
+	assert(i == 3);
+    }
+}
+
+
+/*******************************************************
+ * ditto
+ */
+
+float toFloat(in char[] s)
+{
+    float f;
+    char* endptr;
+    char* sz;
+
+    //writefln("toFloat('%s')", s);
+    sz = toStringz(s);
+    if (std.ctype.isspace(*sz))
+	goto Lerr;
+
+    // BUG: should set __locale_decpoint to "." for DMC
+
+    setErrno(0);
+    f = strtof(sz, &endptr);
+    if (getErrno() == ERANGE)
+	goto Lerr;
+    if (endptr && (endptr == s.ptr || *endptr != 0))
+	goto Lerr;
+
+    return f;
+        
+  Lerr:
+    conv_error(s ~ " not representable as a float");
+    assert(0);
+}
+ 
+unittest
+{
+    debug( conv ) writefln( "conv.toFloat.unittest" );
+    float f;
+    
+    f = toFloat( "123" );
+    assert( f == 123f );
+    f = toFloat( "+123" );
+    assert( f == +123f );
+    f = toFloat( "-123" );
+    assert( f == -123f );
+    f = toFloat( "123e+2" );
+    assert( f == 123e+2f );
+
+    f = toFloat( "123e-2" );
+    assert( f == 123e-2f );
+    f = toFloat( "123." );
+    assert( f == 123.f );
+    f = toFloat( ".456" );
+    assert( f == .456f );
+    
+    // min and max
+    f = toFloat("1.17549e-38");
+    assert(feq(cast(real)f, cast(real)1.17549e-38));
+    assert(feq(cast(real)f, cast(real)float.min));
+    f = toFloat("3.40282e+38");
+    assert(toString(f) == toString(3.40282e+38));
+
+    // nan
+    f = toFloat("nan");
+    assert(toString(f) == toString(float.nan));
+}
+
+/*******************************************************
+ * ditto
+ */
+
+double toDouble(in char[] s)
+{
+    double f;
+    char* endptr;
+    char* sz;
+
+    //writefln("toDouble('%s')", s);
+    sz = toStringz(s);
+    if (std.ctype.isspace(*sz))
+	goto Lerr;
+
+    // BUG: should set __locale_decpoint to "." for DMC
+
+    setErrno(0);
+    f = strtod(sz, &endptr);
+    if (getErrno() == ERANGE)
+	goto Lerr;
+    if (endptr && (endptr == s.ptr || *endptr != 0))
+	goto Lerr;
+
+    return f;
+        
+  Lerr:
+    conv_error(s ~ " not representable as a double");
+    assert(0);
+}
+
+unittest
+{
+    debug( conv ) writefln( "conv.toDouble.unittest" );
+    double d;
+
+    d = toDouble( "123" );
+    assert( d == 123 );
+    d = toDouble( "+123" );
+    assert( d == +123 );
+    d = toDouble( "-123" );
+    assert( d == -123 );
+    d = toDouble( "123e2" );
+    assert( d == 123e2);
+    d = toDouble( "123e-2" );
+    assert( d == 123e-2 );
+    d = toDouble( "123." );
+    assert( d == 123. );
+    d = toDouble( ".456" );
+    assert( d == .456 );
+    d = toDouble( "1.23456E+2" );
+    assert( d == 1.23456E+2 );
+
+    // min and max
+    d = toDouble("2.22507e-308");
+    assert(feq(cast(real)d, cast(real)2.22507e-308));
+    assert(feq(cast(real)d, cast(real)double.min));
+    d = toDouble("1.79769e+308");
+    assert(toString(d) == toString(1.79769e+308));
+    assert(toString(d) == toString(double.max));
+
+    // nan
+    d = toDouble("nan");
+    assert(toString(d) == toString(double.nan));
+    //assert(cast(real)d == cast(real)double.nan);
+}
+
+/*******************************************************
+ * ditto
+ */
+real toReal(in char[] s)
+{
+    real f;
+    char* endptr;
+    char* sz;
+
+    //writefln("toReal('%s')", s);
+    sz = toStringz(s);
+    if (std.ctype.isspace(*sz))
+	goto Lerr;
+
+    // BUG: should set __locale_decpoint to "." for DMC
+
+    setErrno(0);
+    f = strtold(sz, &endptr);
+    if (getErrno() == ERANGE)
+	goto Lerr;
+    if (endptr && (endptr == s.ptr || *endptr != 0))
+	goto Lerr;
+
+    return f;
+        
+  Lerr:
+    conv_error(s ~ " not representable as a real");
+    assert(0);
+}
+
+unittest
+{
+    debug(conv) writefln("conv.toReal.unittest");
+    real r;
+
+    r = toReal("123");
+    assert(r == 123L);
+    r = toReal("+123");
+    assert(r == 123L);
+    r = toReal("-123");
+    assert(r == -123L);
+    r = toReal("123e2");
+    assert(feq(r, 123e2L));
+    r = toReal("123e-2");
+    assert(feq(r, 1.23L));
+    r = toReal("123.");
+    assert(r == 123L);
+    r = toReal(".456");
+    assert(r == .456L);
+
+    r = toReal("1.23456e+2");
+    assert(feq(r,  1.23456e+2L));
+    r = toReal(toString(real.max / 2L));
+    assert(toString(r) == toString(real.max / 2L));
+
+    // min and max
+    r = toReal(toString(real.min));
+    assert(toString(r) == toString(real.min));
+    r = toReal(toString(real.max));
+    assert(toString(r) == toString(real.max));
+
+    // nan
+    r = toReal("nan");
+    assert(toString(r) == toString(real.nan));
+    //assert(r == real.nan);
+
+    r = toReal(toString(real.nan));
+    assert(toString(r) == toString(real.nan));
+    //assert(r == real.nan);
+}
+
+version (none)
+{   /* These are removed for the moment because of concern about
+     * what to do about the 'i' suffix. Should it be there?
+     * Should it not? What about 'nan', should it be 'nani'?
+     * 'infinity' or 'infinityi'?
+     * Should it match what toString(ifloat) does with the 'i' suffix?
+     */
+
+/*******************************************************
+ * ditto
+ */
+
+ifloat toIfloat(in char[] s)
+{
+    return toFloat(s) * 1.0i;
+}
+
+unittest
+{
+    debug(conv) writefln("conv.toIfloat.unittest");
+    ifloat ift;
+    
+    ift = toIfloat(toString(123.45));
+    assert(toString(ift) == toString(123.45i));
+
+    ift = toIfloat(toString(456.77i));
+    assert(toString(ift) == toString(456.77i));
+
+    // min and max
+    ift = toIfloat(toString(ifloat.min));
+    assert(toString(ift) == toString(ifloat.min) );
+    assert(feq(cast(ireal)ift, cast(ireal)ifloat.min));
+
+    ift = toIfloat(toString(ifloat.max));
+    assert(toString(ift) == toString(ifloat.max));
+    assert(feq(cast(ireal)ift, cast(ireal)ifloat.max));
+   
+    // nan
+    ift = toIfloat("nani");
+    assert(cast(real)ift == cast(real)ifloat.nan);
+
+    ift = toIfloat(toString(ifloat.nan));
+    assert(toString(ift) == toString(ifloat.nan));
+    assert(feq(cast(ireal)ift, cast(ireal)ifloat.nan));
+}
+
+/*******************************************************
+ * ditto
+ */
+
+idouble toIdouble(in char[] s)
+{
+    return toDouble(s) * 1.0i;
+}
+
+unittest
+{
+    debug(conv) writefln("conv.toIdouble.unittest");
+    idouble id;
+
+    id = toIdouble(toString("123.45"));
+    assert(id == 123.45i);
+
+    id = toIdouble(toString("123.45e+302i"));
+    assert(id == 123.45e+302i);
+
+    // min and max
+    id = toIdouble(toString(idouble.min));
+    assert(toString( id ) == toString(idouble.min));
+    assert(feq(cast(ireal)id.re, cast(ireal)idouble.min.re));
+    assert(feq(cast(ireal)id.im, cast(ireal)idouble.min.im));
+    
+    id = toIdouble(toString(idouble.max));
+    assert(toString(id) == toString(idouble.max));
+    assert(feq(cast(ireal)id.re, cast(ireal)idouble.max.re));
+    assert(feq(cast(ireal)id.im, cast(ireal)idouble.max.im));
+    
+    // nan
+    id = toIdouble("nani");
+    assert(cast(real)id == cast(real)idouble.nan);
+
+    id = toIdouble(toString(idouble.nan));
+    assert(toString(id) == toString(idouble.nan));
+}
+
+/*******************************************************
+ * ditto
+ */
+
+ireal toIreal(in char[] s)
+{
+    return toReal(s) * 1.0i;
+}
+
+unittest
+{
+    debug(conv) writefln("conv.toIreal.unittest");
+    ireal ir;
+
+    ir = toIreal(toString("123.45"));
+    assert(feq(cast(real)ir.re, cast(real)123.45i)); 
+
+    ir = toIreal(toString("123.45e+82i"));
+    assert(toString(ir) == toString(123.45e+82i));
+    //assert(ir == 123.45e+82i);
+
+    // min and max
+    ir = toIreal(toString(ireal.min));
+    assert(toString(ir) == toString(ireal.min));
+    assert(feq(cast(real)ir.re, cast(real)ireal.min.re));
+    assert(feq(cast(real)ir.im, cast(real)ireal.min.im));
+
+    ir = toIreal(toString(ireal.max));
+    assert(toString(ir) == toString(ireal.max));
+    assert(feq(cast(real)ir.re, cast(real)ireal.max.re));
+    //assert(feq(cast(real)ir.im, cast(real)ireal.max.im));
+
+    // nan
+    ir = toIreal("nani");
+    assert(cast(real)ir == cast(real)ireal.nan);
+
+    ir = toIreal(toString(ireal.nan));
+    assert(toString(ir) == toString(ireal.nan));
+}
+
+
+/*******************************************************
+ * ditto
+ */
+cfloat toCfloat(in char[] s)
+{
+    char[] s1;
+    char[] s2;
+    real   r1;
+    real   r2;
+    cfloat cf;
+    bool    b = 0;
+    char*  endptr;
+
+    if (!s.length)
+        goto Lerr;
+    
+    b = getComplexStrings(s, s1, s2);
+
+    if (!b)
+        goto Lerr;
+    
+    // atof(s1);
+    endptr = &s1[s1.length - 1];
+    r1 = strtold(s1, &endptr); 
+
+    // atof(s2);
+    endptr = &s2[s2.length - 1];
+    r2 = strtold(s2, &endptr); 
+
+    cf = cast(cfloat)(r1 + (r2 * 1.0i));
+
+    //writefln( "toCfloat() r1=%g, r2=%g, cf=%g, max=%g", 
+    //           r1, r2, cf, cfloat.max);
+    // Currently disabled due to a posted bug where a 
+    // complex float greater-than compare to .max compares 
+    // incorrectly.
+    //if (cf > cfloat.max)
+    //    goto Loverflow;
+
+    return cf;
+
+    Loverflow:
+        conv_overflow(s);
+        
+    Lerr:
+        conv_error(s);
+        return cast(cfloat)0.0e-0+0i;   
+}
+
+unittest
+{
+    debug(conv) writefln("conv.toCfloat.unittest");
+    cfloat cf;
+
+    cf = toCfloat(toString("1.2345e-5+0i"));
+    assert(toString(cf) == toString(1.2345e-5+0i));
+    assert(feq(cf, 1.2345e-5+0i));
+
+    // min and max
+    cf = toCfloat(toString(cfloat.min));
+    assert(toString(cf) == toString(cfloat.min));
+
+    cf = toCfloat(toString(cfloat.max));
+    assert(toString(cf) == toString(cfloat.max));
+   
+    // nan ( nan+nani )
+    cf = toCfloat("nani");
+    //writefln("toCfloat() cf=%g, cf=\"%s\", nan=%s", 
+    //         cf, toString(cf), toString(cfloat.nan));
+    assert(toString(cf) == toString(cfloat.nan));
+
+    cf = toCdouble("nan+nani");
+    assert(toString(cf) == toString(cfloat.nan));
+
+    cf = toCfloat(toString(cfloat.nan));
+    assert(toString(cf) == toString(cfloat.nan));
+    assert(feq(cast(creal)cf, cast(creal)cfloat.nan));
+}
+
+/*******************************************************
+ * ditto
+ */
+cdouble toCdouble(in char[] s)
+{
+    char[]  s1;
+    char[]  s2;
+    real    r1;
+    real    r2;
+    cdouble cd;
+    bool     b = 0;
+    char*   endptr;
+
+    if (!s.length)
+        goto Lerr;
+    
+    b = getComplexStrings(s, s1, s2);
+
+    if (!b)
+        goto Lerr;
+
+    // atof(s1);
+    endptr = &s1[s1.length - 1];
+    r1 = strtold(s1, &endptr); 
+
+    // atof(s2);
+    endptr = &s2[s2.length - 1];
+    r2 = strtold(s2, &endptr); //atof(s2);
+
+    cd = cast(cdouble)(r1 + (r2 * 1.0i));
+ 
+    //Disabled, waiting on a bug fix.
+    //if (cd > cdouble.max)  //same problem the toCfloat() having
+    //    goto Loverflow;
+
+    return cd;
+
+    Loverflow:
+        conv_overflow(s);
+        
+    Lerr:
+        conv_error(s);
+        return cast(cdouble)0.0e-0+0i; 
+}
+
+unittest
+{
+    debug(conv) writefln("conv.toCdouble.unittest");
+    cdouble cd;
+
+    cd = toCdouble(toString("1.2345e-5+0i"));
+    assert(toString( cd ) == toString(1.2345e-5+0i));
+    assert(feq(cd, 1.2345e-5+0i));
+
+    // min and max
+    cd = toCdouble(toString(cdouble.min));
+    assert(toString(cd) == toString(cdouble.min));
+    assert(feq(cast(creal)cd, cast(creal)cdouble.min));
+
+    cd = toCdouble(toString(cdouble.max));
+    assert(toString( cd ) == toString(cdouble.max));
+    assert(feq(cast(creal)cd, cast(creal)cdouble.max));
+
+    // nan ( nan+nani )
+    cd = toCdouble("nani");
+    assert(toString(cd) == toString(cdouble.nan));
+
+    cd = toCdouble("nan+nani");
+    assert(toString(cd) == toString(cdouble.nan));
+
+    cd = toCdouble(toString(cdouble.nan));
+    assert(toString(cd) == toString(cdouble.nan));
+    assert(feq(cast(creal)cd, cast(creal)cdouble.nan));
+}
+
+/*******************************************************
+ * ditto
+ */
+creal toCreal(in char[] s)
+{
+    char[] s1;
+    char[] s2;
+    real   r1;
+    real   r2;
+    creal  cr;
+    bool    b = 0;
+    char*  endptr;
+
+    if (!s.length)
+        goto Lerr;
+
+    b = getComplexStrings(s, s1, s2);
+
+    if (!b)
+        goto Lerr;
+ 
+    // atof(s1);
+    endptr = &s1[s1.length - 1];
+    r1 = strtold(s1, &endptr); 
+
+    // atof(s2);
+    endptr = &s2[s2.length - 1];
+    r2 = strtold(s2, &endptr); //atof(s2);
+
+    //writefln("toCreal() r1=%g, r2=%g, s1=\"%s\", s2=\"%s\", nan=%g", 
+    //          r1, r2, s1, s2, creal.nan);
+   
+    if (s1 =="nan" && s2 == "nani")
+        cr = creal.nan;
+    else if (r2 != 0.0)
+        cr = cast(creal)(r1 + (r2 * 1.0i));
+    else
+        cr = cast(creal)(r1 + 0.0i);    
+    
+    return cr;
+
+    Lerr:
+        conv_error(s);
+        return cast(creal)0.0e-0+0i;    
+}
+
+unittest
+{
+    debug(conv) writefln("conv.toCreal.unittest");
+    creal cr;
+
+    cr = toCreal(toString("1.2345e-5+0i"));
+    assert(toString(cr) == toString(1.2345e-5+0i));
+    assert(feq(cr, 1.2345e-5+0i));
+
+    cr = toCreal(toString("0.0e-0+0i"));
+    assert(toString(cr) == toString(0.0e-0+0i));
+    assert(cr == 0.0e-0+0i);
+    assert(feq(cr, 0.0e-0+0i));
+    
+    cr = toCreal("123");
+    assert(cr == 123);
+
+    cr = toCreal("+5");
+    assert(cr == 5);
+ 
+    cr = toCreal("-78");
+    assert(cr == -78);
+
+    // min and max
+    cr = toCreal(toString(creal.min));
+    assert(toString(cr) == toString(creal.min));
+    assert(feq(cr, creal.min));
+    
+    cr = toCreal(toString(creal.max));
+    assert(toString(cr) == toString(creal.max));
+    assert(feq(cr, creal.max));
+
+    // nan ( nan+nani )
+    cr = toCreal("nani");
+    assert(toString(cr) == toString(creal.nan));
+
+    cr = toCreal("nan+nani");
+    assert(toString(cr) == toString(creal.nan));
+
+    cr = toCreal(toString(cdouble.nan));
+    assert(toString(cr) == toString(creal.nan));
+    assert(feq(cr, creal.nan));
+}
+
+}
+
+/* **************************************************************
+ * Splits a complex float (cfloat, cdouble, and creal) into two workable strings.
+ * Grammar:
+ * ['+'|'-'] string floating-point digit {digit}
+ */
+private bool getComplexStrings(in char[] s, out char[] s1, out char[] s2)
+{
+    int len = s.length;
+
+    if (!len) 
+        goto Lerr;
+
+    // When "nan" or "nani" just return them.
+    if (s == "nan" || s == "nani" || s == "nan+nani")
+    {
+        s1 = "nan";
+        s2 = "nani";
+        return 1;
+    }
+    
+    // Split the original string out into two strings.
+    for (int i = 1; i < len; i++)
+        if ((s[i - 1] != 'e' && s[i - 1] != 'E') && s[i] == '+')
+        {
+            s1 = s[0..i];
+            if (i + 1 < len - 1)
+                s2 = s[i + 1..len - 1];
+            else 
+                s2 = "0e+0i";
+            
+            break;
+        }   
+
+    // Handle the case when there's only a single value 
+    // to work with, and set the other string to zero.
+    if (!s1.length)
+    {
+        s1 = s;
+        s2 = "0e+0i";
+    }
+ 
+    //writefln( "getComplexStrings() s=\"%s\", s1=\"%s\", s2=\"%s\", len=%d", 
+    //           s, s1, s2, len );
+   
+    return 1;
+
+    Lerr:
+        // Display the original string in the error message.
+        conv_error("getComplexStrings() \"" ~ s ~ "\"" ~ " s1=\"" ~ s1 ~ "\"" ~ " s2=\"" ~ s2 ~ "\"");
+        return 0;
+}
+
+// feq() functions now used only in unittesting
+
+/* ***************************************
+ * Main function to compare reals with given precision
+ */
+private bool feq(in real rx, in real ry, in real precision)
+{
+    if (rx == ry)
+        return 1;
+    
+    if (isnan(rx))
+        return cast(bool)isnan(ry);
+
+    if (isnan(ry))
+        return 0;
+       
+    return cast(bool)(fabs(rx - ry) <= precision);
+}
+
+/* ***************************************
+ * (Note: Copied here from std.math's mfeq() function for unittesting)
+ * Simple function to compare two floating point values
+ * to a specified precision.
+ * Returns:
+ *  1   match
+ *  0   nomatch
+ */
+private bool feq(in real r1, in real r2)
+{
+    if (r1 == r2)
+        return 1;
+    
+    if (isnan(r1))
+        return cast(bool)isnan(r2);
+
+    if (isnan(r2))
+        return 0;
+        
+    return cast(bool)(feq(r1, r2, 0.000001L));
+} 
+ 
+/* ***************************************
+ * compare ireals with given precision
+ */
+private bool feq(in ireal r1, in ireal r2)
+{
+    real rx = cast(real)r1;
+    real ry = cast(real)r2;
+
+    if (rx == ry)
+        return 1;
+    
+    if (isnan(rx)) 
+        return cast(bool)isnan(ry);
+
+    if (isnan(ry))
+        return 0;
+    
+    return feq(rx, ry, 0.000001L);
+} 
+
+/* ***************************************
+ * compare creals with given precision
+ */
+private bool feq(in creal r1, in creal r2)
+{
+    real r1a = fabs(cast(real)r1.re - cast(real)r2.re);
+    real r2b = fabs(cast(real)r1.im - cast(real)r2.im);
+
+    if ((cast(real)r1.re == cast(real)r2.re) &&
+        (cast(real)r1.im == cast(real)r2.im))
+        return 1;
+    
+    if (isnan(r1a))
+        return cast(bool)isnan(r2b);
+
+    if (isnan(r2b))
+        return 0;
+
+    return feq(r1a, r2b, 0.000001L);
+}
+