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