created mirror
This commit is contained in:
commit
6764738d92
600 files changed
+87187
No files matched your search
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
ZZCacheDimension.java
|
||||
*
|
||||
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
|
||||
*
|
||||
* You may use and distribute under the terms of either the GNU Lesser
|
||||
* General Public License, either version 2 of the license or,
|
||||
* at your choice, any later version. Alternatively, you may use and
|
||||
* distribute under the terms of the XPL.
|
||||
*
|
||||
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
|
||||
* the licenses.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
|
||||
* file for more details.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Written by Tuomas Lukka
|
||||
*/
|
||||
package org.gzigzag;
|
||||
import java.util.*;
|
||||
|
||||
/** Dimension-centric implementation of a locally
|
||||
* cached dimension.
|
||||
* This class may be used as a cache to
|
||||
* a dimension stored on disk, and includes facilities for tracking
|
||||
* the changes.
|
||||
* XXX Look into replacing hashtable with a more memory-saving constructions?
|
||||
* <p>
|
||||
* This, uglily, shares some code with ZZLocalDimension but making
|
||||
* this an inheritance relationship would have been difficult, and
|
||||
* the point is to keep ZZLocalDimension a truly simple basic
|
||||
* example implementation of a dimension.
|
||||
* <p>
|
||||
* The mechanism for the undolist is quite interesting:
|
||||
* we save each connect / disconnect operation with the two cells,
|
||||
* so we know the inverse of each operation.
|
||||
* We can then, at commit time, build a hash table by taking the first
|
||||
* operation and seeing if it cancels an earlier operation (undolist does
|
||||
* commits in reverse order) and if it does, we do nothing.
|
||||
* This allows the user to move the cursor without wasting storage on all
|
||||
* positions.
|
||||
* Interestingly, although we store all connections bidirectionally as
|
||||
* connect/disconnect pairs in the undolist, we cannot save them like that
|
||||
* after compression: they must be saved as single-sided disconnects and
|
||||
* pair connects.
|
||||
*/
|
||||
public class ZZCacheDimension extends ZZDimension implements ZZDimStorer {
|
||||
public static final String rcsid = "$Id: ZZCacheDimension.java,v 1.11 2001/02/23 08:33:37 ajk Exp $";
|
||||
public static final boolean dbg = true;
|
||||
final static void p(String s) { if(dbg) System.out.println(s); }
|
||||
final static void pa(String s) { System.out.println(s); }
|
||||
|
||||
UndoList undo;
|
||||
public void setUndoList(UndoList l) { undo = l; }
|
||||
|
||||
protected boolean readonly;
|
||||
|
||||
public ZZCacheDimension() { this(false); }
|
||||
public ZZCacheDimension(boolean readonly) {
|
||||
this.readonly = readonly;
|
||||
}
|
||||
|
||||
/** Connections to the positive direction. */
|
||||
Hashtable cp = new Hashtable();
|
||||
/** Connections to the negative direction. */
|
||||
Hashtable cm = new Hashtable();
|
||||
|
||||
/** The earlier connection on each cell's poswards or negwards
|
||||
* direction at commit time.
|
||||
* This list is created at commit time by reversing all operations
|
||||
* so we can then compare these values and the current values to
|
||||
* see which have changed.
|
||||
* Hmm.. do we really even need comm?
|
||||
*/
|
||||
Hashtable comp;
|
||||
Hashtable comm;
|
||||
|
||||
/** A null marker for the hashtables. */
|
||||
static final Object nolla = new Object();
|
||||
|
||||
synchronized public void startCommit() {
|
||||
if (readonly) throw new ZZError("readonly dimension");
|
||||
comp = new Hashtable();
|
||||
comm = new Hashtable();
|
||||
}
|
||||
|
||||
synchronized public void endCommit(ZZDimStorer sto) {
|
||||
if (readonly) throw new ZZError("readonly dimension");
|
||||
for(Enumeration e = comp.keys();
|
||||
e.hasMoreElements();) {
|
||||
String id = (String)e.nextElement();
|
||||
Object oidto = comp.get(id);
|
||||
String idto = (oidto == nolla ? null : (String)oidto);
|
||||
String idwasto = (String)cp.get(id);
|
||||
// If it's the same, then nevermind.
|
||||
if(idto == idwasto || (
|
||||
idto != null && idto.equals(idwasto)))
|
||||
continue;
|
||||
if(idwasto != null)
|
||||
sto.storeConnect(id, idwasto);
|
||||
else
|
||||
sto.storeDisconnect(id, 1);
|
||||
|
||||
}
|
||||
for(Enumeration e = comm.keys();
|
||||
e.hasMoreElements();) {
|
||||
String id = (String)e.nextElement();
|
||||
Object oidto = comm.get(id);
|
||||
String idto = (oidto == nolla ? null : (String)oidto);
|
||||
String idwasto = (String)cm.get(id);
|
||||
// If it's the same, then nevermind.
|
||||
if(idto == idwasto || (
|
||||
idto != null && idto.equals(idwasto)))
|
||||
continue;
|
||||
if(idwasto == null)
|
||||
sto.storeDisconnect(id, -1);
|
||||
// Not here: we only call connect once.
|
||||
// else
|
||||
// sto.connect(id, -1, idto);
|
||||
|
||||
}
|
||||
comp = null;
|
||||
comm = null;
|
||||
}
|
||||
|
||||
ZZCellHandle ch(Object o) {
|
||||
if(o instanceof ZZCellHandle) return (ZZCellHandle)o;
|
||||
return (ZZCellHandle)space.getCellByID((String)o);
|
||||
}
|
||||
String cid(Object o) {
|
||||
if(o instanceof ZZCellHandle) return ((ZZCellHandle)o).id;
|
||||
return (String)o;
|
||||
}
|
||||
|
||||
/** The abstracted operation of connecting two cells.
|
||||
* Parameters: cell1 cell2.
|
||||
* The cells are explicitly assumed to be not connected before
|
||||
* this.
|
||||
*/
|
||||
protected class Connect implements UndoList.Op {
|
||||
public void undo(Object[] list, int nth) {
|
||||
String c1 = (String)list[nth+1];
|
||||
String c2 = (String)list[nth+2];
|
||||
if(!s((ZZCellHandle)space.getCellByID(c1), 1, null).id.equals(c2))
|
||||
throw new ZZError(
|
||||
"Error when undoing change: disconnect assertion broken");
|
||||
cp.remove(c1);
|
||||
cm.remove(c2);
|
||||
triggers.chg(c1);
|
||||
triggers.chg(c2);
|
||||
}
|
||||
public void redo(Object[] list, int nth) {
|
||||
String c1 = (String)list[nth+1];
|
||||
String c2 = (String)list[nth+2];
|
||||
if(cp.get(c1) != null ||
|
||||
cm.get(c2) != null)
|
||||
throw new ZZError(
|
||||
"Error when redoing change: unconnected assertion broken");
|
||||
cp.put(c1, c2);
|
||||
cm.put(c2, c1);
|
||||
triggers.chg(c1);
|
||||
triggers.chg(c2);
|
||||
}
|
||||
public void commit(Object[] list, int nth) {
|
||||
String c1 = (String)list[nth+1];
|
||||
String c2 = (String)list[nth+2];
|
||||
comp.put(c1, nolla);
|
||||
comm.put(c2, nolla);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** The abstracted operation of disconnecting two cells.
|
||||
* Parameters: cell1 cell2.
|
||||
*/
|
||||
protected class Disconnect implements UndoList.Op {
|
||||
public void undo(Object[] list, int nth) {
|
||||
String c1 = (String)list[nth+1];
|
||||
String c2 = (String)list[nth+2];
|
||||
// Note we can't use disconnect() since that would make
|
||||
// new undolist entries.
|
||||
if(cp.get(c1) != null ||
|
||||
cm.get(c2) != null)
|
||||
throw new ZZError(
|
||||
"Error when undoing change: unconnected assertion broken");
|
||||
cp.put(c1, c2);
|
||||
cm.put(c2, c1);
|
||||
triggers.chg(c1);
|
||||
triggers.chg(c2);
|
||||
}
|
||||
public void redo(Object[] list, int nth) {
|
||||
String c1 = (String)list[nth+1];
|
||||
String c2 = (String)list[nth+2];
|
||||
if(!s((ZZCellHandle)space.getCellByID(c1), 1, null).id.equals(c2))
|
||||
throw new ZZError(
|
||||
"Error when redoing change: disconnect assertion broken");
|
||||
cp.remove(c1);
|
||||
cm.remove(c2);
|
||||
triggers.chg(c1);
|
||||
triggers.chg(c2);
|
||||
}
|
||||
public void commit(Object[] list, int nth) {
|
||||
String c1 = (String)list[nth+1];
|
||||
String c2 = (String)list[nth+2];
|
||||
comp.put(c1, c2);
|
||||
comm.put(c2, c1);
|
||||
}
|
||||
}
|
||||
|
||||
Connect myconnect = new Connect();
|
||||
Disconnect mydisconnect = new Disconnect();
|
||||
|
||||
public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs o) {
|
||||
String s = c.id;
|
||||
if(o != null) triggers.addObs(s, o);
|
||||
if(steps>0)
|
||||
while(steps-- > 0 && s != null) {
|
||||
s = (String)cp.get(s);
|
||||
if(o != null && s!=null) triggers.addObs(s, o);
|
||||
}
|
||||
else
|
||||
while(steps++ < 0 && s != null) {
|
||||
s = (String)cm.get(s);
|
||||
if(o != null && s!=null) triggers.addObs(s, o);
|
||||
}
|
||||
if(s==null) return null;
|
||||
return (ZZCellHandle)space.getCellByID(s);
|
||||
}
|
||||
|
||||
public void connect(ZZCellHandle c0, ZZCellHandle d0) {
|
||||
if (readonly) throw new ZZError("readonly dimension");
|
||||
String c = c0.id;
|
||||
String d = d0.id;
|
||||
disconnect(c0, 1);
|
||||
disconnect(d0, -1);
|
||||
cp.put(c, d);
|
||||
cm.put(d, c);
|
||||
undo.add(myconnect, c, d);
|
||||
triggers.chg(c);
|
||||
triggers.chg(d);
|
||||
}
|
||||
|
||||
public void disconnect(ZZCellHandle c0, int dir) {
|
||||
if (readonly) throw new ZZError("readonly dimension");
|
||||
String c = c0.id;
|
||||
String o;
|
||||
if(dir>0) {
|
||||
o = (String)cp.get(c);
|
||||
if(o!=null) {
|
||||
undo.add(mydisconnect, c, o);
|
||||
cp.remove(c);
|
||||
cm.remove(o);
|
||||
}
|
||||
} else {
|
||||
o = (String)cm.get(c);
|
||||
if(o!=null) {
|
||||
undo.add(mydisconnect, o, c);
|
||||
cm.remove(c);
|
||||
cp.remove(o);
|
||||
}
|
||||
}
|
||||
triggers.chg(c);
|
||||
if(o!=null) triggers.chg(o);
|
||||
}
|
||||
|
||||
// ZZDimStorer implementation
|
||||
|
||||
public void storeConnect(String a, String b) {
|
||||
cp.put(a, b);
|
||||
cm.put(b, a);
|
||||
}
|
||||
public void storeDisconnect(String a, int dir) {
|
||||
Hashtable h = (dir > 0 ? cp : cm);
|
||||
h.remove(a);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user