2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
6 * The Java Pathfinder core (jpf-core) platform is licensed under the
7 * Apache License, Version 2.0 (the "License"); you may not use this file except
8 * in compliance with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0.
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 package gov.nasa.jpf.util;
21 import gov.nasa.jpf.ListenerAdapter;
22 import gov.nasa.jpf.search.Search;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.Iterator;
27 import java.util.List;
30 * a generic, listener- created trace over property specific operations
32 * we could register this as a listener itself, but since it usually is used from
33 * a listener, we might as well just delegate from there
35 public class Trace<T> extends ListenerAdapter implements Iterable<T> {
37 TraceElement<T> lastElement;
38 TraceElement<T> lastTransition;
40 // for HeuristicSearches. Ok, that's braindead but at least no need for cloning
41 HashMap<Integer,TraceElement<T>> storedTransition;
44 // iterator that traverses the trace LIFO, i.e. starting from the last T
45 class TraceIterator implements Iterator<T> {
54 public boolean hasNext () {
62 cur = cur.prevElement;
70 public void remove () {
71 throw new UnsupportedOperationException("TraceElement removal not supported");
76 public Iterator<T> iterator() {
77 return new TraceIterator();
80 public void addOp (T o){
81 TraceElement<T> op = new TraceElement<T>(o);
83 if (lastElement == null){
86 assert lastElement.stateId == 0;
88 op.prevElement = lastElement;
93 public void removeLastOp() {
94 if (lastElement != null){
95 lastElement = lastElement.prevElement;
99 public T getLastOp() {
100 if (lastElement != null) {
101 return lastElement.getOp();
109 for (TraceElement<T> te = lastElement; te != null; te = te.prevElement) {
116 public List<T> getOps () {
117 // this is a rather braindead way around the limitation that we can't explicitly
118 // create an T[] array object
120 ArrayList<T> list = new ArrayList<T>();
122 for (TraceElement<T> te = lastElement; te != null; te = te.prevElement) {
123 list.add(te.getOp());
127 for (int i=0, j=list.size()-1; i<j; i++, j--) {
129 list.set(j, list.get(i));
137 public void stateAdvanced (Search search) {
138 if (search.isNewState() && (lastElement != null)) {
139 int stateId = search.getStateId();
141 for (TraceElement<T> op=lastElement; op != null; op=op.prevElement) {
142 assert op.stateId == 0;
144 op.stateId = stateId;
147 lastElement.prevTransition = lastTransition;
148 lastTransition = lastElement;
155 public void stateBacktracked (Search search){
156 int stateId = search.getStateId();
157 while ((lastTransition != null) && (lastTransition.stateId > stateId)){
158 lastTransition = lastTransition.prevTransition;
164 public void stateStored (Search search) {
165 if (storedTransition == null){
166 storedTransition = new HashMap<Integer,TraceElement<T>>();
169 // always called after stateAdvanced
170 storedTransition.put(search.getStateId(), lastTransition);
174 public void stateRestored (Search search) {
175 int stateId = search.getStateId();
176 TraceElement<T> op = storedTransition.get(stateId);
179 storedTransition.remove(stateId); // not strictly required, but we don't come back
184 public Trace clone() {
185 TraceElement<T> e0 = null, eLast = null;
187 for (TraceElement<T> e = lastElement; e != null; e = e.prevElement){
188 TraceElement<T> ec = e.clone();
191 eLast.prevElement = ec;
198 Trace<T> t = new Trace<T>();