root/dwt/dwthelper/utils.d

Revision 325:0c891bed575f, 33.0 kB (checked in by Frank Benoit <benoit@tionex.de>, 5 days ago)

Remove debug prints

Line 
1 /**
2  * Authors: Frank Benoit <keinfarbton@googlemail.com>
3  */
4 module dwt.dwthelper.utils;
5
6 public import dwt.dwthelper.System;
7 public import dwt.dwthelper.Runnable;
8 public import Math = tango.math.Math;
9
10 public import tango.core.Exception : IllegalArgumentException, IOException;
11
12 import tango.io.Stdout;
13 import tango.io.Print;
14 static import tango.stdc.stringz;
15 static import tango.text.Util;
16 static import tango.text.Text;
17 static import tango.text.Ascii;
18 import tango.text.Unicode;
19 import tango.text.convert.Utf;
20 import tango.core.Exception;
21 import tango.stdc.stdlib : exit;
22
23 import tango.util.log.Trace;
24 import tango.text.UnicodeData;
25
26 alias char[] String;
27 alias tango.text.Text.Text!(char) StringBuffer;
28
29 alias ArrayBoundsException ArrayIndexOutOfBoundsException;
30
31 void implMissing( String file, uint line ){
32     Stderr.formatln( "implementation missing in file {} line {}", file, line );
33     Stderr.formatln( "exiting ..." );
34     exit(1);
35 }
36
37 abstract class ArrayWrapper{
38 }
39 abstract class ValueWrapper{
40 }
41
42 class ArrayWrapperT(T) : ArrayWrapper {
43     public T[] array;
44     public this( T[] data ){
45         array = data;
46     }
47     public override int opEquals( Object o ){
48         if( auto other = cast(ArrayWrapperT!(T))o){
49             return array == other.array;
50         }
51         return false;
52     }
53     public override hash_t toHash(){
54         return (typeid(T[])).getHash(&array);
55     }
56 }
57
58 class ValueWrapperT(T) : ValueWrapper {
59     public T value;
60     public this( T data ){
61         value = data;
62     }
63     static if( is(T==class) || is(T==interface)){
64         public int opEquals( Object other ){
65             if( auto o = cast(ValueWrapperT!(T))other ){
66                 return value == o.value;
67             }
68             if( auto o = cast(T)other ){
69                 if( value is o ){
70                     return true;
71                 }
72                 if( value is null || o is null ){
73                     return false;
74                 }
75                 return value == o;
76             }
77             return false;
78         }
79     }
80     else{
81         public int opEquals( Object other ){
82             if( auto o = cast(ValueWrapperT!(T))other ){
83                 return value == o.value;
84             }
85             return false;
86         }
87         public int opEquals( T other ){
88             return value == other;
89         }
90     }
91     public override hash_t toHash(){
92         return (typeid(T)).getHash(&value);
93     }
94 }
95
96 class Boolean : ValueWrapperT!(bool) {
97     public static Boolean TRUE;
98     public static Boolean FALSE;
99
100     static this(){
101         TRUE  = new Boolean(true);
102         FALSE = new Boolean(false);
103     }
104     public this( bool v ){
105         super(v);
106     }
107
108     alias ValueWrapperT!(bool).opEquals opEquals;
109     public int opEquals( int other ){
110         return value == ( other !is 0 );
111     }
112     public int opEquals( Object other ){
113         if( auto o = cast(Boolean)other ){
114             return value == o.value;
115         }
116         return false;
117     }
118     public bool booleanValue(){
119         return value;
120     }
121     public static Boolean valueOf( String s ){
122         if( s == "yes" || s == "true" ){
123             return TRUE;
124         }
125         return FALSE;
126     }
127     public static Boolean valueOf( bool b ){
128         return b ? TRUE : FALSE;
129     }
130     public static bool getBoolean(String name){
131         return tango.text.Ascii.icompare(System.getProperty(name, "false"), "true" ) is 0;
132     }
133 }
134
135 alias Boolean    ValueWrapperBool;
136
137
138 class Byte : ValueWrapperT!(byte) {
139     public static byte parseByte( String s ){
140         try{
141             int res = tango.text.convert.Integer.parse( s );
142             if( res < byte.min || res > byte.max ){
143                 throw new NumberFormatException( "out of range" );
144             }
145             return res;
146         }
147         catch( IllegalArgumentException e ){
148             throw new NumberFormatException( e );
149         }
150     }
151     this( byte value ){
152         super( value );
153     }
154
155     public static String toString( byte i ){
156         return tango.text.convert.Integer.toString(i);
157     }
158
159 }
160 alias Byte ValueWrapperByte;
161
162
163 class Integer : ValueWrapperT!(int) {
164
165     public static const int MIN_VALUE = 0x80000000;
166     public static const int MAX_VALUE = 0x7fffffff;
167     public static const int SIZE = 32;
168
169     public this ( int value ){
170         super( value );
171     }
172
173     public this ( String s ){
174         super(parseInt(s));
175     }
176
177     public static String toString( int i, int radix ){
178         switch( radix ){
179         case 2:
180             return toBinaryString(i);
181         case 8:
182             return toOctalString(i);
183         case 10:
184             return toString(i);
185         case 16:
186             return toHexString(i);
187         default:
188             implMissing( __FILE__, __LINE__ );
189             return null;
190         }
191     }
192
193     public static String toHexString( int i ){
194         return tango.text.convert.Integer.toString(i, "x" );
195     }
196
197     public static String toOctalString( int i ){
198         return tango.text.convert.Integer.toString(i, "o" );
199     }
200
201     public static String toBinaryString( int i ){
202         return tango.text.convert.Integer.toString(i, "b" );
203     }
204
205     public static String toString( int i ){
206         return tango.text.convert.Integer.toString(i);
207     }
208
209     public static int parseInt( String s, int radix ){
210         try{
211             return tango.text.convert.Integer.toLong( s, radix );
212         }
213         catch( IllegalArgumentException e ){
214             throw new NumberFormatException( e );
215         }
216     }
217
218     public static int parseInt( String s ){
219         try{
220             return tango.text.convert.Integer.toLong( s );
221         }
222         catch( IllegalArgumentException e ){
223             throw new NumberFormatException( e );
224         }
225     }
226
227     public static Integer valueOf( String s, int radix ){
228         implMissing( __FILE__, __LINE__ );
229         return null;
230     }
231
232     public static Integer valueOf( String s ){
233         return valueOf( parseInt(s));
234     }
235
236     public static Integer valueOf( int i ){
237         return new Integer(i);
238     }
239
240     public byte byteValue(){
241         return cast(byte)value;
242     }
243
244     public short shortValue(){
245         return cast(short)value;
246     }
247
248     public int intValue(){
249         return value;
250     }
251
252     public long longValue(){
253         return cast(long)value;
254     }
255
256     public float floatValue(){
257         return cast(float)value;
258     }
259
260     public double doubleValue(){
261         return cast(double)value;
262     }
263
264     public override  hash_t toHash(){
265         return intValue();
266     }
267
268     public override String toString(){
269         return tango.text.convert.Integer.toString( value );
270     }
271 }
272 alias Integer ValueWrapperInt;
273
274 class Double : ValueWrapperT!(double) {
275     public static double MAX_VALUE = double.max;
276     public static double MIN_VALUE = double.min;
277     this( double value ){
278         super(value);
279     }
280     this( String str ){
281         implMissing( __FILE__, __LINE__ );
282         super(0.0);
283     }
284     public double doubleValue(){
285         return value;
286     }
287     public static String toString( double value ){
288         implMissing( __FILE__, __LINE__ );
289         return null;
290     }
291     public static double parseDouble(String s){
292         implMissing( __FILE__, __LINE__ );
293         return 0.0;
294     }
295 }
296
297 class Float : ValueWrapperT!(float) {
298
299     public static float POSITIVE_INFINITY = (1.0f / 0.0f);
300     public static float NEGATIVE_INFINITY = ((-1.0f) / 0.0f);
301     public static float NaN = (0.0f / 0.0f);
302     public static float MAX_VALUE = 3.4028235e+38f;
303     public static float MIN_VALUE = 1.4e-45f;
304     public static int SIZE = 32;
305
306     this( float value ){
307         super(value);
308     }
309     this( String str ){
310         implMissing( __FILE__, __LINE__ );
311         super(0.0);
312     }
313     public float floatValue(){
314         return value;
315     }
316     public static String toString( float value ){
317         implMissing( __FILE__, __LINE__ );
318         return null;
319     }
320     public static float parseFloat( String s ){
321         try{
322             return tango.text.convert.Float.toFloat( s );
323         }
324         catch( IllegalArgumentException e ){
325             throw new NumberFormatException( e );
326         }
327     }
328
329 }
330 class Long : ValueWrapperT!(long) {
331     public static const long MIN_VALUE = long.min;
332     public static const long MAX_VALUE = long.max;
333     this( long value ){
334         super(value);
335     }
336     this( String str ){
337         implMissing( __FILE__, __LINE__ );
338         super(0);
339     }
340     public long longValue(){
341         return value;
342     }
343     public static long parseLong(String s){
344         implMissing( __FILE__, __LINE__ );
345         return 0;
346     }
347     public static String toString( double value ){
348         implMissing( __FILE__, __LINE__ );
349         return null;
350     }
351 }
352 alias Long ValueWrapperLong;
353
354
355 // alias ValueWrapperT!(int)     ValueWrapperInt;
356
357 alias ArrayWrapperT!(byte)    ArrayWrapperByte;
358 alias ArrayWrapperT!(int)     ArrayWrapperInt;
359 alias ArrayWrapperT!(Object)  ArrayWrapperObject;
360 alias ArrayWrapperT!(char)    ArrayWrapperString;
361 alias ArrayWrapperT!(String)  ArrayWrapperString2;
362
363 Object[] StringArrayToObjectArray( String[] strs ){
364     Object[] res = new Object[strs.length];
365     foreach( idx, str; strs ){
366         res[idx] = new ArrayWrapperString(str);
367     }
368     return res;
369 }
370 int codepointIndexToIndex( String str, int cpIndex ){
371     int cps = cpIndex;
372     int res = 0;
373     while( cps > 0 ){
374         cps--;
375         if( str[res] < 0x80 ){
376             res+=1;
377         }
378         else if( str[res] < 0xE0 ){
379             res+=2;
380         }
381         else if( str[res] & 0xF0 ){
382             res+=3;
383         }
384         else{
385             res+=4;
386         }
387     }
388     return res;
389 }
390
391 /++
392  +
393  +/
394 int indexToCodepointIndex( String str, int index ){
395     if( index < 0 ) return index;
396     int i = 0;
397     int res = 0;
398     while( i < index ){
399         if( i >= str.length ){
400             break;
401         }
402         if( str[i] < 0x80 ){
403             i+=1;
404         }
405         else if( str[i] < 0xE0 ){
406             i+=2;
407         }
408         else if( str[i] & 0xF0 ){
409             i+=3;
410         }
411         else{
412             i+=4;
413         }
414         res++;
415     }
416     return res;
417 }
418
419 /++
420  + Get that String, that contains the next codepoint of a String.
421  +/
422 String firstCodePointStr( String str, out int consumed ){
423     dchar[1] buf;
424     uint ate;
425     dchar[] res = str.toString32( buf, &ate );
426     consumed = ate;
427     return str[ 0 .. ate ];
428 }
429
430 /++
431  + Get first codepoint of a String. If an offset is needed, simply use a slice:
432  + ---
433  + dchar res = str[ offset .. $ ].firstCodePoint();
434  + ---
435  +/
436 dchar firstCodePoint( String str ){
437     int dummy;
438     return firstCodePoint( str, dummy );
439 }
440 dchar firstCodePoint( String str, out int consumed ){
441     dchar[1] buf;
442     uint ate;
443     dchar[] res = str.toString32( buf, &ate );
444     consumed = ate;
445     if( ate is 0 || res.length is 0 ){
446         Trace.formatln( "dwthelper.utils {}: str.length={} str={:X2}", __LINE__, str.length, cast(ubyte[])str );
447     }
448     assert( ate > 0 );
449     assert( res.length is 1 );
450     return res[0];
451 }
452 dchar firstCodePoint( wchar[] str, out int consumed ){
453     dchar[1] buf;
454     uint ate;
455     dchar[] res = str.toString32( buf, &ate );
456     consumed = ate;
457     if( ate is 0 || res.length is 0 ){
458         Trace.formatln( "dwthelper.utils {}: str.length={} str={:X2}", __LINE__, str.length, cast(ubyte[])str );
459     }
460     assert( ate > 0 );
461     assert( res.length is 1 );
462     return res[0];
463 }
464
465 String dcharToString( dchar key ){
466     dchar[1] buf;
467     buf[0] = key;
468     return tango.text.convert.Utf.toString( buf );
469 }
470
471 int codepointCount( String str ){
472     scope dchar[] buf = new dchar[]( str.length );
473     uint ate;
474     dchar[] res = tango.text.convert.Utf.toString32( str, buf, &ate );
475     assert( ate is str.length );
476     return res.length;
477 }
478
479 alias tango.text.convert.Utf.toString16 toString16;
480 alias tango.text.convert.Utf.toString toString;
481
482 int toAbsoluteCodePointStartOffset( String str, int index ){
483     //Trace.formatln( "str={}, str.length={}, index={}", str, str.length, index );
484     //Trace.memory( str );
485     if( ( str[index] & 0x80 ) is 0x00 )
486     {
487         return index;
488     }
489     else{
490         int steps = 0;
491         while(( str[index] & 0xC0 ) is 0x80 ){
492             index--;
493             steps++;
494             if( steps > 3 || index < 0 ){
495                 break;
496             }
497         }
498         if((( str[index] & 0xE0 ) is 0xC0) && ( steps <= 1 )){
499             // ok
500         }
501         else if((( str[index] & 0xF0 ) is 0xE0) && ( steps <= 2 )){
502             // ok
503         }
504         else if((( str[index] & 0xF8 ) is 0xF0) && ( steps <= 3 )){
505             // ok
506         }
507         else{
508             tango.text.convert.Utf.onUnicodeError( "invalid utf8 input to toAbsoluteCodePointStartOffset" );
509         }
510         return index;
511     }
512 }
513 int getRelativeCodePointOffset( String str, int startIndex, int searchRelCp ){
514     return getAbsoluteCodePointOffset( str, startIndex, searchRelCp ) - startIndex;
515 }
516 int getAbsoluteCodePointOffset( String str, int startIndex, int searchRelCp ){
517
518     //Trace.formatln( "str={}, str.length={}, startIndex={}, searchRelCp={}", str, str.length, startIndex, searchRelCp );
519     //Trace.memory( str );
520
521     int ignore;
522     int i = startIndex;
523     if( searchRelCp > 0 ){
524         while( searchRelCp !is 0 ){
525
526             if( ( i < str.length )
527             && (( str[i] & 0x80 ) is 0x00 ))
528             {
529                 i+=1;
530             }
531             else if( ( i+1 < str.length )
532                 && (( str[i+1] & 0xC0 ) is 0x80 )
533                 && (( str[i  ] & 0xE0 ) is 0xC0 ))
534             {
535                 i+=2;
536             }
537             else if( ( i+2 < str.length )
538                 && (( str[i+2] & 0xC0 ) is 0x80 )
539                 && (( str[i+1] & 0xC0 ) is 0x80 )
540                 && (( str[i  ] & 0xF0 ) is 0xE0 ))
541             {
542                 i+=3;
543             }
544             else if(( i+3 < str.length )
545                 && (( str[i+3] & 0xC0 ) is 0x80 )
546                 && (( str[i+2] & 0xC0 ) is 0x80 )
547                 && (( str[i+1] & 0xC0 ) is 0x80 )
548                 && (( str[i  ] & 0xF8 ) is 0xF0 ))
549             {
550                 i+=4;
551             }
552             else{
553                 Trace.formatln( "getAbsoluteCodePointOffset invalid utf8 characters:  {:X2}", cast(ubyte[]) str );
554                 tango.text.convert.Utf.onUnicodeError( "invalid utf8 input", i );
555             }
556             searchRelCp--;
557         }
558     }
559     else if( searchRelCp < 0 ){
560         while( searchRelCp !is 0 ){
561             do{
562                 i--;
563                 if( i < 0 ){
564                     return startIndex-1;
565                 }
566             } while(( str[i] & 0xC0 ) is 0x80 );
567             searchRelCp++;
568         }
569     }
570     return i;
571 }
572 int getAbsoluteCodePointOffset( wchar[] str, int startIndex, int searchRelCp ){
573     int ignore;
574     int i = startIndex;
575     if( searchRelCp > 0 ){
576         while( searchRelCp !is 0 ){
577
578             if( ( i < str.length )
579                 && ( str[i] & 0xD800 ) !is 0xD800 )
580             {
581                 i+=1;
582             }
583             else if( ( i+1 < str.length )
584                 && (( str[i+1] & 0xDC00 ) is 0xDC00 )
585                 && (( str[i  ] & 0xDC00 ) is 0xD800 ))
586             {
587                 i+=2;
588             }
589             else{
590                 Trace.formatln( "invalid utf16 characters:  {:X2}", cast(ubyte[]) str );
591                 tango.text.convert.Utf.onUnicodeError( "invalid utf16 input", i );
592             }
593             searchRelCp--;
594 &nbs