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 }