/*
* Replication Benchmarker
* https://github.com/score-team/replication-benchmarker/
* Copyright (C) 2012 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.logootsplitO;
import crdt.Operation;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/**
*
* @author Stephane Martin <stephane@stephanemartin.fr>
*/
public class LogootSRopes<T> implements LogootSDoc<T>, Serializable {
int replicatNumber = 0;
int clock = 0;
RopesNodes root = null;
private HashMap<List<Integer>, LogootSBlockLight> mapBaseToBlock = new HashMap<List<Integer>, LogootSBlockLight>(); //for test
HashMap<List<Integer>, LogootSBlockLight> getMapBaseToBlock() {
return mapBaseToBlock;
}
public LogootSBlockLight getBlock(IdentifierInterval id) {
LogootSBlockLight ret = mapBaseToBlock.get(id.base);
if (ret == null) {
ret = new LogootSBlockLight<String>(id);
mapBaseToBlock.put(id.base, ret);
}
return ret;
}
@Override
public void addBlock(Identifier id, List<T> str) {
// //size += str.size();
//LinkedList l2 = new LinkedList();
/*if (!scoreCheckT(root, l2)) {
System.out.println("\n\n" + root.viewRec());
System.out.println(l2);
}*/
// LinkedList path42 = searchErr();
// assert (path42 == null);
IdentifierInterval idi = new IdentifierInterval(id.base, id.last, id.last + str.size() - 1);
if (root == null) {
LogootSBlockLight bl = new LogootSBlockLight(idi);
mapBaseToBlock.put(bl.id.base, bl);
root = new RopesNodes(str, id.getLast(), bl);
} else {
addBlock(idi, str, root);
}
// l2 = new LinkedList();
/* if (!scoreCheckT(root, l2)) {
System.out.println("\n\n" + root.viewRec());
System.out.println(l2);
}*/
}
void addBlock(IdentifierInterval idi, List<T> str, RopesNodes from) {
LinkedList<RopesNodes> path = new LinkedList();
LinkedList<RopesNodes> path2;
boolean con = true;
while (con) {
path.add(from);
IteratorHelperIdentifier ihi = new IteratorHelperIdentifier(idi, from.getIdentifierInterval());
//System.out.println(ihi.computeResults() + "; " + from + "; " + str + " " + idi.getBegin());
int split;
switch (ihi.computeResults()) {
case B1AfterB2:
if (from.getRight() == null) {
from.setRight(new RopesNodes(str, idi.getBegin(), getBlock(idi)));
con = false;
} else {
from = from.getRight();
}
break;
case B1BeforeB2:
if (from.getLeft() == null) {
from.setLeft(new RopesNodes(str, idi.getBegin(), getBlock(idi)));
con = false;
} else {
from = from.getLeft();
}
break;
case B1InsideB2: //split b2 the object node
//int split = maxOffsetBeforeNex(node.getIdBegin(), id, node.str.size() + node.offset - 1);
split = Math.min(from.maxOffset(), ihi.getNextOffset());
RopesNodes rp = new RopesNodes(str, idi.getBegin(), getBlock(idi));
path.add(from.split(split - from.offset + 1, rp));
con = false;
break;
case B2insideB1: // split b1 the node to insert
//int split2 = maxOffsetBeforeNex(id, node.getIdBegin(), str.size() + id.last - 1);
//boolean mod = false;
int split2 = /*Math.min(idi.getEnd(), */ ihi.getNextOffset()/*)*/;
List ls = str.subList(0, split2 + 1 - idi.getBegin());
IdentifierInterval idi1 = new IdentifierInterval(idi.base, idi.getBegin(), split2);
if (from.getLeft() == null) {
from.setLeft(new RopesNodes(ls, idi1.getBegin(), getBlock(idi1)));
//mod = true;
} else {
addBlock(idi1, ls, from.getLeft());
}
ls = str.subList(split2 + 1 - idi.getBegin(), str.size());
idi1 = new IdentifierInterval(idi.base, split2 + 1, idi.end);
if (from.getRight() == null) {
from.setRight(new RopesNodes(ls, idi1.getBegin(), getBlock(idi1)));
//mod = true;
} else {
addBlock(idi1, ls, from.getRight());
}
//if (mod) {
con = false;
break;
/*} else {
return;
}*/
case B1concatB2: //node to insert concat the node
if (from.getLeft() != null) {
path2 = (LinkedList) path.clone();
path2.add(from.getLeft());
getXest(RopesNodes.RIGHT, path2);
split = from.getIdBegin().minOffsetAfterPrev(path2.getLast().getIdEnd(), idi.getBegin());
List l = new ArrayList(str.subList(split + 1 - idi.getBegin(), str.size()));
from.appendBegin(l);
ascendentUpdate(path, l.size());
str = new ArrayList(str.subList(0, split + 1 - idi.getBegin()));
idi = new IdentifierInterval(idi.base, idi.begin, split);
//check if previous is smaller or not
if (idi.end >= idi.begin) {
from = from.getLeft();
} else {
return;
}
} else {
from.appendBegin(str);
ascendentUpdate(path, str.size());
return;
}
break;
case B2ConcatB1://concat at end
if (from.getRight() != null) {
path2 = (LinkedList) path.clone();
path2.add(from.getRight());
getXest(RopesNodes.LEFT, path2);
split = from.getIdEnd().maxOffsetBeforeNex(path2.getLast().getIdBegin(), idi.getEnd());
List l = new ArrayList(str.subList(0, split + 1 - idi.getBegin()));
from.appendEnd(l);
ascendentUpdate(path, l.size());
str = new ArrayList(str.subList(split + 1 - idi.getBegin(), str.size()));
idi = new IdentifierInterval(idi.base, split + 1, idi.end);
if (idi.end >= idi.begin) {
from = from.getRight();
} else {
return;
}
} else {
from.appendEnd(str);
ascendentUpdate(path, str.size());
return;
}
break;
default:
throw new UnsupportedOperationException("Not implemented yet");
}
}
balance(path);
}
boolean searchFull(RopesNodes node, Identifier id, LinkedList<RopesNodes> path) {
if (node == null) {
return false;
}
path.add(node);
if (node.getIdBegin().compareTo(id) == 0
|| searchFull(node.getLeft(), id, path)
|| searchFull(node.getRight(), id, path)) {
return true;
}
path.removeLast();
return false;
}
RopesNodes mkNode(Identifier id1, Identifier id2, List l) {
List<Integer> base = IDFactory.createBetweenPosition(id1, id2, replicatNumber, clock++);
IdentifierInterval idi = new IdentifierInterval(base, 0, l.size() - 1);
LogootSBlockLight newBlock = new LogootSBlockLight(idi);
mapBaseToBlock.put(idi.base, newBlock);
return new RopesNodes(l, 0, newBlock);
}
//Todo: improve readability with search function
@Override
public LogootSOp insertLocal(int pos, List l) {
/* LinkedList l2 = new LinkedList();
if (!scoreCheckT(root, l2)) {
System.out.println("\n\n" + root.viewRec());
System.out.println(l2);
}*/
if (root == null) {//empty tree
root = mkNode(null, null, l);
root.block.setMine(true);
return new LogootSOpAdd(root.getIdBegin(), l);
} else {
RopesNodes newNode;
int length = this.viewLength();
LinkedList<RopesNodes> path;
if (pos == 0) {//begin of string
// System.out.println("begin");
path = new LinkedList();
path.add(root);
RopesNodes n = getXest(RopesNodes.LEFT, path);
if (n.isAppendableBefore()) {
Identifier id = n.appendBegin(l);
ascendentUpdate(path, l.size());
return new LogootSOpAdd(id, l);
} else {//add node
newNode = mkNode(null, n.getIdBegin(), l);
newNode.block.setMine(true);
n.setLeft(newNode);
}
} else if (pos >= length) {//end
// System.out.println("end");
path = new LinkedList();
path.add(root);
RopesNodes n = getXest(RopesNodes.RIGHT, path);
if (n.isAppendableAfter()) {//append
Identifier id = n.appendEnd(l);
ascendentUpdate(path, l.size());
return new LogootSOpAdd(id, l);
} else {//add at end
newNode = mkNode(n.getIdEnd(), null, l);
newNode.block.setMine(true);
n.setRight(newNode);
}
} else {//middle
ResponseIntNode inPos = search(pos);
if (inPos.getI() > 0) {//split
// System.out.println("split");
Identifier id1 = inPos.getNode().block.id.getBaseId(inPos.getNode().offset + inPos.getI() - 1);
Identifier id2 = inPos.getNode().block.id.getBaseId(inPos.getNode().offset + inPos.getI());
newNode = mkNode(id1, id2, l);
newNode.block.setMine(true);
path = inPos.getPath();
path.add(inPos.getNode().split(inPos.getI(), newNode));
} else {
ResponseIntNode prev = search(pos - 1);
if (inPos.getNode().isAppendableBefore() && inPos.getNode().getIdBegin().hasPlaceBefore(prev.getNode().getIdEnd(), l.size())) {//append before
// System.out.println("Append before");
Identifier id = inPos.getNode().appendBegin(l);
ascendentUpdate(inPos.path, l.size());
// path42 = searchErr();
// assert (path42 == null);
return new LogootSOpAdd(id, l);
} else {
if (prev.getNode().isAppendableAfter() && prev.getNode().getIdEnd().hasPlaceAfter(inPos.getNode().getIdBegin(), l.size())) {//append after
// System.out.println("Append after");
Identifier id = prev.getNode().appendEnd(l);
ascendentUpdate(prev.path, l.size());
// path42 = searchErr();
// assert (path42 == null);
return new LogootSOpAdd(id, l);
} else {
//System.out.println("between");
newNode = mkNode(prev.getNode().getIdEnd(), inPos.getNode().getIdBegin(), l);
newNode.block.setMine(true);
newNode.setRight(prev.getNode().getRight());
prev.getNode().setRight(newNode);
path = prev.getPath();
path.add(newNode);
}
}
}
}
//path42 = searchErr();
//assert (path42 == null);
balance(path);
/*TEST===*/
// LinkedList<RopesNodes> l25 = new LinkedList();
// LinkedList<RopesNodes> lp25 = new LinkedList();
/* boolean b = true;
if (!search(newNode.getIdBegin(), l25)) {
b = searchFull(this.root, newNode.getIdBegin(), lp25);
}
if (l25.getLast().getIdBegin().compareTo(newNode.getIdBegin()) != 0) {
assert (false);
}
l25 = new LinkedList();
if (scoreCheckT(root, l25)) {
System.out.println("\n\n" + root.viewRec());
System.out.println(l25);
}*/
/*end Test */
return new LogootSOpAdd(newNode.getIdBegin(), l);
}
}
/* static boolean scoreCheckT(RopesNodes node, LinkedList<RopesNodes> list) {
if (node == null) {
return true;
}
boolean ret = true;
list.add(node);
ret &= scoreCheckT(node.getLeft(), list);
ret &= scoreCheckT(node.getRight(), list);
int nodeinsub = node.str.size() + node.getSizeNodeAndChildren(0) + node.getSizeNodeAndChildren(1);
if (node.getSizeNodeAndChildren() != nodeinsub) {
System.err.println("error lenght : " + node.getSizeNodeAndChildren() + "<>" + nodeinsub + " " + list);
ret = false;
}
nodeinsub = 1 + Math.max(node.getSubtreeHeigh(0), node.getSubtreeHeigh(1));
if (node.getHeighOfTree() != nodeinsub) {
System.err.println("error height : " + node.getHeighOfTree() + "<>" + nodeinsub + " " + list);
ret = false;
}
int bal = node.balanceScore();
if (Math.abs(bal) > 1) {
System.err.println("Balance broken " + bal + ":" + node.getSubtreeHeigh(1) + " vs " + node.getSubtreeHeigh(0) + " " + list);
ret = false;
// assertTrue("fuck",false);
}
list.removeLast();
return ret;
}*/
// public LinkedList searchErr() {
// LinkedList path = new LinkedList();
// if (searchErr(root, path)) {
// return path;
// } else {
// return null;
// }
//
// }
//
// boolean searchErr(RopesNodes node, LinkedList<RopesNodes> path) {
// if (node == null) {
// return false;
// }
// path.add(node);
// if (node.getRight() != null && node.getRight().getIdBegin().compareTo(node.getIdEnd()) < 0) {
// return true;
// }
// if (node.getLeft() != null && node.getLeft().getIdEnd().compareTo(node.getIdBegin()) > 0) {
// return true;
// }
// if (searchErr(node.getLeft(), path)
// || searchErr(node.getRight(), path)) {
// return true;
// }
// path.removeLast();
// return false;
// }
/*public RopesNodes getPrevious(LinkedList<RopesNodes> path) {
RopesNodes n = path.getLast();
if (n.getLeft() != null) {
if (n.getLeft().getRight() == null) {
return n.getLeft();
} else {
return getXest(RopesNodes.RIGHT, n);
}
} else {
if (path.size() > 1) {
}
}
}
*/
RopesNodes getXest(int i, RopesNodes n) {
while (n.getChild(i) != null) {
n = n.getChild(i);
}
return n;
}
RopesNodes getXest(int i, LinkedList<RopesNodes> path) {
RopesNodes n = path.getLast();
while (n.getChild(i) != null) {
n = n.getChild(i);
path.add(n);
}
return n;
}
boolean search(Identifier id, LinkedList<RopesNodes> path) {
RopesNodes node = root;
while (node != null) {
path.addLast(node);
if (id.compareTo(node.getIdBegin()) < 0) {
node = node.getLeft();
} else if (id.compareTo(node.getIdEnd()) > 0) {
node = node.getRight();
} else {
return true;
}
}
return false;
}
ResponseIntNode search(int pos) {
RopesNodes node = root;
LinkedList<RopesNodes> path = new LinkedList();
while (node != null) {
path.add(node);
int before = node.getLeft() == null ? 0 : node.getLeft().sizeNodeAndChildren;
if (pos < before) {//Before
node = node.getLeft();
} else if (pos < before + node.str.size()) {
return new ResponseIntNode(pos - before, node, path);
} else {
pos -= before + node.str.size();
node = node.getRight();
}
}
return null;
}
/**
*
* @param path the value of path
* @param string the value of string
*/
void ascendentUpdate(LinkedList<RopesNodes> path, int string) {
Iterator<RopesNodes> it = path.descendingIterator();
while (it.hasNext()) {
it.next().addString(string);
}
}
@Override
public LogootSOp delLocal(int begin, int end) {
/* LinkedList l2 = new LinkedList();
if (!scoreCheckT(root, l2)) {
System.out.println("\n\n" + root.viewRec());
System.out.println(l2);
}*/
// LinkedList l = new LinkedList();
// if (scoreCheckT(root, l)) {
// System.out.println("\n\n" + root.viewRec());
// System.out.println(l);
// }
// LinkedList path42 = searchErr();
// assert (path42 == null);
// assert (begin < this.view().length());
// assert (end < this.view().length());
// size -= end - begin + 1;
int lenght = end - begin + 1;
List<IdentifierInterval> li = new LinkedList<IdentifierInterval>();
do {
ResponseIntNode start = search(begin);
int be = start.node.offset + start.getI();
int en = Math.min(be + lenght - 1, start.node.maxOffset());
//int i = this.view().length();
li.add(new IdentifierInterval(start.getNode().block.getId().getBase(), be, en));
RopesNodes r = start.node.deleteOffsets(be, en);
lenght -= en - be + 1;
//begin -= en - be+1;
if (start.node.getSize() == 0) {
// assert (i - this.view().length() == en - be + 1);
delNode(start.getPath());
//assert (i - this.view().length() == en - be + 1);
//this.ascendentUpdate(start.path, 1, en-be);
} else if (r != null) {//node has been splited
start.path.add(r);
balance(start.path);
} else {
this.ascendentUpdate(start.path, be - en - 1);
}
// path42 = searchErr();
// assert (path42 == null);
// l = new LinkedList();
// if (scoreCheckT(root, l)) {
// System.out.println("\n\n" + root.viewRec());
// System.out.println(l);
// }
} while (lenght > 0);
return new LogootSOpDel(li);
}
void delNode(LinkedList< RopesNodes> path) {
RopesNodes node = path.getLast();
//assert (node.block.numberOfElements() >= 0);
if (node.block.numberOfElements() == 0) {
this.mapBaseToBlock.remove(node.block.id.base);
}
if (node.getRight() == null) {
if (node == root) {
root = node.getLeft();
} else {
path.removeLast();
path.getLast().replaceChildren(node, node.getLeft());
}
} else if (node.getLeft() == null) {
if (node == root) {
root = node.getRight();
} else {
path.removeLast();
path.getLast().replaceChildren(node, node.getRight());
}
} else {//two children
path.add(node.getRight());
RopesNodes min = getMinPath(path);
node.become(min);
path.removeLast();
path.getLast().replaceChildren(min, min.getRight());
}
balance(path);
}
RopesNodes getMinPath(LinkedList<RopesNodes> path) {
RopesNodes node = path.getLast();
if (node == null) {
return null;
}
while (node.getLeft() != null) {
node = node.getLeft();
path.add(node);
}
return node;
}
RopesNodes getLeftest(RopesNodes node) {
if (node == null) {
return null;
}
while (node.getLeft() != null) {
node = node.getLeft();
}
return node;
}
Identifier getMinId(RopesNodes node) {
RopesNodes back = getLeftest(node);
return back != null ? back.getIdBegin() : null;
}
/*
* Balancing
*/
/**
* Balance tree on path ascendent
*
* @param path
*/
void balance(LinkedList<RopesNodes> path) {
// LinkedList path42 = searchErr();
// assert (path42 == null);
/*System.out.println("\n\n");
System.out.println(root != null ? root.viewRec() : "null");*/
//Iterator<RopesNodes> it = path.descendingIterator();
LinkedList<RopesNodes> path2=/*new LinkedList(*/path;//);
/*RopesNodes node = it.hasNext() ? it.next() : null;
RopesNodes father = it.hasNext() ? it.next() : null;*/
RopesNodes node = path2.isEmpty()?null:path2.removeLast();
RopesNodes father = path2.isEmpty()?null:path2.getLast();
while (node != null) {
node.sumDirectChildren();
int balance = node.balanceScore();
//System.out.println("node" + node + " balance:" + balance);
while (Math.abs(balance) >= 2) {
if (balance >= 2) {
if (node.getRight() != null && node.getRight().balanceScore() <= -1) {
// System.out.println("double left");
/*node =*/ father=rotateRL(node, father);//double left
} else {
//System.out.println("left");
/*node =*/ father=rotateLeft(node, father);
}
} else /*if (balance <= -2)*/ {
if (node.getLeft() != null && node.getLeft().balanceScore() >= 1) {
//System.out.println("double Right");
/*node =*/ father=rotateLR(node, father);//Double right
} else {
//System.out.println("Right");
/*node =*/ father=rotateRight(node, father);
}
}
path2.addLast(father);
balance = node.balanceScore();
/*System.out.println("new"+balance+" "+node);
System.out.println(root.viewRec());*/
}
node = path2.isEmpty()?null:path2.removeLast();
father = path2.isEmpty()?null:path2.getLast();
//father = it.hasNext() ? it.next() : null;
}
/*LinkedList path42 = new LinkedList();
if (!scoreCheckT(this.root, path42)) {
System.out.println(root != null ? root.viewRec() : "null");
System.out.println("oops");
assert (false);
}*/
// path42 = searchErr();
// assert (path42 == null);
}
RopesNodes rotateLeft(RopesNodes node, RopesNodes father) {
RopesNodes r = node.getRight();
if (node == root) {
root = r;
} else {
father.replaceChildren(node, r);
}
node.setRight(r.getLeft());
r.setLeft(node);
node.sumDirectChildren();
r.sumDirectChildren();
return r;
}
RopesNodes rotateRight(RopesNodes node, RopesNodes father) {
RopesNodes r = node.getLeft();
if (node == root) {
root = r;
} else {
father.replaceChildren(node, r);
}
node.setLeft(r.getRight());
r.setRight(node);
node.sumDirectChildren();
r.sumDirectChildren();
return r;
}
//public void remove()
RopesNodes rotateRL(RopesNodes node, RopesNodes father) {
rotateRight(node.getRight(), node);
return rotateLeft(node, father);
}
RopesNodes rotateLR(RopesNodes node, RopesNodes father) {
rotateLeft(node.getLeft(), node);
return rotateRight(node, father);
}
@Override
public void delBlock(IdentifierInterval id) {
// LinkedList path42 = searchErr();
// assert (path42 == null);
// LinkedList l2 = new LinkedList();
// if (scoreCheckT(root, l2)) {
// System.out.println("\n\n" + root.viewRec());
// System.out.println(l2);
// }
/* LinkedList l2 = new LinkedList();
if (!scoreCheckT(root, l2)) {
System.out.println("\n\n" + root.viewRec());
System.out.println(l2);
}*/
while (true) {
LinkedList<RopesNodes> path = new LinkedList<RopesNodes>();
// LinkedList<RopesNodes> path = ;
if (!search(id.getBeginId(), path)) {
if (id.getBegin() < id.end) {
id = new IdentifierInterval(id.base, id.getBegin() + 1, id.end);
} else {
// path42 = searchErr();
// assert (path42 == null);
return;
}
} else {
RopesNodes node = path.getLast();
int end = Math.min(id.end, node.maxOffset());
RopesNodes t = node.deleteOffsets(id.getBegin(), end);
//size -= end - id.getBegin() - 1;
if (node.getSize() == 0) {//del node
delNode(path);
} else if (t != null) {
path.add(t);
balance(path);
} else {
ascendentUpdate(path, id.getBegin() - end - 1);
}
if (end == id.end) {
break;
} else {
id = new IdentifierInterval(id.base, end, id.end);
}
}
}
// path42 = searchErr();
// assert (path42 == null);
// l2 = new LinkedList();
// if (scoreCheckT(root, l2)) {
// System.out.println("\n\n" + root.viewRec());
// System.out.println(l2);
// }
}
boolean getNext(LinkedList<RopesNodes> path) {
RopesNodes node = path.getLast();
if (node.getRight() == null) {
if (path.size() > 1) {
RopesNodes father = path.get(path.size() - 2);
if (father.getLeft() == node) {
path.removeLast();
return true;
}
}
return false;
} else {
path.add(node.getRight());
getXest(RopesNodes.LEFT, path);
return true;
}
}
@Override
public LogootSDoc create() {
return new LogootSRopes();
}
@Override
public void setReplicaNumber(int i) {
this.replicatNumber = i;
}
@Override
public String view() {
if (root == null) {
return "";
}
StringBuilder ret = new StringBuilder(root.sizeNodeAndChildren);
LinkedList<RopesNodes> pile = new LinkedList();
pile.add(root);
RopesNodes<T> n = root;
while (pile.size() > 0) {
while (n.getLeft() != null) {
pile.addLast(n.getLeft());
n = n.getLeft();
}
do {
for (T t : n.str) {
ret.append(t);
}
pile.removeLast();
if (n.getRight() != null) {
pile.addLast(n.getRight());
n = n.getRight();
break;
}
n = pile.size() > 0 ? pile.getLast() : null;
} while (pile.size() > 0);
}
return ret.toString();
}
// static boolean scoreCheckT(RopesNodes node, LinkedList<RopesNodes> list) {
// if (node == null) {
// return false;
// }
// boolean ret = false;
// list.add(node);
// ret = scoreCheckT(node.getLeft(), list);
// ret |= scoreCheckT(node.getRight(), list);
// int nodeinsub = 1 + node.getSubtreeHeigh(0) + node.getSubtreeHeigh(1);
// if (node.getSubtreeHeigh() != nodeinsub) {
// System.err.println("error number node : " + node.getSubtreeHeigh() + "<>" + nodeinsub + " " + node.str);
// ret = true;
// }
// nodeinsub = node.str.size() + node.getSizeNodeAndChildren(0) + node.getSizeNodeAndChildren(1);
// if (node.getSizeNodeAndChildren() != nodeinsub) {
// System.err.println("error lenght : " + node.getSizeNodeAndChildren() + "<>" + nodeinsub + " " + node.str);
// ret = true;
// }
// list.removeLast();
// return ret;
// }
@Override
public int viewLength() {
int ret = root == null ? 0 : root.sizeNodeAndChildren;
return ret;
}
@Override
public void apply(Operation op) {
throw new UnsupportedOperationException("Not supported yet.");
}
public static class RopesNodes<T> {
/**
* Node childrenLeftRight
*/
public static int LEFT = 0;
public static int RIGHT = 1;
private RopesNodes[] childrenLeftRight = new RopesNodes[2];
private int height = 1;
private int sizeNodeAndChildren = 0;
/**
* String info
*/
int offset;
List<T> str;
LogootSBlockLight<String> block;
public Identifier getIdBegin() {
return this.block.id.getBaseId(offset);
}
public Identifier getIdEnd() {
return this.block.id.getBaseId(offset + str.size() - 1);
}
public RopesNodes(List<T> str, int offset, LogootSBlockLight block) {
this(str, offset, block, true);
}
public RopesNodes(List<T> str, int offset, LogootSBlockLight block, boolean newer) {
this.str = new ArrayList(str);
this.block = block;
this.offset = offset;
this.sizeNodeAndChildren = str.size();
if (newer && block != null) {
block.addBlock(offset, str);
}
}
/**
*
* @param string the value of string
*/
public void addString(int string) {
this.sizeNodeAndChildren += string;
}
public RopesNodes getChild(int i) {
return childrenLeftRight[i];
}
public Identifier appendEnd(List s) {
int b = this.maxOffset() + 1;
str.addAll(s);
block.addBlock(b, s);
return this.block.id.getBaseId(b);
}
public Identifier appendBegin(List s) {
str.addAll(0, s);
offset -= s.size();
block.addBlock(this.offset, s);
return this.getIdBegin();
}
public RopesNodes deleteOffsets(int begin, int end) {
// assert (begin >= this.offset);
// assert (end < this.offset + str.size());
// assert (begin <= end);
int sizeToDelete = end - begin + 1;
//this.sizeNodeAndChildren -= sizeToDelete;
this.block.delBlock(begin, end, sizeToDelete);
if (sizeToDelete == this.str.size()) {
this.str.clear();
return null;
}
RopesNodes ret = null;
if (end == this.offset + str.size() - 1) {
this.str = new ArrayList(str.subList(0, begin - offset));
} else if (begin == this.offset) {
this.str = new ArrayList(str.subList(end - offset + 1, str.size()));
offset = end + 1;
} else {
ret = this.split(end - offset + 1);
str = new ArrayList(str.subList(0, begin - offset));
}
return ret;
}
public RopesNodes split(int size) {
this.height++;
RopesNodes n = new RopesNodes(new ArrayList(str.subList(size, str.size())), offset + size, block, false);
this.str = new ArrayList(str.subList(0, size));
if (this.childrenLeftRight[RIGHT] != null) {
n.childrenLeftRight[RIGHT] = this.childrenLeftRight[RIGHT];
n.height += n.childrenLeftRight[RIGHT].height + 1;
n.sizeNodeAndChildren += n.childrenLeftRight[RIGHT].sizeNodeAndChildren;
}
this.childrenLeftRight[RIGHT] = n;
return n;
}
public RopesNodes split(int size, RopesNodes node) {
this.height++;
RopesNodes n = split(size);
n.childrenLeftRight[LEFT] = node;
n.height++;
return n;
}
int maxOffset() {
return offset + str.size() - 1;
}
int getSize() {
return str.size();
}
public void setLeft(RopesNodes n) {
this.childrenLeftRight[LEFT] = n;
}
public void setRight(RopesNodes n) {
this.childrenLeftRight[RIGHT] = n;
}
public RopesNodes getLeft() {
return this.childrenLeftRight[LEFT];
}
public RopesNodes getRight() {
return this.childrenLeftRight[RIGHT];
}
public void sumDirectChildren() {
height = Math.max(getSubtreeHeigh(LEFT), getSubtreeHeigh(RIGHT)) + 1;
sizeNodeAndChildren = getSizeNodeAndChildren(LEFT) + getSizeNodeAndChildren(RIGHT) + str.size();
}
public int getSubtreeHeigh(int i) {
RopesNodes s = childrenLeftRight[i];
return s == null ? 0 : s.height;
}
public int getSizeNodeAndChildren(int i) {
RopesNodes s = childrenLeftRight[i];
return s == null ? 0 : s.sizeNodeAndChildren;
}
public int getHeighOfTree() {
return height;
}
public void setChildrens(int childrens) {
this.height = childrens;
}
public int getSizeNodeAndChildren() {
return sizeNodeAndChildren;
}
public void replaceChildren(RopesNodes node, RopesNodes by) {
if (childrenLeftRight[LEFT] == node) {
childrenLeftRight[LEFT] = by;
} else if (childrenLeftRight[RIGHT] == node) {
childrenLeftRight[RIGHT] = by;
}
}
public int balanceScore() {
return getSubtreeHeigh(RIGHT) - getSubtreeHeigh(LEFT);
}
public void become(RopesNodes node) {
this.sizeNodeAndChildren = -str.size() + node.str.size();
this.str = node.str;
this.offset = node.offset;
this.block = node.block;
}
public boolean isAppendableAfter() {
return this.block.isMine() && block.id.end == this.maxOffset();
}
public boolean isAppendableBefore() {
return this.block.isMine() && block.id.getBegin() == this.offset;
}
@Override
public String toString() {
//return str.toString();
//return "{" + nodesInSubtree + "," + sizeNodeAndChildren + ", " + offset + ", " + str + "," + block + ",[" + this.childrenLeftRight[0] + "," + this.childrenLeftRight[1] + "]}";
String str2 = "";
for (Object o : str) {
str2 += o;
}
return new IdentifierInterval(this.block.id.base, this.offset, this.maxOffset()).toString() + "," + str2;
}
public String viewRec() {
String str2 = "";
if (getLeft() != null || getRight() != null) {
str2 += "( ";
}
if (getLeft() != null) {
str2 += getLeft().viewRec();
}
if (getLeft() != null || getRight() != null) {
str2 += " , ";
}
for (Object o : str) {
str2 += o;
}
if (getLeft() != null || getRight() != null) {
str2 += " , ";
}
if (getRight() != null) {
str2 += getRight().viewRec();
}
if (getLeft() != null || getRight() != null) {
str2 += " )";
}
return str2;
}
public IdentifierInterval getIdentifierInterval() {
return new IdentifierInterval(this.block.id.base, this.offset, this.offset + str.size() - 1);
}
}
public static class ResponseIntNode {
int i;
RopesNodes node;
LinkedList path;
public ResponseIntNode(int i, RopesNodes node, LinkedList path) {
this.i = i;
this.node = node;
this.path = path;
}
public LinkedList getPath() {
return path;
}
public int getI() {
return i;
}
public RopesNodes getNode() {
return node;
}
}
}