diff base/src/java/lang/String.d @ 120:536e43f63c81

Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661 ===D2=== * added [Try]Immutable/Const/Shared templates to work with differenses in D1/D2 instead of version statements used these templates to work with strict type storage rules of dmd-2.053 * com.ibm.icu now also compilable with D2, but not tested yet * small fixes Snippet288 - shared data is in TLS ===Phobos=== * fixed critical bugs in Phobos implemention completely incorrect segfault prone fromStringz (Linux's port ruthless killer) terrible, incorrect StringBuffer realization (StyledText killer) * fixed small bugs as well Snippet72 - misprint in the snippet * implemented missed functionality for Phobos ByteArrayOutputStream implemented (image loading available) formatting correctly works for all DWT's cases As a result, folowing snippets now works with Phobos (Snippet### - what is fixed): Snippet24, 42, 111, 115, 130, 235, 276 - bad string formatting Snippet48, 282 - crash on image loading Snippet163, 189, 211, 213, 217, 218, 222 - crash on copy/cut in StyledText Snippet244 - hang-up ===Tango=== * few changes for the latest Tango trunc-r5661 * few small performance improvments ===General=== * implMissing-s for only one version changed to implMissingInTango/InPhobos * incorrect calls to Format in toString-s fixed * fixed loading \uXXXX characters in ResourceBundle * added good UTF-8 support for StyledText, TextLayout (Win32) and friends UTF functions revised and tested. It is now in java.nonstandard.*Utf modules StyledText and TextLayout (Win32) modules revised for UTF-8 support * removed small diferences in most identical files in *.swt.* folders *.swt.internal.image, *.swt.events and *.swt.custom are identical in Win32/Linux32 now 179 of 576 (~31%) files in *.swt.* folders are fully identical * Win32: snippets now have right subsystem, pretty icons and native system style controls * small fixes in snippets Snippet44 - it's not Snippet44 Snippet212 - functions work with different images and offsets arrays Win32: Snippet282 - crash on close if the button has an image Snippet293 - setGrayed is commented and others Win32: As a result, folowing snippets now works Snippet68 - color doesn't change Snippet163, 189, 211, 213, 217, 218, 222 - UTF-8 issues (see above) Snippet193 - no tabel headers
author Denis Shelomovskij <verylonglogin.reg@gmail.com>
date Sat, 09 Jul 2011 15:50:20 +0300
parents d00e8db0a568
children dc6fc593e8d7
line wrap: on
line diff
--- a/base/src/java/lang/String.d	Sun Apr 17 17:58:36 2011 +0200
+++ b/base/src/java/lang/String.d	Sat Jul 09 15:50:20 2011 +0300
@@ -11,379 +11,21 @@
     static import tango.text.Unicode;
     static import tango.text.convert.Utf;
 } else { // Phobos
-    static import core.exception;
-    static import std.uni;
-    static import std.utf;
     static import std.array;
     static import std.string;
     static import std.conv;
     static import std.exception;
 }
 
-version(Tango){
-    public alias char[] String;
-    public alias char[] CString;
-    public alias wchar[] String16;
-    public alias wchar[] CString16;
-    public alias char*   ICharPtr;
-    public alias char*   CCharPtr;
-    public alias wchar*  CWCharPtr;
-    public alias wchar*  IWCharPtr;
-} else { // Phobos
-    public alias string String;
-    public alias wstring String16;
-    mixin(
-        "public alias const(char)[]     CString;
-        public alias const(wchar)[]    CString16;
-        public alias immutable(char)*  ICharPtr;
-        public alias const(char)*      CCharPtr;
-        public alias const(wchar)*     CWCharPtr;
-        public alias immutable(wchar)* IWCharPtr;"
-    );
-}
-
-int codepointIndexToIndex( CString str, int cpIndex ){
-    int cps = cpIndex;
-    int res = 0;
-    while( cps > 0 ){
-        cps--;
-        if( str[res] < 0x80 ){
-            res+=1;
-        }
-        else if( str[res] < 0xE0 ){
-            res+=2;
-        }
-        else if( str[res] & 0xF0 ){
-            res+=3;
-        }
-        else{
-            res+=4;
-        }
-    }
-    return res;
-}
-
-/++
-+
-+/
-int indexToCodepointIndex( CString str, int index ){
-    if( index < 0 ) return index;
-    int i = 0;
-    int res = 0;
-    while( i < index ){
-        if( i >= str.length ){
-            break;
-        }
-        if( str[i] < 0x80 ){
-            i+=1;
-        }
-        else if( str[i] < 0xE0 ){
-            i+=2;
-        }
-        else if( str[i] & 0xF0 ){
-            i+=3;
-        }
-        else{
-            i+=4;
-        }
-        res++;
-    }
-    return res;
-}
+alias TryImmutable!(char)[]  String;
+alias TryImmutable!(wchar)[] String16;
 
-/++
-+ Get that String, that contains the next codepoint of a String.
-+/
-String firstCodePointStr( CString str, out int consumed ){
-    version(Tango){
-        dchar[1] buf;
-        uint ate;
-        dchar[] res = tango.text.convert.Utf.toString32( str, buf, &ate );
-        consumed = ate;
-        return str[ 0 .. ate ];
-    } else { // Phobos
-        implMissing( __FILE__, __LINE__ );
-        return null;
-    }
-}
-
-/++
-+ Get first codepoint of a String. If an offset is needed, simply use a slice:
-+ ---
-+ dchar res = str[ offset .. $ ].firstCodePoint();
-+ ---
-+/
-dchar firstCodePoint( CString str ){
-    int dummy;
-    return firstCodePoint( str, dummy );
-}
-dchar firstCodePoint( CString str, out int consumed ){
-    version(Tango){
-        dchar[1] buf;
-        uint ate;
-        dchar[] res = tango.text.convert.Utf.toString32( str, buf, &ate );
-        consumed = ate;
-        if( ate is 0 || res.length is 0 ){
-            getDwtLogger().trace( __FILE__, __LINE__, "str.length={} str={:X2}", str.length, cast(ubyte[])str );
-        }
-        assert( ate > 0 );
-        assert( res.length is 1 );
-        return res[0];
-    } else { // Phobos
-        size_t ate = 0;
-        auto res = std.utf.decode(str, ate);
-
-        if (ate == 0)
-            getDwtLogger().trace( __FILE__, __LINE__, "str.length={} str={:X2}", str.length, cast(ubyte[])str );
-
-        assert(ate > 0);
-        consumed = ate;
-
-        return res;
-    }
-}
-dchar firstCodePoint( CString16 str, out int consumed ){
-    version(Tango){
-        dchar[1] buf;
-        uint ate;
-        dchar[] res = tango.text.convert.Utf.toString32( str, buf, &ate );
-        consumed = ate;
-        if( ate is 0 || res.length is 0 ){
-            getDwtLogger().trace( __FILE__, __LINE__, "str.length={} str={:X2}", str.length, cast(ubyte[])str );
-        }
-        assert( ate > 0 );
-        assert( res.length is 1 );
-        return res[0];
-    } else { // Phobos
-        size_t ate = 0;
-        auto res = std.utf.decode(str, ate);
-
-        if (ate == 0)
-            getDwtLogger().trace( __FILE__, __LINE__, "str.length={} str={:X2}", str.length, cast(ubyte[])str );
-
-        assert(ate > 0);
-        consumed = ate;
-
-        return res;
-    }
-}
-
-String dcharToString( dchar key ){
-    version(Tango){
-        dchar[1] buf;
-        buf[0] = key;
-        return tango.text.convert.Utf.toString( buf );
-    } else { // Phobos
-        return std.conv.to!(string)(key);
-    }
-}
-
-int codepointCount( CString str ){
-    version(Tango){
-        scope dchar[] buf = new dchar[]( str.length );
-        uint ate;
-        dchar[] res = tango.text.convert.Utf.toString32( str, buf, &ate );
-        assert( ate is str.length );
-        return res.length;
-    } else { // Phobos
-        return std.utf.count(str);
-    }
+String new_String( String cont, int offset, int len ){
+    return _idup(cont[ offset .. offset+len ]);
 }
 
-//alias tango.text.convert.Utf.toString16 toString16;
-//alias tango.text.convert.Utf.toString toString;
-
-int toAbsoluteCodePointStartOffset( CString str, int index ){
-    //getDwtLogger().trace( __FILE__, __LINE__, "str={}, str.length={}, index={}", str, str.length, index );
-    //getDwtLogger().trace( __FILE__, __LINE__, Trace.memory( str );
-    if( str.length is index ){
-        return index;
-    }
-    if( ( str[index] & 0x80 ) is 0x00 ) {
-        return index;
-    }
-    else{
-        int steps = 0;
-        while(( str[index] & 0xC0 ) is 0x80 ){
-            index--;
-            steps++;
-            if( steps > 3 || index < 0 ){
-                break;
-            }
-        }
-        if((( str[index] & 0xE0 ) is 0xC0) && ( steps <= 1 )){
-            // ok
-        }
-        else if((( str[index] & 0xF0 ) is 0xE0) && ( steps <= 2 )){
-            // ok
-        }
-        else if((( str[index] & 0xF8 ) is 0xF0) && ( steps <= 3 )){
-            // ok
-        }
-        else{
-            throw new UnicodeException( "invalid utf8 input to toAbsoluteCodePointStartOffset", index );
-        }
-        return index;
-    }
-}
-int getRelativeCodePointOffset( CString str, int startIndex, int searchRelCp ){
-    return getAbsoluteCodePointOffset( str, startIndex, searchRelCp ) - startIndex;
-}
-int getAbsoluteCodePointOffset( CString str, int startIndex, int searchRelCp ){
-
-    //getDwtLogger().trace( __FILE__, __LINE__, "str={}, str.length={}, startIndex={}, searchRelCp={}", str, str.length, startIndex, searchRelCp );
-    //getDwtLogger().trace( __FILE__, __LINE__, Trace.memory( str );
-
-    int ignore;
-    int i = startIndex;
-    if( searchRelCp > 0 ){
-        while( searchRelCp !is 0 ){
-
-            if( ( i < str.length )
-                    && (( str[i] & 0x80 ) is 0x00 ))
-            {
-                i+=1;
-            }
-            else if( ( i+1 < str.length )
-                    && (( str[i+1] & 0xC0 ) is 0x80 )
-                    && (( str[i  ] & 0xE0 ) is 0xC0 ))
-            {
-                i+=2;
-            }
-            else if( ( i+2 < str.length )
-                    && (( str[i+2] & 0xC0 ) is 0x80 )
-                    && (( str[i+1] & 0xC0 ) is 0x80 )
-                    && (( str[i  ] & 0xF0 ) is 0xE0 ))
-            {
-                i+=3;
-            }
-            else if(( i+3 < str.length )
-                    && (( str[i+3] & 0xC0 ) is 0x80 )
-                    && (( str[i+2] & 0xC0 ) is 0x80 )
-                    && (( str[i+1] & 0xC0 ) is 0x80 )
-                    && (( str[i  ] & 0xF8 ) is 0xF0 ))
-            {
-                i+=4;
-            }
-            else{
-                getDwtLogger().trace( __FILE__, __LINE__, "getAbsoluteCodePointOffset invalid utf8 characters:  {:X2}", cast(ubyte[]) str );
-                throw new UnicodeException( "invalid utf8 input", i );
-            }
-            searchRelCp--;
-        }
-    }
-    else if( searchRelCp < 0 ){
-        while( searchRelCp !is 0 ){
-            do{
-                i--;
-                if( i < 0 ){
-                    return startIndex-1;
-                }
-            } while(( str[i] & 0xC0 ) is 0x80 );
-            searchRelCp++;
-        }
-    }
-    return i;
-}
-int getAbsoluteCodePointOffset( CString16 str, int startIndex, int searchRelCp ){
-    int ignore;
-    int i = startIndex;
-    if( searchRelCp > 0 ){
-        while( searchRelCp !is 0 ){
-
-            if( ( i < str.length )
-                    && ( str[i] & 0xD800 ) !is 0xD800 )
-            {
-                i+=1;
-            }
-            else if( ( i+1 < str.length )
-                    && (( str[i+1] & 0xDC00 ) is 0xDC00 )
-                    && (( str[i  ] & 0xDC00 ) is 0xD800 ))
-            {
-                i+=2;
-            }
-            else{
-                getDwtLogger().trace( __FILE__, __LINE__, "invalid utf16 characters:  {:X2}", cast(ubyte[]) str );
-                throw new UnicodeException( "invalid utf16 input", i );
-            }
-            searchRelCp--;
-        }
-    }
-    else if( searchRelCp < 0 ){
-        while( searchRelCp !is 0 ){
-            do{
-                i--;
-                if( i < 0 ){
-                    return startIndex-1;
-                    //getDwtLogger().trace( __FILE__, __LINE__, "dwthelper.utils getRelativeCodePointOffset {}: str={}, startIndex={}, searchRelCp={}", __LINE__, str, startIndex, searchRelCp );
-                    //tango.text.convert.Utf.onUnicodeError( "invalid utf16 input", i );
-                }
-            } while(( str[i] & 0xDC00 ) is 0xDC00 );
-            searchRelCp++;
-        }
-    }
-    return i;
-}
-dchar getRelativeCodePoint( CString str, int startIndex, int searchRelCp ){
-    int dummy;
-    return getRelativeCodePoint( str, startIndex, dummy );
-}
-dchar getRelativeCodePoint( CString str, int startIndex, int searchRelCp, out int relIndex ){
-    relIndex = getRelativeCodePointOffset( str, startIndex, searchRelCp );
-    int ignore;
-    return firstCodePoint( str[ startIndex+relIndex .. $ ], ignore );
-}
-
-int utf8AdjustOffset( CString str, int offset ){
-    if( str.length <= offset || offset <= 0 ){
-        return offset;
-    }
-    while(( str[offset] & 0xC0 ) is 0x80 ){
-        offset--;
-    }
-    return offset;
-}
-int utf8OffsetIncr( CString str, int offset ){
-    int res = offset +1;
-    if( str.length <= res || res <= 0 ){
-        return res;
-    }
-    int tries = 4;
-    while(( str[res] & 0xC0 ) is 0x80 ){
-        res++;
-        assert( tries-- > 0 );
-    }
-    return res;
-}
-int utf8OffsetDecr( CString str, int offset ){
-    int res = offset-1;
-    if( str.length <= res || res <= 0 ){
-        return res;
-    }
-    int tries = 4;
-    while(( str[res] & 0xC0 ) is 0x80 ){
-        res--;
-        assert( tries-- > 0 );
-    }
-    getDwtLogger().trace( __FILE__, __LINE__, "utf8OffsetDecr {}->{}", offset, res );
-    getDwtLogger().trace( __FILE__, __LINE__, "{}", str );
-    return res;
-}
-
-String new_String( CString cont, int offset, int len ){
-    version(D_Version2){
-        return cont[ offset .. offset+len ].idup;
-    } else {
-        return cont[ offset .. offset+len ].dup;
-    }
-}
-
-String new_String( CString cont ){
-    version(D_Version2){
-        return cont.idup;
-    } else {
-        return cont.dup;
-    }
+String new_String( String cont ){
+    return _idup(cont);
 }
 
 String String_valueOf( bool v ){
@@ -391,38 +33,19 @@
 }
 
 String String_valueOf( byte v ){
-    version(Tango){
-        return tango.text.convert.Integer.toString(v);
-    } else { // Phobos
-        implMissing( __FILE__, __LINE__ );
-        return null;
-    }
+    return String_valueOf( cast(long) v );
 }
 
 String String_valueOf( ubyte v ){
-    version(Tango){
-        return tango.text.convert.Integer.toString(v);
-    } else { // Phobos
-        implMissing( __FILE__, __LINE__ );
-        return null;
-    }
+    return String_valueOf( cast(uint) v );
 }
 
 String String_valueOf( short v ){
-    version(Tango){
-        return tango.text.convert.Integer.toString(v);
-    } else { // Phobos
-        implMissing( __FILE__, __LINE__ );
-        return null;
-    }
+    return String_valueOf( cast(long) v );
 }
 
 String String_valueOf( int v ){
-    version(Tango){
-        return tango.text.convert.Integer.toString(v);
-    } else { // Phobos
-        return std.conv.to!(String)(v);
-    }
+    return String_valueOf( cast(long) v );
 }
 
 String String_valueOf( uint v ){
@@ -458,30 +81,31 @@
 }
 
 String String_valueOf( dchar v ){
-    return dcharToString(v);
+    version(Tango){
+        dchar[1] buf = v;
+        return tango.text.convert.Utf.toString( buf );
+    } else { // Phobos
+        return std.conv.to!(String)(v);
+    }
+}
+
+String dcharToString( dchar v ){
+    return String_valueOf(v);
 }
 
 String String_valueOf( char[] v ){
-    version(D_Version2){
-        return v.idup;
-    } else {
-        return v.dup;
-    }
+    return _idup(v);
 }
 
 String String_valueOf( char[] v, int offset, int len ){
-    version(D_Version2){
-        return v[ offset .. offset+len ].idup;
-    } else {
-        return v[ offset .. offset+len ].dup;
-    }
+    return _idup(v[ offset .. offset+len ]);
 }
 
 String String_valueOf( Object v ){
     return v is null ? "null" : v.toString();
 }
 
-String String_valueOf( CString16 wstr ){
+String String_valueOf( in wchar[] wstr ){
     version(Tango){
         return tango.text.convert.Utf.toString(wstr);
     } else { // Phobos
@@ -489,152 +113,270 @@
     }
 }
 
-int length( CString str ){
+int length( String str ){
     return str.length;
 }
 
 /// Extension to String
-public String toUpperCase( CString str ){
+public String toUpperCase( String str ){
     version(Tango){
         return tango.text.Unicode.toUpper( str );
     } else { // Phobos
-        implMissing( __FILE__, __LINE__ );
-        return null;
+        return cast(String) std.string.toupper( str );
     }
 }
 
 /// Extension to String
-public String replaceFirst( CString str, CString regex, CString replacement ){
+public String replaceFirst( String str, String regex, String replacement ){
     implMissing(__FILE__,__LINE__);
     return null;
 }
 
+version(Tango) int tangoToJavaIdx(T)(int idx, T[] arr) {
+    return idx is arr.length ? -1 : idx;
+}
+
 /// Extension to String
-public int indexOf( CString str, char searched ){
+public int indexOf( in char[] str, char searched ){
     version(Tango){
-        int res = tango.text.Util.locate( str, searched );
-        if( res is str.length ) res = -1;
-        return res;
+        return tangoToJavaIdx(tango.text.Util.locate( str, searched ), str);
     } else { // Phobos
         return std.string.indexOf(str, searched);
     }
 }
 
 /// Extension to String
-public int indexOf( CString str, char searched, int startpos ){
+public int indexOf( in char[] str, char searched, int fromIndex ){
+    if(fromIndex >= str.length)
+        return -1;
     version(Tango){
-        int res = tango.text.Util.locate( str, searched, startpos );
-        if( res is str.length ) res = -1;
+        return tangoToJavaIdx(tango.text.Util.locate( str, searched, fromIndex ), str);
+    } else { // Phobos
+        int res = std.string.indexOf(str[fromIndex .. $], searched);
+        if (res !is -1) res += fromIndex;
         return res;
+    }
+}
+
+/// Extension to String
+public int indexOf(in char[] str, in char[] sub){
+    return indexOf( str, sub, 0 );
+}
+
+/// Extension to String
+public int indexOf(in char[] str, in char[] sub, int fromIndex){
+    if(fromIndex + sub.length > str.length)
+        return -1;
+    if(!sub.length)
+        return fromIndex;
+    version(Tango){
+        return tangoToJavaIdx(tango.text.Util.locatePattern( str, sub, fromIndex ), str);
     } else { // Phobos
-        int res = std.string.indexOf(str[startpos .. $], searched);
-        if (res !is -1) res += startpos;
+        int res = std.string.indexOf(str[fromIndex .. $], sub);
+        if (res !is -1) res += fromIndex;
         return res;
     }
 }
 
 /// Extension to String
-public int indexOf(CString str, String ch){
-    return indexOf( str, ch, 0 );
+public int lastIndexOf(in char[] str, char ch){
+    return lastIndexOf( str, ch, str.length - 1 );
 }
 
 /// Extension to String
-public int indexOf(CString str, String ch, int start){
+public int lastIndexOf(in char[] str, char ch, int fromIndex){
+    if(fromIndex >= str.length)
+        fromIndex = str.length - 1;
     version(Tango){
-        int res = tango.text.Util.locatePattern( str, ch, start );
-        if( res is str.length ) res = -1;
-        return res;
+        return tangoToJavaIdx(tango.text.Util.locatePrior( str, ch, fromIndex + 1 ), str);
     } else { // Phobos
-        return std.string.indexOf(str[start .. $], ch);
+        return std.string.lastIndexOf(str[0 .. fromIndex + 1], ch);
     }
 }
 
 /// Extension to String
-public int lastIndexOf(CString str, char ch){
-    return lastIndexOf( str, ch, str.length );
-}
-
-/// Extension to String
-public int lastIndexOf(CString str, char ch, int formIndex){
-    version(Tango){
-        int res = tango.text.Util.locatePrior( str, ch, formIndex );
-        if( res is str.length ) res = -1;
-        return res;
-    } else { // Phobos
-        return std.string.lastIndexOf(str[0 .. formIndex], ch);
-    }
+public int lastIndexOf(in char[] str, in char[] sub ){
+    return lastIndexOf( str, sub, str.length - sub.length );
 }
 
 /// Extension to String
-public int lastIndexOf(CString str, String ch ){
-    return lastIndexOf( str, ch, str.length );
+public int lastIndexOf(in char[] str, in char[] sub, int fromIndex){
+    int max = cast(int)str.length - cast(int)sub.length;
+    if(fromIndex > max)
+        fromIndex = max;
+    if(!sub.length)
+        return fromIndex;
+    version(Tango){
+        return tangoToJavaIdx(tango.text.Util.locatePatternPrior( str, sub, fromIndex + 1 ), str);
+    } else { // Phobos
+        size_t to = fromIndex + sub.length;
+        return std.string.lastIndexOf(str[0 .. to < $ ? to : $], sub);
+    }
+}
+
+unittest {
+    sizediff_t i;
+
+    i = lastIndexOf("", 'a');
+    assert(i == -1);
+    i = lastIndexOf("def", 'a');
+    assert(i == -1);
+    i = lastIndexOf("abba", 'a');
+    assert(i == 3);
+    i = lastIndexOf("abba", 'a', 0);
+    assert(i == 0);
+    i = lastIndexOf("abba", 'a', 1);
+    assert(i == 0);
+    i = lastIndexOf("abba", 'a', 2);
+    assert(i == 0);
+    i = lastIndexOf("abba", 'a', 3);
+    assert(i == 3);
+    i = lastIndexOf("abba", 'a', 4);
+    assert(i == 3);
+    i = lastIndexOf("abba", 'a', 10);
+    assert(i == 3);
+    i = lastIndexOf("def", 'f');
+    assert(i == 2);
+
+    i = lastIndexOf("", "a");
+    assert(i == -1);
+    i = lastIndexOf("", "");
+    assert(i == 0);
+    i = lastIndexOf("abcdefcdef", "c");
+    assert(i == 6);
+    i = lastIndexOf("abcdefcdef", "cd");
+    assert(i == 6);
+    i = lastIndexOf("abcdefcdef", "cd", 5);
+    assert(i == 2);
+    i = lastIndexOf("abcdefcdef", "cd", 6);
+    assert(i == 6);
+    i = lastIndexOf("abcdefcdef", "cd", 7);
+    assert(i == 6);
+    i = lastIndexOf("abcdefcdef", "cd", 10);
+    assert(i == 6);
+    i = lastIndexOf("abcdefcdef", "x");
+    assert(i == -1);
+    i = lastIndexOf("abcdefcdef", "xy");
+    assert(i == -1);
+    i = lastIndexOf("abcdefcdef", "");
+    assert(i == 10);
+    i = lastIndexOf("abcdefcdef", "", 9);
+    assert(i == 9);
+    i = lastIndexOf("abcabc", "abc");
+    assert(i == 3);
+    i = lastIndexOf("abcabc", "abc", 2);
+    assert(i == 0);
+    i = lastIndexOf("abcabc", "abc", 3);
+    assert(i == 3);
+    i = lastIndexOf("abcabc", "abc", 4);
+    assert(i == 3);
+
+
+
+    i = indexOf("", 'a');
+    assert(i == -1);
+    i = indexOf("def", 'a');
+    assert(i == -1);
+    i = indexOf("abba", 'a');
+    assert(i == 0);
+    i = indexOf("abba", 'a', 0);
+    assert(i == 0);
+    i = indexOf("abba", 'a', 1);
+    assert(i == 3);
+    i = indexOf("abba", 'a', 2);
+    assert(i == 3);
+    i = indexOf("abba", 'a', 3);
+    assert(i == 3);
+    i = indexOf("abba", 'a', 4);
+    assert(i == -1);
+    i = indexOf("abba", 'a', 10);
+    assert(i == -1);
+    i = indexOf("def", 'f');
+    assert(i == 2);
+
+    i = indexOf("", "a");
+    assert(i == -1);
+    i = indexOf("", "");
+    assert(i == 0);
+    i = indexOf("abcdefcdef", "c");
+    assert(i == 2);
+    i = indexOf("abcdefcdef", "cd");
+    assert(i == 2);
+    i = indexOf("abcdefcdef", "cd", 4);
+    assert(i == 6);
+    i = indexOf("abcdefcdef", "cd", 5);
+    assert(i == 6);
+    i = indexOf("abcdefcdef", "cd", 6);
+    assert(i == 6);
+    i = indexOf("abcdefcdef", "cd", 7);
+    assert(i == -1);
+    i = indexOf("abcdefcdef", "cd", 10);
+    assert(i == -1);
+    i = indexOf("abcdefcdef", "x");
+    assert(i == -1);
+    i = indexOf("abcdefcdef", "xy");
+    assert(i == -1);
+    i = indexOf("abcdefcdef", "");
+    assert(i == 0);
+    i = indexOf("abcabc", "abc");
+    assert(i == 0);
+    i = indexOf("abcabc", "abc", 2);
+    assert(i == 3);
+    i = indexOf("abcabc", "abc", 3);
+    assert(i == 3);
+    i = indexOf("abcabc", "abc", 4);
+    assert(i == -1);
 }
 
 /// Extension to String
-public int lastIndexOf(CString str, String ch, int start ){
-    version(Tango){
-        int res = tango.text.Util.locatePatternPrior( str, ch, start );
-        if( res is str.length ) res = -1;
-        return res;
-    } else { // Phobos
-        implMissing( __FILE__, __LINE__ );
-        return 0;
-    }
-}
-
-/// Extension to String
-public String replaceAll( CString str, String regex, String replacement ){
+public String replaceAll( String str, String regex, String replacement ){
     implMissing(__FILE__,__LINE__);
     return null;
 }
 
 /// Extension to String
-public String replace( CString str, char from, char to ){
+public String replace( String str, char from, char to ){
     version(Tango){
         return tango.text.Util.replace( str.dup, from, to );
     } else { // Phobos
-        auto res = std.array.replace(str, [from], [to]);
+        char[1] f = from, t = to;
+        auto res = std.array.replace(str, f[], t[]);
         return std.exception.assumeUnique(res);
     }
 }
 
 /// Extension to String
-public String substring( CString str, int start ){
-    return cast(String)str[ start .. $ ].dup;
+public String substring( String str, int start ){
+    return _idup(str[ start .. $ ]);
 }
 
 /// Extension to String
-public String substring( CString str, int start, int end ){
-    return cast(String)str[ start .. end ].dup;
+public String substring( String str, int start, int end ){
+    return _idup(str[ start .. end ]);
 }
 
 /// Extension to String
-public wchar[] substring( CString16 str, int start ){
-    return cast(wchar[])(str[ start .. $ ].dup);
+public wchar[] substring( String16 str, int start ){
+    return str[ start .. $ ].dup;
 }
 
 /// Extension to String
-public wchar[] substring( CString16 str, int start, int end ){
+public wchar[] substring( String16 str, int start, int end ){
     return str[ start .. end ].dup;
 }
 
 /// Extension to String
-public char charAt( CString str, int pos ){
+public char charAt( String str, int pos ){
     return str[ pos ];
 }
 
 /// Extension to String
-public dchar dcharAt( CString str, int pos ){
-    return str[ pos .. $ ].firstCodePoint();
-}
-
-/// Extension to String
 public void getChars( String src, int srcBegin, int srcEnd, char[] dst, int dstBegin){
     dst[ dstBegin .. dstBegin + srcEnd - srcBegin ] = src[ srcBegin .. srcEnd ];
 }
 
 /// Extension to String
-public String16 toWCharArray( CString str ){
+public String16 toWCharArray( in char[] str ){
     version(Tango){
         return tango.text.convert.Utf.toString16(str);
     } else { // Phobos
@@ -643,12 +385,12 @@
 }
 
 /// Extension to String
-public char[] toCharArray( CString str ){
+public char[] toCharArray( String str ){
     return cast(char[])str;
 }
 
 /// Extension to String
-public bool endsWith( CString src, CString pattern ){
+public bool endsWith( String src, String pattern ){
     if( src.length < pattern.length ){
         return false;
     }
@@ -656,37 +398,55 @@
 }
 
 /// Extension to String
-public bool equals( CString src, CString other ){
+public bool equals( in char[] src, in char[] other ){
     return src == other;
 }
 
 /// Extension to String
-public bool equalsIgnoreCase( CString src, CString other ){
-    version(Tango){
-        return tango.text.Unicode.toFold(src) == tango.text.Unicode.toFold(other);
+public bool equalsIgnoreCase( in char[] src, in char[] other ){
+    version(Tango) {
+        if(src.length != other.length)
+            return false;
+        String s1b = new char[ src.length * 2 ]; //*2, or Tango may reallocate buffers
+        String s2b = new char[ other.length * 2 ];
+        scope(exit) {
+            delete s1b;
+            delete s2b;
+        }
+        return tango.text.Unicode.toFold( src, s1b ) ==
+            tango.text.Unicode.toFold( other, s2b );
     } else { // Phobos
-        implMissing( __FILE__, __LINE__ );
-        return false;
+        return std.string.icmp(src, other) == 0;
     }
 }
 
 /// Extension to String
-public int compareToIgnoreCase( CString src, CString other ){
+public int compareToIgnoreCase( in char[] src, in char[] other ){
     version(Tango){
-        return compareTo( tango.text.Unicode.toFold(src), tango.text.Unicode.toFold(other));
+        String s1b = new char[ src.length * 2 ]; //*2, or Tango may reallocate buffers
+        String s2b = new char[ other.length * 2 ];
+        scope(exit) {
+            delete s1b;
+            delete s2b;
+        }
+        return compareTo( tango.text.Unicode.toFold(src, s1b),
+            tango.text.Unicode.toFold(other, s2b));
     } else { // Phobos
-        implMissing( __FILE__, __LINE__ );
-        return 0;
+        return std.string.icmp(src, other);
     }
 }
 
 /// Extension to String
-public int compareTo( CString src, CString other ){
-    return typeid(String).compare( cast(void*)&src, cast(void*)&other );
+public int compareTo( in char[] src, in char[] other ){
+    version(Tango){
+        return typeid(String).compare( cast(void*)&src, cast(void*)&other );
+    } else { // Phobos
+        return std.string.cmp(src, other);
+    }
 }
 
 /// Extension to String
-public bool startsWith( CString src, CString pattern ){
+public bool startsWith( String src, String pattern ){
     if( src.length < pattern.length ){
         return false;
     }
@@ -694,23 +454,22 @@
 }
 
 /// Extension to String
-public String toLowerCase( CString src ){
+public String toLowerCase( String src ){
     version(Tango){
         return tango.text.Unicode.toLower( src );
     } else { // Phobos
-        implMissing( __FILE__, __LINE__ );
-        return null;
+        return cast(String) std.string.tolower(src);
     }
 }
 
 /// Extension to String
-public hash_t toHash( CString src ){
+public hash_t toHash( String src ){
     return typeid(String).getHash(&src);
 }
 public alias toHash String_toHash;
 
 /// Extension to String
-public String trim( CString str ){
+public String trim( String str ){
     version(Tango){
         return tango.text.Util.trim( str ).dup;
     } else { // Phobos
@@ -719,22 +478,8 @@
 }
 
 /// Extension to String
-public String intern( CString str ){
-    return str._idup();
-}
-
-/++
- + This is like tango.stdc.stringz.toStringz, but in case of an empty input string,
- + this function returns a pointer to a null value instead of a null ptr.
- +/
-public char* toStringzValidPtr( CString src ){
-    if( src ){
-        return src.toStringz();
-    }
-    else{
-        static const char[] nullPtr = "\0";
-        return cast(char*)nullPtr.ptr;
-    }
+public String intern( String str ){
+    return _idup(str);
 }
 
 version(Tango){
@@ -742,60 +487,67 @@
     public alias tango.stdc.stringz.toString16z toString16z;
     public alias tango.stdc.stringz.fromStringz fromStringz;
     public alias tango.stdc.stringz.fromString16z fromString16z;
-} else { // Phobos
-    public char* toStringz( CString s ){
-        if (s.ptr) {
-            if (s.length == 0)
-                return "\0".dup.ptr;
-                
-            else
-                return (s ~ "\0").dup.ptr;
+
+    /++
+     + This is like tango.stdc.stringz.toStringz, but in case of an empty input string,
+     + this function returns a pointer to a null value instead of a null ptr.
+     +/
+    public char* toStringzValidPtr( String src ){
+        if( src ){
+            return src.toStringz();
         }
-        
-        return null;
-    }
-    public wchar* toString16z( CString16 s ){
-        if (s.ptr) {
-            if (s.length == 0)
-                return "\0"w.dup.ptr;
-                
-            else
-                return (s ~ "\0"w).dup.ptr;
+        else{
+            return "".ptr;
         }
-        
-        return null;
+    }
+} else { // Phobos
+    static import std.c.string;
+    
+    public char* toStringzValidPtr( in char[] s ) {
+        auto copy = new char[s.length + 1];
+        copy[0..s.length] = s;
+        copy[s.length] = 0;
+        return copy.ptr;
+    }
+    
+    public char* toStringz( in char[] s ) {
+        return s is null ? null : toStringzValidPtr(s);
+    }
+    
+    public char[] fromStringz( in char* s ){
+        return s ? s[0 .. std.c.string.strlen(s)].dup : cast(char[])null;
     }
-    public char[] fromStringz( CCharPtr s ){
-        size_t len;
-        
-        if (s)
-            while (*s++)
-                len++;
-                
-        return s[0 .. len].dup;
+    /*public string fromStringz( in char* s ){
+        return std.conv.to!(string)(s);
+    }*/
+    
+    private size_t w_strlen(in wchar* s) {
+        size_t res = 0;
+        while(*(s+res))
+            ++res;
+        return res;
     }
-    public wchar[] fromString16z( CWCharPtr s ){
-        size_t len;
-        
-        if (s)
-            while (*s++)
-                len++;
-                
-        return s[0 .. len].dup;
+    
+    public wchar* toString16z( in wchar[] s ){
+        if(s is null)
+            return null;
+        auto copy = new wchar[s.length + 1];
+        copy[0..s.length] = s;
+        copy[s.length] = 0;
+        return copy.ptr;
+    }
+    
+    //Copy of std.conv.toImpl(T, S)(S s) for C-style strings
+    public wstring fromString16z( in wchar* s ){
+        return s ? s[0 .. w_strlen(s)].idup : cast(wstring)null;
     }
 }
 
-static String toHex(uint value, bool prefix = true, int radix = 8){
+static String toHex(uint i){
     version(Tango){
-        return tango.text.convert.Integer.toString(
-                value,
-                radix is 10 ? "d" :
-                radix is  8 ? "o" :
-                radix is 16 ? "x" :
-                "d" );
+        return tango.text.convert.Integer.toString(i, "x");
     } else { // Phobos
-        implMissing( __FILE__, __LINE__ );
-        return null;
+        return std.conv.to!(String)(i, 16);
     }
 }
 
@@ -807,16 +559,16 @@
     this( String str ){
         this.str = str;
     }
-    char           charAt(int index){
+    char charAt(int index){
         return str[index];
     }
-    int             length(){
+    int length(){
         return str.length;
     }
-    CharSequence    subSequence(int start, int end){
+    CharSequence subSequence(int start, int end){
         return new StringCharSequence( str[ start .. end ]);
     }
-    String          toString(){
+    String toString(){
         return str;
     }
 }
@@ -831,5 +583,3 @@
     }
 
 }
-
-