import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import java.util.Arrays;
import java.util.List;
import org.eclipse.tracecompass.segmentstore.core.BasicSegment;
public void setup() {
fSegmentStore = new TreeMapStore<>();
for (ISegment segment : SEGMENTS) {
- fSegmentStore.addElement(checkNotNull(segment));
+ fSegmentStore.add(checkNotNull(segment));
}
}
}
/**
- * Testing method getNbElements
+ * Testing method size()
*/
@Test
- public void testGetNbElements() {
- assertEquals(SEGMENTS.size(), fSegmentStore.getNbElements());
+ public void testSize() {
+ assertEquals(SEGMENTS.size(), fSegmentStore.size());
+ }
+
+ /**
+ * Test the contains() method.
+ */
+ @Test
+ public void testContains() {
+ ISegment otherSegment = new BasicSegment(0, 20);
+
+ assertTrue(fSegmentStore.contains(SEGMENT_2_6));
+ assertTrue(fSegmentStore.contains(SEGMENT_4_8));
+ assertFalse(fSegmentStore.contains(otherSegment));
+ }
+
+ /**
+ * Test the toArray() method.
+ */
+ @Test
+ public void testToObjectArray() {
+ Object[] array = fSegmentStore.toArray();
+
+ assertEquals(SEGMENTS.size(), array.length);
+ assertTrue(Arrays.asList(array).containsAll(SEGMENTS));
+ }
+
+ /**
+ * Test the toArray(T[]) method.
+ */
+ @Test
+ public void testToSpecificArray() {
+ ISegment[] array = fSegmentStore.toArray(new ISegment[0]);
+
+ assertEquals(SEGMENTS.size(), array.length);
+ assertTrue(Arrays.asList(array).containsAll(SEGMENTS));
+ }
+
+ /**
+ * Test the toArray(T[]) method with a subtype of ISegment.
+ */
+ @Test
+ public void testToSpecifyArraySubtype() {
+ TreeMapStore<BasicSegment> tms2 = new TreeMapStore<>();
+ BasicSegment otherSegment = new BasicSegment(2, 6);
+ tms2.add(otherSegment);
+ BasicSegment[] array = tms2.toArray(new BasicSegment[0]);
+
+ assertEquals(1, array.length);
+ assertTrue(Arrays.asList(array).contains(otherSegment));
+
+ tms2.dispose();
}
/**
@Test
public void testNoDuplicateElements() {
for (ISegment segment : SEGMENTS) {
- fSegmentStore.addElement(new BasicSegment(segment.getStart(), segment.getEnd()));
+ fSegmentStore.add(new BasicSegment(segment.getStart(), segment.getEnd()));
}
- assertEquals(SEGMENTS.size(), fSegmentStore.getNbElements());
+ assertEquals(SEGMENTS.size(), fSegmentStore.size());
}
/**
/* Prepare the segment store, we don't use the 'fixture' in this test */
TreeMapStore<ISegment> store = new TreeMapStore<>();
for (ISegment segment : REVERSE_SEGMENTS) {
- store.addElement(checkNotNull(segment));
+ store.add(checkNotNull(segment));
}
/*
@Test
public void testDispose() {
TreeMapStore<ISegment> store = new TreeMapStore<>();
- store.addElement(checkNotNull(SEGMENT_2_6));
+ store.add(SEGMENT_2_6);
store.dispose();
- assertEquals(0, store.getNbElements());
+ assertEquals(0, store.size());
}
}
\ No newline at end of file
package org.eclipse.tracecompass.segmentstore.core;
+import java.util.Collection;
+
/**
* Interface for segment-storing backends.
*
- * @param <T>
+ * @param <E>
* The type of {@link ISegment} element that will be stored in this
* database.
*
* @author Alexandre Montplaisir
*/
-public interface ISegmentStore<T extends ISegment> extends Iterable<T> {
-
- /**
- * Add an element to the database.
- *
- * @param elem The element to add.
- */
- void addElement(T elem);
-
- /**
- * Get the number of element currently existing in the database.
- *
- * @return The number of elements.
- */
- long getNbElements();
+public interface ISegmentStore<E extends ISegment> extends Collection<E> {
/**
* Retrieve all elements that inclusively cross the given position.
* tree's X axis represents time.
* @return The intervals that cross this position
*/
- Iterable<T> getIntersectingElements(long position);
+ Iterable<E> getIntersectingElements(long position);
/**
* Retrieve all elements that inclusively cross another segment. We define
* The target end position
* @return The elements overlapping with this segment
*/
- Iterable<T> getIntersectingElements(long start, long end);
+ Iterable<E> getIntersectingElements(long start, long end);
/**
* Dispose the data structure and release any system resources associated
import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
+import java.util.Collection;
import java.util.Iterator;
import java.util.TreeMap;
import java.util.concurrent.locks.ReadWriteLock;
* that if you want several segments with the same start and end times, make
* sure their compareTo() differentiates them.
*
- * @param <T>
+ * Removal operations are not supported.
+ *
+ * @param <E>
* The type of segment held in this store
*
* @author Alexandre Montplaisir
*/
-public class TreeMapStore<T extends ISegment> implements ISegmentStore<T> {
+public class TreeMapStore<E extends ISegment> implements ISegmentStore<E> {
private final ReadWriteLock fLock = new ReentrantReadWriteLock(false);
- private final TreeMultimap<Long, T> fStartTimesIndex;
- private final TreeMultimap<Long, T> fEndTimesIndex;
+ private final TreeMultimap<Long, E> fStartTimesIndex;
+ private final TreeMultimap<Long, E> fEndTimesIndex;
- private long fSize;
+ private volatile long fSize;
- private @Nullable transient Iterable<T> fLastSnapshot = null;
+ private @Nullable transient Iterable<E> fLastSnapshot = null;
/**
* Constructor
* The same is done for the end times index, but swapping the first two
* comparators instead.
*/
- fStartTimesIndex = checkNotNull(TreeMultimap.<Long, T> create(
+ fStartTimesIndex = checkNotNull(TreeMultimap.<Long, E> create(
SegmentComparators.LONG_COMPARATOR,
Ordering.from(SegmentComparators.INTERVAL_END_COMPARATOR).compound(Ordering.natural())));
- fEndTimesIndex = checkNotNull(TreeMultimap.<Long, T> create(
+ fEndTimesIndex = checkNotNull(TreeMultimap.<Long, E> create(
SegmentComparators.LONG_COMPARATOR,
Ordering.from(SegmentComparators.INTERVAL_START_COMPARATOR).compound(Ordering.natural())));
fSize = 0;
}
+ // ------------------------------------------------------------------------
+ // Methods from Collection
+ // ------------------------------------------------------------------------
+
@Override
- public Iterator<T> iterator() {
+ public Iterator<E> iterator() {
fLock.readLock().lock();
try {
- Iterable<T> lastSnapshot = fLastSnapshot;
+ Iterable<E> lastSnapshot = fLastSnapshot;
if (lastSnapshot == null) {
lastSnapshot = checkNotNull(ImmutableList.copyOf(fStartTimesIndex.values()));
fLastSnapshot = lastSnapshot;
}
@Override
- public void addElement(T val) {
+ public boolean add(@Nullable E val) {
+ if (val == null) {
+ throw new IllegalArgumentException();
+ }
+
fLock.writeLock().lock();
try {
+ /* We can take a read lock while holding the write lock. */
+ if (contains(val)) {
+ return false;
+ }
+
if (fStartTimesIndex.put(Long.valueOf(val.getStart()), val)) {
fEndTimesIndex.put(Long.valueOf(val.getEnd()), val);
fSize++;
} finally {
fLock.writeLock().unlock();
}
+ return true;
+ }
+
+ @Override
+ public int size() {
+ return Long.valueOf(fSize).intValue();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return (fSize == 0);
}
@Override
- public long getNbElements() {
+ public boolean contains(@Nullable Object o) {
fLock.readLock().lock();
try {
- return fSize;
+ return fStartTimesIndex.containsValue(o);
} finally {
fLock.readLock().unlock();
}
}
+
+ @Override
+ public boolean containsAll(@Nullable Collection<?> c) {
+ fLock.readLock().lock();
+ try {
+ return fStartTimesIndex.values().containsAll(c);
+ } finally {
+ fLock.readLock().unlock();
+ }
+ }
+
+ @Override
+ public Object[] toArray() {
+ fLock.readLock().lock();
+ try {
+ return checkNotNull(fStartTimesIndex.values().toArray());
+ } finally {
+ fLock.readLock().unlock();
+ }
+ }
+
+ @Override
+ public <T> T[] toArray(@Nullable T[] a) {
+ fLock.readLock().lock();
+ try {
+ return checkNotNull(fStartTimesIndex.values().toArray(a));
+ } finally {
+ fLock.readLock().unlock();
+ }
+ }
+
+ @Override
+ public boolean remove(@Nullable Object o) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean addAll(@Nullable Collection<? extends E> c) {
+ if (c == null) {
+ throw new IllegalArgumentException();
+ }
+
+ fLock.writeLock().lock();
+ try {
+ boolean changed = false;
+ for (E elem : c) {
+ if (this.add(elem)) {
+ changed = true;
+ }
+ }
+ return changed;
+ } finally {
+ fLock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public boolean removeAll(@Nullable Collection<?> c) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean retainAll(@Nullable Collection<?> c) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods added by ISegmentStore
+ // ------------------------------------------------------------------------
+
@Override
- public Iterable<T> getIntersectingElements(long position) {
+ public Iterable<E> getIntersectingElements(long position) {
/*
* The intervals intersecting 't' are those whose 1) start time is
* *lower* than 't' AND 2) end time is *higher* than 't'.
*/
fLock.readLock().lock();
try {
- Iterable<T> matchStarts = Iterables.concat(fStartTimesIndex.asMap().headMap(position, true).values());
- Iterable<T> matchEnds = Iterables.concat(fEndTimesIndex.asMap().tailMap(position, true).values());
+ Iterable<E> matchStarts = Iterables.concat(fStartTimesIndex.asMap().headMap(position, true).values());
+ Iterable<E> matchEnds = Iterables.concat(fEndTimesIndex.asMap().tailMap(position, true).values());
return checkNotNull(Sets.intersection(Sets.newHashSet(matchStarts), Sets.newHashSet(matchEnds)));
} finally {
fLock.readLock().unlock();
}
@Override
- public Iterable<T> getIntersectingElements(long start, long end) {
+ public Iterable<E> getIntersectingElements(long start, long end) {
fLock.readLock().lock();
try {
- Iterable<T> matchStarts = Iterables.concat(fStartTimesIndex.asMap().headMap(end, true).values());
- Iterable<T> matchEnds = Iterables.concat(fEndTimesIndex.asMap().tailMap(start, true).values());
+ Iterable<E> matchStarts = Iterables.concat(fStartTimesIndex.asMap().headMap(end, true).values());
+ Iterable<E> matchEnds = Iterables.concat(fEndTimesIndex.asMap().tailMap(start, true).values());
return checkNotNull(Sets.intersection(Sets.newHashSet(matchStarts), Sets.newHashSet(matchEnds)));
} finally {
fLock.readLock().unlock();