comparison base/src/java/lang/util.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 fb3aa8075988
children dc6fc593e8d7
comparison
equal deleted inserted replaced
119:d00e8db0a568 120:536e43f63c81
16 static import core.exception; 16 static import core.exception;
17 static import std.c.stdlib; 17 static import std.c.stdlib;
18 static import std.stdio; 18 static import std.stdio;
19 static import std.array; 19 static import std.array;
20 static import std.format; 20 static import std.format;
21 static import std.typetuple;
22 static import std.traits;
21 static import std.exception; 23 static import std.exception;
22 alias std.c.stdlib.exit exit; 24 alias std.c.stdlib.exit exit;
23 } 25 }
24 26
25 version(Tango){ 27 version(Tango){
76 logger.fatal( format( file, line, fmt, _arguments, _argptr )); 78 logger.fatal( format( file, line, fmt, _arguments, _argptr ));
77 } 79 }
78 } 80 }
79 } 81 }
80 } else { // Phobos 82 } else { // Phobos
83 static import core.vararg;
84
81 class DwtLogger : IDwtLogger { 85 class DwtLogger : IDwtLogger {
82 private this( String name ){ 86 private this( String name ) {
83 } 87 }
84 void trace( String file, ulong line, String fmt, ... ){ 88 void trace( String file, ulong line, String fmt, ... ){
85 std.stdio.writefln( "TRC %s %d: %s", file, line, fmt ); 89 fmt = fmtFromTangoFmt(fmt);
86 } 90 std.stdio.writefln( "TRC %s %s: %s", file, line, doVarArgFormat(typeid(fmt) ~ _arguments, &fmt) );
87 void info( String file, ulong line, String fmt, ... ){ 91 }
88 std.stdio.writefln( "INF %s %d: %s", file, line, fmt ); 92 void info( String file, ulong line, String fmt, ... ){
89 } 93 fmt = fmtFromTangoFmt(fmt);
90 void warn( String file, ulong line, String fmt, ... ){ 94 std.stdio.writefln( "INF %s %s: %s", file, line, doVarArgFormat(typeid(fmt) ~ _arguments, &fmt) );
91 std.stdio.writefln( "WRN %s %d: %s", file, line, fmt ); 95 }
92 } 96 void warn( String file, ulong line, String fmt, ... ){
97 fmt = fmtFromTangoFmt(fmt);
98 std.stdio.writefln( "WRN %s %s: %s", file, line, doVarArgFormat(typeid(fmt) ~ _arguments, &fmt) );
99 }
93 void error( String file, ulong line, String fmt, ... ){ 100 void error( String file, ulong line, String fmt, ... ){
94 std.stdio.writefln( "ERR %s %d: %s", file, line, fmt ); 101 fmt = fmtFromTangoFmt(fmt);
95 } 102 std.stdio.writefln( "ERR %s %s: %s", file, line, doVarArgFormat(typeid(fmt) ~ _arguments, &fmt) );
103 }
96 void fatal( String file, ulong line, String fmt, ... ){ 104 void fatal( String file, ulong line, String fmt, ... ){
97 std.stdio.writefln( "FAT %s %d: %s", file, line, fmt ); 105 fmt = fmtFromTangoFmt(fmt);
106 std.stdio.writefln( "FAT %s %s: %s", file, line, doVarArgFormat(typeid(fmt) ~ _arguments, &fmt) );
98 } 107 }
99 } 108 }
100 } 109 }
101 110
102 private DwtLogger dwtLoggerInstance; 111 private DwtLogger dwtLoggerInstance;
117 getDwtLogger().fatal( file, line, "Please create a bug report at http://www.dsource.org/projects/dwt" ); 126 getDwtLogger().fatal( file, line, "Please create a bug report at http://www.dsource.org/projects/dwt" );
118 getDwtLogger().fatal( file, line, "exiting ..." ); 127 getDwtLogger().fatal( file, line, "exiting ..." );
119 exit(1); 128 exit(1);
120 } 129 }
121 130
131 void implMissingInTango(T = void)( String file, uint line ) {
132 version(Tango) {} else static assert(0, "For Tango implMissings only");
133 getDwtLogger().fatal( file, line, "implementation missing in Tango version" );
134 implMissing( file, line );
135 }
136
137 void implMissingInPhobos( String file = __FILE__, uint line = __LINE__ )() {
138 version(Tango) static assert(0, "For Phobos implMissings only");
139 getDwtLogger().fatal( file, line, "implementation missing in Phobos version" );
140 implMissing( file, line );
141 }
142
122 version(Tango){ 143 version(Tango){
123 public alias tango.text.convert.Format.Format Format; 144 public alias tango.text.convert.Format.Format Format;
124 } else { // Phobos 145 } else { // Phobos
146 private string fmtFromTangoFmt(string tangoFmt) {
147 auto app = std.array.appender!(string)();
148 app.reserve(tangoFmt.length);
149 L: for(int i = 0; i < tangoFmt.length; ++i) {
150 char c = tangoFmt[i];
151 if(c == '%')
152 app.put("%%");
153 else if(c == '{') {
154 if(i + 1 < tangoFmt.length && tangoFmt[i + 1] == '{') {
155 app.put('{');
156 ++i;
157 } else {
158 int j = i;
159 do {
160 ++j;
161 if(j == tangoFmt.length) {
162 app.put("{malformed format}");
163 break L;
164 }
165 } while(tangoFmt[j] != '}');
166 string f = tangoFmt[i + 1 .. j];
167 i = j;
168 if(f.length) {
169 string fres = "%";
170 try {
171 if(std.ctype.isdigit(f[0])) {
172 int n = std.conv.parse!(int)(f);
173 fres ~= std.conv.to!(string)(n + 1) ~ '$';
174 }
175 if(f.length) {
176 std.exception.enforce(f[0] == ':' && f.length > 1);
177 c = f[1];
178 if(f.length == 2 && "bodxXeEfFgG".indexOf(c) != -1)
179 fres ~= c;
180 else
181 fres = null;
182 } else
183 fres ~= 's';
184 } catch {
185 fres = "{malformed format}";
186 }
187 if(fres)
188 app.put(fres);
189 else
190 implMissingInPhobos();
191 } else
192 app.put("%s");
193 }
194 } else
195 app.put(c);
196 }
197 return app.data();
198 }
199
200 unittest
201 {
202 alias Format Formatter;
203
204 // basic layout tests
205 assert( Formatter( "abc" ) == "abc" );
206 assert( Formatter( "{0}", 1 ) == "1" );
207 assert( Formatter( "{0}", -1 ) == "-1" );
208
209 assert( Formatter( "{}", 1 ) == "1" );
210 assert( Formatter( "{} {}", 1, 2) == "1 2" );
211 // assert( Formatter( "{} {0} {}", 1, 3) == "1 1 3" );
212 // assert( Formatter( "{} {0} {} {}", 1, 3) == "1 1 3 {invalid index}" );
213 // assert( Formatter( "{} {0} {} {:x}", 1, 3) == "1 1 3 {invalid index}" );
214 assert( Formatter( "{0} {0} {1}", 1, 3) == "1 1 3" );
215 assert( Formatter( "{0} {0} {1} {0}", 1, 3) == "1 1 3 1" );
216
217 assert( Formatter( "{0}", true ) == "true" , Formatter( "{0}", true ));
218 assert( Formatter( "{0}", false ) == "false" );
219
220 assert( Formatter( "{0}", cast(byte)-128 ) == "-128" );
221 assert( Formatter( "{0}", cast(byte)127 ) == "127" );
222 assert( Formatter( "{0}", cast(ubyte)255 ) == "255" );
223
224 assert( Formatter( "{0}", cast(short)-32768 ) == "-32768" );
225 assert( Formatter( "{0}", cast(short)32767 ) == "32767" );
226 assert( Formatter( "{0}", cast(ushort)65535 ) == "65535" );
227 // assert( Formatter( "{0:x4}", cast(ushort)0xafe ) == "0afe" );
228 // assert( Formatter( "{0:X4}", cast(ushort)0xafe ) == "0AFE" );
229
230 assert( Formatter( "{0}", -2147483648 ) == "-2147483648" );
231 assert( Formatter( "{0}", 2147483647 ) == "2147483647" );
232 assert( Formatter( "{0}", 4294967295 ) == "4294967295" );
233
234 // large integers
235 assert( Formatter( "{0}", -9223372036854775807L) == "-9223372036854775807" );
236 assert( Formatter( "{0}", 0x8000_0000_0000_0000L) == "9223372036854775808" );
237 assert( Formatter( "{0}", 9223372036854775807L ) == "9223372036854775807" );
238 assert( Formatter( "{0:X}", 0xFFFF_FFFF_FFFF_FFFF) == "FFFFFFFFFFFFFFFF" );
239 assert( Formatter( "{0:x}", 0xFFFF_FFFF_FFFF_FFFF) == "ffffffffffffffff" );
240 assert( Formatter( "{0:x}", 0xFFFF_1234_FFFF_FFFF) == "ffff1234ffffffff" );
241 // assert( Formatter( "{0:x19}", 0x1234_FFFF_FFFF) == "00000001234ffffffff" );
242 assert( Formatter( "{0}", 18446744073709551615UL ) == "18446744073709551615" );
243 assert( Formatter( "{0}", 18446744073709551615UL ) == "18446744073709551615" );
244
245 // fragments before and after
246 assert( Formatter( "d{0}d", "s" ) == "dsd" );
247 assert( Formatter( "d{0}d", "1234567890" ) == "d1234567890d" );
248
249 // brace escaping
250 assert( Formatter( "d{0}d", "<string>" ) == "d<string>d");
251 assert( Formatter( "d{{0}d", "<string>" ) == "d{0}d");
252 assert( Formatter( "d{{{0}d", "<string>" ) == "d{<string>d");
253 assert( Formatter( "d{0}}d", "<string>" ) == "d<string>}d");
254
255 // hex conversions, where width indicates leading zeroes
256 assert( Formatter( "{0:x}", 0xafe0000 ) == "afe0000" );
257 // assert( Formatter( "{0:x7}", 0xafe0000 ) == "afe0000" );
258 // assert( Formatter( "{0:x8}", 0xafe0000 ) == "0afe0000" );
259 // assert( Formatter( "{0:X8}", 0xafe0000 ) == "0AFE0000" );
260 // assert( Formatter( "{0:X9}", 0xafe0000 ) == "00AFE0000" );
261 // assert( Formatter( "{0:X13}", 0xafe0000 ) == "000000AFE0000" );
262 // assert( Formatter( "{0:x13}", 0xafe0000 ) == "000000afe0000" );
263
264 // decimal width
265 // assert( Formatter( "{0:d6}", 123 ) == "000123" );
266 // assert( Formatter( "{0,7:d6}", 123 ) == " 000123" );
267 // assert( Formatter( "{0,-7:d6}", 123 ) == "000123 " );
268
269 // width & sign combinations
270 // assert( Formatter( "{0:d7}", -123 ) == "-0000123" );
271 // assert( Formatter( "{0,7:d6}", 123 ) == " 000123" );
272 // assert( Formatter( "{0,7:d7}", -123 ) == "-0000123" );
273 // assert( Formatter( "{0,8:d7}", -123 ) == "-0000123" );
274 // assert( Formatter( "{0,5:d7}", -123 ) == "-0000123" );
275
276 // Negative numbers in various bases
277 assert( Formatter( "{:b}", cast(byte) -1 ) == "11111111" );
278 assert( Formatter( "{:b}", cast(short) -1 ) == "1111111111111111" );
279 assert( Formatter( "{:b}", cast(int) -1 )
280 == "11111111111111111111111111111111" );
281 assert( Formatter( "{:b}", cast(long) -1 )
282 == "1111111111111111111111111111111111111111111111111111111111111111" );
283
284 assert( Formatter( "{:o}", cast(byte) -1 ) == "377" );
285 assert( Formatter( "{:o}", cast(short) -1 ) == "177777" );
286 assert( Formatter( "{:o}", cast(int) -1 ) == "37777777777" );
287 assert( Formatter( "{:o}", cast(long) -1 ) == "1777777777777777777777" );
288
289 assert( Formatter( "{:d}", cast(byte) -1 ) == "-1" );
290 assert( Formatter( "{:d}", cast(short) -1 ) == "-1" );
291 assert( Formatter( "{:d}", cast(int) -1 ) == "-1" );
292 assert( Formatter( "{:d}", cast(long) -1 ) == "-1" );
293
294 assert( Formatter( "{:x}", cast(byte) -1 ) == "ff" );
295 assert( Formatter( "{:x}", cast(short) -1 ) == "ffff" );
296 assert( Formatter( "{:x}", cast(int) -1 ) == "ffffffff" );
297 assert( Formatter( "{:x}", cast(long) -1 ) == "ffffffffffffffff" );
298
299 // argument index
300 assert( Formatter( "a{0}b{1}c{2}", "x", "y", "z" ) == "axbycz" );
301 assert( Formatter( "a{2}b{1}c{0}", "x", "y", "z" ) == "azbycx" );
302 assert( Formatter( "a{1}b{1}c{1}", "x", "y", "z" ) == "aybycy" );
303
304 // alignment does not restrict the length
305 // assert( Formatter( "{0,5}", "hellohello" ) == "hellohello" );
306
307 // alignment fills with spaces
308 // assert( Formatter( "->{0,-10}<-", "hello" ) == "->hello <-" );
309 // assert( Formatter( "->{0,10}<-", "hello" ) == "-> hello<-" );
310 // assert( Formatter( "->{0,-10}<-", 12345 ) == "->12345 <-" );
311 // assert( Formatter( "->{0,10}<-", 12345 ) == "-> 12345<-" );
312
313 // chop at maximum specified length; insert ellipses when chopped
314 // assert( Formatter( "->{.5}<-", "hello" ) == "->hello<-" );
315 // assert( Formatter( "->{.4}<-", "hello" ) == "->hell...<-" );
316 // assert( Formatter( "->{.-3}<-", "hello" ) == "->...llo<-" );
317
318 // width specifier indicates number of decimal places
319 assert( Formatter( "{0:f}", 1.23f ) == "1.230000" );
320 // assert( Formatter( "{0:f4}", 1.23456789L ) == "1.2346" );
321 // assert( Formatter( "{0:e4}", 0.0001) == "1.0000e-04");
322
323 assert( Formatter( "{0:f}", 1.23f*1i ) == "1.230000i");
324 // assert( Formatter( "{0:f4}", 1.23456789L*1i ) == "1.2346*1i" );
325 // assert( Formatter( "{0:e4}", 0.0001*1i) == "1.0000e-04*1i");
326
327 assert( Formatter( "{0:f}", 1.23f+1i ) == "1.230000+1.000000i" );
328 // assert( Formatter( "{0:f4}", 1.23456789L+1i ) == "1.2346+1.0000*1i" );
329 // assert( Formatter( "{0:e4}", 0.0001+1i) == "1.0000e-04+1.0000e+00*1i");
330 assert( Formatter( "{0:f}", 1.23f-1i ) == "1.230000+-1.000000i" );
331 // assert( Formatter( "{0:f4}", 1.23456789L-1i ) == "1.2346-1.0000*1i" );
332 // assert( Formatter( "{0:e4}", 0.0001-1i) == "1.0000e-04-1.0000e+00*1i");
333
334 // 'f.' & 'e.' format truncates zeroes from floating decimals
335 // assert( Formatter( "{:f4.}", 1.230 ) == "1.23" );
336 // assert( Formatter( "{:f6.}", 1.230 ) == "1.23" );
337 // assert( Formatter( "{:f1.}", 1.230 ) == "1.2" );
338 // assert( Formatter( "{:f.}", 1.233 ) == "1.23" );
339 // assert( Formatter( "{:f.}", 1.237 ) == "1.24" );
340 // assert( Formatter( "{:f.}", 1.000 ) == "1" );
341 // assert( Formatter( "{:f2.}", 200.001 ) == "200");
342
343 // array output
344 int[] a = [ 51, 52, 53, 54, 55 ];
345 assert( Formatter( "{}", a ) == "[51, 52, 53, 54, 55]" );
346 assert( Formatter( "{:x}", a ) == "[33, 34, 35, 36, 37]" );
347 // assert( Formatter( "{,-4}", a ) == "[51 , 52 , 53 , 54 , 55 ]" );
348 // assert( Formatter( "{,4}", a ) == "[ 51, 52, 53, 54, 55]" );
349 int[][] b = [ [ 51, 52 ], [ 53, 54, 55 ] ];
350 assert( Formatter( "{}", b ) == "[[51, 52], [53, 54, 55]]" );
351
352 char[1024] static_buffer;
353 static_buffer[0..10] = "1234567890";
354
355 assert (Formatter( "{}", static_buffer[0..10]) == "1234567890");
356
357 version(X86)
358 {
359 ushort[3] c = [ cast(ushort)51, 52, 53 ];
360 assert( Formatter( "{}", c ) == "[51, 52, 53]" );
361 }
362
363 /*// integer AA
364 ushort[long] d;
365 d[234] = 2;
366 d[345] = 3;
367
368 assert( Formatter( "{}", d ) == "{234 => 2, 345 => 3}" ||
369 Formatter( "{}", d ) == "{345 => 3, 234 => 2}");
370
371 // bool/string AA
372 bool[char[]] e;
373 e[ "key".dup ] = true;
374 e[ "value".dup ] = false;
375 assert( Formatter( "{}", e ) == "{key => true, value => false}" ||
376 Formatter( "{}", e ) == "{value => false, key => true}");
377
378 // string/double AA
379 char[][ double ] f;
380 f[ 1.0 ] = "one".dup;
381 f[ 3.14 ] = "PI".dup;
382 assert( Formatter( "{}", f ) == "{1.00 => one, 3.14 => PI}" ||
383 Formatter( "{}", f ) == "{3.14 => PI, 1.00 => one}");*/
384 }
385
386 private String doVarArgFormat(TypeInfo[] _arguments, core.vararg.va_list _argptr) {
387 char[] res;
388 void putc(dchar c) {
389 std.utf.encode(res, c);
390 }
391 std.format.doFormat(&putc, _arguments, _argptr);
392 return std.exception.assumeUnique(res);
393 }
394
125 class Format{ 395 class Format{
126 static String opCall( String fmt, ... ){ 396 template UnTypedef(T) {
127 fmt = std.array.replace(fmt, "%", "%%"); 397 static if (is(T U == typedef))
128 fmt = std.array.replace(fmt, "{}", "%s"); 398 alias std.traits.Unqual!(U) UnTypedef;
129 char[] buf; 399 else
130 void putc(dchar c) { 400 alias std.traits.Unqual!(T) UnTypedef;
131 if (c <= 0x7F) { 401 }
132 buf ~= cast(char)c; 402 static String opCall(A...)( String _fmt, A _args ){
133 } else { 403 //Formatting a typedef is deprecated
134 char[4] buf2; 404 std.typetuple.staticMap!(UnTypedef, A) args;
135 buf ~= std.utf.toUTF8(buf2, c); 405 foreach(i, _a; _args)
136 } 406 static if (is(T U == typedef))
137 } 407 args[i] = cast(U) _a;
138 std.format.doFormat(&putc, _arguments, _argptr); 408 else
139 return std.exception.assumeUnique(buf); 409 args[i] = _a;
140 } 410
141 } 411 auto writer = std.array.appender!(String)();
142 } 412 std.format.formattedWrite(writer, fmtFromTangoFmt(_fmt), args);
143 413 auto res = writer.data();
144 version( D_Version2 ){ 414 return std.exception.assumeUnique(res);
145 mixin("immutable(T)[] _idup(T)( T[] str ){ return str.idup; }"); 415 }
416 }
417 }
418
419 version( D_Version2 ) {
420 //dmd v2.052 bug: mixin("alias const(Type) Name;"); will be unvisible outside it's module => we should write alias Const!(Type) Name;
421 template Immutable(T) {
422 mixin("alias immutable(T) Immutable;");
423 }
424 template Const(T) {
425 mixin("alias const(T) Const;");
426 }
427 template Shared(T) {
428 mixin("alias shared(T) Shared;");
429 }
430
431 alias Immutable TryImmutable;
432 alias Const TryConst;
433 alias Shared TryShared;
434
435 //e.g. for passing strings to com.ibm.icu: *.text.* modules assepts String,
436 //but internal *.mangoicu.* modules work with char[] even if they don't modify it
437 std.traits.Unqual!(T)[] Unqual(T)(T[] t) {
438 return cast(std.traits.Unqual!(T)[])t;
439 }
440
441 Immutable!(T)[] _idup(T)( T[] str ){ return str.idup; }
442
443 template prefixedIfD2(String prefix, String content) {
444 const prefixedIfD2 = prefix ~ " " ~ content;
445 }
146 } else { // D1 446 } else { // D1
447 template AliasT(T) { alias T AliasT; }
448
449 alias AliasT TryImmutable;
450 alias AliasT TryConst;
451 alias AliasT TryShared;
452
453 T Unqual(T)(T t) { return t; }
454
147 String16 _idup( String16 str ){ 455 String16 _idup( String16 str ){
148 return str.dup; 456 return str.dup;
149 } 457 }
150 String _idup( String str ){ 458 String _idup( String str ){
151 return str.dup; 459 return str.dup;
152 } 460 }
461
462 template prefixedIfD2(String prefix, String content) {
463 const prefixedIfD2 = content;
464 }
465 }
466
467 template sharedStaticThis(String content) {
468 const sharedStaticThis = prefixedIfD2!("shared", "static this()" ~ content);
469 }
470
471 template gshared(String content) {
472 const gshared = prefixedIfD2!("__gshared:", content);
473 }
474
475 template constFuncs(String content) {
476 const constFuncs = prefixedIfD2!("const:", content);
153 } 477 }
154 478
155 private struct GCStats { 479 private struct GCStats {
156 size_t poolsize; // total size of pool 480 size_t poolsize; // total size of pool
157 size_t usedsize; // bytes allocated 481 size_t usedsize; // bytes allocated
261 res.name = name; 585 res.name = name;
262 return res; 586 return res;
263 } 587 }
264 } 588 }
265 589
266 template getImportData(String name ){ 590 template getImportData(String name) {
267 const ImportData getImportData = ImportData( cast(void[]) import(name), name ); 591 const ImportData getImportData = ImportData( cast(void[]) import(name), name );
268 } 592 }
269
270 template gshared (String content)
271 {
272 version (D_Version2)
273 const gshared = "__gshared: " ~ content;
274
275 else
276 const gshared = content;
277 }