/* * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.openapi.util; import com.intellij.reference.SoftReference; import com.intellij.util.Function; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; /** * @author max */ @SuppressWarnings("unchecked") public class Conditions { private Conditions() { } public final static Condition<Object> TRUE = Condition.TRUE; public final static Condition<Object> FALSE = Condition.FALSE; public static <T> Condition<T> alwaysTrue() { return (Condition<T>)TRUE; } public static <T> Condition<T> alwaysFalse() { return (Condition<T>)FALSE; } public static <T> Condition<T> notNull() { return (Condition<T>)Condition.NOT_NULL; } public static <T> Condition<T> constant(boolean value) { return (Condition<T>)(value ? TRUE : FALSE); } public static <T> Condition<T> instanceOf(final Class<?> clazz) { return new Condition<T>() { public boolean value(T t) { return clazz.isInstance(t); } }; } public static <T> Condition<T> notInstanceOf(final Class<?> clazz) { return new Condition<T>() { public boolean value(T t) { return !clazz.isInstance(t); } }; } public static Condition<Class> assignableTo(final Class clazz) { return new Condition<Class>() { public boolean value(Class t) { return clazz.isAssignableFrom(t); } }; } public static <T> Condition<T> instanceOf(final Class<?>... clazz) { return new Condition<T>() { public boolean value(T t) { for (Class<?> aClass : clazz) { if (aClass.isInstance(t)) return true; } return false; } }; } public static <T> Condition<T> is(final T option) { return equalTo(option); } public static <T> Condition<T> equalTo(final Object option) { return new Condition<T>() { public boolean value(T t) { return Comparing.equal(t, option); } }; } public static <T> Condition<T> notEqualTo(final Object option) { return new Condition<T>() { public boolean value(T t) { return !Comparing.equal(t, option); } }; } public static <T> Condition<T> oneOf(T... options) { return oneOf(Arrays.asList(options)); } public static <T> Condition<T> oneOf(final Collection<? extends T> options) { return new Condition<T>() { public boolean value(T t) { return options.contains(t); } }; } public static <T> Condition<T> not(Condition<T> c) { if (c == TRUE) return alwaysFalse(); if (c == FALSE) return alwaysTrue(); if (c instanceof Not) return ((Not)c).c; return new Not<T>(c); } public static <T> Condition<T> and(Condition<T> c1, Condition<T> c2) { return and2(c1, c2); } public static <T> Condition<T> and2(Condition<? super T> c1, Condition<? super T> c2) { if (c1 == TRUE || c2 == FALSE) return (Condition<T>)c2; if (c2 == TRUE || c1 == FALSE) return (Condition<T>)c1; return new And<T>(c1, c2); } public static <T> Condition<T> or(Condition<T> c1, Condition<T> c2) { return or2(c1, c2); } public static <T> Condition<T> or2(Condition<? super T> c1, Condition<? super T> c2) { if (c1 == FALSE || c2 == TRUE) return (Condition<T>)c2; if (c2 == FALSE || c1 == TRUE) return (Condition<T>)c1; return new Or<T>(c1, c2); } public static <A, B> Condition<A> compose(final Function<? super A, B> fun, final Condition<? super B> condition) { return new Condition<A>() { public boolean value(A o) { return condition.value(fun.fun(o)); } }; } public static <T> Condition<T> cached(Condition<T> c) { return new SoftRefCache<T>(c); } private static class Not<T> implements Condition<T> { final Condition<T> c; Not(Condition<T> c) { this.c = c; } public boolean value(T value) { return !c.value(value); } } private static class And<T> implements Condition<T> { final Condition<? super T> c1; final Condition<? super T> c2; And(Condition<? super T> c1, Condition<? super T> c2) { this.c1 = c1; this.c2 = c2; } public boolean value(T object) { return c1.value(object) && c2.value(object); } } private static class Or<T> implements Condition<T> { final Condition<? super T> c1; final Condition<? super T> c2; Or(Condition<? super T> c1, Condition<? super T> c2) { this.c1 = c1; this.c2 = c2; } public boolean value(T object) { return c1.value(object) || c2.value(object); } } private static class SoftRefCache<T> implements Condition<T> { private final HashMap<Integer, Pair<SoftReference<T>, Boolean>> myCache = new HashMap<Integer, Pair<SoftReference<T>, Boolean>>(); private final Condition<T> myCondition; public SoftRefCache(Condition<T> condition) { myCondition = condition; } public final boolean value(T object) { final int key = object.hashCode(); final Pair<SoftReference<T>, Boolean> entry = myCache.get(key); if (entry == null || entry.first.get() != object) { boolean value = myCondition.value(object); myCache.put(key, Pair.create(new SoftReference<T>(object), value)); return value; } else { return entry.second; } } } }