33
33
34
34
import java .util .Iterator ;
35
35
import java .util .List ;
36
+ import java .util .Map ;
37
+ import java .util .NoSuchElementException ;
38
+ import java .util .Spliterator ;
39
+ import java .util .Spliterators ;
40
+ import java .util .concurrent .ConcurrentHashMap ;
36
41
import java .util .concurrent .CopyOnWriteArrayList ;
42
+ import java .util .concurrent .atomic .AtomicLong ;
37
43
import java .util .stream .Stream ;
44
+ import java .util .stream .StreamSupport ;
38
45
39
46
import org .scijava .log .CallingClassUtils ;
40
47
import org .scijava .log .IgnoreAsCallingClass ;
54
61
@ IgnoreAsCallingClass
55
62
public class LogRecorder implements LogListener , Iterable <LogMessage > {
56
63
57
- private ConcurrentExpandableList recorded = new ConcurrentExpandableList ();
64
+ private ConcurrentExpandableList <LogMessage > recorded =
65
+ new ConcurrentExpandableList <>();
58
66
59
67
private List <Runnable > observers = new CopyOnWriteArrayList <>();
60
68
@@ -79,6 +87,7 @@ public void removeObserver(Runnable observer) {
79
87
* {@link Iterator#hasNext()} will return true again, and
80
88
* {@link Iterator#next()} will return the new log messages element.
81
89
*/
90
+ @ Override
82
91
public Iterator <LogMessage > iterator () {
83
92
return recorded .iterator ();
84
93
}
@@ -122,4 +131,74 @@ private void notifyListeners() {
122
131
for (Runnable listener : observers )
123
132
listener .run ();
124
133
}
134
+
135
+ /**
136
+ * This Container manages a list of items. Items can only be added to end of
137
+ * the list. It's possible to add items, while iterating over the list.
138
+ * Iterators never fail, and they will always be updated. Even if an element
139
+ * is added after an iterator reached the end of the list,
140
+ * {@link Iterator#hasNext()} will return true again, and
141
+ * {@link Iterator#next()} will return the newly added element. This Container
142
+ * is fully thread safe.
143
+ *
144
+ * @author Matthias Arzt
145
+ */
146
+ private class ConcurrentExpandableList <T > implements Iterable <T > {
147
+
148
+ private final AtomicLong lastKey = new AtomicLong (0 );
149
+
150
+ private long firstKey = 0 ;
151
+
152
+ private final Map <Long , T > map = new ConcurrentHashMap <>();
153
+
154
+ public Stream <T > stream () {
155
+ Spliterator <T > spliterator = Spliterators .spliteratorUnknownSize (
156
+ iterator (), Spliterator .ORDERED );
157
+ return StreamSupport .stream (spliterator , /* parallel */ false );
158
+ }
159
+
160
+ @ Override
161
+ public Iterator <T > iterator () {
162
+ return new MyIterator (firstKey );
163
+ }
164
+
165
+ public Iterator <T > iteratorAtEnd () {
166
+ return new MyIterator (lastKey .get ());
167
+ }
168
+
169
+ public long add (T value ) {
170
+ long key = lastKey .getAndIncrement ();
171
+ map .put (key , value );
172
+ return key ;
173
+ }
174
+
175
+ public void clear () {
176
+ map .clear ();
177
+ firstKey = lastKey .get ();
178
+ }
179
+
180
+ private class MyIterator implements Iterator <T > {
181
+
182
+ private long nextIndex ;
183
+
184
+ public MyIterator (long nextIndex ) {
185
+ this .nextIndex = nextIndex ;
186
+ }
187
+
188
+ @ Override
189
+ public boolean hasNext () {
190
+ return map .containsKey (nextIndex );
191
+ }
192
+
193
+ @ Override
194
+ public T next () {
195
+ T value = map .get (nextIndex );
196
+ if (value == null )
197
+ throw new NoSuchElementException ();
198
+ nextIndex ++;
199
+ return value ;
200
+ }
201
+ }
202
+ }
203
+
125
204
}
0 commit comments