add explicit event list
This commit is contained in:
		| @@ -15,6 +15,7 @@ import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.Map.Entry; | ||||
|  | ||||
| import com.minres.scviewer.database.EventEntry; | ||||
| import com.minres.scviewer.database.EventKind; | ||||
| import com.minres.scviewer.database.HierNode; | ||||
| import com.minres.scviewer.database.IEvent; | ||||
| @@ -35,7 +36,7 @@ abstract class AbstractTxStream extends HierNode implements IWaveform { | ||||
| 	 | ||||
| 	private Integer maxConcurrency; | ||||
|  | ||||
| 	private IEventList<Long, IEvent[]> events; | ||||
| 	private IEventList events; | ||||
|  | ||||
| 	private List<RelationType> usedRelationsList; | ||||
|  | ||||
| @@ -71,9 +72,9 @@ abstract class AbstractTxStream extends HierNode implements IWaveform { | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public  IEventList<Long, IEvent[]> getEvents(){ | ||||
| 	public  IEventList getEvents(){ | ||||
| 		if(events==null){ | ||||
| 			events=new EventList<>(); | ||||
| 			events=new EventList(); | ||||
| 			for(Entry<Integer, ITx> entry:getTransactions().entrySet()){ | ||||
| 				putEvent(new TxEvent(EventKind.BEGIN, entry.getValue())); | ||||
| 				putEvent(new TxEvent(EventKind.END, entry.getValue())); | ||||
| @@ -114,11 +115,11 @@ abstract class AbstractTxStream extends HierNode implements IWaveform { | ||||
|  | ||||
| 	@Override | ||||
| 	public IEvent[] getEventsBeforeTime(Long time) { | ||||
| 		Entry<Long, IEvent[]> e = events.floorEntry(time); | ||||
| 		EventEntry e = events.floorEntry(time); | ||||
| 		if(e==null) | ||||
| 			return new IEvent[]{}; | ||||
| 		else | ||||
| 			return  events.floorEntry(time).getValue(); | ||||
| 			return  events.floorEntry(time).events; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
|   | ||||
| @@ -14,8 +14,8 @@ package com.minres.scviewer.database.text; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Arrays; | ||||
| import java.util.HashMap; | ||||
| import java.util.Map.Entry; | ||||
|  | ||||
| import com.minres.scviewer.database.EventEntry; | ||||
| import com.minres.scviewer.database.EventList; | ||||
| import com.minres.scviewer.database.HierNode; | ||||
| import com.minres.scviewer.database.IEvent; | ||||
| @@ -39,7 +39,7 @@ abstract class AbstractTxStream extends HierNode implements IWaveform { | ||||
| 	protected TextDbLoader loader; | ||||
|  | ||||
| 	/** The events. */ | ||||
| 	IEventList<Long, IEvent[]> events = new EventList<Long, IEvent[]>(); | ||||
| 	IEventList events = new EventList(); | ||||
|  | ||||
| 	/** The max concurrency. */ | ||||
| 	private int rowCount = -1; | ||||
| @@ -89,7 +89,7 @@ abstract class AbstractTxStream extends HierNode implements IWaveform { | ||||
| 	 * @return the events | ||||
| 	 */ | ||||
| 	@Override | ||||
| 	public IEventList<Long, IEvent[]> getEvents() { | ||||
| 	public IEventList getEvents() { | ||||
| 		return events; | ||||
| 	} | ||||
|  | ||||
| @@ -112,11 +112,11 @@ abstract class AbstractTxStream extends HierNode implements IWaveform { | ||||
| 	 */ | ||||
| 	@Override | ||||
| 	public IEvent[] getEventsBeforeTime(Long time) { | ||||
| 		Entry<Long, IEvent[]> e = events.floorEntry(time); | ||||
| 		EventEntry e = events.floorEntry(time); | ||||
| 		if (e == null) | ||||
| 			return new IEvent[] {}; | ||||
| 		else | ||||
| 			return events.floorEntry(time).getValue(); | ||||
| 			return events.floorEntry(time).events; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| @@ -159,8 +159,8 @@ abstract class AbstractTxStream extends HierNode implements IWaveform { | ||||
| 			return; | ||||
| 		ArrayList<Long> rowEndTime = new ArrayList<>(); | ||||
| 		HashMap<Long, Integer> rowByTxId = new HashMap<>(); | ||||
| 		for(Entry<Long, IEvent[]> entry: events.entrySet()) { | ||||
| 			for(IEvent evt:entry.getValue()) { | ||||
| 		for(EventEntry entry: events) { | ||||
| 			for(IEvent evt:entry.events) { | ||||
| 				TxEvent txEvt = (TxEvent) evt; | ||||
| 				ITx tx = txEvt.getTransaction(); | ||||
| 				int rowIdx = 0; | ||||
|   | ||||
| @@ -12,7 +12,6 @@ package com.minres.scviewer.database.ui.swt.internal; | ||||
|  | ||||
| import java.util.Arrays; | ||||
| import java.util.Collection; | ||||
| import java.util.Map.Entry; | ||||
|  | ||||
| import javax.swing.JPanel; | ||||
|  | ||||
| @@ -25,6 +24,7 @@ import org.eclipse.swt.graphics.Rectangle; | ||||
|  | ||||
| import com.minres.scviewer.database.BitVector; | ||||
| import com.minres.scviewer.database.DoubleVal; | ||||
| import com.minres.scviewer.database.EventEntry; | ||||
| import com.minres.scviewer.database.IEvent; | ||||
| import com.minres.scviewer.database.IEventList; | ||||
| import com.minres.scviewer.database.IWaveform; | ||||
| @@ -37,16 +37,16 @@ public class SignalPainter extends TrackPainter { | ||||
| 		IEvent value; | ||||
| 		boolean fromMap; | ||||
|  | ||||
| 		public SignalChange(Entry<Long, IEvent[]> entry) { | ||||
| 			time = entry.getKey(); | ||||
| 			value = entry.getValue()[0]; | ||||
| 		public SignalChange(EventEntry entry) { | ||||
| 			time = entry.timestamp; | ||||
| 			value = entry.events[0]; | ||||
| 			fromMap = true; | ||||
| 		} | ||||
|  | ||||
| 		public void set(Entry<Long, IEvent[]> entry, Long actTime) { | ||||
| 		public void set(EventEntry entry, Long actTime) { | ||||
| 			if (entry != null) { | ||||
| 				time = entry.getKey(); | ||||
| 				value = entry.getValue()[0]; | ||||
| 				time = entry.timestamp; | ||||
| 				value = entry.events[0]; | ||||
| 				fromMap = true; | ||||
| 			} else { | ||||
| 				time = actTime; | ||||
| @@ -100,8 +100,8 @@ public class SignalPainter extends TrackPainter { | ||||
| 		long beginTime = beginPos*scaleFactor; | ||||
|         long endTime = beginTime + area.width*scaleFactor; | ||||
| 		 | ||||
| 		Entry<Long, IEvent[]> first = signal.getEvents().floorEntry(beginTime); | ||||
| 		Entry<Long, IEvent[]> last = signal.getEvents().floorEntry(endTime); | ||||
| 		EventEntry first = signal.getEvents().floorEntry(beginTime); | ||||
| 		EventEntry last = signal.getEvents().floorEntry(endTime); | ||||
| 		if (first == null) { | ||||
| 			if (last == null) | ||||
| 				return; | ||||
| @@ -112,7 +112,7 @@ public class SignalPainter extends TrackPainter { | ||||
| 		proj.setForeground(this.waveCanvas.styleProvider.getColor(WaveformColors.LINE)); | ||||
| 		proj.setLineStyle(SWT.LINE_SOLID); | ||||
| 		proj.setLineWidth(1); | ||||
| 		IEventList<Long, IEvent[]> entries = signal.getEvents().subMap(first.getKey(), false, last.getKey(), true); | ||||
| 		IEventList entries = signal.getEvents().subMap(first.timestamp, false, last.timestamp); | ||||
| 		SignalChange left = new SignalChange(first); | ||||
| 		SignalChange right = new SignalChange(entries.size() > 0 ? entries.firstEntry() : first); | ||||
| 		maxPosX = area.x + area.width; | ||||
| @@ -153,15 +153,15 @@ public class SignalPainter extends TrackPainter { | ||||
| 			if (xSigChangeEndPos == xSigChangeBeginPos) { | ||||
| 				multiple = true; | ||||
| 				long eTime = (xSigChangeBeginPos + 1) * this.waveCanvas.getScaleFactor(); | ||||
| 				Entry<Long, IEvent[]> entry = entries.floorEntry(eTime); | ||||
| 				if(entry!=null && entry.getKey()> right.time) | ||||
| 				EventEntry entry = entries.floorEntry(eTime); | ||||
| 				if(entry!=null && entry.timestamp> right.time) | ||||
| 					right.set(entry, endTime); | ||||
| 				xSigChangeEndPos = getXPosEnd(eTime); | ||||
| 			} | ||||
| 		} while (left.time < endTime); | ||||
| 	} | ||||
|  | ||||
| 	private SignalStencil getStencil(GC gc, SignalChange left, IEventList<Long, IEvent[]> entries) { | ||||
| 	private SignalStencil getStencil(GC gc, SignalChange left, IEventList entries) { | ||||
| 		IEvent val = left.value; | ||||
| 		if(val instanceof BitVector) { | ||||
| 			BitVector bv = (BitVector) val; | ||||
| @@ -253,15 +253,15 @@ public class SignalPainter extends TrackPainter { | ||||
| 		private long maxVal; | ||||
| 		private long minVal; | ||||
| 		double yRange = (yOffsetB-yOffsetT); | ||||
| 		public MultiBitStencilAnalog(IEventList<Long, IEvent[]> entries, Object left, boolean continous, boolean signed) { | ||||
| 		public MultiBitStencilAnalog(IEventList entries, Object left, boolean continous, boolean signed) { | ||||
| 			this.continous=continous; | ||||
| 			this.signed=signed; | ||||
| 			Collection<IEvent[]> values = entries.values(); | ||||
| 			Collection<EventEntry> ievents = entries.entrySet(); | ||||
| 			minVal=signed?((BitVector)left).toSignedValue():((BitVector)left).toUnsignedValue(); | ||||
| 			if(!values.isEmpty()) { | ||||
| 			if(!ievents.isEmpty()) { | ||||
| 				maxVal=minVal; | ||||
| 				for (IEvent[] tp : entries.values()) | ||||
| 					for(IEvent e: tp) { | ||||
| 				for (EventEntry tp : ievents) | ||||
| 					for(IEvent e: tp.events) { | ||||
| 						long v = signed?((BitVector)e).toSignedValue():((BitVector)e).toUnsignedValue(); | ||||
| 						maxVal=Math.max(maxVal, v); | ||||
| 						minVal=Math.min(minVal, v); | ||||
| @@ -358,15 +358,15 @@ public class SignalPainter extends TrackPainter { | ||||
| 		 | ||||
| 		boolean continous=true; | ||||
| 		 | ||||
| 		public RealStencil(IEventList<Long, IEvent[]> entries, Object left, boolean continous) { | ||||
| 		public RealStencil(IEventList entries, Object left, boolean continous) { | ||||
| 			this.continous=continous; | ||||
| 			Collection<IEvent[]> values = entries.values(); | ||||
| 			Collection<EventEntry> values = entries.entrySet(); | ||||
| 			minVal=(Double) left; | ||||
| 			range=2.0; | ||||
| 			if(!values.isEmpty()) { | ||||
| 				double maxVal=minVal; | ||||
| 				for (IEvent[] val : entries.values()) | ||||
| 					for(IEvent e:val) { | ||||
| 				for (EventEntry val : values) | ||||
| 					for(IEvent e:val.events) { | ||||
| 						double v = ((DoubleVal)e).value; | ||||
| 						if(Double.isNaN(maxVal)) | ||||
| 							maxVal=v; | ||||
|   | ||||
| @@ -10,7 +10,6 @@ | ||||
|  *******************************************************************************/ | ||||
| package com.minres.scviewer.database.ui.swt.internal; | ||||
|  | ||||
| import java.util.Map.Entry; | ||||
| import java.util.TreeMap; | ||||
|  | ||||
| import org.eclipse.swt.SWT; | ||||
| @@ -18,9 +17,9 @@ import org.eclipse.swt.graphics.Color; | ||||
| import org.eclipse.swt.graphics.Point; | ||||
| import org.eclipse.swt.graphics.Rectangle; | ||||
|  | ||||
| import com.minres.scviewer.database.EventEntry; | ||||
| import com.minres.scviewer.database.EventKind; | ||||
| import com.minres.scviewer.database.IEvent; | ||||
| import com.minres.scviewer.database.IEventList; | ||||
| import com.minres.scviewer.database.IWaveform; | ||||
| import com.minres.scviewer.database.tx.ITx; | ||||
| import com.minres.scviewer.database.tx.ITxEvent; | ||||
| @@ -72,8 +71,8 @@ public class StreamPainter extends TrackPainter{ | ||||
| 		long beginTime = beginPos*scaleFactor; | ||||
| 		long endTime = beginTime + area.width*scaleFactor; | ||||
|  | ||||
| 		Entry<Long,  IEvent[]> firstTx=stream.getEvents().floorEntry(beginTime); | ||||
| 		Entry<Long,  IEvent[]> lastTx=stream.getEvents().ceilingEntry(endTime); | ||||
| 		EventEntry firstTx=stream.getEvents().floorEntry(beginTime); | ||||
| 		EventEntry lastTx=stream.getEvents().ceilingEntry(endTime); | ||||
| 		if(firstTx==null) firstTx = stream.getEvents().firstEntry(); | ||||
| 		if(lastTx==null) lastTx=stream.getEvents().lastEntry(); | ||||
| 		proj.setFillRule(SWT.FILL_EVEN_ODD); | ||||
| @@ -84,16 +83,15 @@ public class StreamPainter extends TrackPainter{ | ||||
| 		for( int y1=area.y+trackHeight/2; y1<area.y+trackEntry.height; y1+=trackHeight) | ||||
| 			proj.drawLine(area.x, y1, area.x+area.width, y1); | ||||
| 		if(firstTx==lastTx) { | ||||
| 			for(IEvent txEvent: firstTx.getValue()) | ||||
| 			for(IEvent txEvent: firstTx.events) | ||||
| 				drawTx(proj, area, ((ITxEvent)txEvent).getTransaction(), ((ITxEvent)txEvent).getRowIndex(), false); | ||||
| 		}else{ | ||||
| 			seenTx.clear(); | ||||
| 			IEventList<Long, IEvent[]> entries = stream.getEvents().subMap(firstTx.getKey(), true, lastTx.getKey(), true); | ||||
| 			ITxEvent highlighed=null; | ||||
| 			proj.setForeground(this.waveCanvas.styleProvider.getColor(WaveformColors.LINE)); | ||||
| 			long selectedId=waveCanvas.currentSelection!=null? waveCanvas.currentSelection.getId():-1; | ||||
| 			for(Entry<Long, IEvent[]> entry: entries.entrySet()) | ||||
| 				for(IEvent e:entry.getValue()){ | ||||
| 			for(EventEntry entry: stream.getEvents().subMap(firstTx.timestamp, true, lastTx.timestamp)) | ||||
| 				for(IEvent e:entry.events){ | ||||
| 					ITxEvent evt = (ITxEvent) e; | ||||
| 					ITx tx = evt.getTransaction(); | ||||
| 					if(selectedId==tx.getId()) | ||||
| @@ -155,12 +153,12 @@ public class StreamPainter extends TrackPainter{ | ||||
|  | ||||
| 	public ITx getClicked(Point point) { | ||||
| 		int lane=point.y/waveCanvas.styleProvider.getTrackHeight(); | ||||
| 		Entry<Long, IEvent[]> firstTx=stream.getEvents().floorEntry(point.x*waveCanvas.getScaleFactor()); | ||||
| 		EventEntry firstTx=stream.getEvents().floorEntry(point.x*waveCanvas.getScaleFactor()); | ||||
| 		if(firstTx!=null){ | ||||
| 			do { | ||||
| 				ITx tx = getTxFromEntry(lane, point.x, firstTx.getValue()); | ||||
| 				ITx tx = getTxFromEntry(lane, point.x, firstTx.events); | ||||
| 				if(tx!=null) return tx; | ||||
| 				firstTx=stream.getEvents().lowerEntry(firstTx.getKey()); | ||||
| 				firstTx=stream.getEvents().lowerEntry(firstTx.timestamp); | ||||
| 			}while(firstTx!=null); | ||||
| 		} | ||||
| 		return null; | ||||
|   | ||||
| @@ -34,6 +34,7 @@ import org.eclipse.swt.widgets.Event; | ||||
| import org.eclipse.swt.widgets.ScrollBar; | ||||
|  | ||||
| import com.google.common.collect.Lists; | ||||
| import com.minres.scviewer.database.EventEntry; | ||||
| import com.minres.scviewer.database.IEvent; | ||||
| import com.minres.scviewer.database.IWaveform; | ||||
| import com.minres.scviewer.database.RelationType; | ||||
| @@ -427,8 +428,8 @@ public class WaveformCanvas extends Canvas { | ||||
|         } | ||||
|         for (IWaveformPainter painter : wave2painterMap.values()) { | ||||
|             if (painter instanceof StreamPainter && ((StreamPainter) painter).getStream() == tx.getStream()) { | ||||
|             	Entry<Long, IEvent[]> entry = tx.getStream().getEvents().floorEntry(tx.getBeginTime()); | ||||
|             	Optional<IEvent> res = Arrays.stream(entry.getValue()).filter(e -> ((ITxEvent)e).getTransaction().equals(tx)).findFirst(); | ||||
|             	EventEntry entry = tx.getStream().getEvents().floorEntry(tx.getBeginTime()); | ||||
|             	Optional<IEvent> res = Arrays.stream(entry.events).filter(e -> ((ITxEvent)e).getTransaction().equals(tx)).findFirst(); | ||||
|             	if(res.isPresent()) { | ||||
|                     int top = painter.getVerticalOffset() + styleProvider.getTrackHeight() * ((ITxEvent)res.get()).getRowIndex(); | ||||
|                     int bottom = top + styleProvider.getTrackHeight(); | ||||
|   | ||||
| @@ -76,6 +76,7 @@ import org.eclipse.wb.swt.SWTResourceManager; | ||||
| import com.google.common.collect.Lists; | ||||
| import com.minres.scviewer.database.BitVector; | ||||
| import com.minres.scviewer.database.DoubleVal; | ||||
| import com.minres.scviewer.database.EventEntry; | ||||
| import com.minres.scviewer.database.EventKind; | ||||
| import com.minres.scviewer.database.IEvent; | ||||
| import com.minres.scviewer.database.IEventList; | ||||
| @@ -255,29 +256,29 @@ public class WaveformView implements IWaveformView { | ||||
| 			long time = waveformCanvas.getTimeForOffset(p.x); | ||||
| 			long scaling = 5 * waveformCanvas.getScaleFactor(); | ||||
| 			for (Object o : waveformCanvas.getElementsAt(p)) { | ||||
| 				Entry<Long, IEvent[]> floorEntry = null; | ||||
| 				Entry<Long, IEvent[]> ceilEntry = null; | ||||
| 				EventEntry floorEntry = null; | ||||
| 				EventEntry ceilEntry = null; | ||||
| 				if (o instanceof TrackEntry) { | ||||
| 					TrackEntry entry = (TrackEntry) o; | ||||
| 					IEventList<Long, IEvent[]> map = entry.waveform.getEvents(); | ||||
| 					IEventList map = entry.waveform.getEvents(); | ||||
| 					floorEntry = map.floorEntry(time); | ||||
| 					ceilEntry = map.ceilingEntry(time); | ||||
| 				} else if (o instanceof ITx) { | ||||
| 					IEventList<Long, IEvent[]> map = ((ITx) o).getStream().getEvents(); | ||||
| 					IEventList map = ((ITx) o).getStream().getEvents(); | ||||
| 					floorEntry = map.floorEntry(time); | ||||
| 					ceilEntry = map.ceilingEntry(time); | ||||
| 				} | ||||
| 				if (floorEntry != null && time - floorEntry.getKey() > scaling) | ||||
| 				if (floorEntry != null && time - floorEntry.timestamp > scaling) | ||||
| 					floorEntry = null; | ||||
| 				if (ceilEntry != null && ceilEntry.getKey() - time > scaling) | ||||
| 				if (ceilEntry != null && ceilEntry.timestamp - time > scaling) | ||||
| 					ceilEntry = null; | ||||
| 				if (ceilEntry == null && floorEntry != null) { | ||||
| 					time = floorEntry.getKey(); | ||||
| 					time = floorEntry.timestamp; | ||||
| 				} else if (ceilEntry != null && floorEntry == null) { | ||||
| 					time = ceilEntry.getKey(); | ||||
| 					time = ceilEntry.timestamp; | ||||
| 				} else if (ceilEntry != null && floorEntry != null) { | ||||
| 					time = time - floorEntry.getKey() < ceilEntry.getKey() - time ? floorEntry.getKey() | ||||
| 							: ceilEntry.getKey(); | ||||
| 					time = time - floorEntry.timestamp < ceilEntry.timestamp - time ? floorEntry.timestamp | ||||
| 							: ceilEntry.timestamp; | ||||
| 				} | ||||
| 			} | ||||
| 			return time; | ||||
| @@ -580,10 +581,10 @@ public class WaveformView implements IWaveformView { | ||||
| 				} | ||||
| 			} else if (entry.waveform.getType() == WaveformType.TRANSACTION) { | ||||
| 				ITx[] resultsList = new ITx[entry.waveform.getRowCount()]; | ||||
| 				Entry<Long, IEvent[]> firstTx = entry.waveform.getEvents().floorEntry(time); | ||||
| 				EventEntry firstTx = entry.waveform.getEvents().floorEntry(time); | ||||
| 				if (firstTx != null) { | ||||
| 					do { | ||||
| 						for (IEvent e : firstTx.getValue()) { | ||||
| 						for (IEvent e : firstTx.events) { | ||||
| 							if (e instanceof ITxEvent) { | ||||
| 								ITxEvent evt = ((ITxEvent) e); | ||||
| 								ITx tx = evt.getTransaction(); | ||||
| @@ -593,7 +594,7 @@ public class WaveformView implements IWaveformView { | ||||
| 									resultsList[evt.getRowIndex()] = evt.getTransaction(); | ||||
| 							} | ||||
| 						} | ||||
| 						firstTx = entry.waveform.getEvents().lowerEntry(firstTx.getKey()); | ||||
| 						firstTx = entry.waveform.getEvents().lowerEntry(firstTx.timestamp); | ||||
| 					} while (firstTx != null && !isArrayFull(resultsList)); | ||||
| 					boolean separator = false; | ||||
| 					StringBuilder sb = new StringBuilder(); | ||||
| @@ -854,11 +855,11 @@ public class WaveformView implements IWaveformView { | ||||
| 						} | ||||
| 					} | ||||
| 					if (transaction == null) { | ||||
| 						Entry<Long, IEvent[]> entry = selectedWaveform.waveform.getEvents() | ||||
| 						EventEntry entry = selectedWaveform.waveform.getEvents() | ||||
| 								.higherEntry(currentTxSelection.getBeginTime()); | ||||
| 						if (entry != null) | ||||
| 							do { | ||||
| 								for (IEvent evt : entry.getValue()) { | ||||
| 								for (IEvent evt : entry.events) { | ||||
| 									if (evt instanceof ITxEvent && (evt.getKind() == EventKind.BEGIN | ||||
| 											|| evt.getKind() == EventKind.SINGLE)) { | ||||
| 										transaction = ((ITxEvent) evt).getTransaction(); | ||||
| @@ -866,7 +867,7 @@ public class WaveformView implements IWaveformView { | ||||
| 									} | ||||
| 								} | ||||
| 								if (transaction == null) | ||||
| 									entry = selectedWaveform.waveform.getEvents().higherEntry(entry.getKey()); | ||||
| 									entry = selectedWaveform.waveform.getEvents().higherEntry(entry.timestamp); | ||||
| 							} while (entry != null && transaction == null); | ||||
| 					} | ||||
| 				} else if (direction == GotoDirection.PREV) { | ||||
| @@ -883,11 +884,11 @@ public class WaveformView implements IWaveformView { | ||||
| 						} | ||||
| 					} | ||||
| 					if (transaction == null) { | ||||
| 						Entry<Long, IEvent[]> entry = selectedWaveform.waveform.getEvents() | ||||
| 						EventEntry entry = selectedWaveform.waveform.getEvents() | ||||
| 								.lowerEntry(currentTxSelection.getBeginTime()); | ||||
| 						if (entry != null) | ||||
| 							do { | ||||
| 								for (IEvent evt : Lists.reverse(Arrays.asList(entry.getValue()))) { | ||||
| 								for (IEvent evt : Lists.reverse(Arrays.asList(entry.events))) { | ||||
| 									if (evt instanceof ITxEvent && (evt.getKind() == EventKind.BEGIN | ||||
| 											|| evt.getKind() == EventKind.SINGLE)) { | ||||
| 										transaction = ((ITxEvent) evt).getTransaction(); | ||||
| @@ -895,7 +896,7 @@ public class WaveformView implements IWaveformView { | ||||
| 									} | ||||
| 								} | ||||
| 								if (transaction == null) | ||||
| 									entry = selectedWaveform.waveform.getEvents().lowerEntry(entry.getKey()); | ||||
| 									entry = selectedWaveform.waveform.getEvents().lowerEntry(entry.timestamp); | ||||
| 							} while (entry != null && transaction == null); | ||||
| 					} | ||||
| 				} | ||||
| @@ -958,14 +959,14 @@ public class WaveformView implements IWaveformView { | ||||
| 			return; | ||||
| 		TrackEntry sel = currentWaveformSelection.get(0); | ||||
| 		long time = getCursorTime(); | ||||
| 		IEventList<Long, ?> map = null; | ||||
| 		IEventList map = null; | ||||
| 		if (sel.waveform.getType() == WaveformType.TRANSACTION || sel.waveform.getType() == WaveformType.SIGNAL) { | ||||
| 			map = sel.waveform.getEvents(); | ||||
| 		} | ||||
| 		if (map != null) { | ||||
| 			Entry<Long, ?> entry = direction == GotoDirection.PREV ? map.lowerEntry(time) : map.higherEntry(time); | ||||
| 			EventEntry entry = direction == GotoDirection.PREV ? map.lowerEntry(time) : map.higherEntry(time); | ||||
| 			if (entry != null) { | ||||
| 				time = entry.getKey(); | ||||
| 				time = entry.timestamp; | ||||
| 				setCursorTime(time); | ||||
| 				waveformCanvas.reveal(time); | ||||
| 				waveformCanvas.redraw(); | ||||
|   | ||||
| @@ -26,7 +26,6 @@ import java.util.zip.GZIPInputStream; | ||||
| import com.google.common.collect.Iterables; | ||||
| import com.minres.scviewer.database.BitVector; | ||||
| import com.minres.scviewer.database.DoubleVal; | ||||
| import com.minres.scviewer.database.IEvent; | ||||
| import com.minres.scviewer.database.IEventList; | ||||
| import com.minres.scviewer.database.IWaveform; | ||||
| import com.minres.scviewer.database.IWaveformDb; | ||||
| @@ -117,16 +116,16 @@ public class VCDDbLoader implements IWaveformDbLoader, IVCDDatabaseBuilder { | ||||
| 		if(!res) throw new InputFormatException("Could not parse VCD file"); | ||||
| 		// calculate max time of this database | ||||
| 		for(IWaveform waveform:signals) { | ||||
| 			IEventList<Long, IEvent[]> events =waveform.getEvents(); | ||||
| 			IEventList events =waveform.getEvents(); | ||||
| 			if(!events.isEmpty()) | ||||
| 				maxTime= Math.max(maxTime, events.lastKey()); | ||||
| 		} | ||||
| 		// extend signals to have a last value set at max time | ||||
| 		for(IWaveform s:signals){ | ||||
| 			if(s instanceof VCDSignal<?>) { | ||||
| 				IEventList<Long, IEvent[]> events = ((VCDSignal<?>)s).getEvents(); | ||||
| 				IEventList events = ((VCDSignal<?>)s).getEvents(); | ||||
| 				if(events.size()>0 && events.lastKey()<maxTime){ | ||||
| 					Object val = events.lastEntry().getValue(); | ||||
| 					Object val = events.lastEntry().events[0]; | ||||
| 					if(val instanceof BitVector) { | ||||
| 						((VCDSignal<BitVector>)s).addSignalChange(maxTime, (BitVector) val); | ||||
| 					} else if(val instanceof DoubleVal) | ||||
|   | ||||
| @@ -10,8 +10,7 @@ | ||||
|  *******************************************************************************/ | ||||
| package com.minres.scviewer.database.vcd; | ||||
|  | ||||
| import java.util.Map.Entry; | ||||
|  | ||||
| import com.minres.scviewer.database.EventEntry; | ||||
| import com.minres.scviewer.database.EventList; | ||||
| import com.minres.scviewer.database.HierNode; | ||||
| import com.minres.scviewer.database.IEvent; | ||||
| @@ -27,7 +26,7 @@ public class VCDSignal<T extends IEvent> extends HierNode implements IWaveform { | ||||
|  | ||||
| 	private final int width; | ||||
|  | ||||
| 	private IEventList<Long, IEvent[]> values; | ||||
| 	private IEventList values; | ||||
| 	 | ||||
| 	public VCDSignal(String name) { | ||||
| 		this(0, name, 1); | ||||
| @@ -42,7 +41,7 @@ public class VCDSignal<T extends IEvent> extends HierNode implements IWaveform { | ||||
| 		fullName=name; | ||||
| 		this.id=id; | ||||
| 		this.width=width; | ||||
| 		this.values=new EventList<>(); | ||||
| 		this.values=new EventList(); | ||||
| 	} | ||||
|  | ||||
| 	public VCDSignal(VCDSignal<T> o, int id, String name) { | ||||
| @@ -80,7 +79,7 @@ public class VCDSignal<T extends IEvent> extends HierNode implements IWaveform { | ||||
| 	} | ||||
| 	 | ||||
| 	@Override | ||||
| 	public IEventList<Long, IEvent[]> getEvents() { | ||||
| 	public IEventList getEvents() { | ||||
| 		return values; | ||||
| 	} | ||||
|  | ||||
| @@ -91,11 +90,11 @@ public class VCDSignal<T extends IEvent> extends HierNode implements IWaveform { | ||||
|  | ||||
|     @Override | ||||
|     public IEvent[] getEventsBeforeTime(Long time) { | ||||
|     	Entry<Long, IEvent[]> e = values.floorEntry(time); | ||||
|     	EventEntry e = values.floorEntry(time); | ||||
|     	if(e==null) | ||||
|     		return new IEvent[] {}; | ||||
|     	else | ||||
|     		return values.floorEntry(time).getValue(); | ||||
|     		return values.floorEntry(time).events; | ||||
|     } | ||||
|  | ||||
| 	@Override | ||||
|   | ||||
| @@ -10,3 +10,4 @@ Export-Package: com.minres.scviewer.database, | ||||
| Bundle-ActivationPolicy: lazy | ||||
| Service-Component: OSGI-INF/component.xml,OSGI-INF/component2.xml | ||||
| Automatic-Module-Name: com.minres.scviewer.database | ||||
| Require-Bundle: org.eclipse.collections;bundle-version="10.4.0" | ||||
|   | ||||
| @@ -0,0 +1,28 @@ | ||||
| package com.minres.scviewer.database; | ||||
|  | ||||
| public class EventEntry implements Comparable<EventEntry>{ | ||||
| 	public long timestamp; // unsigned | ||||
| 	public IEvent[] events = null; | ||||
| 	 | ||||
| 	 | ||||
| 	public EventEntry(long timestamp) { | ||||
| 		this.timestamp = timestamp; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	public EventEntry(long timestamp, IEvent[] events) { | ||||
| 		this.timestamp = timestamp; | ||||
| 		this.events = events; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	@Override | ||||
| 	public int compareTo(EventEntry o) { | ||||
| 		return Long.compareUnsigned(timestamp, o.timestamp); | ||||
| 	} | ||||
| 	 | ||||
| 	@Override | ||||
| 	public String toString() { | ||||
| 		return String.format("e.%d@%d", events.length,timestamp); | ||||
| 	} | ||||
| } | ||||
| @@ -1,100 +1,196 @@ | ||||
| package com.minres.scviewer.database; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collection; | ||||
| import java.util.Map.Entry; | ||||
| import java.util.NavigableMap; | ||||
| import java.util.TreeMap; | ||||
| import java.util.Collections; | ||||
|  | ||||
| public class EventList<K,V>  implements IEventList<K,V>{ | ||||
| public class EventList  implements IEventList { | ||||
|  | ||||
| 	NavigableMap<K,V> backing ; | ||||
| 	ArrayList<EventEntry> store = new ArrayList<>(); | ||||
| 	int start = 0; | ||||
| 	int end = store.size(); | ||||
| 	boolean unmodifiable = false; | ||||
| 			 | ||||
| 	public class Iterator implements java.util.Iterator<EventEntry> { | ||||
| 		 | ||||
| 		EventList list; | ||||
| 		 | ||||
| 		private int pos; | ||||
| 		 | ||||
| 		public Iterator(EventList list) { | ||||
| 			this.list=list; | ||||
| 			this.pos=-1; | ||||
| 		} | ||||
|  | ||||
| 		@Override | ||||
| 		public boolean hasNext() { | ||||
| 			return pos<(list.end-1); | ||||
| 		} | ||||
|  | ||||
| 		@Override | ||||
| 		public EventEntry next() { | ||||
| 			if(hasNext()) { | ||||
| 				pos++; | ||||
| 				return list.store.get(pos); | ||||
| 			} else | ||||
| 				return null; | ||||
| 		} | ||||
|  | ||||
| 		@Override | ||||
| 		public void remove() { | ||||
| 			list.store.remove(pos); | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| 	 | ||||
| 	public EventList() { | ||||
| 		backing=new TreeMap<>(); | ||||
| 	} | ||||
|  | ||||
| 	public EventList(NavigableMap<K, V> subMap) { | ||||
| 		backing=subMap; | ||||
| 	private EventList(ArrayList<EventEntry> store , int start, int end) { | ||||
| 		this.store=store; | ||||
| 		this.start=start; | ||||
| 		this.end=end; | ||||
| 		this.unmodifiable=true; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public Entry<K, V> floorEntry(K key) { | ||||
| 		return backing.floorEntry(key); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public Entry<K, V> ceilingEntry(K key) { | ||||
| 		return backing.ceilingEntry(key); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public Entry<K, V> firstEntry() { | ||||
| 		return  backing.firstEntry(); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public Entry<K, V> lastEntry() { | ||||
| 		return backing.lastEntry(); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public V get(K key) { | ||||
| 		return backing.get(key); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public Entry<K, V> higherEntry(K key) { | ||||
| 		return backing.higherEntry(key); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public Entry<K, V> lowerEntry(K key) { | ||||
| 		return backing.lowerEntry(key); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public IEventList<K, V> subMap(K key, boolean b, K key2, boolean c) { | ||||
| 		return new EventList<K,V>( backing.subMap(key, b, key2, c)); | ||||
| 	public IEventList subMap(long from, boolean includeFrom, long to) { | ||||
| 		//the index of the first element greater than the key, or list.size() | ||||
| 		int beginIndex = Collections.binarySearch(store, new EventEntry(from)); | ||||
| 		int startIndex = beginIndex < 0? -(beginIndex + 1): beginIndex; | ||||
| 		int endIndex = Collections.binarySearch(store, new EventEntry(to)); | ||||
| 		endIndex = endIndex < 0? -(endIndex + 1): endIndex+1; | ||||
| 		if(beginIndex>0 && !includeFrom) | ||||
| 			return new EventList(store, startIndex+1, endIndex); | ||||
| 		else | ||||
| 			return new EventList(store, startIndex, endIndex); | ||||
| 	} | ||||
| 	 | ||||
| 	@Override | ||||
| 	public int size() { | ||||
| 		return backing.size(); | ||||
| 		return end-start; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public Collection<K> keys() { | ||||
| 		return backing.keySet(); | ||||
| 	public boolean containsKey(long key) { | ||||
| 		int index = Collections.binarySearch(store, new EventEntry(key)); | ||||
| 		return index>=0 && index>=start && index<end; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public Collection<V> values() { | ||||
| 		return backing.values(); | ||||
| 	public IEvent[] get(long key) { | ||||
| 		int index = Collections.binarySearch(store, new EventEntry(key)); | ||||
| 		if(index<0) return null; | ||||
| 		return index>=start && index<end? store.get(index).events: null; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public boolean containsKey(K key) { | ||||
| 		return backing.containsKey(key); | ||||
| 	public IEvent[] put(long key, IEvent[] value) { | ||||
| 		if(unmodifiable) throw new UnsupportedOperationException(); | ||||
| 		EventEntry e = new EventEntry(key, value); | ||||
| 		if(store.size()==0 || store.get(store.size()-1).timestamp < key) { | ||||
| 			store.add(e); | ||||
| 		} else { | ||||
| 			int index = Collections.binarySearch(store, new EventEntry(key)); | ||||
| 	        // < 0 if element is not in the list, see Collections.binarySearch | ||||
| 	        if (index < 0) { | ||||
| 	        	index = -(index + 1); | ||||
| 		        store.add(index, e); | ||||
| 	        } else {  | ||||
| 	            // Insertion index is index of existing element, to add new element behind it increase index | ||||
| 	        	store.set(index, e); | ||||
| 	        } | ||||
| 		} | ||||
| 		end=store.size(); | ||||
|         return e.events; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public V put(K key, V value) { | ||||
| 		return backing.put(key, value); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public Collection<Entry<K, V>> entrySet() { | ||||
| 		return backing.entrySet(); | ||||
| 	public Collection<EventEntry> entrySet() { | ||||
| 		if(start != 0 || end != store.size()) | ||||
| 			return Collections.unmodifiableList(store.subList(start, end)); | ||||
| 		else | ||||
| 			return Collections.unmodifiableList(store); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public boolean isEmpty() { | ||||
| 		return backing.isEmpty(); | ||||
| 		return start==end || store.isEmpty(); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public K lastKey() { | ||||
| 		return backing.lastKey(); | ||||
| 	public long firstKey() { | ||||
| 		return store.get(start).timestamp; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public long lastKey() { | ||||
| 		return store.get(end-1).timestamp; | ||||
| 	} | ||||
|  | ||||
| 	// Navigable map functions | ||||
| 	@Override | ||||
| 	public EventEntry firstEntry() { | ||||
| 		return  store.get(start); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public EventEntry lastEntry() { | ||||
| 		return store.get(end-1); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public EventEntry floorEntry(long key) { | ||||
| 		int index = Collections.binarySearch(store, new EventEntry(key)); | ||||
|     	if(index==-1) return null; | ||||
|         // < 0 if element is not in the list, see Collections.binarySearch | ||||
|         if (index < 0) { | ||||
|         	index = -(index + 2); | ||||
|         } | ||||
|         if(index>=end) | ||||
|         	return store.get(end-1); | ||||
| 		return index<start? null: store.get(index); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public EventEntry ceilingEntry(long key) { | ||||
| 		int index = Collections.binarySearch(store, new EventEntry(key)); | ||||
|         // < 0 if element is not in the list, see Collections.binarySearch | ||||
|         if (index < 0)  | ||||
|         	index = -(index + 1); | ||||
|         if(index<start) | ||||
|         	return store.get(start); | ||||
| 		return index>=end? null: store.get(index); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public EventEntry lowerEntry(long key) { | ||||
| 		int index = Collections.binarySearch(store, new EventEntry(key)); | ||||
|         // < 0 if element is not in the list, see Collections.binarySearch | ||||
|         if (index < 0)  | ||||
|         	index = -(index + 1); | ||||
|     	index--; | ||||
|         if(index>=end) | ||||
|         	return store.get(end-1); | ||||
| 		return index>=end || index<start ?null:store.get(index); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public EventEntry higherEntry(long key) { | ||||
| 		int index = Collections.binarySearch(store, new EventEntry(key)); | ||||
|         // < 0 if element is not in the list, see Collections.binarySearch | ||||
|         if (index < 0)  | ||||
|         	index = -(index + 1); | ||||
|         else | ||||
|         	index++; | ||||
|         if(index<start) | ||||
|         	return store.get(start); | ||||
| 		return index>=end || index<start ?null:store.get(index); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public java.util.Iterator<EventEntry> iterator() { | ||||
| 		return new Iterator(this); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1,40 +1,84 @@ | ||||
| package com.minres.scviewer.database; | ||||
|  | ||||
| import java.util.Collection; | ||||
| import java.util.Map.Entry; | ||||
|  | ||||
| public interface IEventList<K,V> { | ||||
|  | ||||
| 	Entry<K, V> floorEntry(K key); | ||||
|  | ||||
| 	Entry<K, V> ceilingEntry(K key); | ||||
|  | ||||
| 	Entry<K, V> firstEntry(); | ||||
|  | ||||
| 	Entry<K, V> lastEntry(); | ||||
|  | ||||
| 	V get(K key); | ||||
|  | ||||
| 	Entry<K, V> higherEntry(K key); | ||||
|  | ||||
| 	Entry<K, V> lowerEntry(K key); | ||||
|  | ||||
| 	IEventList<K, V> subMap(K key, boolean b, K key2, boolean c); | ||||
| public interface IEventList extends Iterable<EventEntry> { | ||||
|  | ||||
| 	int size(); | ||||
|  | ||||
| 	Collection<K> keys(); | ||||
| 	Collection<EventEntry> entrySet(); | ||||
|  | ||||
| 	Collection<V> values(); | ||||
| 	boolean containsKey(long key); | ||||
|  | ||||
| 	boolean containsKey(K key); | ||||
| 	IEvent[] get(long key); | ||||
|  | ||||
| 	V put(K key, V value); | ||||
| 	IEvent[] put(long key, IEvent[] value); | ||||
|  | ||||
| 	Collection<Entry<K, V>> entrySet(); | ||||
| 	long firstKey(); | ||||
|  | ||||
| 	long lastKey(); | ||||
|  | ||||
| 	boolean isEmpty(); | ||||
|  | ||||
| 	K lastKey(); | ||||
| 	/** | ||||
| 	 * Returns a key-value mapping associated with the greatest key less  | ||||
| 	 * than or equal to the given key, or null if there is no such key. | ||||
| 	 *  | ||||
| 	 * @param key | ||||
| 	 * @return | ||||
| 	 */ | ||||
| 	EventEntry floorEntry(long key); | ||||
| 	/** | ||||
| 	 * Returns a key-value mapping associated with the least key greater  | ||||
| 	 * than or equal to the given key, or null if there is no such key. | ||||
| 	 *  | ||||
| 	 * @param key | ||||
| 	 * @return | ||||
| 	 */ | ||||
| 	EventEntry ceilingEntry(long key); | ||||
| 	/** | ||||
| 	 * Returns a key-value mapping associated with the least key in this map, | ||||
| 	 * or null if the map is empty. | ||||
| 	 *  | ||||
| 	 * @return | ||||
| 	 */ | ||||
| 	EventEntry firstEntry(); | ||||
| 	/** | ||||
| 	 * Returns a key-value mapping associated with the least key in this map, | ||||
| 	 * or null if the map is empty. | ||||
| 	 *  | ||||
| 	 * @return | ||||
| 	 */ | ||||
| 	EventEntry lastEntry(); | ||||
| 	/** | ||||
| 	 * Returns a key-value mapping associated with the least key strictly greater | ||||
| 	 * than the given key, or null if there is no such key. | ||||
| 	 *  | ||||
| 	 * @param key | ||||
| 	 * @return | ||||
| 	 */ | ||||
| 	EventEntry higherEntry(long key); | ||||
| 	/** | ||||
| 	 * Returns a key-value mapping associated with the greatest key strictly less  | ||||
| 	 * than the given key, or null if there is no such key. | ||||
| 	 *  | ||||
| 	 * @param key | ||||
| 	 * @return | ||||
| 	 */ | ||||
| 	EventEntry lowerEntry(long key); | ||||
|     /** | ||||
|      * Returns a view of the portion of this map whose keys range from | ||||
|      * {@code fromKey} to {@code toKey}.  If {@code fromKey} and | ||||
|      * {@code toKey} are equal, the returned map is empty unless | ||||
|      * {@code fromInclusive} is true.  The | ||||
|      * returned map is backed by this map, so changes in the returned map are | ||||
|      * reflected in this map, and vice-versa.  The returned map supports all | ||||
|      * optional map operations that this map supports. | ||||
|      * | ||||
|      * @param fromKey low endpoint of the keys in the returned map | ||||
|      * @param fromInclusive {@code true} if the low endpoint | ||||
|      *        is to be included in the returned view | ||||
|      * @param toKey high endpoint of the keys in the returned map (inclusive) | ||||
|      */ | ||||
| 	IEventList subMap(long key, boolean b, long key2); | ||||
| 	 | ||||
| } | ||||
|   | ||||
| @@ -39,7 +39,7 @@ public interface IWaveform extends IHierNode { | ||||
| 	 * | ||||
| 	 * @return the events | ||||
| 	 */ | ||||
| 	public IEventList<Long, IEvent[]> getEvents(); | ||||
| 	public IEventList getEvents(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets the events at time. | ||||
|   | ||||
| @@ -40,7 +40,7 @@ public class WaveformPopupMenuContribution { | ||||
| 				if(elem instanceof TrackEntry) { | ||||
| 					TrackEntry e = (TrackEntry) elem; | ||||
| 					if(e.waveform.getType() == WaveformType.SIGNAL) { | ||||
| 						Object o = e.waveform.getEvents().firstEntry().getValue()[0]; | ||||
| 						Object o = e.waveform.getEvents().firstEntry().events[0]; | ||||
| 						if(checkForDouble && o instanceof DoubleVal)  | ||||
| 							return true; | ||||
| 						else if(o instanceof BitVector && ((BitVector)o).getWidth()>1) | ||||
|   | ||||
| @@ -32,8 +32,8 @@ import org.eclipse.swt.widgets.TableColumn; | ||||
| import org.eclipse.swt.widgets.Text; | ||||
|  | ||||
| import com.minres.scviewer.database.DataType; | ||||
| import com.minres.scviewer.database.EventEntry; | ||||
| import com.minres.scviewer.database.EventKind; | ||||
| import com.minres.scviewer.database.IEvent; | ||||
| import com.minres.scviewer.database.IWaveform; | ||||
| import com.minres.scviewer.database.WaveformType; | ||||
| import com.minres.scviewer.database.tx.ITx; | ||||
| @@ -249,8 +249,10 @@ public class TransactionList extends Composite { | ||||
| 			}catch(SecurityException e){} | ||||
| 			updateThread = new Thread(()-> { | ||||
| 				final ConcurrentHashMap<String, DataType> propNames=new ConcurrentHashMap<>(); | ||||
| 				Collection<IEvent[]> values = stream.getEvents().values(); | ||||
| 				final List<ITx> txList = values.parallelStream().map(Arrays::asList) | ||||
| 				Collection<EventEntry> values = stream.getEvents().entrySet(); | ||||
| 				final List<ITx> txList = values.parallelStream() | ||||
| 						.map(e->e.events) | ||||
| 						.map(Arrays::asList) | ||||
| 						.flatMap(List::stream) | ||||
| 						.filter(evt -> evt.getKind()==EventKind.BEGIN || evt.getKind()==EventKind.SINGLE) | ||||
| 						.map(evt-> { | ||||
|   | ||||
| @@ -815,9 +815,18 @@ public class WaveformViewer implements IFileChangeListener, IPreferenceChangeLis | ||||
| 				String trackentryName = state.get(SELECTED_TRACKENTRY_NAME); | ||||
| 				//get TrackEntry Object based on name and TX Object by id and put into selectionList | ||||
| 				trackEntries.stream().filter(e->trackentryName.equals(e.waveform.getFullName())).forEach(trackEntry -> | ||||
| 				trackEntry.waveform.getEvents().values().stream().filter(Objects::nonNull).forEach(entries->  | ||||
| 				Arrays.stream(entries).filter(e->e instanceof ITxEvent && txId.equals(((ITxEvent)e).getTransaction().getId())).forEach(event -> | ||||
| 				waveformPane.setSelection(new StructuredSelection(new Object[] {((ITxEvent)event).getTransaction(), trackEntry}))))); | ||||
| 					trackEntry.waveform.getEvents().entrySet().stream() | ||||
| 					.map(e->e.events) | ||||
| 					.filter(Objects::nonNull) | ||||
| 					.forEach(entries->  | ||||
| 						Arrays.stream(entries) | ||||
| 						.filter(e->e instanceof ITxEvent && txId.equals(((ITxEvent)e).getTransaction().getId())) | ||||
| 						.forEach(event -> | ||||
| 							waveformPane.setSelection(new StructuredSelection( | ||||
| 									new Object[] {((ITxEvent)event).getTransaction(), trackEntry})) | ||||
| 						) | ||||
| 					) | ||||
| 				); | ||||
| 			} catch (NumberFormatException e) { | ||||
| 			} | ||||
| 		} | ||||
|   | ||||
| @@ -16,13 +16,12 @@ import static org.junit.Assert.assertTrue; | ||||
|  | ||||
| import java.io.File; | ||||
| import java.util.List; | ||||
| import java.util.Map.Entry; | ||||
|  | ||||
| import org.junit.After; | ||||
| import org.junit.Before; | ||||
| import org.junit.Test; | ||||
|  | ||||
| import com.minres.scviewer.database.IEvent; | ||||
| import com.minres.scviewer.database.EventEntry; | ||||
| import com.minres.scviewer.database.IWaveform; | ||||
| import com.minres.scviewer.database.IWaveformDb; | ||||
|  | ||||
| @@ -50,11 +49,11 @@ public class DatabaseServicesTest { | ||||
| 		assertEquals(14,  waves.size()); | ||||
| 		assertEquals(2,  waveformDb.getChildNodes().size()); | ||||
| 		IWaveform bus_data_wave = waves.get(0); | ||||
| 		Entry<Long, IEvent[]> bus_data_entry = bus_data_wave.getEvents().floorEntry(1400000000L); | ||||
| 		assertEquals("01111000", bus_data_entry.getValue()[0].toString()); | ||||
| 		EventEntry bus_data_entry = bus_data_wave.getEvents().floorEntry(1400000000L); | ||||
| 		assertEquals("01111000", bus_data_entry.events[0].toString()); | ||||
| 		IWaveform rw_wave = waves.get(2); | ||||
| 		Entry<Long, IEvent[]> rw_entry = rw_wave.getEvents().floorEntry(2360000000L); | ||||
| 		assertEquals("1", rw_entry.getValue()[0].toString()); | ||||
| 		EventEntry rw_entry = rw_wave.getEvents().floorEntry(2360000000L); | ||||
| 		assertEquals("1", rw_entry.events[0].toString()); | ||||
| 	} | ||||
|  | ||||
| 	@Test | ||||
|   | ||||
| @@ -0,0 +1,198 @@ | ||||
| package com.minres.scviewer.database.test; | ||||
|  | ||||
| import static org.junit.Assert.assertArrayEquals; | ||||
| import static org.junit.Assert.assertEquals; | ||||
| import static org.junit.Assert.assertFalse; | ||||
| import static org.junit.Assert.assertNotNull; | ||||
| import static org.junit.Assert.assertNull; | ||||
| import static org.junit.Assert.assertTrue; | ||||
|  | ||||
| import java.util.stream.Collectors; | ||||
|  | ||||
| import org.junit.Test; | ||||
|  | ||||
| import com.minres.scviewer.database.EventList; | ||||
| import com.minres.scviewer.database.IEvent; | ||||
| import com.minres.scviewer.database.IEventList; | ||||
|  | ||||
| public class EventListTest { | ||||
|  | ||||
| 	EventList createList(int[] times) { | ||||
| 		EventList list = new EventList(); | ||||
| 		for(int time: times) | ||||
| 			list.put(time, new IEvent[] {}); | ||||
| 		return list; | ||||
| 	} | ||||
| 	 | ||||
| 	Long[] getTimestamps(IEventList list) { | ||||
| 		return list.entrySet().stream().map(e->e.timestamp).collect(Collectors.toList()).toArray(new Long[] {}); | ||||
| 	} | ||||
| 	 | ||||
| 	@Test | ||||
| 	public void testInsertion() throws Exception { | ||||
| 		IEventList list = createList(new int[] {5, 7, 3, 6, 2, 0}); | ||||
| 		assertEquals(6, list.size()); | ||||
| 		assertArrayEquals(new Long[]{0L, 2L, 3L, 5L, 6L, 7L}, getTimestamps(list)); | ||||
| 	} | ||||
| 	 | ||||
| 	@Test | ||||
| 	public void testSublist() throws Exception { | ||||
| 		IEventList list = createList(new int[] {5, 7, 3, 8, 2, 0}); | ||||
| 		{ | ||||
| 			IEventList subList = list.subMap(3, true, 5); | ||||
| 			assertEquals(2, subList.size()); | ||||
| 			assertArrayEquals(new Long[]{3L, 5L}, getTimestamps(subList)); | ||||
| 		} { | ||||
| 			IEventList subList = list.subMap(3, false, 5); | ||||
| 			assertEquals(1, subList.size()); | ||||
| 			assertArrayEquals(new Long[]{5L}, getTimestamps(subList)); | ||||
| 		} { | ||||
| 			IEventList subList = list.subMap(4, true, 6); | ||||
| 			assertEquals(1, subList.size()); | ||||
| 			assertArrayEquals(new Long[]{5L}, getTimestamps(subList)); | ||||
| 		} { | ||||
| 			IEventList subList = list.subMap(4, false, 6); | ||||
| 			assertEquals(1, subList.size()); | ||||
| 			assertArrayEquals(new Long[]{5L}, getTimestamps(subList)); | ||||
| 		} { | ||||
| 			IEventList subList = list.subMap(4, true, 9); | ||||
| 			assertEquals(3, subList.size()); | ||||
| 			assertArrayEquals(new Long[]{5L, 7L, 8L}, getTimestamps(subList)); | ||||
| 		} { | ||||
| 			IEventList subList = list.subMap(4, false, 9); | ||||
| 			assertEquals(3, subList.size()); | ||||
| 			assertArrayEquals(new Long[]{5L, 7L, 8L}, getTimestamps(subList)); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	@Test | ||||
| 	public void testEntries() throws Exception { | ||||
| 		IEventList list = createList(new int[] {2, 5, 8, 11}); | ||||
| 		assertEquals(2, list.firstEntry().timestamp); | ||||
| 		assertEquals(11, list.lastEntry().timestamp); | ||||
| 		 | ||||
| 		assertNull(list.floorEntry(1)); | ||||
| 		assertEquals(2, list.floorEntry(2).timestamp); | ||||
| 		assertEquals(2, list.floorEntry(3).timestamp); | ||||
| 		assertEquals(2, list.floorEntry(4).timestamp); | ||||
| 		assertEquals(5, list.floorEntry(5).timestamp); | ||||
| 		assertEquals(5, list.floorEntry(6).timestamp); | ||||
| 		assertEquals(8, list.floorEntry(10).timestamp); | ||||
| 		assertEquals(11, list.floorEntry(11).timestamp); | ||||
| 		assertEquals(11, list.floorEntry(12).timestamp); | ||||
| 		 | ||||
| 		assertEquals(2, list.ceilingEntry(1).timestamp); | ||||
| 		assertEquals(2, list.ceilingEntry(2).timestamp); | ||||
| 		assertEquals(5, list.ceilingEntry(3).timestamp); | ||||
| 		assertEquals(5, list.ceilingEntry(4).timestamp); | ||||
| 		assertEquals(5, list.ceilingEntry(5).timestamp); | ||||
| 		assertEquals(8, list.ceilingEntry(6).timestamp); | ||||
| 		assertEquals(11, list.ceilingEntry(10).timestamp); | ||||
| 		assertEquals(11, list.ceilingEntry(11).timestamp); | ||||
| 		assertNull(list.ceilingEntry(12)); | ||||
|  | ||||
| 		assertNull(list.lowerEntry(1)); | ||||
| 		assertNull(list.lowerEntry(2)); | ||||
| 		assertEquals(2, list.lowerEntry(3).timestamp); | ||||
| 		assertEquals(2, list.lowerEntry(4).timestamp); | ||||
| 		assertEquals(2, list.lowerEntry(5).timestamp); | ||||
| 		assertEquals(5, list.lowerEntry(6).timestamp); | ||||
| 		assertEquals(8, list.lowerEntry(10).timestamp); | ||||
| 		assertEquals(8, list.lowerEntry(11).timestamp); | ||||
| 		assertEquals(11, list.lowerEntry(12).timestamp); | ||||
| 		 | ||||
| 		assertEquals(2, list.higherEntry(1).timestamp); | ||||
| 		assertEquals(5, list.higherEntry(2).timestamp); | ||||
| 		assertEquals(5, list.higherEntry(3).timestamp); | ||||
| 		assertEquals(5, list.higherEntry(4).timestamp); | ||||
| 		assertEquals(8, list.higherEntry(5).timestamp); | ||||
| 		assertEquals(8, list.higherEntry(6).timestamp); | ||||
| 		assertEquals(11, list.higherEntry(10).timestamp); | ||||
| 		assertNull(list.higherEntry(11)); | ||||
| 		assertNull(list.higherEntry(12)); | ||||
| 	} | ||||
|  | ||||
| 	@Test | ||||
| 	public void testSubListEntries() throws Exception { | ||||
| 		IEventList fullList = createList(new int[] {2, 5, 8, 11}); | ||||
| 		IEventList list = fullList.subMap(5, true, 8); | ||||
|  | ||||
| 		assertEquals(5, list.firstEntry().timestamp); | ||||
| 		assertEquals(8, list.lastEntry().timestamp); | ||||
| 		 | ||||
| 		assertNull(list.floorEntry(1)); | ||||
| 		assertNull(list.floorEntry(2)); | ||||
| 		assertNull(list.floorEntry(3)); | ||||
| 		assertNull(list.floorEntry(4)); | ||||
| 		assertEquals(5, list.floorEntry(5).timestamp); | ||||
| 		assertEquals(5, list.floorEntry(6).timestamp); | ||||
| 		assertEquals(8, list.floorEntry(10).timestamp); | ||||
| 		assertEquals(8, list.floorEntry(11).timestamp); | ||||
| 		assertEquals(8, list.floorEntry(12).timestamp); | ||||
| 		 | ||||
| 		assertEquals(5, list.ceilingEntry(1).timestamp); | ||||
| 		assertEquals(5, list.ceilingEntry(2).timestamp); | ||||
| 		assertEquals(5, list.ceilingEntry(3).timestamp); | ||||
| 		assertEquals(5, list.ceilingEntry(4).timestamp); | ||||
| 		assertEquals(5, list.ceilingEntry(5).timestamp); | ||||
| 		assertEquals(8, list.ceilingEntry(6).timestamp); | ||||
| 		assertEquals(8, list.ceilingEntry(8).timestamp); | ||||
| 		assertNull(list.ceilingEntry(10)); | ||||
| 		assertNull(list.ceilingEntry(11)); | ||||
| 		assertNull(list.ceilingEntry(12)); | ||||
|  | ||||
| 		assertNull(list.lowerEntry(1)); | ||||
| 		assertNull(list.lowerEntry(2)); | ||||
| 		assertNull(list.lowerEntry(3)); | ||||
| 		assertNull(list.lowerEntry(4)); | ||||
| 		assertNull(list.lowerEntry(5)); | ||||
| 		assertEquals(5, list.lowerEntry(6).timestamp); | ||||
| 		assertEquals(8, list.lowerEntry(10).timestamp); | ||||
| 		assertEquals(8, list.lowerEntry(11).timestamp); | ||||
| 		assertEquals(8, list.lowerEntry(12).timestamp); | ||||
| 		 | ||||
| 		assertEquals(5, list.higherEntry(1).timestamp); | ||||
| 		assertEquals(5, list.higherEntry(2).timestamp); | ||||
| 		assertEquals(5, list.higherEntry(3).timestamp); | ||||
| 		assertEquals(5, list.higherEntry(4).timestamp); | ||||
| 		assertEquals(8, list.higherEntry(5).timestamp); | ||||
| 		assertEquals(8, list.higherEntry(6).timestamp); | ||||
| 		assertNull(list.higherEntry(8)); | ||||
| 		assertNull(list.higherEntry(10)); | ||||
| 		assertNull(list.higherEntry(11)); | ||||
| 		assertNull(list.higherEntry(12)); | ||||
| 	} | ||||
| 	 | ||||
| 	@Test | ||||
| 	public void testInterface() throws Exception { | ||||
| 		EventList emptyList = new EventList(); | ||||
| 		IEventList populatedList = createList(new int[] {0, 2, 3, 5, 6, 7}); | ||||
| 		assertEquals(0, emptyList.size()); | ||||
| 		assertEquals(6, populatedList.size()); | ||||
| 		assertTrue(emptyList.isEmpty()); | ||||
| 		assertFalse(populatedList.isEmpty()); | ||||
| 		assertFalse(emptyList.containsKey(5)); | ||||
| 		assertTrue(populatedList.containsKey(5)); | ||||
| 		assertFalse(populatedList.containsKey(8)); | ||||
| 		assertNull(emptyList.get(5)); | ||||
| 		assertNotNull(populatedList.get(5)); | ||||
| 		assertNull(populatedList.get(8)); | ||||
| 	} | ||||
|  | ||||
| 	@Test | ||||
| 	public void testInterfaceSublist() throws Exception { | ||||
| 		IEventList fullList = createList(new int[] {0, 2, 3, 5, 6, 7}); | ||||
| 		IEventList emptyList = fullList.subMap(3, false, 4); | ||||
| 		IEventList populatedList = fullList.subMap(2, true, 6); | ||||
| 		assertEquals(0, emptyList.size()); | ||||
| 		assertEquals(4, populatedList.size()); | ||||
| 		assertTrue(emptyList.isEmpty()); | ||||
| 		assertFalse(populatedList.isEmpty()); | ||||
| 		assertFalse(emptyList.containsKey(5)); | ||||
| 		assertTrue(populatedList.containsKey(5)); | ||||
| 		assertFalse(populatedList.containsKey(8)); | ||||
| 		assertNull(emptyList.get(5)); | ||||
| 		assertNotNull(populatedList.get(5)); | ||||
| 		assertNull(populatedList.get(7)); | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user