comparison 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
comparison
equal deleted inserted replaced
119:d00e8db0a568 120:536e43f63c81
9 static import tango.stdc.stringz; 9 static import tango.stdc.stringz;
10 static import tango.text.Util; 10 static import tango.text.Util;
11 static import tango.text.Unicode; 11 static import tango.text.Unicode;
12 static import tango.text.convert.Utf; 12 static import tango.text.convert.Utf;
13 } else { // Phobos 13 } else { // Phobos
14 static import core.exception;
15 static import std.uni;
16 static import std.utf;
17 static import std.array; 14 static import std.array;
18 static import std.string; 15 static import std.string;
19 static import std.conv; 16 static import std.conv;
20 static import std.exception; 17 static import std.exception;
21 } 18 }
22 19
23 version(Tango){ 20 alias TryImmutable!(char)[] String;
24 public alias char[] String; 21 alias TryImmutable!(wchar)[] String16;
25 public alias char[] CString; 22
26 public alias wchar[] String16; 23 String new_String( String cont, int offset, int len ){
27 public alias wchar[] CString16; 24 return _idup(cont[ offset .. offset+len ]);
28 public alias char* ICharPtr; 25 }
29 public alias char* CCharPtr; 26
30 public alias wchar* CWCharPtr; 27 String new_String( String cont ){
31 public alias wchar* IWCharPtr; 28 return _idup(cont);
32 } else { // Phobos
33 public alias string String;
34 public alias wstring String16;
35 mixin(
36 "public alias const(char)[] CString;
37 public alias const(wchar)[] CString16;
38 public alias immutable(char)* ICharPtr;
39 public alias const(char)* CCharPtr;
40 public alias const(wchar)* CWCharPtr;
41 public alias immutable(wchar)* IWCharPtr;"
42 );
43 }
44
45 int codepointIndexToIndex( CString str, int cpIndex ){
46 int cps = cpIndex;
47 int res = 0;
48 while( cps > 0 ){
49 cps--;
50 if( str[res] < 0x80 ){
51 res+=1;
52 }
53 else if( str[res] < 0xE0 ){
54 res+=2;
55 }
56 else if( str[res] & 0xF0 ){
57 res+=3;
58 }
59 else{
60 res+=4;
61 }
62 }
63 return res;
64 }
65
66 /++
67 +
68 +/
69 int indexToCodepointIndex( CString str, int index ){
70 if( index < 0 ) return index;
71 int i = 0;
72 int res = 0;
73 while( i < index ){
74 if( i >= str.length ){
75 break;
76 }
77 if( str[i] < 0x80 ){
78 i+=1;
79 }
80 else if( str[i] < 0xE0 ){
81 i+=2;
82 }
83 else if( str[i] & 0xF0 ){
84 i+=3;
85 }
86 else{
87 i+=4;
88 }
89 res++;
90 }
91 return res;
92 }
93
94 /++
95 + Get that String, that contains the next codepoint of a String.
96 +/
97 String firstCodePointStr( CString str, out int consumed ){
98 version(Tango){
99 dchar[1] buf;
100 uint ate;
101 dchar[] res = tango.text.convert.Utf.toString32( str, buf, &ate );
102 consumed = ate;
103 return str[ 0 .. ate ];
104 } else { // Phobos
105 implMissing( __FILE__, __LINE__ );
106 return null;
107 }
108 }
109
110 /++
111 + Get first codepoint of a String. If an offset is needed, simply use a slice:
112 + ---
113 + dchar res = str[ offset .. $ ].firstCodePoint();
114 + ---
115 +/
116 dchar firstCodePoint( CString str ){
117 int dummy;
118 return firstCodePoint( str, dummy );
119 }
120 dchar firstCodePoint( CString str, out int consumed ){
121 version(Tango){
122 dchar[1] buf;
123 uint ate;
124 dchar[] res = tango.text.convert.Utf.toString32( str, buf, &ate );
125 consumed = ate;
126 if( ate is 0 || res.length is 0 ){
127 getDwtLogger().trace( __FILE__, __LINE__, "str.length={} str={:X2}", str.length, cast(ubyte[])str );
128 }
129 assert( ate > 0 );
130 assert( res.length is 1 );
131 return res[0];
132 } else { // Phobos
133 size_t ate = 0;
134 auto res = std.utf.decode(str, ate);
135
136 if (ate == 0)
137 getDwtLogger().trace( __FILE__, __LINE__, "str.length={} str={:X2}", str.length, cast(ubyte[])str );
138
139 assert(ate > 0);
140 consumed = ate;
141
142 return res;
143 }
144 }
145 dchar firstCodePoint( CString16 str, out int consumed ){
146 version(Tango){
147 dchar[1] buf;
148 uint ate;
149 dchar[] res = tango.text.convert.Utf.toString32( str, buf, &ate );
150 consumed = ate;
151 if( ate is 0 || res.length is 0 ){
152 getDwtLogger().trace( __FILE__, __LINE__, "str.length={} str={:X2}", str.length, cast(ubyte[])str );
153 }
154 assert( ate > 0 );
155 assert( res.length is 1 );
156 return res[0];
157 } else { // Phobos
158 size_t ate = 0;
159 auto res = std.utf.decode(str, ate);
160
161 if (ate == 0)
162 getDwtLogger().trace( __FILE__, __LINE__, "str.length={} str={:X2}", str.length, cast(ubyte[])str );
163
164 assert(ate > 0);
165 consumed = ate;
166
167 return res;
168 }
169 }
170
171 String dcharToString( dchar key ){
172 version(Tango){
173 dchar[1] buf;
174 buf[0] = key;
175 return tango.text.convert.Utf.toString( buf );
176 } else { // Phobos
177 return std.conv.to!(string)(key);
178 }
179 }
180
181 int codepointCount( CString str ){
182 version(Tango){
183 scope dchar[] buf = new dchar[]( str.length );
184 uint ate;
185 dchar[] res = tango.text.convert.Utf.toString32( str, buf, &ate );
186 assert( ate is str.length );
187 return res.length;
188 } else { // Phobos
189 return std.utf.count(str);
190 }
191 }
192
193 //alias tango.text.convert.Utf.toString16 toString16;
194 //alias tango.text.convert.Utf.toString toString;
195
196 int toAbsoluteCodePointStartOffset( CString str, int index ){
197 //getDwtLogger().trace( __FILE__, __LINE__, "str={}, str.length={}, index={}", str, str.length, index );
198 //getDwtLogger().trace( __FILE__, __LINE__, Trace.memory( str );
199 if( str.length is index ){
200 return index;
201 }
202 if( ( str[index] & 0x80 ) is 0x00 ) {
203 return index;
204 }
205 else{
206 int steps = 0;
207 while(( str[index] & 0xC0 ) is 0x80 ){
208 index--;
209 steps++;
210 if( steps > 3 || index < 0 ){
211 break;
212 }
213 }
214 if((( str[index] & 0xE0 ) is 0xC0) && ( steps <= 1 )){
215 // ok
216 }
217 else if((( str[index] & 0xF0 ) is 0xE0) && ( steps <= 2 )){
218 // ok
219 }
220 else if((( str[index] & 0xF8 ) is 0xF0) && ( steps <= 3 )){
221 // ok
222 }
223 else{
224 throw new UnicodeException( "invalid utf8 input to toAbsoluteCodePointStartOffset", index );
225 }
226 return index;
227 }
228 }
229 int getRelativeCodePointOffset( CString str, int startIndex, int searchRelCp ){
230 return getAbsoluteCodePointOffset( str, startIndex, searchRelCp ) - startIndex;
231 }
232 int getAbsoluteCodePointOffset( CString str, int startIndex, int searchRelCp ){
233
234 //getDwtLogger().trace( __FILE__, __LINE__, "str={}, str.length={}, startIndex={}, searchRelCp={}", str, str.length, startIndex, searchRelCp );
235 //getDwtLogger().trace( __FILE__, __LINE__, Trace.memory( str );
236
237 int ignore;
238 int i = startIndex;
239 if( searchRelCp > 0 ){
240 while( searchRelCp !is 0 ){
241
242 if( ( i < str.length )
243 && (( str[i] & 0x80 ) is 0x00 ))
244 {
245 i+=1;
246 }
247 else if( ( i+1 < str.length )
248 && (( str[i+1] & 0xC0 ) is 0x80 )
249 && (( str[i ] & 0xE0 ) is 0xC0 ))
250 {
251 i+=2;
252 }
253 else if( ( i+2 < str.length )
254 && (( str[i+2] & 0xC0 ) is 0x80 )
255 && (( str[i+1] & 0xC0 ) is 0x80 )
256 && (( str[i ] & 0xF0 ) is 0xE0 ))
257 {
258 i+=3;
259 }
260 else if(( i+3 < str.length )
261 && (( str[i+3] & 0xC0 ) is 0x80 )
262 && (( str[i+2] & 0xC0 ) is 0x80 )
263 && (( str[i+1] & 0xC0 ) is 0x80 )
264 && (( str[i ] & 0xF8 ) is 0xF0 ))
265 {
266 i+=4;
267 }
268 else{
269 getDwtLogger().trace( __FILE__, __LINE__, "getAbsoluteCodePointOffset invalid utf8 characters: {:X2}", cast(ubyte[]) str );
270 throw new UnicodeException( "invalid utf8 input", i );
271 }
272 searchRelCp--;
273 }
274 }
275 else if( searchRelCp < 0 ){
276 while( searchRelCp !is 0 ){
277 do{
278 i--;
279 if( i < 0 ){
280 return startIndex-1;
281 }
282 } while(( str[i] & 0xC0 ) is 0x80 );
283 searchRelCp++;
284 }
285 }
286 return i;
287 }
288 int getAbsoluteCodePointOffset( CString16 str, int startIndex, int searchRelCp ){
289 int ignore;
290 int i = startIndex;
291 if( searchRelCp > 0 ){
292 while( searchRelCp !is 0 ){
293
294 if( ( i < str.length )
295 && ( str[i] & 0xD800 ) !is 0xD800 )
296 {
297 i+=1;
298 }
299 else if( ( i+1 < str.length )
300 && (( str[i+1] & 0xDC00 ) is 0xDC00 )
301 && (( str[i ] & 0xDC00 ) is 0xD800 ))
302 {
303 i+=2;
304 }
305 else{
306 getDwtLogger().trace( __FILE__, __LINE__, "invalid utf16 characters: {:X2}", cast(ubyte[]) str );
307 throw new UnicodeException( "invalid utf16 input", i );
308 }
309 searchRelCp--;
310 }
311 }
312 else if( searchRelCp < 0 ){
313 while( searchRelCp !is 0 ){
314 do{
315 i--;
316 if( i < 0 ){
317 return startIndex-1;
318 //getDwtLogger().trace( __FILE__, __LINE__, "dwthelper.utils getRelativeCodePointOffset {}: str={}, startIndex={}, searchRelCp={}", __LINE__, str, startIndex, searchRelCp );
319 //tango.text.convert.Utf.onUnicodeError( "invalid utf16 input", i );
320 }
321 } while(( str[i] & 0xDC00 ) is 0xDC00 );
322 searchRelCp++;
323 }
324 }
325 return i;
326 }
327 dchar getRelativeCodePoint( CString str, int startIndex, int searchRelCp ){
328 int dummy;
329 return getRelativeCodePoint( str, startIndex, dummy );
330 }
331 dchar getRelativeCodePoint( CString str, int startIndex, int searchRelCp, out int relIndex ){
332 relIndex = getRelativeCodePointOffset( str, startIndex, searchRelCp );
333 int ignore;
334 return firstCodePoint( str[ startIndex+relIndex .. $ ], ignore );
335 }
336
337 int utf8AdjustOffset( CString str, int offset ){
338 if( str.length <= offset || offset <= 0 ){
339 return offset;
340 }
341 while(( str[offset] & 0xC0 ) is 0x80 ){
342 offset--;
343 }
344 return offset;
345 }
346 int utf8OffsetIncr( CString str, int offset ){
347 int res = offset +1;
348 if( str.length <= res || res <= 0 ){
349 return res;
350 }
351 int tries = 4;
352 while(( str[res] & 0xC0 ) is 0x80 ){
353 res++;
354 assert( tries-- > 0 );
355 }
356 return res;
357 }
358 int utf8OffsetDecr( CString str, int offset ){
359 int res = offset-1;
360 if( str.length <= res || res <= 0 ){
361 return res;
362 }
363 int tries = 4;
364 while(( str[res] & 0xC0 ) is 0x80 ){
365 res--;
366 assert( tries-- > 0 );
367 }
368 getDwtLogger().trace( __FILE__, __LINE__, "utf8OffsetDecr {}->{}", offset, res );
369 getDwtLogger().trace( __FILE__, __LINE__, "{}", str );
370 return res;
371 }
372
373 String new_String( CString cont, int offset, int len ){
374 version(D_Version2){
375 return cont[ offset .. offset+len ].idup;
376 } else {
377 return cont[ offset .. offset+len ].dup;
378 }
379 }
380
381 String new_String( CString cont ){
382 version(D_Version2){
383 return cont.idup;
384 } else {
385 return cont.dup;
386 }
387 } 29 }
388 30
389 String String_valueOf( bool v ){ 31 String String_valueOf( bool v ){
390 return v ? "true" : "false"; 32 return v ? "true" : "false";
391 } 33 }
392 34
393 String String_valueOf( byte v ){ 35 String String_valueOf( byte v ){
36 return String_valueOf( cast(long) v );
37 }
38
39 String String_valueOf( ubyte v ){
40 return String_valueOf( cast(uint) v );
41 }
42
43 String String_valueOf( short v ){
44 return String_valueOf( cast(long) v );
45 }
46
47 String String_valueOf( int v ){
48 return String_valueOf( cast(long) v );
49 }
50
51 String String_valueOf( uint v ){
394 version(Tango){ 52 version(Tango){
395 return tango.text.convert.Integer.toString(v); 53 return tango.text.convert.Integer.toString(v);
396 } else { // Phobos 54 } else { // Phobos
397 implMissing( __FILE__, __LINE__ ); 55 return std.conv.to!(String)(v);
398 return null; 56 }
399 } 57 }
400 } 58
401 59 String String_valueOf( long v ){
402 String String_valueOf( ubyte v ){
403 version(Tango){ 60 version(Tango){
404 return tango.text.convert.Integer.toString(v); 61 return tango.text.convert.Integer.toString(v);
405 } else { // Phobos 62 } else { // Phobos
406 implMissing( __FILE__, __LINE__ );
407 return null;
408 }
409 }
410
411 String String_valueOf( short v ){
412 version(Tango){
413 return tango.text.convert.Integer.toString(v);
414 } else { // Phobos
415 implMissing( __FILE__, __LINE__ );
416 return null;
417 }
418 }
419
420 String String_valueOf( int v ){
421 version(Tango){
422 return tango.text.convert.Integer.toString(v);
423 } else { // Phobos
424 return std.conv.to!(String)(v); 63 return std.conv.to!(String)(v);
425 } 64 }
426 } 65 }
427 66
428 String String_valueOf( uint v ){ 67 String String_valueOf( float v ){
429 version(Tango){ 68 version(Tango){
430 return tango.text.convert.Integer.toString(v); 69 return tango.text.convert.Float.toString(v);
431 } else { // Phobos 70 } else { // Phobos
432 return std.conv.to!(String)(v); 71 return std.conv.to!(String)(v);
433 } 72 }
434 } 73 }
435 74
436 String String_valueOf( long v ){ 75 String String_valueOf( double v ){
437 version(Tango){ 76 version(Tango){
438 return tango.text.convert.Integer.toString(v); 77 return tango.text.convert.Float.toString(v);
439 } else { // Phobos 78 } else { // Phobos
440 return std.conv.to!(String)(v); 79 return std.conv.to!(String)(v);
441 } 80 }
442 } 81 }
443 82
444 String String_valueOf( float v ){ 83 String String_valueOf( dchar v ){
445 version(Tango){ 84 version(Tango){
446 return tango.text.convert.Float.toString(v); 85 dchar[1] buf = v;
86 return tango.text.convert.Utf.toString( buf );
447 } else { // Phobos 87 } else { // Phobos
448 return std.conv.to!(String)(v); 88 return std.conv.to!(String)(v);
449 } 89 }
450 } 90 }
451 91
452 String String_valueOf( double v ){ 92 String dcharToString( dchar v ){
453 version(Tango){ 93 return String_valueOf(v);
454 return tango.text.convert.Float.toString(v);
455 } else { // Phobos
456 return std.conv.to!(String)(v);
457 }
458 }
459
460 String String_valueOf( dchar v ){
461 return dcharToString(v);
462 } 94 }
463 95
464 String String_valueOf( char[] v ){ 96 String String_valueOf( char[] v ){
465 version(D_Version2){ 97 return _idup(v);
466 return v.idup;
467 } else {
468 return v.dup;
469 }
470 } 98 }
471 99
472 String String_valueOf( char[] v, int offset, int len ){ 100 String String_valueOf( char[] v, int offset, int len ){
473 version(D_Version2){ 101 return _idup(v[ offset .. offset+len ]);
474 return v[ offset .. offset+len ].idup;
475 } else {
476 return v[ offset .. offset+len ].dup;
477 }
478 } 102 }
479 103
480 String String_valueOf( Object v ){ 104 String String_valueOf( Object v ){
481 return v is null ? "null" : v.toString(); 105 return v is null ? "null" : v.toString();
482 } 106 }
483 107
484 String String_valueOf( CString16 wstr ){ 108 String String_valueOf( in wchar[] wstr ){
485 version(Tango){ 109 version(Tango){
486 return tango.text.convert.Utf.toString(wstr); 110 return tango.text.convert.Utf.toString(wstr);
487 } else { // Phobos 111 } else { // Phobos
488 return std.conv.to!(String)(wstr); 112 return std.conv.to!(String)(wstr);
489 } 113 }
490 } 114 }
491 115
492 int length( CString str ){ 116 int length( String str ){
493 return str.length; 117 return str.length;
494 } 118 }
495 119
496 /// Extension to String 120 /// Extension to String
497 public String toUpperCase( CString str ){ 121 public String toUpperCase( String str ){
498 version(Tango){ 122 version(Tango){
499 return tango.text.Unicode.toUpper( str ); 123 return tango.text.Unicode.toUpper( str );
500 } else { // Phobos 124 } else { // Phobos
501 implMissing( __FILE__, __LINE__ ); 125 return cast(String) std.string.toupper( str );
502 return null; 126 }
503 } 127 }
504 } 128
505 129 /// Extension to String
506 /// Extension to String 130 public String replaceFirst( String str, String regex, String replacement ){
507 public String replaceFirst( CString str, CString regex, CString replacement ){
508 implMissing(__FILE__,__LINE__); 131 implMissing(__FILE__,__LINE__);
509 return null; 132 return null;
510 } 133 }
511 134
512 /// Extension to String 135 version(Tango) int tangoToJavaIdx(T)(int idx, T[] arr) {
513 public int indexOf( CString str, char searched ){ 136 return idx is arr.length ? -1 : idx;
514 version(Tango){ 137 }
515 int res = tango.text.Util.locate( str, searched ); 138
516 if( res is str.length ) res = -1; 139 /// Extension to String
140 public int indexOf( in char[] str, char searched ){
141 version(Tango){
142 return tangoToJavaIdx(tango.text.Util.locate( str, searched ), str);
143 } else { // Phobos
144 return std.string.indexOf(str, searched);
145 }
146 }
147
148 /// Extension to String
149 public int indexOf( in char[] str, char searched, int fromIndex ){
150 if(fromIndex >= str.length)
151 return -1;
152 version(Tango){
153 return tangoToJavaIdx(tango.text.Util.locate( str, searched, fromIndex ), str);
154 } else { // Phobos
155 int res = std.string.indexOf(str[fromIndex .. $], searched);
156 if (res !is -1) res += fromIndex;
517 return res; 157 return res;
518 } else { // Phobos 158 }
519 return std.string.indexOf(str, searched); 159 }
520 } 160
521 } 161 /// Extension to String
522 162 public int indexOf(in char[] str, in char[] sub){
523 /// Extension to String 163 return indexOf( str, sub, 0 );
524 public int indexOf( CString str, char searched, int startpos ){ 164 }
525 version(Tango){ 165
526 int res = tango.text.Util.locate( str, searched, startpos ); 166 /// Extension to String
527 if( res is str.length ) res = -1; 167 public int indexOf(in char[] str, in char[] sub, int fromIndex){
168 if(fromIndex + sub.length > str.length)
169 return -1;
170 if(!sub.length)
171 return fromIndex;
172 version(Tango){
173 return tangoToJavaIdx(tango.text.Util.locatePattern( str, sub, fromIndex ), str);
174 } else { // Phobos
175 int res = std.string.indexOf(str[fromIndex .. $], sub);
176 if (res !is -1) res += fromIndex;
528 return res; 177 return res;
529 } else { // Phobos 178 }
530 int res = std.string.indexOf(str[startpos .. $], searched); 179 }
531 if (res !is -1) res += startpos; 180
532 return res; 181 /// Extension to String
533 } 182 public int lastIndexOf(in char[] str, char ch){
534 } 183 return lastIndexOf( str, ch, str.length - 1 );
535 184 }
536 /// Extension to String 185
537 public int indexOf(CString str, String ch){ 186 /// Extension to String
538 return indexOf( str, ch, 0 ); 187 public int lastIndexOf(in char[] str, char ch, int fromIndex){
539 } 188 if(fromIndex >= str.length)
540 189 fromIndex = str.length - 1;
541 /// Extension to String 190 version(Tango){
542 public int indexOf(CString str, String ch, int start){ 191 return tangoToJavaIdx(tango.text.Util.locatePrior( str, ch, fromIndex + 1 ), str);
543 version(Tango){ 192 } else { // Phobos
544 int res = tango.text.Util.locatePattern( str, ch, start ); 193 return std.string.lastIndexOf(str[0 .. fromIndex + 1], ch);
545 if( res is str.length ) res = -1; 194 }
546 return res; 195 }
547 } else { // Phobos 196
548 return std.string.indexOf(str[start .. $], ch); 197 /// Extension to String
549 } 198 public int lastIndexOf(in char[] str, in char[] sub ){
550 } 199 return lastIndexOf( str, sub, str.length - sub.length );
551 200 }
552 /// Extension to String 201
553 public int lastIndexOf(CString str, char ch){ 202 /// Extension to String
554 return lastIndexOf( str, ch, str.length ); 203 public int lastIndexOf(in char[] str, in char[] sub, int fromIndex){
555 } 204 int max = cast(int)str.length - cast(int)sub.length;
556 205 if(fromIndex > max)
557 /// Extension to String 206 fromIndex = max;
558 public int lastIndexOf(CString str, char ch, int formIndex){ 207 if(!sub.length)
559 version(Tango){ 208 return fromIndex;
560 int res = tango.text.Util.locatePrior( str, ch, formIndex ); 209 version(Tango){
561 if( res is str.length ) res = -1; 210 return tangoToJavaIdx(tango.text.Util.locatePatternPrior( str, sub, fromIndex + 1 ), str);
562 return res; 211 } else { // Phobos
563 } else { // Phobos 212 size_t to = fromIndex + sub.length;
564 return std.string.lastIndexOf(str[0 .. formIndex], ch); 213 return std.string.lastIndexOf(str[0 .. to < $ ? to : $], sub);
565 } 214 }
566 } 215 }
567 216
568 /// Extension to String 217 unittest {
569 public int lastIndexOf(CString str, String ch ){ 218 sizediff_t i;
570 return lastIndexOf( str, ch, str.length ); 219
571 } 220 i = lastIndexOf("", 'a');
572 221 assert(i == -1);
573 /// Extension to String 222 i = lastIndexOf("def", 'a');
574 public int lastIndexOf(CString str, String ch, int start ){ 223 assert(i == -1);
575 version(Tango){ 224 i = lastIndexOf("abba", 'a');
576 int res = tango.text.Util.locatePatternPrior( str, ch, start ); 225 assert(i == 3);
577 if( res is str.length ) res = -1; 226 i = lastIndexOf("abba", 'a', 0);
578 return res; 227 assert(i == 0);
579 } else { // Phobos 228 i = lastIndexOf("abba", 'a', 1);
580 implMissing( __FILE__, __LINE__ ); 229 assert(i == 0);
581 return 0; 230 i = lastIndexOf("abba", 'a', 2);
582 } 231 assert(i == 0);
583 } 232 i = lastIndexOf("abba", 'a', 3);
584 233 assert(i == 3);
585 /// Extension to String 234 i = lastIndexOf("abba", 'a', 4);
586 public String replaceAll( CString str, String regex, String replacement ){ 235 assert(i == 3);
236 i = lastIndexOf("abba", 'a', 10);
237 assert(i == 3);
238 i = lastIndexOf("def", 'f');
239 assert(i == 2);
240
241 i = lastIndexOf("", "a");
242 assert(i == -1);
243 i = lastIndexOf("", "");
244 assert(i == 0);
245 i = lastIndexOf("abcdefcdef", "c");
246 assert(i == 6);
247 i = lastIndexOf("abcdefcdef", "cd");
248 assert(i == 6);
249 i = lastIndexOf("abcdefcdef", "cd", 5);
250 assert(i == 2);
251 i = lastIndexOf("abcdefcdef", "cd", 6);
252 assert(i == 6);
253 i = lastIndexOf("abcdefcdef", "cd", 7);
254 assert(i == 6);
255 i = lastIndexOf("abcdefcdef", "cd", 10);
256 assert(i == 6);
257 i = lastIndexOf("abcdefcdef", "x");
258 assert(i == -1);
259 i = lastIndexOf("abcdefcdef", "xy");
260 assert(i == -1);
261 i = lastIndexOf("abcdefcdef", "");
262 assert(i == 10);
263 i = lastIndexOf("abcdefcdef", "", 9);
264 assert(i == 9);
265 i = lastIndexOf("abcabc", "abc");
266 assert(i == 3);
267 i = lastIndexOf("abcabc", "abc", 2);
268 assert(i == 0);
269 i = lastIndexOf("abcabc", "abc", 3);
270 assert(i == 3);
271 i = lastIndexOf("abcabc", "abc", 4);
272 assert(i == 3);
273
274
275
276 i = indexOf("", 'a');
277 assert(i == -1);
278 i = indexOf("def", 'a');
279 assert(i == -1);
280 i = indexOf("abba", 'a');
281 assert(i == 0);
282 i = indexOf("abba", 'a', 0);
283 assert(i == 0);
284 i = indexOf("abba", 'a', 1);
285 assert(i == 3);
286 i = indexOf("abba", 'a', 2);
287 assert(i == 3);
288 i = indexOf("abba", 'a', 3);
289 assert(i == 3);
290 i = indexOf("abba", 'a', 4);
291 assert(i == -1);
292 i = indexOf("abba", 'a', 10);
293 assert(i == -1);
294 i = indexOf("def", 'f');
295 assert(i == 2);
296
297 i = indexOf("", "a");
298 assert(i == -1);
299 i = indexOf("", "");
300 assert(i == 0);
301 i = indexOf("abcdefcdef", "c");
302 assert(i == 2);
303 i = indexOf("abcdefcdef", "cd");
304 assert(i == 2);
305 i = indexOf("abcdefcdef", "cd", 4);
306 assert(i == 6);
307 i = indexOf("abcdefcdef", "cd", 5);
308 assert(i == 6);
309 i = indexOf("abcdefcdef", "cd", 6);
310 assert(i == 6);
311 i = indexOf("abcdefcdef", "cd", 7);
312 assert(i == -1);
313 i = indexOf("abcdefcdef", "cd", 10);
314 assert(i == -1);
315 i = indexOf("abcdefcdef", "x");
316 assert(i == -1);
317 i = indexOf("abcdefcdef", "xy");
318 assert(i == -1);
319 i = indexOf("abcdefcdef", "");
320 assert(i == 0);
321 i = indexOf("abcabc", "abc");
322 assert(i == 0);
323 i = indexOf("abcabc", "abc", 2);
324 assert(i == 3);
325 i = indexOf("abcabc", "abc", 3);
326 assert(i == 3);
327 i = indexOf("abcabc", "abc", 4);
328 assert(i == -1);
329 }
330
331 /// Extension to String
332 public String replaceAll( String str, String regex, String replacement ){
587 implMissing(__FILE__,__LINE__); 333 implMissing(__FILE__,__LINE__);
588 return null; 334 return null;
589 } 335 }
590 336
591 /// Extension to String 337 /// Extension to String
592 public String replace( CString str, char from, char to ){ 338 public String replace( String str, char from, char to ){
593 version(Tango){ 339 version(Tango){
594 return tango.text.Util.replace( str.dup, from, to ); 340 return tango.text.Util.replace( str.dup, from, to );
595 } else { // Phobos 341 } else { // Phobos
596 auto res = std.array.replace(str, [from], [to]); 342 char[1] f = from, t = to;
343 auto res = std.array.replace(str, f[], t[]);
597 return std.exception.assumeUnique(res); 344 return std.exception.assumeUnique(res);
598 } 345 }
599 } 346 }
600 347
601 /// Extension to String 348 /// Extension to String
602 public String substring( CString str, int start ){ 349 public String substring( String str, int start ){
603 return cast(String)str[ start .. $ ].dup; 350 return _idup(str[ start .. $ ]);
604 } 351 }
605 352
606 /// Extension to String 353 /// Extension to String
607 public String substring( CString str, int start, int end ){ 354 public String substring( String str, int start, int end ){
608 return cast(String)str[ start .. end ].dup; 355 return _idup(str[ start .. end ]);
609 } 356 }
610 357
611 /// Extension to String 358 /// Extension to String
612 public wchar[] substring( CString16 str, int start ){ 359 public wchar[] substring( String16 str, int start ){
613 return cast(wchar[])(str[ start .. $ ].dup); 360 return str[ start .. $ ].dup;
614 } 361 }
615 362
616 /// Extension to String 363 /// Extension to String
617 public wchar[] substring( CString16 str, int start, int end ){ 364 public wchar[] substring( String16 str, int start, int end ){
618 return str[ start .. end ].dup; 365 return str[ start .. end ].dup;
619 } 366 }
620 367
621 /// Extension to String 368 /// Extension to String
622 public char charAt( CString str, int pos ){ 369 public char charAt( String str, int pos ){
623 return str[ pos ]; 370 return str[ pos ];
624 }
625
626 /// Extension to String
627 public dchar dcharAt( CString str, int pos ){
628 return str[ pos .. $ ].firstCodePoint();
629 } 371 }
630 372
631 /// Extension to String 373 /// Extension to String
632 public void getChars( String src, int srcBegin, int srcEnd, char[] dst, int dstBegin){ 374 public void getChars( String src, int srcBegin, int srcEnd, char[] dst, int dstBegin){
633 dst[ dstBegin .. dstBegin + srcEnd - srcBegin ] = src[ srcBegin .. srcEnd ]; 375 dst[ dstBegin .. dstBegin + srcEnd - srcBegin ] = src[ srcBegin .. srcEnd ];
634 } 376 }
635 377
636 /// Extension to String 378 /// Extension to String
637 public String16 toWCharArray( CString str ){ 379 public String16 toWCharArray( in char[] str ){
638 version(Tango){ 380 version(Tango){
639 return tango.text.convert.Utf.toString16(str); 381 return tango.text.convert.Utf.toString16(str);
640 } else { // Phobos 382 } else { // Phobos
641 return std.conv.to!(String16)(str); 383 return std.conv.to!(String16)(str);
642 } 384 }
643 } 385 }
644 386
645 /// Extension to String 387 /// Extension to String
646 public char[] toCharArray( CString str ){ 388 public char[] toCharArray( String str ){
647 return cast(char[])str; 389 return cast(char[])str;
648 } 390 }
649 391
650 /// Extension to String 392 /// Extension to String
651 public bool endsWith( CString src, CString pattern ){ 393 public bool endsWith( String src, String pattern ){
652 if( src.length < pattern.length ){ 394 if( src.length < pattern.length ){
653 return false; 395 return false;
654 } 396 }
655 return src[ $-pattern.length .. $ ] == pattern; 397 return src[ $-pattern.length .. $ ] == pattern;
656 } 398 }
657 399
658 /// Extension to String 400 /// Extension to String
659 public bool equals( CString src, CString other ){ 401 public bool equals( in char[] src, in char[] other ){
660 return src == other; 402 return src == other;
661 } 403 }
662 404
663 /// Extension to String 405 /// Extension to String
664 public bool equalsIgnoreCase( CString src, CString other ){ 406 public bool equalsIgnoreCase( in char[] src, in char[] other ){
665 version(Tango){ 407 version(Tango) {
666 return tango.text.Unicode.toFold(src) == tango.text.Unicode.toFold(other); 408 if(src.length != other.length)
667 } else { // Phobos 409 return false;
668 implMissing( __FILE__, __LINE__ ); 410 String s1b = new char[ src.length * 2 ]; //*2, or Tango may reallocate buffers
669 return false; 411 String s2b = new char[ other.length * 2 ];
670 } 412 scope(exit) {
671 } 413 delete s1b;
672 414 delete s2b;
673 /// Extension to String 415 }
674 public int compareToIgnoreCase( CString src, CString other ){ 416 return tango.text.Unicode.toFold( src, s1b ) ==
675 version(Tango){ 417 tango.text.Unicode.toFold( other, s2b );
676 return compareTo( tango.text.Unicode.toFold(src), tango.text.Unicode.toFold(other)); 418 } else { // Phobos
677 } else { // Phobos 419 return std.string.icmp(src, other) == 0;
678 implMissing( __FILE__, __LINE__ ); 420 }
679 return 0; 421 }
680 } 422
681 } 423 /// Extension to String
682 424 public int compareToIgnoreCase( in char[] src, in char[] other ){
683 /// Extension to String 425 version(Tango){
684 public int compareTo( CString src, CString other ){ 426 String s1b = new char[ src.length * 2 ]; //*2, or Tango may reallocate buffers
685 return typeid(String).compare( cast(void*)&src, cast(void*)&other ); 427 String s2b = new char[ other.length * 2 ];
686 } 428 scope(exit) {
687 429 delete s1b;
688 /// Extension to String 430 delete s2b;
689 public bool startsWith( CString src, CString pattern ){ 431 }
432 return compareTo( tango.text.Unicode.toFold(src, s1b),
433 tango.text.Unicode.toFold(other, s2b));
434 } else { // Phobos
435 return std.string.icmp(src, other);
436 }
437 }
438
439 /// Extension to String
440 public int compareTo( in char[] src, in char[] other ){
441 version(Tango){
442 return typeid(String).compare( cast(void*)&src, cast(void*)&other );
443 } else { // Phobos
444 return std.string.cmp(src, other);
445 }
446 }
447
448 /// Extension to String
449 public bool startsWith( String src, String pattern ){
690 if( src.length < pattern.length ){ 450 if( src.length < pattern.length ){
691 return false; 451 return false;
692 } 452 }
693 return src[ 0 .. pattern.length ] == pattern; 453 return src[ 0 .. pattern.length ] == pattern;
694 } 454 }
695 455
696 /// Extension to String 456 /// Extension to String
697 public String toLowerCase( CString src ){ 457 public String toLowerCase( String src ){
698 version(Tango){ 458 version(Tango){
699 return tango.text.Unicode.toLower( src ); 459 return tango.text.Unicode.toLower( src );
700 } else { // Phobos 460 } else { // Phobos
701 implMissing( __FILE__, __LINE__ ); 461 return cast(String) std.string.tolower(src);
702 return null; 462 }
703 } 463 }
704 } 464
705 465 /// Extension to String
706 /// Extension to String 466 public hash_t toHash( String src ){
707 public hash_t toHash( CString src ){
708 return typeid(String).getHash(&src); 467 return typeid(String).getHash(&src);
709 } 468 }
710 public alias toHash String_toHash; 469 public alias toHash String_toHash;
711 470
712 /// Extension to String 471 /// Extension to String
713 public String trim( CString str ){ 472 public String trim( String str ){
714 version(Tango){ 473 version(Tango){
715 return tango.text.Util.trim( str ).dup; 474 return tango.text.Util.trim( str ).dup;
716 } else { // Phobos 475 } else { // Phobos
717 return std.string.strip( str.idup ); 476 return std.string.strip( str.idup );
718 } 477 }
719 } 478 }
720 479
721 /// Extension to String 480 /// Extension to String
722 public String intern( CString str ){ 481 public String intern( String str ){
723 return str._idup(); 482 return _idup(str);
724 }
725
726 /++
727 + This is like tango.stdc.stringz.toStringz, but in case of an empty input string,
728 + this function returns a pointer to a null value instead of a null ptr.
729 +/
730 public char* toStringzValidPtr( CString src ){
731 if( src ){
732 return src.toStringz();
733 }
734 else{
735 static const char[] nullPtr = "\0";
736 return cast(char*)nullPtr.ptr;
737 }
738 } 483 }
739 484
740 version(Tango){ 485 version(Tango){
741 public alias tango.stdc.stringz.toStringz toStringz; 486 public alias tango.stdc.stringz.toStringz toStringz;
742 public alias tango.stdc.stringz.toString16z toString16z; 487 public alias tango.stdc.stringz.toString16z toString16z;
743 public alias tango.stdc.stringz.fromStringz fromStringz; 488 public alias tango.stdc.stringz.fromStringz fromStringz;
744 public alias tango.stdc.stringz.fromString16z fromString16z; 489 public alias tango.stdc.stringz.fromString16z fromString16z;
490
491 /++
492 + This is like tango.stdc.stringz.toStringz, but in case of an empty input string,
493 + this function returns a pointer to a null value instead of a null ptr.
494 +/
495 public char* toStringzValidPtr( String src ){
496 if( src ){
497 return src.toStringz();
498 }
499 else{
500 return "".ptr;
501 }
502 }
745 } else { // Phobos 503 } else { // Phobos
746 public char* toStringz( CString s ){ 504 static import std.c.string;
747 if (s.ptr) { 505
748 if (s.length == 0) 506 public char* toStringzValidPtr( in char[] s ) {
749 return "\0".dup.ptr; 507 auto copy = new char[s.length + 1];
750 508 copy[0..s.length] = s;
751 else 509 copy[s.length] = 0;
752 return (s ~ "\0").dup.ptr; 510 return copy.ptr;
753 } 511 }
754 512
755 return null; 513 public char* toStringz( in char[] s ) {
756 } 514 return s is null ? null : toStringzValidPtr(s);
757 public wchar* toString16z( CString16 s ){ 515 }
758 if (s.ptr) { 516
759 if (s.length == 0) 517 public char[] fromStringz( in char* s ){
760 return "\0"w.dup.ptr; 518 return s ? s[0 .. std.c.string.strlen(s)].dup : cast(char[])null;
761 519 }
762 else 520 /*public string fromStringz( in char* s ){
763 return (s ~ "\0"w).dup.ptr; 521 return std.conv.to!(string)(s);
764 } 522 }*/
765 523
766 return null; 524 private size_t w_strlen(in wchar* s) {
767 } 525 size_t res = 0;
768 public char[] fromStringz( CCharPtr s ){ 526 while(*(s+res))
769 size_t len; 527 ++res;
770 528 return res;
771 if (s) 529 }
772 while (*s++) 530
773 len++; 531 public wchar* toString16z( in wchar[] s ){
774 532 if(s is null)
775 return s[0 .. len].dup; 533 return null;
776 } 534 auto copy = new wchar[s.length + 1];
777 public wchar[] fromString16z( CWCharPtr s ){ 535 copy[0..s.length] = s;
778 size_t len; 536 copy[s.length] = 0;
779 537 return copy.ptr;
780 if (s) 538 }
781 while (*s++) 539
782 len++; 540 //Copy of std.conv.toImpl(T, S)(S s) for C-style strings
783 541 public wstring fromString16z( in wchar* s ){
784 return s[0 .. len].dup; 542 return s ? s[0 .. w_strlen(s)].idup : cast(wstring)null;
785 } 543 }
786 } 544 }
787 545
788 static String toHex(uint value, bool prefix = true, int radix = 8){ 546 static String toHex(uint i){
789 version(Tango){ 547 version(Tango){
790 return tango.text.convert.Integer.toString( 548 return tango.text.convert.Integer.toString(i, "x");
791 value, 549 } else { // Phobos
792 radix is 10 ? "d" : 550 return std.conv.to!(String)(i, 16);
793 radix is 8 ? "o" :
794 radix is 16 ? "x" :
795 "d" );
796 } else { // Phobos
797 implMissing( __FILE__, __LINE__ );
798 return null;
799 } 551 }
800 } 552 }
801 553
802 /++ 554 /++
803 + String in java is implementing the interface CharSequence 555 + String in java is implementing the interface CharSequence
805 class StringCharSequence : CharSequence { 557 class StringCharSequence : CharSequence {
806 private String str; 558 private String str;
807 this( String str ){ 559 this( String str ){
808 this.str = str; 560 this.str = str;
809 } 561 }
810 char charAt(int index){ 562 char charAt(int index){
811 return str[index]; 563 return str[index];
812 } 564 }
813 int length(){ 565 int length(){
814 return str.length; 566 return str.length;
815 } 567 }
816 CharSequence subSequence(int start, int end){ 568 CharSequence subSequence(int start, int end){
817 return new StringCharSequence( str[ start .. end ]); 569 return new StringCharSequence( str[ start .. end ]);
818 } 570 }
819 String toString(){ 571 String toString(){
820 return str; 572 return str;
821 } 573 }
822 } 574 }
823 575
824 class StringCls { 576 class StringCls {
829 } 581 }
830 return TYPE_; 582 return TYPE_;
831 } 583 }
832 584
833 } 585 }
834
835