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 }