source: release-kits/wirk3/ant-scripts/tasks/antelope/src/ise/antelope/tasks/Math.java_@ 15023

Last change on this file since 15023 was 15023, checked in by oranfry, 16 years ago

did the bulk of the work on wirk3

File size: 21.8 KB
Line 
1/*
2* The Apache Software License, Version 1.1
3*
4* Copyright (c) 2001-2002 The Apache Software Foundation. All rights
5* reserved.
6*
7* Redistribution and use in source and binary forms, with or without
8* modification, are permitted provided that the following conditions
9* are met:
10*
11* 1. Redistributions of source code must retain the above copyright
12* notice, this list of conditions and the following disclaimer.
13*
14* 2. Redistributions in binary form must reproduce the above copyright
15* notice, this list of conditions and the following disclaimer in
16* the documentation and/or other materials provided with the
17* distribution.
18*
19* 3. The end-user documentation included with the redistribution, if
20* any, must include the following acknowlegement:
21* "This product includes software developed by the
22* Apache Software Foundation (http://www.apache.org/)."
23* Alternately, this acknowlegement may appear in the software itself,
24* if and wherever such third-party acknowlegements normally appear.
25*
26* 4. The names "The Jakarta Project", "Ant", and "Apache Software
27* Foundation" must not be used to endorse or promote products derived
28* from this software without prior written permission. For written
29* permission, please contact [email protected].
30*
31* 5. Products derived from this software may not be called "Apache"
32* nor may "Apache" appear in their names without prior written
33* permission of the Apache Group.
34*
35* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46* SUCH DAMAGE.
47* ====================================================================
48*
49* This software consists of voluntary contributions made by many
50* individuals on behalf of the Apache Software Foundation. For more
51* information on the Apache Software Foundation, please see
52* <http://www.apache.org/>.
53*/
54package ise.antelope.tasks;
55
56import java.lang.reflect.Method;
57import java.lang.reflect.Array;
58import java.util.Vector;
59import java.util.Enumeration;
60
61/**
62 * Provides access to java.lang.Math and java.lang.StrictMath for Ant. Provides
63 * add, subtract, multiply, divide and mod methods as well as access to all methods
64 * java.lang.Math and java.lang.StrictMath via reflection.
65 * @author Dale Anson, [email protected]
66 */
67public class Math {
68
69 private boolean strict = false;
70
71 public Math() {}
72
73 public Math( boolean strict ) {
74 this.strict = strict;
75 }
76
77 public void setStrict( boolean strict ) {
78 this.strict = strict;
79 }
80
81 public boolean isStrict() {
82 return strict;
83 }
84
85 public static double add( double a, double b ) {
86 return a + b;
87 }
88 public static float add( float a, float b ) {
89 return a + b;
90 }
91 public static long add( long a, long b ) {
92 return a + b;
93 }
94 public static int add( int a, int b ) {
95 return a + b;
96 }
97 public static double add( double[] a ) {
98 if ( a.length == 0 )
99 throw new IllegalArgumentException();
100 if ( a.length == 1 )
101 return a[ 0 ];
102 double b = a[ 0 ];
103 for ( int i = 1; i < a.length; i++ )
104 b += a[ i ];
105 return b;
106 }
107 public static float add( float[] a ) {
108 if ( a.length == 0 )
109 throw new IllegalArgumentException();
110 if ( a.length == 1 )
111 return a[ 0 ];
112 float b = a[ 0 ];
113 for ( int i = 1; i < a.length; i++ )
114 b += a[ i ];
115 return b;
116 }
117 public static long add( long[] a ) {
118 if ( a.length == 0 )
119 throw new IllegalArgumentException();
120 if ( a.length == 1 )
121 return a[ 0 ];
122 long b = a[ 0 ];
123 for ( int i = 1; i < a.length; i++ )
124 b += a[ i ];
125 return b;
126 }
127 public static int add( int[] a ) {
128 if ( a.length == 0 )
129 throw new IllegalArgumentException();
130 if ( a.length == 1 )
131 return a[ 0 ];
132 int b = a[ 0 ];
133 for ( int i = 1; i < a.length; i++ )
134 b += a[ i ];
135 return b;
136 }
137
138 public static double subtract( double a, double b ) {
139 return a - b;
140 }
141 public static float subtract( float a, float b ) {
142 return a - b;
143 }
144 public static long subtract( long a, long b ) {
145 return a - b;
146 }
147 public static int subtract( int a, int b ) {
148 return a - b;
149 }
150 public static double subtract( double[] a ) {
151 if ( a.length == 0 )
152 throw new IllegalArgumentException();
153 if ( a.length == 1 )
154 return a[ 0 ];
155 double b = a[ 0 ];
156 for ( int i = 1; i < a.length; i++ )
157 b -= a[ i ];
158 return b;
159 }
160 public static float subtract( float[] a ) {
161 if ( a.length == 0 )
162 throw new IllegalArgumentException();
163 if ( a.length == 1 )
164 return a[ 0 ];
165 float b = a[ 0 ];
166 for ( int i = 1; i < a.length; i++ )
167 b -= a[ i ];
168 return b;
169 }
170 public static long subtract( long[] a ) {
171 if ( a.length == 0 )
172 throw new IllegalArgumentException();
173 if ( a.length == 1 )
174 return a[ 0 ];
175 long b = a[ 0 ];
176 for ( int i = 1; i < a.length; i++ )
177 b -= a[ i ];
178 return b;
179 }
180 public static int subtract( int[] a ) {
181 if ( a.length == 0 )
182 throw new IllegalArgumentException();
183 if ( a.length == 1 )
184 return a[ 0 ];
185 int b = a[ 0 ];
186 for ( int i = 1; i < a.length; i++ )
187 b -= a[ i ];
188 return b;
189 }
190
191 public static double multiply( double a, double b ) {
192 return a * b;
193 }
194 public static float multiply( float a, float b ) {
195 return a * b;
196 }
197 public static long multiply( long a, long b ) {
198 return a * b;
199 }
200 public static int multiply( int a, int b ) {
201 return a * b;
202 }
203 public static double multiply( double[] a ) {
204 if ( a.length == 0 )
205 throw new IllegalArgumentException();
206 if ( a.length == 1 )
207 return a[ 0 ];
208 double b = a[ 0 ];
209 for ( int i = 1; i < a.length; i++ )
210 b *= a[ i ];
211 return b;
212 }
213 public static float multiply( float[] a ) {
214 if ( a.length == 0 )
215 throw new IllegalArgumentException();
216 if ( a.length == 1 )
217 return a[ 0 ];
218 float b = a[ 0 ];
219 for ( int i = 1; i < a.length; i++ )
220 b *= a[ i ];
221 return b;
222 }
223 public static long multiply( long[] a ) {
224 if ( a.length == 0 )
225 throw new IllegalArgumentException();
226 if ( a.length == 1 )
227 return a[ 0 ];
228 long b = a[ 0 ];
229 for ( int i = 1; i < a.length; i++ )
230 b *= a[ i ];
231 return b;
232 }
233 public static int multiply( int[] a ) {
234 if ( a.length == 0 )
235 throw new IllegalArgumentException();
236 if ( a.length == 1 )
237 return a[ 0 ];
238 int b = a[ 0 ];
239 for ( int i = 1; i < a.length; i++ )
240 b *= a[ i ];
241 return b;
242 }
243
244 public static double divide( double a, double b ) {
245 return a / b;
246 }
247 public static float divide( float a, float b ) {
248 return a / b;
249 }
250 public static long divide( long a, long b ) {
251 return a / b;
252 }
253 public static int divide( int a, int b ) {
254 return a / b;
255 }
256 public static double divide( double[] a ) {
257 if ( a.length == 0 )
258 throw new IllegalArgumentException();
259 if ( a.length == 1 )
260 return a[ 0 ];
261 double b = a[ 0 ];
262 for ( int i = 1; i < a.length; i++ )
263 b /= a[ i ];
264 return b;
265 }
266 public static float divide( float[] a ) {
267 if ( a.length == 0 )
268 throw new IllegalArgumentException();
269 if ( a.length == 1 )
270 return a[ 0 ];
271 float b = a[ 0 ];
272 for ( int i = 1; i < a.length; i++ )
273 b /= a[ i ];
274 return b;
275 }
276 public static long divide( long[] a ) {
277 if ( a.length == 0 )
278 throw new IllegalArgumentException();
279 if ( a.length == 1 )
280 return a[ 0 ];
281 long b = a[ 0 ];
282 for ( int i = 1; i < a.length; i++ )
283 b /= a[ i ];
284 return b;
285 }
286 public static int divide( int[] a ) {
287 if ( a.length == 0 )
288 throw new IllegalArgumentException();
289 if ( a.length == 1 )
290 return a[ 0 ];
291 int b = a[ 0 ];
292 for ( int i = 1; i < a.length; i++ )
293 b /= a[ i ];
294 return b;
295 }
296
297 public static double mod( double a, double b ) {
298 return a % b;
299 }
300 public static float mod( float a, float b ) {
301 return a % b;
302 }
303 public static long mod( long a, long b ) {
304 return a % b;
305 }
306 public static int mod( int a, int b ) {
307 return a % b;
308 }
309 public static double mod( double[] a ) {
310 if ( a.length == 0 )
311 throw new IllegalArgumentException();
312 if ( a.length == 1 )
313 return a[ 0 ];
314 double b = a[ 0 ];
315 for ( int i = 1; i < a.length; i++ )
316 b %= a[ i ];
317 return b;
318 }
319 public static float mod( float[] a ) {
320 if ( a.length == 0 )
321 throw new IllegalArgumentException();
322 if ( a.length == 1 )
323 return a[ 0 ];
324 float b = a[ 0 ];
325 for ( int i = 1; i < a.length; i++ )
326 b %= a[ i ];
327 return b;
328 }
329 public static long mod( long[] a ) {
330 if ( a.length == 0 )
331 throw new IllegalArgumentException();
332 if ( a.length == 1 )
333 return a[ 0 ];
334 long b = a[ 0 ];
335 for ( int i = 1; i < a.length; i++ )
336 b %= a[ i ];
337 return b;
338 }
339 public static int mod( int[] a ) {
340 if ( a.length == 0 )
341 throw new IllegalArgumentException();
342 if ( a.length == 1 )
343 return a[ 0 ];
344 int b = a[ 0 ];
345 for ( int i = 1; i < a.length; i++ )
346 b %= a[ i ];
347 return b;
348 }
349
350 /**
351 * Do a mathematical calculation. The allowed operations are all
352 * operations supported by java.lang.Math and this class. Assumes data
353 * type is "double".
354 * @param op the name of a mathematical operation to perform
355 * @param the operands for the operation, these strings must parse to numbers.
356 */
357 public Number calculate( String op, String[] operands ) {
358 return calculate( op, "double", operands );
359 }
360
361 /**
362 * Do a mathematical calculation. The allowed operations are all
363 * operations supported by java.lang.Math.
364 * @param op the name of a mathematical operation to perform
365 * @param type the data type of the operands
366 * @param the operands for the operation
367 */
368 public Number calculate( String op, String type, String[] operands ) {
369 try {
370 if ( operands.length > 2 ) {
371 if ( op.equals( "add" ) ||
372 op.equals( "subtract" ) ||
373 op.equals( "multiply" ) ||
374 op.equals( "divide" ) ||
375 op.equals( "mod" ) ) {
376 return calculateArray( op, type, operands );
377 }
378 else
379 throw new IllegalArgumentException( "too many operands" );
380 }
381
382 Class c;
383 if ( strict )
384 c = Class.forName( "java.lang.StrictMath" );
385 else
386 c = Class.forName( "java.lang.Math" );
387
388 // check if op is 'random'. Random is a special case in that it is
389 // the only method in Math that takes no parameters.
390 if ( op.equals( "random" ) ) {
391 Method m = c.getDeclaredMethod( op, new Class[] {} );
392 Object result = m.invoke( c, null );
393 return ( Number ) result;
394 }
395
396 // find candidate methods for the requested operation
397 Vector candidates = new Vector();
398 Method[] methods = c.getDeclaredMethods();
399 for ( int i = 0; i < methods.length; i++ ) {
400 String name = methods[ i ].getName();
401 if ( name.equals( op ) ) {
402 candidates.addElement( methods[ i ] );
403 }
404 }
405
406 if ( candidates.size() == 0 ) {
407 // try the other Math
408 //c = Class.forName( "ise.antelope.tasks.Math" );
409 c = this.getClass();
410 methods = c.getDeclaredMethods();
411 for ( int i = 0; i < methods.length; i++ ) {
412 String name = methods[ i ].getName();
413 if ( name.equals( op ) ) {
414 candidates.addElement( methods[ i ] );
415 }
416 }
417 }
418
419 if ( candidates.size() == 0 )
420 throw new RuntimeException( "Unknown operation: " + op );
421
422 // get the desired data type for the operation, default is
423 // Double.TYPE if no other match is found
424 Class wantTypeClass = getDataType( type );
425
426 // get the parameter count for the candidate methods -- in Math,
427 // all like named methods have the same number of parameters, just
428 // the data types are different. (Fix for bug # 724812 -- the above
429 // statement is true of java.lang.Math, but not of this class.)
430 //int paramCount = ( ( Method ) candidates.elementAt( 0 ) ).getParameterTypes().length;
431 int paramCount = -1;
432 try {
433 for (int i = 0; i <= candidates.size(); i++) {
434 Method candidate = (Method)candidates.elementAt(i);
435 paramCount = candidate.getParameterTypes().length;
436 if (paramCount == operands.length)
437 break;
438 }
439 }
440 catch(Exception e) {
441 throw new RuntimeException("Wrong number of arguments, have " +
442 operands.length + ", but can't find corresponding method.");
443 }
444
445 // make sure there are enough arguments to pass to the method
446 // see bug fix above, this is no longer necessary
447 //if ( operands.length != paramCount )
448 // throw new RuntimeException( "Wrong number of arguments, have " +
449 // operands.length + ", expected " + paramCount );
450
451 // determine the actual type class for the method to invoke.
452 // Some methods have only one implementation so determine the
453 // typeClass from the method itself, not the desired.
454 Class typeClass = null;
455 if ( candidates.size() == 1 ) {
456 Method m = ( Method ) candidates.elementAt( 0 );
457 typeClass = m.getParameterTypes() [ 0 ];
458 }
459 else {
460 // check each candidate to find one with the desired type
461 Enumeration en = candidates.elements();
462 while ( en.hasMoreElements() ) {
463 Method m = ( Method ) en.nextElement();
464 if ( m.getParameterTypes() [ 0 ].equals( wantTypeClass ) ) {
465 typeClass = wantTypeClass;
466 break;
467 }
468 }
469 if ( typeClass == null )
470 throw new RuntimeException( "Can't find a method with parameters of type " + type );
471 }
472
473 // get the method to invoke
474 Class[] paramTypes = new Class[ paramCount ];
475 for ( int i = 0; i < paramCount; i++ ) {
476 paramTypes[ i ] = typeClass;
477 }
478 Method m = c.getDeclaredMethod( op, paramTypes );
479
480 // load the parameters and invoke the method
481 Object[] params = getParams( typeClass, operands );
482 Object result = m.invoke( c, params );
483
484 return ( Number ) result;
485
486 }
487 catch ( Exception e ) {
488 e.printStackTrace();
489 }
490 return null;
491 }
492
493 /**
494 * Performs a calculation on an array of numbers. The mathematical methods
495 * in this class will accept an array of numbers, so
496 * <code>add(new int[]{1, 2, 3})</code>
497 * is equivalent to
498 * <code>add(add(1, 2), 3)</code>
499 * which is equivalent to 1 + 2 + 3.
500 * @param op the operation to perform
501 * @type the data type of the operands. All operands will be cast to the same
502 * data type
503 * @param operands these strings must parse to numbers.
504 */
505 private Number calculateArray( String op, String type, String[] operands ) {
506 try {
507 Class c = this.getClass();
508
509 // find candidate methods for the requested operation
510 Vector candidates = new Vector();
511 Method[] methods = c.getDeclaredMethods();
512 for ( int i = 0; i < methods.length; i++ ) {
513 String name = methods[ i ].getName();
514 if ( name.equals( op ) ) {
515 if ( methods[ i ].getParameterTypes().length == 1 ) {
516 if ( methods[ i ].getParameterTypes() [ 0 ].isArray() )
517 candidates.addElement( methods[ i ] );
518 }
519 }
520 }
521 if ( candidates.size() == 0 )
522 throw new RuntimeException( "Unknown operation: " + op );
523
524 // get the desired data type for the operation, default is
525 // Double.TYPE if no other match is found
526 Object wantTypeClass = getDataTypeArray( type, operands.length );
527
528 // find the actual method to invoke and invoke it immediately once
529 // it is found
530 Class typeClass = null;
531 Enumeration en = candidates.elements();
532 while ( en.hasMoreElements() ) {
533 Method m = ( Method ) en.nextElement();
534 if ( m.getParameterTypes() [ 0 ].equals( wantTypeClass.getClass() ) ) {
535 typeClass = getDataType( type );
536 Object[] params = getParamsArray( typeClass, operands );
537 Object result = m.invoke( c, params );
538 return ( Number ) result;
539 }
540 }
541 }
542 catch ( Exception e ) {
543 e.printStackTrace();
544 }
545 return null;
546 }
547
548 /**
549 * Converts a string representing a data type into the actual type.
550 * @param type one of "int", "long", "float", or "double"
551 * @return one of Integer.TYPE, Long.TYPE, Float.TYPE, or Double.TYPE. If the
552 * given type is null or not one of the allowed types, Double.TYPE will be
553 * returned.
554 */
555 private Class getDataType( String type ) {
556 if ( type == null )
557 return Double.TYPE;
558 if ( type.equals( "int" ) ) {
559 return Integer.TYPE;
560 }
561 else if ( type.equals( "long" ) ) {
562 return Long.TYPE;
563 }
564 else if ( type.equals( "float" ) ) {
565 return Float.TYPE;
566 }
567 else {
568 return Double.TYPE;
569 }
570 }
571
572 /**
573 * Converts a string representing a data type into an Array.
574 * @param type one of "int", "long", "float", or "double"
575 * @param length how long to make the array
576 * @return an Array representing the data type
577 */
578 private Object getDataTypeArray( String type, int length ) {
579 if ( type == null )
580 return Array.newInstance( Double.TYPE, length );
581 if ( type.equals( "int" ) ) {
582 return Array.newInstance( Integer.TYPE, length );
583 }
584 else if ( type.equals( "long" ) ) {
585 return Array.newInstance( Long.TYPE, length );
586 }
587 else if ( type.equals( "float" ) ) {
588 return Array.newInstance( Float.TYPE, length );
589 }
590 else {
591 return Array.newInstance( Double.TYPE, length );
592 }
593 }
594
595 /**
596 * @returns the given operands as an array of the given type.
597 */
598 private Object[] getParams( Class typeClass, String[] operands ) {
599 int paramCount = operands.length;
600 Object[] params = new Object[ paramCount ];
601 if ( typeClass == Double.TYPE ) {
602 for ( int i = 0; i < paramCount; i++ ) {
603 params[ i ] = new Double( operands[ i ] );
604 }
605 }
606 else if ( typeClass == Long.TYPE ) {
607 for ( int i = 0; i < paramCount; i++ ) {
608 params[ i ] = new Long( operands[ i ] );
609 }
610 }
611 else if ( typeClass == Float.TYPE ) {
612 for ( int i = 0; i < paramCount; i++ ) {
613 params[ i ] = new Float( operands[ i ] );
614 }
615 }
616 else {
617 // Integer.TYPE is only other choice
618 for ( int i = 0; i < paramCount; i++ ) {
619 params[ i ] = new Integer( operands[ i ] );
620 }
621 }
622 if ( paramCount > 2 )
623 params = new Object[] {params};
624 return params;
625 }
626
627 /**
628 * Converts the given operands into an array of the given type.
629 */
630 private Object[] getParamsArray( Class typeClass, String[] operands ) {
631 int paramCount = operands.length;
632 if ( typeClass == Double.TYPE ) {
633 double[] array = ( double[] ) Array.newInstance( typeClass, operands.length );
634 for ( int i = 0; i < paramCount; i++ ) {
635 Array.setDouble( array, i, new Double( operands[ i ] ).doubleValue() );
636 }
637 return new Object[] {array};
638 }
639 else if ( typeClass == Long.TYPE ) {
640 long[] array = ( long[] ) Array.newInstance( typeClass, operands.length );
641 for ( int i = 0; i < paramCount; i++ ) {
642 Array.setLong( array, i, new Long( operands[ i ] ).longValue() );
643 }
644 return new Object[] {array};
645 }
646 else if ( typeClass == Float.TYPE ) {
647 float[] array = ( float[] ) Array.newInstance( typeClass, operands.length );
648 for ( int i = 0; i < paramCount; i++ ) {
649 Array.setFloat( array, i, new Float( operands[ i ] ).floatValue() );
650 }
651 return new Object[] {array};
652 }
653 else {
654 // Integer.TYPE is only other choice
655 Object array = Array.newInstance( typeClass, operands.length );
656 for ( int i = 0; i < paramCount; i++ ) {
657 Array.setInt( array, i, new Integer( operands[ i ] ).intValue() );
658 }
659 return new Object[] {array};
660 }
661 }
662
663 public static void main ( String[] args ) {
664 Math math = new Math();
665 System.out.println( math.calculate( "add", new String[] {"6", "5", "4"} ) );
666 }
667}
Note: See TracBrowser for help on using the repository browser.