001    package edu.rice.cs.cunit.util;
002    
003    import java.util.Arrays;
004    import java.util.LinkedList;
005    
006    /**
007     * Unary lambda interface R <- P.
008     * @author Mathias Ricken
009     */
010    public interface ILambda<R, P> {
011        /**
012         * Apply the lambda.
013         * @param param lambda-specific parameter
014         * @return lambda-specific return value
015         */
016        public abstract R apply(P param);
017    
018        /**
019         * Binary lambda interface R <- P x Q.
020         */
021        public static interface Binary<R, P, Q> {
022            /**
023             * Apply the lambda.
024             * @param param1 lambda-specific first parameter
025             * @param param2 lambda-specific second parameter
026             * @return lambda-specific return value
027             */
028            public abstract R apply(P param1, Q param2);
029    
030            /**
031             * Unary decorator for a binary lambda that binds a constant to its first parameter.
032             */
033            public static class Bind1st<R, P, Q> implements ILambda<R, Q> {
034                /**
035                 * The constant first argument.
036                 */
037                private P _constant;
038    
039                /**
040                 * The binary lambda that is decorated.
041                 */
042                private ILambda.Binary<R, P, Q> _decoree;
043    
044                /**
045                 * Create a new unary decorator for a binary lambda, binding a constant to its first parameter.
046                 * @param decoree binary lambda
047                 * @param constant constant for the binary lambda's first parameter
048                 */
049                public Bind1st(Binary<R, P, Q> decoree, P constant) {
050                    _constant = constant;
051                    _decoree = decoree;
052                }
053    
054                /**
055                 * Apply the unary decorator, i.e. apply the constant and the parameter to the binary lambda.
056                 * @param param argument for the binary lambda's second parameter
057                 * @return return value of the binary lambda
058                 */
059                public R apply(Q param) {
060                    return _decoree.apply(_constant, param);
061                }
062            }
063    
064            /**
065             * Unary decorator for a binary lambda that binds a constant to its second parameter.
066             */
067            public static class Bind2nd<R, P, Q> implements ILambda<R, P> {
068                /**
069                 * The constant second argument.
070                 */
071                private Q _constant;
072    
073                /**
074                 * The binary lambda that is decorated.
075                 */
076                private ILambda.Binary<R, P, Q> _decoree;
077    
078                /**
079                 * Create a new unary decorator for a binary lambda, binding a constant to its second parameter.
080                 * @param decoree binary lambda
081                 * @param constant constant for the binary lambda's second parameter
082                 */
083                public Bind2nd(Binary<R, P, Q> decoree, Q constant) {
084                    _constant = constant;
085                    _decoree = decoree;
086                }
087    
088                /**
089                 * Apply the unary decorator, i.e. apply the parameter and the constant to the binary lambda.
090                 * @param param argument for the binary lambda's first parameter
091                 * @return return value of the binary lambda
092                 */
093                public R apply(P param) {
094                    return _decoree.apply(param, _constant);
095                }
096            }
097    
098            /**
099             * Adapter to turn an N-ary lambda into a binary lambda.
100             */
101            public static class NaryAdaptor<R, P> implements ILambda.Binary<R, P, P> {
102                /**
103                 * The N-ary lambda.
104                 */
105                private ILambda.Nary<R, P> _decoree;
106    
107                /**
108                 * Creates a new binary lambda.
109                 * @param decoree N-ary lambda
110                 */
111                public NaryAdaptor(ILambda.Nary<R, P> decoree) {
112                    _decoree = decoree;
113                }
114    
115                /**
116                 * Apply the N-ary lambda.
117                 * @param param1 the first parameter.
118                 * @param param2 the second parameter.
119                 * @return return value of the N-ary lambda
120                 */
121                public R apply(P param1, P param2) {
122                    @SuppressWarnings("unchecked") R retval = _decoree.apply(param1, param2);
123                    return retval;
124                }
125            }
126    
127            /**
128             * Binary maximum.
129             */
130            public static class Max<T extends Comparable<T>> implements ILambda.Binary<T, T, T> {
131                public T apply(T param1, T param2) {
132                    return (param1.compareTo(param2) > 0) ? param1 : param2;
133                }
134            }
135    
136            /**
137             * Binary minimum.
138             */
139            public static class Min<T extends Comparable<T>> implements ILambda.Binary<T, T, T> {
140                public T apply(T param1, T param2) {
141                    return (param1.compareTo(param2) < 0) ? param1 : param2;
142                }
143            }
144        }
145    
146        /**
147         * Ternary lambda interface R <- P x Q x S.
148         */
149        public static interface Ternary<R, P, Q, S> {
150            /**
151             * Apply the lambda.
152             * @param param1 lambda-specific first parameter
153             * @param param2 lambda-specific second parameter
154             * @param param3 lambda-specific third parameter
155             * @return lambda-specific return value
156             */
157            public abstract R apply(P param1, Q param2, S param3);
158    
159            /**
160             * Binary decorator for a ternary lambda that binds a constant to its first parameter.
161             */
162            public static class Bind1st<R, P, Q, S> implements ILambda.Binary<R, Q, S> {
163                /**
164                 * The constant first argument.
165                 */
166                private P _constant;
167    
168                /**
169                 * The ternary lambda that is decorated.
170                 */
171                private ILambda.Ternary<R, P, Q, S> _decoree;
172    
173                /**
174                 * Create a new binary decorator for a ternary lambda, binding a constant to its first parameter.
175                 * @param decoree ternary lambda
176                 * @param constant constant for the ternary lambda's first parameter
177                 */
178                public Bind1st(Ternary<R, P, Q, S> decoree, P constant) {
179                    _constant = constant;
180                    _decoree = decoree;
181                }
182    
183                /**
184                 * Apply the binary decorator, i.e. apply the constant and the parameters to the ternary lambda.
185                 * @param param2 argument for the ternary lambda's second parameter
186                 * @param param3 argument for the ternary lambda's third parameter
187                 * @return return value of the binary lambda
188                 */
189                public R apply(Q param2, S param3) {
190                    return _decoree.apply(_constant, param2, param3);
191                }
192            }
193    
194            /**
195             * Binary decorator for a ternary lambda that binds a constant to its second parameter.
196             */
197            public static class Bind2nd<R, P, Q, S> implements ILambda.Binary<R, P, S> {
198                /**
199                 * The constant second argument.
200                 */
201                private Q _constant;
202    
203                /**
204                 * The ternary lambda that is decorated.
205                 */
206                private ILambda.Ternary<R, P, Q, S> _decoree;
207    
208                /**
209                 * Create a new binary decorator for a ternary lambda, binding a constant to its second parameter.
210                 * @param decoree ternary lambda
211                 * @param constant constant for the ternary lambda's second parameter
212                 */
213                public Bind2nd(Ternary<R, P, Q, S> decoree, Q constant) {
214                    _constant = constant;
215                    _decoree = decoree;
216                }
217    
218                /**
219                 * Apply the binary decorator, i.e. apply the constant and the parameters to the ternary lambda.
220                 * @param param1 argument for the ternary lambda's first parameter
221                 * @param param3 argument for the ternary lambda's third parameter
222                 * @return return value of the binary lambda
223                 */
224                public R apply(P param1, S param3) {
225                    return _decoree.apply(param1, _constant, param3);
226                }
227            }
228    
229            /**
230             * Binary decorator for a ternary lambda that binds a constant to its third parameter.
231             */
232            public static class Bind3rd<R, P, Q, S> implements ILambda.Binary<R, P, Q> {
233                /**
234                 * The constant third argument.
235                 */
236                private S _constant;
237    
238                /**
239                 * The ternary lambda that is decorated.
240                 */
241                private ILambda.Ternary<R, P, Q, S> _decoree;
242    
243                /**
244                 * Create a new binary decorator for a ternary lambda, binding a constant to its third parameter.
245                 * @param decoree ternary lambda
246                 * @param constant constant for the ternary lambda's third parameter
247                 */
248                public Bind3rd(Ternary<R, P, Q, S> decoree, S constant) {
249                    _constant = constant;
250                    _decoree = decoree;
251                }
252    
253                /**
254                 * Apply the binary decorator, i.e. apply the constant and the parameters to the ternary lambda.
255                 * @param param1 argument for the ternary lambda's first parameter
256                 * @param param2 argument for the ternary lambda's second parameter
257                 * @return return value of the binary lambda
258                 */
259                public R apply(P param1, Q param2) {
260                    return _decoree.apply(param1, param2, _constant);
261                }
262            }
263    
264            /**
265             * Unary decorator for a ternary lambda that binds constants to its first and second parameters.
266             */
267            public static class Bind1st2nd<R, P, Q, S> extends ILambda.Binary.Bind1st<R, P, S> {
268                /**
269                 * Creates a new unary decorator for a ternary lambda, binding constants to its first and second parameter.
270                 * @param decoree ternary lambda
271                 * @param constant1 constant for the ternary lambda's first parameter
272                 * @param constant2 constant for the ternary lambda's second parameter
273                 */
274                public Bind1st2nd(Ternary<R, P, Q, S> decoree, P constant1, Q constant2) {
275                    super(new Bind2nd<R, P, Q, S>(decoree, constant2), constant1);
276                }
277            }
278    
279            /**
280             * Unary decorator for a ternary lambda that binds constants to its first and third parameters.
281             */
282            public static class Bind1st3rd<R, P, Q, S> extends ILambda.Binary.Bind1st<R, P, Q> {
283                /**
284                 * Creates a new unary decorator for a ternary lambda, binding constants to its first and third parameter.
285                 * @param decoree ternary lambda
286                 * @param constant1 constant for the ternary lambda's first parameter
287                 * @param constant3 constant for the ternary lambda's third parameter
288                 */
289                public Bind1st3rd(Ternary<R, P, Q, S> decoree, P constant1, S constant3) {
290                    super(new Bind3rd<R, P, Q, S>(decoree, constant3), constant1);
291                }
292            }
293    
294            /**
295             * Unary decorator for a ternary lambda that binds constants to its second and third parameters.
296             */
297            public static class Bind2nd3rd<R, P, Q, S> extends ILambda.Binary.Bind2nd<R, P, Q> {
298                /**
299                 * Creates a new unary decorator for a ternary lambda, binding constants to its second and third parameter.
300                 * @param decoree ternary lambda
301                 * @param constant2 constant for the ternary lambda's second parameter
302                 * @param constant3 constant for the ternary lambda's third parameter
303                 */
304                public Bind2nd3rd(Ternary<R, P, Q, S> decoree, Q constant2, S constant3) {
305                    super(new Bind3rd<R, P, Q, S>(decoree, constant3), constant2);
306                }
307            }
308    
309            /**
310             * Adapter to turn an N-ary lambda into a ternary lambda.
311             */
312            public static class NaryAdaptor<R, P> implements ILambda.Ternary<R, P, P, P> {
313                /**
314                 * The N-ary lambda.
315                 */
316                private ILambda.Nary<R, P> _decoree;
317    
318                /**
319                 * Creates a new ternary lambda.
320                 * @param decoree N-ary lambda
321                 */
322                public NaryAdaptor(ILambda.Nary<R, P> decoree) {
323                    _decoree = decoree;
324                }
325    
326                /**
327                 * Apply the N-ary lambda.
328                 * @param param1 the first parameter.
329                 * @param param2 the second parameter.
330                 * @param param3 the third parameter.
331                 * @return return value of the N-ary lambda
332                 */
333                public R apply(P param1, P param2, P param3) {
334                    @SuppressWarnings("unchecked") R retval = _decoree.apply(param1, param2, param3);
335                    return retval;
336                }
337            }
338    
339            /**
340             * Ternary maximum.
341             */
342            public static class Max<T extends Comparable<T>> implements ILambda.Ternary<T, T, T, T> {
343                public T apply(T param1, T param2, T param3) {
344                    T temp12 = (param1.compareTo(param2) > 0) ? param1 : param2;
345                    return (temp12.compareTo(param3) > 0) ? temp12 : param3;
346                }
347            }
348    
349            /**
350             * Ternary minimum.
351             */
352            public static class Min<T extends Comparable<T>> implements ILambda.Ternary<T, T, T, T> {
353                public T apply(T param1, T param2, T param3) {
354                    T temp12 = (param1.compareTo(param2) < 0) ? param1 : param2;
355                    return (temp12.compareTo(param3) < 0) ? temp12 : param3;
356                }
357            }
358        }
359    
360        /**
361         * N-ary lambda interface R <- P x P x ... x P.
362         */
363        public static interface Nary<R, P> {
364            /**
365             * Apply the lambda.
366             * @param param lambda-specific parameters
367             * @return lambda-specific return value
368             */
369            public abstract R apply(P ... param);
370    
371            /**
372             * Adapter to turn a unary lambda into an N-ary lambda (with N=1).
373             */
374            public static class UnaryAdaptor<R, P> implements Nary<R, P> {
375                /**
376                 * The unary lambda.
377                 */
378                private ILambda<R, P> _decoree;
379    
380                /**
381                 * Creates a new N-ary lambda (with N=1).
382                 * @param decoree unary lambda
383                 */
384                public UnaryAdaptor(ILambda<R, P> decoree) {
385                    _decoree = decoree;
386                }
387    
388                /**
389                 * Apply the unary lambda.
390                 * @param param exactly one parameter.
391                 * @return return value of the unary lambda
392                 * @throws IllegalArgumentException if param.length != 1
393                 */
394                public R apply(P... param) {
395                    if (param.length != 1) {
396                        throw new IllegalArgumentException("UnaryAdapter.apply expects exactly one argument.");
397                    }
398                    return _decoree.apply(param[0]);
399                }
400            }
401    
402            /**
403             * Adapter to turn a binary lambda into an N-ary lambda (with N=2).
404             */
405            public static class BinaryAdaptor<R, P> implements Nary<R, P> {
406                /**
407                 * The binary lambda.
408                 */
409                private ILambda.Binary<R, P, P> _decoree;
410    
411                /**
412                 * Creates a new N-ary lambda (with N=2).
413                 * @param decoree binary lambda
414                 */
415                public BinaryAdaptor(ILambda.Binary<R, P, P> decoree) {
416                    _decoree = decoree;
417                }
418    
419                /**
420                 * Apply the binary lambda.
421                 * @param param exactly two parameter.
422                 * @return return value of the binary lambda
423                 * @throws IllegalArgumentException if param.length != 2
424                 */
425                public R apply(P... param) {
426                    if (param.length != 2) {
427                        throw new IllegalArgumentException("BinaryAdapter.apply expects exactly two arguments.");
428                    }
429                    return _decoree.apply(param[0], param[1]);
430                }
431            }
432    
433            /**
434             * Adapter to turn a ternary lambda into an N-ary lambda (with N=3).
435             */
436            public static class TernaryAdaptor<R, P> implements Nary<R, P> {
437                /**
438                 * The ternary lambda.
439                 */
440                private ILambda.Ternary<R, P, P, P> _decoree;
441    
442                /**
443                 * Creates a new N-ary lambda (with N=3).
444                 * @param decoree ternarylambda
445                 */
446                public TernaryAdaptor(ILambda.Ternary<R, P, P, P> decoree) {
447                    _decoree = decoree;
448                }
449    
450                /**
451                 * Apply the ternary lambda.
452                 * @param param exactly three parameter.
453                 * @return return value of the ternary lambda
454                 * @throws IllegalArgumentException if param.length != 3
455                 */
456                public R apply(P... param) {
457                    if (param.length != 3) {
458                        throw new IllegalArgumentException("TernaryAdapter.apply expects exactly three arguments.");
459                    }
460                    return _decoree.apply(param[0], param[1], param[2]);
461                }
462            }
463    
464            /**
465             * (N-1)-ary decorator for an N-ary lambda that binds a constant to one of its parameters.
466             */
467            public static class Bind<R, P> implements Nary<R, P> {
468                /**
469                 * The index of the constant parameter.
470                 */
471                private int _index;
472    
473                /**
474                 * The constant argument.
475                 */
476                private P _constant;
477    
478                /**
479                 * The N-ary lambda.
480                 */
481                private ILambda.Nary<R, P> _decoree;
482    
483                /**
484                 * Creates a new (N-1)-ary decorator for an N-ary lambda, binding a constant to one of its parameters.
485                 * @param decoree N-ary lambda
486                 * @param index index of the constant parameter, 0 <= index < N
487                 * @param constant constant for the specified parameter
488                 */
489                public Bind(Nary<R, P> decoree, int index, P constant) {
490                    _index = index;
491                    _constant = constant;
492                    _decoree = decoree;
493                }
494    
495                /**
496                 * Apply the (N-1)-ary decorator, i.e. apply the N-ary lambda with the constant spliced into the given
497                 * (N-1) arguments.
498                 * @param param (N-1) arguments
499                 * @return return value of the N-ary lambda
500                 */
501                public R apply(P... param) {
502                    LinkedList<P> ps = new LinkedList<P>(Arrays.asList(param));
503                    ps.add(_index, _constant);
504                    return _decoree.apply(ps.toArray(param));
505                }
506            }
507    
508            /**
509             * (N-K)-ary decorator for an N-ary lambda that binds constants to K of its parameters.
510             */
511            public static class BindK<R, P> implements Nary<R, P> {
512                /**
513                 * Array with indices of the constant parameters.
514                 */
515                private int[] _indices;
516    
517                /**
518                 * Array with constant arguments.
519                 */
520                private P[] _constants;
521    
522                /**
523                 * The N-ary lambda.
524                 */
525                private Nary<R, P> _decoree;
526    
527                /**
528                 * Creates a new (N-K)-ary decorator for an N-ary lambda, binding constants to K of its parameters.
529                 * @param decoree N-ary lambda
530                 * @param indices array of K indices in strictly ascending order, each 0 <= index < N
531                 * @param constants K constant arguments
532                 * @throws IllegalArgumentException if indices.length != constants.length
533                 */
534                public BindK(Nary<R, P> decoree, int[] indices, P... constants) {
535                    if (indices.length != constants.length) {
536                        throw new IllegalArgumentException("Indices and constants arrays need to be the same length.");
537                    }
538                    _indices = indices;
539                    _constants = constants;
540                    _decoree = decoree;
541                }
542    
543                /**
544                 * Apply the (N-K)-ary decorator, i.e. apply the N-ary lambda with the K constants spliced into the given
545                 * (N-K) arguments.
546                 * @param param (N-K) arguments
547                 * @return return value of the N-ary lambda
548                 */
549                public R apply(P... param) {
550                    LinkedList<P> ps = new LinkedList<P>(Arrays.asList(param));
551                    for(int i = 0; i < _indices.length; ++i) {
552                        ps.add(_indices[i], _constants[i]);
553                    }
554                    return _decoree.apply(ps.toArray(param));
555                }
556            }
557    
558            /**
559             * N-ary maximum.
560             */
561            public static class Max<T extends Comparable<T>> implements ILambda.Nary<T, T> {
562                public T apply(T ... param) {
563                    if (param.length==0) {
564                        throw new IllegalArgumentException("N-ary Max needs at least one argument.");
565                    }
566                    T accum = param[0];
567                    for (int i=1; i<param.length; ++i) {
568                        if (param[i].compareTo(accum) > 0) { accum = param[i]; }
569                    }
570                    return accum;
571                }
572            }
573    
574            /**
575             * N-ary minimum.
576             */
577            public static class Min<T extends Comparable<T>> implements ILambda.Nary<T, T> {
578                public T apply(T ... param) {
579                    if (param.length==0) {
580                        throw new IllegalArgumentException("N-ary Min needs at least one argument.");
581                    }
582                    T accum = param[0];
583                    for (int i=1; i<param.length; ++i) {
584                        if (param[i].compareTo(accum) < 0) { accum = param[i]; }
585                    }
586                    return accum;
587                }
588            }
589        }
590    
591        /**
592         * Adapter to turn an N-ary lambda into a unary lambda.
593         */
594        public static class NaryAdaptor<R, P> implements ILambda<R, P> {
595            /**
596             * The N-ary lambda.
597             */
598            private ILambda.Nary<R, P> _decoree;
599    
600            /**
601             * Creates a new unary lambda.
602             * @param decoree N-ary lambda
603             */
604            public NaryAdaptor(ILambda.Nary<R, P> decoree) {
605                _decoree = decoree;
606            }
607    
608            /**
609             * Apply the N-ary lambda.
610             * @param param the parameter.
611             * @return return value of the N-ary lambda
612             */
613            public R apply(P param) {
614                @SuppressWarnings("unchecked") R retval = _decoree.apply(param);
615                return retval;
616            }
617        }
618    }