001/*
002 * Copyright 2010-2013 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package jet.runtime;
018
019import jet.Function0;
020
021import java.util.*;
022
023@SuppressWarnings("unused")
024public class Intrinsics {
025    private Intrinsics() {
026    }
027
028    public static String stringPlus(String self, Object other) {
029        return ((self == null) ? "null" : self) + ((other == null) ? "null" : other.toString());
030    }
031
032    public static void throwNpe() {
033        throw new JetNullPointerException();
034    }
035
036    public static void checkReturnedValueIsNotNull(Object value, String className, String methodName) {
037        if (value == null) {
038            IllegalStateException exception =
039                    new IllegalStateException("Method specified as non-null returned null: " + className + "." + methodName);
040            throw sanitizeStackTrace(exception);
041        }
042    }
043
044    public static void checkFieldIsNotNull(Object value, String className, String fieldName) {
045        if (value == null) {
046            IllegalStateException exception =
047                    new IllegalStateException("Field specified as non-null contains null: " + className + "." + fieldName);
048            throw sanitizeStackTrace(exception);
049        }
050    }
051
052    public static void checkParameterIsNotNull(Object value, String paramName) {
053        if (value == null) {
054            StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
055
056            // #0 is Thread.getStackTrace(), #1 is Intrinsics.checkParameterIsNotNull, #2 is our caller
057            StackTraceElement caller = stackTraceElements[2];
058            String className = caller.getClassName();
059            String methodName = caller.getMethodName();
060
061            IllegalArgumentException exception =
062                    new IllegalArgumentException("Parameter specified as non-null contains null: " +
063                                                 "method " + className + "." + methodName +
064                                                 ", parameter " + paramName);
065            throw sanitizeStackTrace(exception);
066        }
067    }
068
069    public static <T> Class<T> getJavaClass(T self) {
070        return (Class<T>) self.getClass();
071    }
072
073    public static int compare(long thisVal, long anotherVal) {
074        return (thisVal<anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1));
075    }
076
077    public static int compare(int thisVal, int anotherVal) {
078        return (thisVal<anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1));
079    }
080
081    public static boolean areEqual(Object first, Object second) {
082        return first == null ? second == null : first.equals(second);
083    }
084
085    public static <R> R stupidSync(Object lock, Function0<R> block) {
086        synchronized (lock) {
087            return block.invoke();
088        }
089    }
090
091    private static final Set<String> METHOD_NAMES_TO_SKIP = new HashSet<String>(Arrays.asList(
092            "throwNpe", "checkReturnedValueIsNotNull", "checkFieldIsNotNull", "checkParameterIsNotNull"
093    ));
094
095    private static <T extends Throwable> T sanitizeStackTrace(T throwable) {
096        StackTraceElement[] stackTrace = throwable.getStackTrace();
097        ArrayList<StackTraceElement> list = new ArrayList<StackTraceElement>();
098        boolean skip = true;
099        for(StackTraceElement ste : stackTrace) {
100            if (!skip) {
101                list.add(ste);
102            }
103            else {
104                if ("jet.runtime.Intrinsics".equals(ste.getClassName())) {
105                    if (METHOD_NAMES_TO_SKIP.contains(ste.getMethodName())) {
106                        skip = false;
107                    }
108                }
109            }
110        }
111        throwable.setStackTrace(list.toArray(new StackTraceElement[list.size()]));
112        return throwable;
113    }
114
115    private static class JetNullPointerException extends NullPointerException {
116        @Override
117        public synchronized Throwable fillInStackTrace() {
118            super.fillInStackTrace();
119            return sanitizeStackTrace(this);
120        }
121    }
122
123    public static class SpreadBuilder extends ArrayList {
124        public void addSpread(Object array) {
125            if (array != null) {
126                if (array instanceof Object[]) {
127                    Object[] arr = (Object[]) array;
128                    if (arr.length > 0) {
129                        ensureCapacity(size() + arr.length);
130                        for (int i = 0; i < arr.length; i++) {
131                            add(arr[i]);
132                        }
133                    }
134                }
135                else if (array instanceof Collection) {
136                    addAll((Collection) array);
137                }
138                else if (array instanceof Iterable) {
139                    for(Iterator iterator = ((Iterable) array).iterator(); iterator.hasNext(); ) {
140                        add(iterator.next());
141                    }
142                }
143                else if (array instanceof Iterator) {
144                    for(Iterator iterator = ((Iterator) array); iterator.hasNext(); ) {
145                        add(iterator.next());
146                    }
147                }
148                else {
149                    throw new UnsupportedOperationException("Don't know how to spread " + array.getClass());
150                }
151            }
152        }
153    }
154}