blob: 4d78ad14f6a4797b20e72e3c83dbe56ddbd67af8 [file] [log] [blame]
/*
* Copyright 2000-2014 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);
}
public void testLockFreeCOWIteratorRemove() {
List<String> seq = Arrays.asList("0", "1", "2", "3", "4");
LockFreeCopyOnWriteArrayList<String> my = (LockFreeCopyOnWriteArrayList<String>)ContainerUtil.createLockFreeCopyOnWriteList(seq);
{
Iterator<String> iterator = my.iterator();
try {
iterator.remove();
fail("must not be able to remove before next() call");
}
catch (NoSuchElementException ignored) {
}
}
int size = my.size();
Iterator<String> iterator = my.iterator();
for (int i = 0; i<size; i++) {
assertTrue(iterator.hasNext());
String next = iterator.next();
assertEquals(next, String.valueOf(i));
iterator.remove();
assertEquals(my.size(), size - i-1);
if (i == size-1) {
assertTrue(my.isEmpty());
}
else {
assertEquals(my.toArray()[0], String.valueOf(i+1));
assertEquals(my.toString(), seq.subList(i+1,seq.size()).toString());
}
}
try {
iterator.remove();
fail("must not be able to double remove()");
}
catch (NoSuchElementException ignored) {
}
}
}