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    
017    package jet.runtime;
018    
019    import jet.Function0;
020    
021    import java.util.*;
022    
023    @SuppressWarnings("unused")
024    public 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    }