/**
* Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Eclipse Public License (EPL).
* Please see the license.txt included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
/*
* Created on Jun 23, 2006
* @author Fabio
*/
package org.python.pydev.debug.model;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IVariable;
import org.python.pydev.core.log.Log;
/**
* This class should check for value modifications in the stacks while debugging.
* Its public interface is completely synchronized.
*
* @author Fabio
*/
public class ValueModificationChecker {
/**
* compares stack frames to check for modified variables (and mark them as modified in the new stack)
*
* @param newFrame the new frame
* @param oldFrame the old frame
*/
public void verifyVariablesModified(IVariable[] newFrameVariables, IVariable[] oldVariables) {
if (oldVariables == null) {
return; //All variables are new, so, no point in notifying it.
}
PyVariable newVariable = null;
try {
HashMap<String, IVariable> map = new HashMap<String, IVariable>();
for (IVariable var : oldVariables) {
map.put(var.getName(), var);
}
Map<String, IVariable> variablesAsMap = map;
//we have to check for each new variable
for (int i = 0; i < newFrameVariables.length; i++) {
newVariable = (PyVariable) newFrameVariables[i];
PyVariable oldVariable = (PyVariable) variablesAsMap.get(newVariable.getName());
if (oldVariable != null) {
boolean equals = newVariable.getValueString().equals(oldVariable.getValueString());
//if it is not equal, it was modified
newVariable.setModified(!equals);
} else { //it didn't exist before...
newVariable.setModified(true);
}
}
} catch (DebugException e) {
Log.log(e);
}
}
/**
* Thread id --> stack id --> stack
*/
private Map<String, Map<String, PyStackFrame>> cache = new HashMap<String, Map<String, PyStackFrame>>();
private Object lock = new Object();
/**
* Synched access to verify the modification
* @param frame the frame that we're checking
* @param newFrameVariables the variables that were added to the stack.
*/
public synchronized void verifyModified(PyStackFrame frame, IVariable[] newFrameVariables) {
synchronized (lock) {
Map<String, PyStackFrame> threadIdCache = cache.get(frame.getThreadId());
if (threadIdCache == null) {
threadIdCache = new HashMap<String, PyStackFrame>();
cache.put(frame.getThreadId(), threadIdCache);
}
PyStackFrame cacheFrame = threadIdCache.get(frame.getId());
if (cacheFrame == null) {
threadIdCache.put(frame.getId(), frame);
return;
}
//not null
if (cacheFrame == frame) { //if is same, it has already been checked.
return;
}
//if it is not the same, we have to check it and mark it as the new frame.
verifyVariablesModified(newFrameVariables, cacheFrame.getInternalVariables());
threadIdCache.put(frame.getId(), frame);
}
}
/**
* Removes from the cache all the threads that are not present in the threads passed.
*/
public synchronized void onlyLeaveThreads(PyThread[] threads) {
synchronized (lock) {
HashSet<String> ids = new HashSet<String>();
for (PyThread thread : threads) {
ids.add(thread.getId());
}
//Must iterate in a copy.
Set<String> keySet = new HashSet<String>(cache.keySet());
for (String id : keySet) {
if (!ids.contains(id)) {
cache.remove(id);
}
}
}
}
}