package jbenchmarker.rgasplit; import jbenchmarker.core.Document; import jbenchmarker.core.SequenceOperation; import java.util.HashMap; import java.util.List; import java.util.ArrayList; import crdt.Operation; public class RgaSDocument<T> implements Document { private HashMap<RgaSS3Vector, RgaSNode> hash; private RgaSNode head; private int size = 0; public RgaSDocument() { super(); head = new RgaSNode(); hash=(new HashMap<RgaSS3Vector, RgaSNode>()); } /* Methods to apply each type of remote operations: * * Insertion, Deletion && Split */ public void apply(Operation op) { RgaSOperation rgaop = (RgaSOperation) op; if (rgaop.getType() == SequenceOperation.OpType.delete) { remoteDelete(rgaop); } else { remoteInsert(rgaop); } } private void remoteInsert(RgaSOperation op) { RgaSNode newnd = new RgaSNode(op.getS3vtms(), op.getContent()); RgaSNode node, next=null; RgaSS3Vector s3v = op.getS3vtms(); if (op.getS3vpos() == null) { node = head; } else { int offsetAbs = op.getOffset1()+op.getS3vpos().getOffset()+1; // du au -1 du get position node = hash.get(op.getS3vpos()); node = findGoodNode(node, offsetAbs); remoteSplit(node, offsetAbs); } next = node.getNext(); while (next!=null) { if (s3v.compareTo(next.getKey()) == RgaSS3Vector.AFTER) { break; } node = next; next = next.getNext(); } newnd.setNext(next); node.setNext(newnd); hash.put(op.getS3vtms(), newnd); size+=newnd.size(); } private void remoteDelete(RgaSOperation op) { int offsetAbs1 = op.getOffset1()+op.getS3vpos().getOffset(); int offsetRel1 = op.getOffset1(); int offsetAbs2 = op.getOffset2()+op.getS3vpos().getOffset(); int offsetRel2 = op.getOffset2(); RgaSNode node = hash.get(op.getS3vpos()); node=findGoodNode(node, offsetAbs1); if (offsetRel1>0){ remoteSplit(node,offsetAbs1); node=node.getLink(); } while (node.getOffset() + node.size() < offsetAbs2){ if (node.isVisible()) size-=node.size(); node.makeTombstone(); node=node.getLink(); } if (offsetRel2>0){ remoteSplit(node,offsetAbs2); if (node.isVisible()) size-=node.size(); node.makeTombstone(); } } public void remoteSplit(RgaSNode node, int offsetAbs) { if (offsetAbs-node.getOffset()>0 && node.size()-offsetAbs+node.getOffset()>0){ List<T> a= null; List<T> b = null; if (node.isVisible()){ a = node.getContent().subList(0,offsetAbs-node.getOffset()); b = node.getContent().subList(offsetAbs-node.getOffset(),node.size()); } RgaSNode end = new RgaSNode(node.clone(), b, offsetAbs); end.setSize(node.size()-offsetAbs+node.getOffset()); end.setNext(node.getNext()); node.setContent(a); node.setSize(offsetAbs-node.getOffset()); node.setNext(end); node.setLink(end); hash.put(node.getKey(), node); hash.put(end.getKey(), end); } } /* Methods to display the view of the document * * view(): normal view of the document, without separator between each node * viewWithSeparator(): view with separators between each node for debugging */ @Override public String view() { StringBuilder s = new StringBuilder(); RgaSNode node = head.getNext(); while (node != null) { if (node.isVisible() && node.getContent()!=null) { for (int i=0; i<node.size();i++) s.append(node.getContent().get(i)); } node = node.getNext(); } return s.toString(); } public String viewWithSeparator() { StringBuilder s = new StringBuilder(); StringBuilder a = new StringBuilder(); RgaSNode node = head.getNext(); while (node != null) { if (node.isVisible() && node.getContent()!=null) { a = new StringBuilder(); for (int i=0; i<node.size();i++){ a.append(node.getContent().get(i)); } s.append("->|"+a+"|"); } node = node.getNext(); } return s.toString(); } // Obtenir des objets de la classe Position protected class Position { protected RgaSNode node; protected int offset; public Position(RgaSNode n, int offset) { this.node= n; this.offset = offset; } public String toString(){ return "[" + node + "," + offset +"]"; } } public Position getPosition(RgaSNode node, int start){ Position pos; int i = node.size(); while (node != null && i <= start ) { node = node.getNextVisible(); if (node!=null) { i+=node.size(); } } if (node!=null){ return pos = new Position(node, node.size() - i + start); } else { return pos = new Position(null, 0); } } public RgaSNode findGoodNode(RgaSNode target, int off){ while (target.getOffset() + target.size() < off){ target=target.getLink(); } return target; } public HashMap<RgaSS3Vector, RgaSNode> getHash() { return hash; } public RgaSNode getHead(){ return head; } @Override public int viewLength() { return size; } }