/** * 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.logootsplit; import crdt.Operation; import java.util.ArrayList; import java.util.List; import jbenchmarker.core.Document; import jbenchmarker.core.SequenceOperation; public class LogootSDocument<T> implements Document { private List<LogootSElement> elements; private List<List<T>> view; private int clock; private int maxId; private int replicaNumber; public LogootSDocument(int max) { this.maxId = max; elements = new ArrayList<LogootSElement>(); view = new ArrayList<List<T>>(); clock = 0; LogootSIdentifier lowest = new LogootSIdentifier(0, 0); LogootSIdentifier greatest = new LogootSIdentifier(max, 0); List<LogootSIdentifier> ll = new ArrayList<LogootSIdentifier>(); ll.add(lowest); List<LogootSIdentifier> gl = new ArrayList<LogootSIdentifier>(); gl.add(greatest); elements.add(new LogootSElement(ll, 0)); elements.add(new LogootSElement(gl, 0)); List l1 = new ArrayList<T>(); l1.add(null); List l2 = new ArrayList<T>(); l2.add(null); view.add(l1); view.add(l2); } public int clockIncrement() { return ++this.clock; } public int max() { return maxId; } public void setReplicaNumber(int i) { replicaNumber = i; } private Position getPositionFromCarret(int start) { int i = 0; int index = 1; while (i + view.get(index).size() <= start) { i = i + view.get(index).size(); index++; } return new Position(index, start - i); } private Position[] getPositionFromCarret(int start, int end) { Position[] res = new Position[2]; int i = 0; int index = 1; while (i + view.get(index).size() <= start) { i = i + view.get(index).size(); index++; } res[0] = new Position(index, start - i); while (i + view.get(index).size() < end) { i = i + view.get(index).size(); index++; } res[1] = new Position(index, end - i); return res; } public List<Operation> generateInsertion(SequenceOperation so) { int start = so.getPosition(); Position position = getPositionFromCarret(start); List<Operation> list = new ArrayList<Operation>(); if (position.offset == 0) { LogootSElement el = new LogootSElement(elements.get(position.index - 1), view.get(position.index - 1).size() - 1); list.add(new LogootSInsertion(el, elements.get(position.index), so.getContent(), this, replicaNumber)); } else { list.add(new LogootSSplit(elements.get(position.index), position.offset)); list.add(new LogootSInsertion(elements.get(position.index), position.offset, so.getContent(), this, replicaNumber)); } return list; } public List<Operation> generateDeletion(SequenceOperation so) { int start = so.getPosition(); int end = start + so.getLenghOfADel(); Position[] positions = getPositionFromCarret(start, end); List<Operation> list = new ArrayList<Operation>(); int n = positions[0].index; int o = positions[0].offset; while (n != positions[1].index) { list.add(new LogootSDeletion(elements.get(n), o, view.get(n).size())); o = 0; n++; } list.add(new LogootSDeletion(elements.get(n), o, positions[1].offset)); return list; } public int IndexOf(LogootSElement el, boolean insert) { int min = 0; int max = elements.size() - 1; int medium; while (min <= max) { medium = (min + max) / 2; switch (elements.get(medium).compareTo(el) / (elements.get(medium).compareTo(el) == 0 ? 1 : Math.abs(elements.get(medium).compareTo(el)))) { case -1: min = medium + 1; break; case 0: return medium; case 1: max = medium - 1; break; } } return insert ? min : -1; } public List<Integer> getAllLike(LogootSElement el) { List<Integer> list = new ArrayList<Integer>(); LogootSElement minEl = el.origin(); LogootSElement maxEl = el.origin(); maxEl.getIdAt(maxEl.size() - 1).setOffset(maxId); int min = IndexOf(minEl, true); int max = IndexOf(maxEl, true); for (int i = min; i < max; i++) { if (elements.get(i).size() == el.size()) { list.add(i); } } return list; } public List<T> get(int index) { return view.get(index); } public LogootSElement getEl(int index) { return elements.get(index); } public void add(LogootSElement el, List<T> content) { int index = IndexOf(el, true); elements.add(index, el); view.add(index, content); } public void remove(int index) { elements.remove(index); view.remove(index); } public void delete(int index, int start, int end) { List<T> s = view.get(index); LogootSElement el = elements.get(index); if (start == 0) {//end !=s.length too //String ns=s.substring(end); List<T> ns = new ArrayList<T>(s.subList(end, s.size())); LogootSElement nel = new LogootSElement(el, end); view.remove(index); elements.remove(index); int nindex = IndexOf(nel, true); view.add(nindex, ns); elements.add(nindex, nel); } else {//start!=0 if (end == s.size()) { //String ns=s.substring(0, start); List<T> ns = new ArrayList<T>(s.subList(0, start)); view.set(index, ns); } else { //String ns1=s.substring(0, start); //String ns2=s.substring(end); List<T> ns1 = new ArrayList<T>(s.subList(0, start)); List<T> ns2 = new ArrayList<T>(s.subList(end, s.size())); LogootSElement nel = new LogootSElement(el, end); int nindex = IndexOf(nel, true); view.set(index, ns1); view.add(nindex, ns2); elements.add(nindex, nel); } } } @Override public String view() { StringBuilder sb = new StringBuilder(); for (int i = 1; i < view.size() - 1; i++) { for (int j = 0; j < view.get(i).size(); j++) { sb.append(view.get(i).get(j)); } } return sb.toString(); } @Override public void apply(Operation op) { ((LogootSOperation) op).apply(this); } public String elements() { String s = ""; for (int i = 0; i < elements.size(); i++) { s = s + elements.get(i) + "*" + view.get(i) + "\n"; } return s; } public int size() { return elements.size(); } @Override public int viewLength() { return view().length(); } } class Position { int index; int offset; public Position(int index, int offset) { this.index = index; this.offset = offset; } }