1 module java.lang.util;
2 
3 public import java.lang.wrappers;
4 public import java.lang.String;
5 public import java.lang.interfaces;
6 
7 version(Tango){
8     static import tango.text.convert.Format;
9     static import tango.core.Exception;
10     static import tango.util.log.Log;
11     static import tango.util.log.Config;
12     static import tango.stdc.stdlib;
13 
14     alias tango.stdc.stdlib.exit exit;
15 } else { // Phobos
16     static import core.exception;
17     static import core.stdc.stdlib;
18     static import std.stdio;
19     static import std.ascii;
20     static import std.array;
21     static import std.conv;
22     static import std.format;
23     static import std.typetuple;
24     static import std.traits;
25     static import std.exception;
26     static import std..string;
27     static import std.utf;
28     alias core.stdc.stdlib.exit exit;
29 }
30 
31 version(Tango){
32     interface IDwtLogger {
33         void trace( String file, ulong line, String fmt, ... );
34         void info( String file, ulong line, String fmt, ... );
35         void warn( String file, ulong line, String fmt, ... );
36         void error( String file, ulong line, String fmt, ... );
37         void fatal( String file, ulong line, String fmt, ... );
38     }
39 
40     class DwtLogger : IDwtLogger {
41         tango.util.log.Log.Logger logger;
42         private this( char[] name ){
43             logger = tango.util.log.Log.Log.lookup( name );
44         }
45         private char[] format( String file, ulong line, String fmt, TypeInfo[] types, void* argptr ){
46             auto msg = Format.convert( types, argptr, fmt );
47             auto text = Format( "{} {}: {}", file, line, msg );
48             return text;
49         }
50         void trace( String file, ulong line, String fmt, ... ){
51             if( logger.trace ){
52                 logger.trace( format( file, line, fmt, _arguments, _argptr ));
53             }
54         }
55         void info( String file, ulong line, String fmt, ... ){
56             if( logger.info ){
57                 logger.info( format( file, line, fmt, _arguments, _argptr ));
58             }
59         }
60         void warn( String file, ulong line, String fmt, ... ){
61             if( logger.warn ){
62                 logger.warn( format( file, line, fmt, _arguments, _argptr ));
63             }
64         }
65         void error( String file, ulong line, String fmt, ... ){
66             if( logger.error ){
67                 logger.error( format( file, line, fmt, _arguments, _argptr ));
68             }
69         }
70         void fatal( String file, ulong line, String fmt, ... ){
71             if( logger.fatal ){
72                 logger.fatal( format( file, line, fmt, _arguments, _argptr ));
73             }
74         }
75     }
76 } else { // Phobos
77     class IDwtLogger {
78         private this( String name ) {
79         }
80         void trace(T...)( String file, ulong line, String fmt, T args ){
81             fmt = fmtFromTangoFmt(fmt);
82             std.stdio.writefln( "TRC %s %s: %s", file, line, std..string.format(fmt, args) );
83         }
84         void info(T...)( String file, ulong line, String fmt, T args ){
85             fmt = fmtFromTangoFmt(fmt);
86             std.stdio.writefln( "INF %s %s: %s", file, line, std..string.format(fmt, args) );
87         }
88         void warn(T...)( String file, ulong line, String fmt, T args ){
89             fmt = fmtFromTangoFmt(fmt);
90             std.stdio.writefln( "WRN %s %s: %s", file, line, std..string.format(fmt, args) );
91         }
92         void error(T...)( String file, ulong line, String fmt, T args ){
93             fmt = fmtFromTangoFmt(fmt);
94             std.stdio.writefln( "ERR %s %s: %s", file, line, std..string.format(fmt, args) );
95         }
96         void fatal(T...)( String file, ulong line, String fmt, T args ){
97             fmt = fmtFromTangoFmt(fmt);
98             std.stdio.writefln( "FAT %s %s: %s", file, line, std..string.format(fmt, args) );
99         }
100     }
101 
102     alias IDwtLogger DwtLogger;
103 }
104 
105 private IDwtLogger dwtLoggerInstance;
106 
107 IDwtLogger getDwtLogger(){
108     if( dwtLoggerInstance is null ){
109         synchronized{
110             if( dwtLoggerInstance is null ){
111                 dwtLoggerInstance = new DwtLogger( "dwt" );
112             }
113         }
114     }
115     return dwtLoggerInstance;
116 }
117 
118 void implMissing( String file, uint line ){
119     getDwtLogger().fatal( file, line, "implementation missing in file {} line {}", file, line );
120     getDwtLogger().fatal( file, line, "Please create a bug report at http://www.dsource.org/projects/dwt" );
121     throw new core.exception.AssertError("Implementation missing", file, line);
122 }
123 
124 void implMissingInTango(T = void)( String file, uint line ) {
125     version(Tango) {} else static assert(0, "For Tango implMissings only");
126     getDwtLogger().fatal( file, line, "implementation missing in Tango version" );
127     implMissing( file, line );
128 }
129 
130 void implMissingInPhobos( String file = __FILE__, uint line = __LINE__ )() {
131     version(Tango) static assert(0, "For Phobos implMissings only");
132     getDwtLogger().fatal( file, line, "implementation missing in Phobos version" );
133     implMissing( file, line );
134 }
135 
136 version(Tango){
137     alias implMissing implMissingSafe;
138 } else { // Phobos
139     mixin(`@safe nothrow
140     void implMissingSafe( String file, uint line ) {
141         // impossible processing
142     }`);
143 }
144 
145 version(Tango){
146     public alias tango.text.convert.Format.Format Format;
147 } else { // Phobos
148 	private string fmtFromTangoFmt(string tangoFmt) {
149 		auto app = std.array.appender!(string)();
150 		app.reserve(tangoFmt.length);
151 	L:	for(int i = 0; i < tangoFmt.length; ++i) {
152 			char c = tangoFmt[i];
153 			if(c == '%')
154 				app.put("%%");
155 			else if(c == '{') {
156                 if(i + 1 < tangoFmt.length && tangoFmt[i + 1] == '{') {
157                     app.put('{');
158                     ++i;
159                 } else {
160                     int j = i;
161                     do {
162                         ++j;
163                         if(j == tangoFmt.length) {
164                             app.put("{malformed format}");
165                             break L;
166                         }
167                     } while(tangoFmt[j] != '}');
168                     string f = tangoFmt[i + 1 .. j];
169                     i = j;
170                     if(f.length) {
171                         string fres = "%";
172                         try {
173                             if(std.ascii.isDigit(f[0])) {
174                                 int n = std.conv.parse!(int)(f);
175                                 fres ~= std.conv.to!(string)(n + 1) ~ '$';
176                             }
177                             if(f.length) {
178                                 std.exception.enforce(f[0] == ':' && f.length > 1);
179                                 c = f[1];
180                                 if(f.length == 2 && "bodxXeEfFgG".indexOf(c) != -1)
181                                     fres ~= c;
182                                 else
183                                     fres = null;
184                             } else
185                                 fres ~= 's';
186                         } catch (Exception) {
187                             fres = "{malformed format}";
188                         }
189                         if(fres)
190                             app.put(fres);
191                         else
192                             implMissingInPhobos();
193                     } else
194                         app.put("%s");
195                 }
196 			} else
197 				app.put(c);
198 		}
199         return app.data();
200 	}
201 
202     unittest
203     {
204         alias Format Formatter;
205 
206         // basic layout tests
207         assert( Formatter( "abc" ) == "abc" );
208         assert( Formatter( "{0}", 1 ) == "1" );
209         assert( Formatter( "{0}", -1 ) == "-1" );
210 
211         assert( Formatter( "{}", 1 ) == "1" );
212         assert( Formatter( "{} {}", 1, 2) == "1 2" );
213         // assert( Formatter( "{} {0} {}", 1, 3) == "1 1 3" );
214         // assert( Formatter( "{} {0} {} {}", 1, 3) == "1 1 3 {invalid index}" );
215         // assert( Formatter( "{} {0} {} {:x}", 1, 3) == "1 1 3 {invalid index}" );
216         assert( Formatter( "{0} {0} {1}", 1, 3) == "1 1 3" );
217         assert( Formatter( "{0} {0} {1} {0}", 1, 3) == "1 1 3 1" );
218 
219         assert( Formatter( "{0}", true ) == "true" , Formatter( "{0}", true ));
220         assert( Formatter( "{0}", false ) == "false" );
221 
222         assert( Formatter( "{0}", cast(byte)-128 ) == "-128" );
223         assert( Formatter( "{0}", cast(byte)127 ) == "127" );
224         assert( Formatter( "{0}", cast(ubyte)255 ) == "255" );
225 
226         assert( Formatter( "{0}", cast(short)-32768  ) == "-32768" );
227         assert( Formatter( "{0}", cast(short)32767 ) == "32767" );
228         assert( Formatter( "{0}", cast(ushort)65535 ) == "65535" );
229         // assert( Formatter( "{0:x4}", cast(ushort)0xafe ) == "0afe" );
230         // assert( Formatter( "{0:X4}", cast(ushort)0xafe ) == "0AFE" );
231 
232         assert( Formatter( "{0}", -2147483648 ) == "-2147483648" );
233         assert( Formatter( "{0}", 2147483647 ) == "2147483647" );
234         assert( Formatter( "{0}", 4294967295 ) == "4294967295" );
235 
236         // large integers
237         assert( Formatter( "{0}", -9223372036854775807L) == "-9223372036854775807" );
238         assert( Formatter( "{0}", 0x8000_0000_0000_0000L) == "9223372036854775808" );
239         assert( Formatter( "{0}", 9223372036854775807L ) == "9223372036854775807" );
240         assert( Formatter( "{0:X}", 0xFFFF_FFFF_FFFF_FFFF) == "FFFFFFFFFFFFFFFF" );
241         assert( Formatter( "{0:x}", 0xFFFF_FFFF_FFFF_FFFF) == "ffffffffffffffff" );
242         assert( Formatter( "{0:x}", 0xFFFF_1234_FFFF_FFFF) == "ffff1234ffffffff" );
243         // assert( Formatter( "{0:x19}", 0x1234_FFFF_FFFF) == "00000001234ffffffff" );
244         assert( Formatter( "{0}", 18446744073709551615UL ) == "18446744073709551615" );
245         assert( Formatter( "{0}", 18446744073709551615UL ) == "18446744073709551615" );
246 
247         // fragments before and after
248         assert( Formatter( "d{0}d", "s" ) == "dsd" );
249         assert( Formatter( "d{0}d", "1234567890" ) == "d1234567890d" );
250 
251         // brace escaping
252         assert( Formatter( "d{0}d", "<string>" ) == "d<string>d");
253         assert( Formatter( "d{{0}d", "<string>" ) == "d{0}d");
254         assert( Formatter( "d{{{0}d", "<string>" ) == "d{<string>d");
255         assert( Formatter( "d{0}}d", "<string>" ) == "d<string>}d");
256 
257         // hex conversions, where width indicates leading zeroes
258         assert( Formatter( "{0:x}", 0xafe0000 ) == "afe0000" );
259         // assert( Formatter( "{0:x7}", 0xafe0000 ) == "afe0000" );
260         // assert( Formatter( "{0:x8}", 0xafe0000 ) == "0afe0000" );
261         // assert( Formatter( "{0:X8}", 0xafe0000 ) == "0AFE0000" );
262         // assert( Formatter( "{0:X9}", 0xafe0000 ) == "00AFE0000" );
263         // assert( Formatter( "{0:X13}", 0xafe0000 ) == "000000AFE0000" );
264         // assert( Formatter( "{0:x13}", 0xafe0000 ) == "000000afe0000" );
265 
266         // decimal width
267         // assert( Formatter( "{0:d6}", 123 ) == "000123" );
268         // assert( Formatter( "{0,7:d6}", 123 ) == " 000123" );
269         // assert( Formatter( "{0,-7:d6}", 123 ) == "000123 " );
270 
271         // width & sign combinations
272         // assert( Formatter( "{0:d7}", -123 ) == "-0000123" );
273         // assert( Formatter( "{0,7:d6}", 123 ) == " 000123" );
274         // assert( Formatter( "{0,7:d7}", -123 ) == "-0000123" );
275         // assert( Formatter( "{0,8:d7}", -123 ) == "-0000123" );
276         // assert( Formatter( "{0,5:d7}", -123 ) == "-0000123" );
277 
278         // Negative numbers in various bases
279         assert( Formatter( "{:b}", cast(byte) -1 ) == "11111111" );
280         assert( Formatter( "{:b}", cast(short) -1 ) == "1111111111111111" );
281         assert( Formatter( "{:b}", cast(int) -1 )
282                 == "11111111111111111111111111111111" );
283         assert( Formatter( "{:b}", cast(long) -1 )
284                 == "1111111111111111111111111111111111111111111111111111111111111111" );
285 
286         assert( Formatter( "{:o}", cast(byte) -1 ) == "377" );
287         assert( Formatter( "{:o}", cast(short) -1 ) == "177777" );
288         assert( Formatter( "{:o}", cast(int) -1 ) == "37777777777" );
289         assert( Formatter( "{:o}", cast(long) -1 ) == "1777777777777777777777" );
290 
291         assert( Formatter( "{:d}", cast(byte) -1 ) == "-1" );
292         assert( Formatter( "{:d}", cast(short) -1 ) == "-1" );
293         assert( Formatter( "{:d}", cast(int) -1 ) == "-1" );
294         assert( Formatter( "{:d}", cast(long) -1 ) == "-1" );
295 
296         assert( Formatter( "{:x}", cast(byte) -1 ) == "ff" );
297         assert( Formatter( "{:x}", cast(short) -1 ) == "ffff" );
298         assert( Formatter( "{:x}", cast(int) -1 ) == "ffffffff" );
299         assert( Formatter( "{:x}", cast(long) -1 ) == "ffffffffffffffff" );
300 
301         // argument index
302         assert( Formatter( "a{0}b{1}c{2}", "x", "y", "z" ) == "axbycz" );
303         assert( Formatter( "a{2}b{1}c{0}", "x", "y", "z" ) == "azbycx" );
304         assert( Formatter( "a{1}b{1}c{1}", "x", "y", "z" ) == "aybycy" );
305 
306         // alignment does not restrict the length
307         // assert( Formatter( "{0,5}", "hellohello" ) == "hellohello" );
308 
309         // alignment fills with spaces
310         // assert( Formatter( "->{0,-10}<-", "hello" ) == "->hello     <-" );
311         // assert( Formatter( "->{0,10}<-", "hello" ) == "->     hello<-" );
312         // assert( Formatter( "->{0,-10}<-", 12345 ) == "->12345     <-" );
313         // assert( Formatter( "->{0,10}<-", 12345 ) == "->     12345<-" );
314 
315         // chop at maximum specified length; insert ellipses when chopped
316         // assert( Formatter( "->{.5}<-", "hello" ) == "->hello<-" );
317         // assert( Formatter( "->{.4}<-", "hello" ) == "->hell...<-" );
318         // assert( Formatter( "->{.-3}<-", "hello" ) == "->...llo<-" );
319 
320         // width specifier indicates number of decimal places
321         assert( Formatter( "{0:f}", 1.23f ) == "1.230000" );
322         // assert( Formatter( "{0:f4}", 1.23456789L ) == "1.2346" );
323         // assert( Formatter( "{0:e4}", 0.0001) == "1.0000e-04");
324 
325         assert( Formatter( "{0:f}", 1.23f*1i ) == "1.230000i");
326         // assert( Formatter( "{0:f4}", 1.23456789L*1i ) == "1.2346*1i" );
327         // assert( Formatter( "{0:e4}", 0.0001*1i) == "1.0000e-04*1i");
328 
329         assert( Formatter( "{0:f}", 1.23f+1i ) == "1.230000+1.000000i" );
330         // assert( Formatter( "{0:f4}", 1.23456789L+1i ) == "1.2346+1.0000*1i" );
331         // assert( Formatter( "{0:e4}", 0.0001+1i) == "1.0000e-04+1.0000e+00*1i");
332         assert( Formatter( "{0:f}", 1.23f-1i ) == "1.230000+-1.000000i" );
333         // assert( Formatter( "{0:f4}", 1.23456789L-1i ) == "1.2346-1.0000*1i" );
334         // assert( Formatter( "{0:e4}", 0.0001-1i) == "1.0000e-04-1.0000e+00*1i");
335 
336         // 'f.' & 'e.' format truncates zeroes from floating decimals
337         // assert( Formatter( "{:f4.}", 1.230 ) == "1.23" );
338         // assert( Formatter( "{:f6.}", 1.230 ) == "1.23" );
339         // assert( Formatter( "{:f1.}", 1.230 ) == "1.2" );
340         // assert( Formatter( "{:f.}", 1.233 ) == "1.23" );
341         // assert( Formatter( "{:f.}", 1.237 ) == "1.24" );
342         // assert( Formatter( "{:f.}", 1.000 ) == "1" );
343         // assert( Formatter( "{:f2.}", 200.001 ) == "200");
344 
345         // array output
346         int[] a = [ 51, 52, 53, 54, 55 ];
347         assert( Formatter( "{}", a ) == "[51, 52, 53, 54, 55]" );
348         assert( Formatter( "{:x}", a ) == "[33, 34, 35, 36, 37]" );
349         // assert( Formatter( "{,-4}", a ) == "[51  , 52  , 53  , 54  , 55  ]" );
350         // assert( Formatter( "{,4}", a ) == "[  51,   52,   53,   54,   55]" );
351         int[][] b = [ [ 51, 52 ], [ 53, 54, 55 ] ];
352         assert( Formatter( "{}", b ) == "[[51, 52], [53, 54, 55]]" );
353 
354         char[1024] static_buffer;
355         static_buffer[0..10] = "1234567890";
356 
357         assert (Formatter( "{}", static_buffer[0..10]) == "1234567890");
358 
359         version(X86)
360         {
361             ushort[3] c = [ cast(ushort)51, 52, 53 ];
362             assert( Formatter( "{}", c ) == "[51, 52, 53]" );
363         }
364 
365         /*// integer AA
366         ushort[long] d;
367         d[234] = 2;
368         d[345] = 3;
369 
370         assert( Formatter( "{}", d ) == "{234 => 2, 345 => 3}" ||
371                 Formatter( "{}", d ) == "{345 => 3, 234 => 2}");
372 
373         // bool/string AA
374         bool[char[]] e;
375         e[ "key".dup ] = true;
376         e[ "value".dup ] = false;
377         assert( Formatter( "{}", e ) == "{key => true, value => false}" ||
378                 Formatter( "{}", e ) == "{value => false, key => true}");
379 
380         // string/double AA
381         char[][ double ] f;
382         f[ 1.0 ] = "one".dup;
383         f[ 3.14 ] = "PI".dup;
384         assert( Formatter( "{}", f ) == "{1.00 => one, 3.14 => PI}" ||
385                 Formatter( "{}", f ) == "{3.14 => PI, 1.00 => one}");*/
386     }
387 
388     class Format{
389         template UnTypedef(T) {
390             version(Tango){
391                 mixin(r"static if (is(T U == typedef))
392                     alias std.traits.Unqual!(U) UnTypedef;
393                 else
394                     alias std.traits.Unqual!(T) UnTypedef;");
395             } else { // Phobos
396                 alias std.traits.Unqual!(T) UnTypedef;
397             }
398         }
399         static String opCall(A...)( String _fmt, A _args ){
400             //Formatting a typedef is deprecated
401             std.typetuple.staticMap!(UnTypedef, A) args;
402             foreach(i, _a; _args) {
403                 version(Tango){
404                     mixin(r"static if (is(T U == typedef))
405                         args[i] = cast(U) _a;
406                     else
407                         args[i] = _a;");
408                 } else { // Phobos
409                     args[i] = _a;
410                 }
411             }
412 
413 			auto writer = std.array.appender!(String)();
414             std.format.formattedWrite(writer, fmtFromTangoFmt(_fmt), args);
415             auto res = writer.data();
416             return std.exception.assumeUnique(res);
417         }
418     }
419 }
420 
421 version( D_Version2 ) {
422     //dmd v2.052 bug: mixin("alias const(Type) Name;"); will be unvisible outside it's module => we should write alias Const!(Type) Name;
423     template Immutable(T) {
424         mixin("alias immutable(T) Immutable;");
425     }
426     template Const(T) {
427         mixin("alias const(T) Const;");
428     }
429     template Shared(T) {
430         mixin("alias shared(T) Shared;");
431     }
432 
433     alias Immutable TryImmutable;
434     alias Const TryConst;
435     alias Shared TryShared;
436 
437     //e.g. for passing strings to com.ibm.icu: *.text.* modules assepts String,
438     //but internal *.mangoicu.* modules work with char[] even if they don't modify it
439     std.traits.Unqual!(T)[] Unqual(T)(T[] t) {
440         return cast(std.traits.Unqual!(T)[])t;
441     }
442 
443     Immutable!(T)[] _idup(T)( T[] str ){ return str.idup; }
444 
445     template prefixedIfD2(String prefix, String content) {
446         const prefixedIfD2 = prefix ~ " " ~ content;
447     }
448 } else { // D1
449     template AliasT(T) { alias T AliasT; }
450 
451     alias AliasT TryImmutable;
452     alias AliasT TryConst;
453     alias AliasT TryShared;
454 
455     T Unqual(T)(T t) { return t; }
456 
457     String16 _idup( String16 str ){
458         return str.dup;
459     }
460     String _idup( String str ){
461         return str.dup;
462     }
463 
464     template prefixedIfD2(String prefix, String content) {
465         const prefixedIfD2 = content;
466     }
467 }
468 
469 template sharedStaticThis(String content) {
470     const sharedStaticThis = prefixedIfD2!("shared", "static this()" ~ content);
471 }
472 
473 template sharedStatic_This(String content) {
474     const sharedStatic_This = prefixedIfD2!("shared", "private static void static_this()" ~ content);
475 }
476 
477 template gshared(String content) {
478     const gshared = prefixedIfD2!("__gshared:", content);
479 }
480 
481 template constFuncs(String content) {
482     const constFuncs = prefixedIfD2!("const:", content);
483 }
484 
485 private struct GCStats {
486     size_t poolsize;        // total size of pool
487     size_t usedsize;        // bytes allocated
488     size_t freeblocks;      // number of blocks marked FREE
489     size_t freelistsize;    // total of memory on free lists
490     size_t pageblocks;      // number of blocks marked PAGE
491 }
492 private extern(C) GCStats gc_stats();
493 
494 size_t RuntimeTotalMemory(){
495     GCStats s = gc_stats();
496     return s.poolsize;
497 }
498 
499 
500 template arraycast(T) {
501     T[] arraycast(U) (U[] u) {
502         static if (
503             (is (T == interface ) && is (U == interface )) ||
504             (is (T == class ) && is (U == class ))) {
505             return(cast(T[])u);
506         }
507         else {
508             int l = u.length;
509             T[] res;
510             res.length = l;
511             for (int i = 0; i < l; i++) {
512                 res[i] = cast(T)u[i];
513             }
514             return(res);
515         }
516     }
517 }
518 
519 
520 bool ArrayEquals(T)( T[] a, T[] b ){
521     if( a.length !is b.length ){
522         return false;
523     }
524     for( int i = 0; i < a.length; i++ ){
525         static if( is( T==class) || is(T==interface)){
526             if( a[i] !is null && b[i] !is null ){
527                 if( a[i] != b[i] ){
528                     return false;
529                 }
530             }
531             else if( a[i] is null && b[i] is null ){
532             }
533             else{
534                 return false;
535             }
536         }
537         else{
538             if( a[i] != b[i] ){
539                 return false;
540             }
541         }
542     }
543     return true;
544 }
545 
546 int arrayIndexOf(T)( T[] arr, T v ){
547     int res = -1;
548     int idx = 0;
549 
550 
551     static if (is(T == interface))
552     {
553         Object[] array = cast(Object[]) arr;
554         Object value = cast(Object) v;
555     }
556 
557     else
558     {
559         auto array = arr;
560         auto value = v;
561     }
562 
563     foreach( p; array ){
564         if( p == value){
565             res = idx;
566             break;
567         }
568         idx++;
569     }
570     return res;
571 }
572 
573 T[] arrayIndexRemove(T)(T[] arr, uint n) {
574     if (n is 0)
575         return arr[1..$];
576     if (n > arr.length)
577         return arr;
578     if (n is arr.length-1)
579         return arr[0..n-1];
580     // else
581     return arr[0..n] ~ arr[n+1..$];
582 }
583 
584 struct ImportData{
585     TryImmutable!(void)[] data;
586     String name;
587 
588     //empty () is just a hack to force opCall to be included in full in the .di file
589     public static ImportData opCall()( TryImmutable!(void)[] data, String name ){
590         ImportData res;
591         res.data = data;
592         res.name = name;
593         return res;
594     }
595 }
596 
597 template getImportData(String name) {
598     const ImportData getImportData = ImportData( cast(TryImmutable!(void)[]) import(name), name );
599 }