/** * Replication Benchmarker * https://github.com/score-team/replication-benchmarker/ Copyright (C) 2013 * LORIA / Inria / SCORE Team * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * This program 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 GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. */ package jbenchmarker.woot; import crdt.Factory; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import java.util.NoSuchElementException; import jbenchmarker.core.Document; import crdt.Operation; import jbenchmarker.core.SequenceOperation; /** * * @author urso */ public abstract class WootDocument<N extends VisibleNode> implements Document, Factory<Document> { final protected List<N> elements; private int size = 0; public WootDocument(N CB, N CE) { super(); elements = new ArrayList<N>(); elements.add(CB); elements.add(CE); } public String view() { StringBuilder s = new StringBuilder(); for (VisibleNode w : elements) { if (w.isVisible()) { s.append(w.getContent()); } } return s.toString(); } public int find(WootIdentifier id) { return findAfter(0, id); } public boolean has(WootIdentifier id) { for (N n : elements) { if (n.getId().equals(id)) { return true; } } return false; } public int findAfter(int d, WootIdentifier id) { ListIterator<N> it = elements.listIterator(d); while (it.hasNext()) { if (it.next().getId().equals(id)) { return d; } d++; } throw new NoSuchElementException("Don't find " + id + " after position " + d); } @Override public void apply(Operation op) { WootOperation wop = (WootOperation) op; if (wop.getType() == SequenceOperation.OpType.delete) { setInvisible(find(wop.getId())); } else { int ip = find(wop.getIp()), in = findAfter(ip, wop.getIn()); insertBetween(ip, in, wop); ++size; } } protected abstract void insertBetween(int ip, int in, WootOperation wop); /** * pth visible character */ public int getVisible(int p) { ListIterator<N> it = elements.listIterator(1); int i = 1, j = 0; while (j <= p) { if (it.next().isVisible()) { j++; } i++; } return i - 1; } /** * position of next visible character starting from v model position. */ public int nextVisible(int v) { ListIterator<N> it = elements.listIterator(v + 1); int i = v + 1; while (!it.next().isVisible()) { i++; } return i; } /** * Index of previous character of pth visible character. 0 for 0th */ public int getPrevious(int p) { if (p == 0) { return 0; } return getVisible(p - 1); } /** * Index of next character of pth visible characterstarting from v model * position. n-1 for last visible. */ public int getNext(int v) { int i = v + 1; while (i < elements.size() - 1 && !elements.get(i).isVisible()) { i++; } return i; } static public WootOperation delete(SequenceOperation o, WootIdentifier id) { return new WootOperation(SequenceOperation.OpType.delete, id, null); } static public <T> WootOperation insert(SequenceOperation o, WootIdentifier id, WootIdentifier ip, WootIdentifier in, T content) { return new WootOperation(SequenceOperation.OpType.insert, new WootPosition(id, ip, in), content); } /** * Apply a localy generated insert between position ip and in, starting from * indentifier idp. */ void insertLocal(WootOperation wop, int ip, WootIdentifier idp, int in) { ip = findAfter(ip, idp); insertBetween(ip, in, wop); size++; } void setInvisible(int v) { N e = elements.get(v); if (e.isVisible()) { --size; } e.setVisible(false); } N getElement(int v) { return elements.get(v); } @Override public int viewLength() { return size; } }