/* * Copyright 2000-2009 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.util.containers; import com.intellij.openapi.util.Condition; import com.intellij.util.ArrayUtil; import gnu.trove.TIntArrayList; import junit.framework.TestCase; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; public class ContainerUtilTest extends TestCase { public void testFindInstanceOf() { Iterator<Object> iterator = Arrays.<Object>asList(new Integer(1), new ArrayList(), "1").iterator(); String string = (String)ContainerUtil.find(iterator, FilteringIterator.instanceOf(String.class)); assertEquals("1", string); } public void testConcatMulti() { List<Integer> l = ContainerUtil.concat(Arrays.asList(1, 2), Collections.EMPTY_LIST, Arrays.asList(3, 4)); assertEquals(4, l.size()); assertEquals(1, (int)l.get(0)); assertEquals(2, (int)l.get(1)); assertEquals(3, (int)l.get(2)); assertEquals(4, (int)l.get(3)); try { l.get(-1); fail(); } catch (IndexOutOfBoundsException ignore) { } try { l.get(4); fail(); } catch (IndexOutOfBoundsException ignore) { } } public void testIterateWithCondition() throws Exception { Condition<Integer> cond = new Condition<Integer>() { @Override public boolean value(Integer integer) { return integer > 2; } }; asserIterating(Arrays.asList(1, 4, 2, 5), cond, 4, 5); asserIterating(Arrays.asList(1, 2), cond); asserIterating(Collections.<Integer>emptyList(), cond); asserIterating(Arrays.asList(4), cond, 4); } private static void asserIterating(List<Integer> collection, Condition<Integer> condition, Integer... expected) { Iterable<Integer> it = ContainerUtil.iterate(collection, condition); List<Integer> actual = new ArrayList<Integer>(); for (Integer each : it) { actual.add(each); } assertEquals(Arrays.asList(expected), actual); } public void testIteratingBackward() throws Exception { List<String> ss = new ArrayList<String>(); ss.add("a"); ss.add("b"); ss.add("c"); String log = ""; for (String s : ss) { log += s; } for (String s : ContainerUtil.iterateBackward(ss)) { log += s; } assertEquals("abccba", log); } public void testMergeSortedArrays() { TIntArrayList x1 = new TIntArrayList(new int[]{0, 2, 4, 6}); TIntArrayList y1 = new TIntArrayList(new int[]{0, 2, 4, 6}); TIntArrayList x2 = new TIntArrayList(new int[]{1, 2, 2}); TIntArrayList y2 = new TIntArrayList(new int[]{1, 2, 3}); ContainerUtil.mergeSortedArrays(x1, y1, x2, y2); assertEquals(new TIntArrayList(new int[]{0, 1, 2, 2, 4, 6}), x1); assertEquals(new TIntArrayList(new int[]{0, 1, 2, 3, 4, 6}), y1); x2 = new TIntArrayList(new int[]{1, 2, 2}); y2 = new TIntArrayList(new int[]{1, 2, 3}); ContainerUtil.mergeSortedArrays(x1, y1, x2, y2); assertEquals(new TIntArrayList(new int[]{0, 1, 2, 2, 4, 6}), x1); assertEquals(new TIntArrayList(new int[]{0, 1, 2, 3, 4, 6}), y1); x2 = new TIntArrayList(new int[]{-1, -1, -2}); y2 = new TIntArrayList(new int[]{-1, -2, -3}); ContainerUtil.mergeSortedArrays(x1, y1, x2, y2); assertEquals(new TIntArrayList(new int[]{-1, -1, -2, 0, 1, 2, 2, 4, 6}), x1); assertEquals(new TIntArrayList(new int[]{-1, -2, -3, 0, 1, 2, 3, 4, 6}), y1); } public void testLockFreeSingleThreadPerformance() { final List<Object> my = new LockFreeCopyOnWriteArrayList<Object>(); final List<Object> stock = new CopyOnWriteArrayList<Object>(); measure(stock); measure(my); measure(stock); measure(my); // warm up for (int i=0; i<10; i++) { long stockElapsed = measure(stock); long myElapsed = measure(my); System.out.println("LockFree my: "+myElapsed+"; stock: "+stockElapsed); assertTrue("lockFree: "+myElapsed+"; stock: "+stockElapsed, (myElapsed - stockElapsed+0.0)/myElapsed < 0.1); } } private long measure(List<Object> list) { long start = System.currentTimeMillis(); for (int n = 0; n < 10000000; n++) { list.add(this); list.remove(this); list.add(this); list.remove(0); } long finish = System.currentTimeMillis(); assertTrue(list.isEmpty()); return finish - start; } //public void testLockFreeContendedPerformance() throws Exception { // final List<Object> lockFree = new LockFreeCopyOnWriteArrayList<Object>(); // final List<Object> stock = new CopyOnWriteArrayList<Object>(); // LockFreeCopyOnWriteArrayListExpBackoff2<Object> back = new LockFreeCopyOnWriteArrayListExpBackoff2<Object>(); // // measureContended(stock); // measureContended(lockFree); // measureContended(back); // for (int i=0; i<10; i++) { // long stockElapsed = measureContended(stock); // LockFreeCopyOnWriteArrayListExpBackoff2.RETRIES.set(0); // LockFreeCopyOnWriteArrayList.RETRIES.set(0); // long myElapsed = measureContended(lockFree); // long bElapsed = measureContended(back); // int bRetries = LockFreeCopyOnWriteArrayListExpBackoff2.RETRIES.get(); // int mRetries = LockFreeCopyOnWriteArrayList.RETRIES.get(); // // System.out.println("Contended: stock: "+stockElapsed // +"; lockFree: "+myElapsed+"; retries per op: "+(mRetries/1000000.0/2) // +"; backoff: "+bElapsed+"; retries per op: "+(bRetries/1000000.0/2)); // //assertTrue("my: "+myElapsed+"; stock: "+stockElapsed, Math.abs(myElapsed - stockElapsed+0.0)/myElapsed < 0.1); // } //} //private long measureContended(final List<Object> list) throws Exception { // long start = System.currentTimeMillis(); // int N = /*2;//*/Runtime.getRuntime().availableProcessors(); // Thread[] threads = new Thread[N]; // final AtomicReference<Exception> ex = new AtomicReference<Exception>(); // for (int i=0; i< N; i++) { // Thread thread = new Thread(new Runnable() { // @Override // public void run() { // for (int n = 0; n < 1000000; n++) { // list.add(this); // boolean removed = list.remove(this); // if (!removed) { // ex.set(new Exception()); // } // } // } // },"t" + i); // threads[i] = thread; // thread.start(); // } // for (int i=0; i< N; i++) { // try { // threads[i].join(); // } // catch (InterruptedException e) { // throw new RuntimeException(e); // } // } // if (ex.get() != null) throw ex.get(); // long finish = System.currentTimeMillis(); // assertTrue(list.isEmpty()); // return finish - start; //} public void testLockFreeCOWDoesNotCreateEmptyArrays() { LockFreeCopyOnWriteArrayList<Object> my = (LockFreeCopyOnWriteArrayList<Object>)ContainerUtil.createLockFreeCopyOnWriteList(); //LockFreeCopyOnWriteArrayListExpBackoff2<Object> my = new LockFreeCopyOnWriteArrayListExpBackoff2<Object>(); for (int i = 0; i < 2; i++) { Object[] array = my.getArray(); assertSame(ArrayUtil.EMPTY_OBJECT_ARRAY, array); assertReallyEmpty(my); my.add(this); my.remove(this); assertReallyEmpty(my); my.add(this); my.remove(0); assertReallyEmpty(my); my.add(this); my.clear(); assertReallyEmpty(my); } } private static void assertReallyEmpty(List<Object> my) { assertEquals(0, my.size()); Object[] objects = my.toArray(); assertSame(ArrayUtil.EMPTY_OBJECT_ARRAY, objects); Iterator<Object> iterator = my.iterator(); assertSame(EmptyIterator.getInstance(), iterator); } }