1 /*******************************************************************************
2 * Copyright (c) 2016 Ericsson
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *******************************************************************************/
10 package org
.eclipse
.tracecompass
.internal
.segmentstore
.core
.arraylist
;
12 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
14 import java
.util
.ArrayList
;
15 import java
.util
.Collection
;
16 import java
.util
.Collections
;
17 import java
.util
.Comparator
;
18 import java
.util
.Iterator
;
19 import java
.util
.List
;
20 import java
.util
.concurrent
.locks
.ReadWriteLock
;
21 import java
.util
.concurrent
.locks
.ReentrantReadWriteLock
;
22 import java
.util
.stream
.Collectors
;
24 import org
.eclipse
.jdt
.annotation
.NonNull
;
25 import org
.eclipse
.jdt
.annotation
.Nullable
;
26 import org
.eclipse
.tracecompass
.segmentstore
.core
.BasicSegment
;
27 import org
.eclipse
.tracecompass
.segmentstore
.core
.ISegment
;
28 import org
.eclipse
.tracecompass
.segmentstore
.core
.ISegmentStore
;
29 import org
.eclipse
.tracecompass
.segmentstore
.core
.SegmentComparators
;
31 import com
.google
.common
.collect
.ImmutableList
;
32 import com
.google
.common
.collect
.Ordering
;
35 * Implementation of an {@link ISegmentStore} using one in-memory
36 * {@link ArrayList}. This relatively simple implementation holds everything in
37 * memory, and as such cannot contain too much data.
39 * The ArrayListStore itself is {@link Iterable}, and its iteration order will
40 * be by ascending order of start times. For segments with identical start
41 * times, the secondary comparator will be the end time. If even those are
42 * equal, it will defer to the segments' natural ordering (
43 * {@link ISegment#compareTo}).
45 * The store's tree maps will not accept duplicate key-value pairs, which means
46 * that if you want several segments with the same start and end times, make
47 * sure their compareTo() differentiates them.
49 * Removal operations are not supported.
52 * The type of segment held in this store
54 * @author Matthew Khouzam
56 public class ArrayListStore
<@NonNull E
extends ISegment
> implements ISegmentStore
<E
> {
58 private final Comparator
<E
> COMPARATOR
= Ordering
.from(SegmentComparators
.INTERVAL_START_COMPARATOR
)
59 .compound(SegmentComparators
.INTERVAL_END_COMPARATOR
);
61 private final ReadWriteLock fLock
= new ReentrantReadWriteLock(false);
63 private final List
<E
> fStore
;
65 private @Nullable transient Iterable
<E
> fLastSnapshot
= null;
70 public ArrayListStore() {
71 fStore
= new ArrayList
<>();
78 * an array of elements to wrap in the segment store
81 public ArrayListStore(Object
[] array
) {
82 fStore
= new ArrayList
<>();
83 for (int i
= 0; i
< array
.length
; i
++) {
84 if (array
[i
] instanceof ISegment
) {
85 fStore
.add((E
) array
[i
]);
88 fStore
.sort(COMPARATOR
);
90 // ------------------------------------------------------------------------
91 // Methods from Collection
92 // ------------------------------------------------------------------------
95 public Iterator
<E
> iterator() {
96 fLock
.readLock().lock();
98 Iterable
<E
> lastSnapshot
= fLastSnapshot
;
99 if (lastSnapshot
== null) {
100 lastSnapshot
= ImmutableList
.copyOf(fStore
);
101 fLastSnapshot
= lastSnapshot
;
103 return checkNotNull(lastSnapshot
.iterator());
105 fLock
.readLock().unlock();
110 public boolean add(@Nullable E val
) {
112 throw new IllegalArgumentException("Cannot add null value"); //$NON-NLS-1$
115 fLock
.writeLock().lock();
117 int insertPoint
= Collections
.binarySearch(fStore
, val
);
118 insertPoint
= insertPoint
>= 0 ? insertPoint
: -insertPoint
- 1;
119 fStore
.add(insertPoint
, val
);
120 fLastSnapshot
= null;
123 fLock
.writeLock().unlock();
129 fLock
.readLock().lock();
131 return fStore
.size();
133 fLock
.readLock().unlock();
138 public boolean isEmpty() {
139 fLock
.readLock().lock();
141 return fStore
.isEmpty();
143 fLock
.readLock().unlock();
148 public boolean contains(@Nullable Object o
) {
149 fLock
.readLock().lock();
151 return fStore
.contains(o
);
153 fLock
.readLock().unlock();
158 public boolean containsAll(@Nullable Collection
<?
> c
) {
159 fLock
.readLock().lock();
161 return fStore
.containsAll(c
);
163 fLock
.readLock().unlock();
168 public Object
[] toArray() {
169 fLock
.readLock().lock();
171 return fStore
.toArray();
173 fLock
.readLock().unlock();
178 public <T
> T
[] toArray(T
[] a
) {
179 fLock
.readLock().lock();
181 return fStore
.toArray(a
);
183 fLock
.readLock().unlock();
188 public boolean remove(@Nullable Object o
) {
189 throw new UnsupportedOperationException();
193 public boolean addAll(@Nullable Collection
<?
extends E
> c
) {
195 throw new IllegalArgumentException();
198 fLock
.writeLock().lock();
200 boolean changed
= false;
202 if (this.add(elem
)) {
208 fLock
.writeLock().unlock();
213 public boolean removeAll(@Nullable Collection
<?
> c
) {
214 throw new UnsupportedOperationException();
218 public boolean retainAll(@Nullable Collection
<?
> c
) {
219 throw new UnsupportedOperationException();
223 public void clear() {
224 fLock
.writeLock().lock();
228 fLock
.writeLock().unlock();
232 // ------------------------------------------------------------------------
233 // Methods added by ISegmentStore
234 // ------------------------------------------------------------------------
237 public Iterable
<E
> getIntersectingElements(long position
) {
239 * The intervals intersecting 't' are those whose 1) start time is
240 * *lower* than 't' AND 2) end time is *higher* than 't'.
242 fLock
.readLock().lock();
245 * as fStore is sorted by start then end times, restrict sub array
246 * to elements whose start times <= t as stream.filter won't do it.
248 int index
= Collections
.binarySearch(fStore
, new BasicSegment(position
, Long
.MAX_VALUE
));
249 index
= (index
>= 0) ? index
: -index
- 1;
250 return fStore
.subList(0, index
).stream().filter(element
-> position
>= element
.getStart() && position
<= element
.getEnd()).collect(Collectors
.toList());
252 fLock
.readLock().unlock();
257 public Iterable
<E
> getIntersectingElements(long start
, long end
) {
258 fLock
.readLock().lock();
260 int index
= Collections
.binarySearch(fStore
, new BasicSegment(end
, Long
.MAX_VALUE
));
261 index
= (index
>= 0) ? index
: -index
- 1;
262 return fStore
.subList(0, index
).stream().filter(element
-> !(start
> element
.getEnd() || end
< element
.getStart())).collect(Collectors
.toList());
264 fLock
.readLock().unlock();
269 public void dispose() {
270 fLock
.writeLock().lock();
274 fLock
.writeLock().unlock();