/** * 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.logoot; import java.io.Serializable; import java.util.Arrays; /** * Logoot identifier as a list of numbers. * Numbers can be defined in base 2^8 (byte), 2^16 (short) or 2^32 (int). * Last element of the list represent the replica identifier and its clock. * @author urso Stephane Martin <stephane.martin@loria.fr> */ public class LogootListPosition implements ListIdentifier<LogootListPosition> { private final Content position; private Content createContent(int base, int size) { if (base == 8) { return new ByteContent(size); } else if (base == 16) { return new ShortContent(size); } else if (base == 32) { return new IntContent(size); } else { throw new IllegalArgumentException("Illegal base."); } } LogootListPosition(Content position) { this.position = position; } /** * Make object from position. */ public LogootListPosition(int base, int pos) { this.position = createContent(base, 1); this.position.set(0, pos); } /** * Prepare ListPosition with given position size replica identifier and * clock. */ public LogootListPosition(int base, int size, int replicaId, int clock) { if (base < 32) { int nr = nbElem(base, replicaId); int nc = nbElem(base, clock); int iSize = size + nr + nc; this.position = createContent(base, iSize + 1); putInt(size, replicaId); putInt(size + nr, clock); this.position.set(iSize, ((nr << 4) + nc)); } else { // int this.position = createContent(base, size + 2); this.position.set(size, replicaId); this.position.set(size + 1, clock); } } /** * Number of element to represent this int. TODO : More efficient ? */ private static byte nbElem(int base, int value) { byte l = 0; while (value != 0) { value >>>= base; ++l; } return l; } /** * Puts an reserved l-length element presentation of the int value at the * given position. */ private void putInt(int pos, int value) { for (int i = 0; value != 0; ++i) { position.set(pos + i, value & position.mask()); value >>>= position.base(); } } /** * Retrieves the int encodes with length element finishing after position pos. */ private int getInt(int pos, int length) { int value = 0; for (int i = 1; i <= length; ++i) { value = (value << position.base()) + (position.get(pos - i) & position.mask()); } return value; } /** * Return the element in the position i or Byte.MIN_VALUE */ public int getSafe(int i) { return i < position.length() ? position.get(i) : position.min(); } /** * Sets the lement at the given position. * */ void set(int pos, int b) { position.set(pos, b); } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final LogootListPosition other = (LogootListPosition) obj; if (!this.position.equals(other.position)) { return false; } return true; } @Override public int hashCode() { int hash = 7; hash = 67 * hash + (this.position != null ? this.position.hashCode() : 0); return hash; } @Override public String toString() { StringBuilder s = new StringBuilder("FLPosition["); for (int i = 0; i < position.length() - 1; ++i) { s.append(position.get(i)).append(','); } s.append(position.get(position.length() - 1)).append(']'); return s.toString(); } @Override public int length() { return position.length(); } @Override public ListIdentifier clone() { return new LogootListPosition(position.clone()); } @Override public int compareTo(LogootListPosition o) { int i = 0; while (i < this.position.length() && i < o.position.length()) { int d = Integer.compare(this.position.get(i), o.position.get(i)); if (d != 0) { return d; } ++i; } if (i < this.position.length()) { return 1; } else if (i < o.position.length()) { return -1; } return 0; } @Override public int replica() { if (position.base() < 32) { int size = position.get(position.length() - 1); return getInt(position.length() - 1 - size & 0x0F, size >> 4); } else { // int return position.get(position.length() - 2); } } @Override public int clock() { if (position.base() < 32) { int size = position.get(position.length() - 1); return getInt(position.length() - 1, size & 0x0F); } else { // int return position.get(position.length() - 1); } } } interface Content extends Cloneable { int get(int i); void set(int i, int v); Content clone(); int length(); int min(); int base(); public int mask(); } class ByteContent implements Content, Serializable{ final private byte[] position; ByteContent(int size) { position = new byte[size]; } @Override public int get(int i) { return position[i]; } @Override public void set(int i, int v) { position[i] = (byte) v; } ByteContent(byte [] pos) { position = pos; } @Override public Content clone() { return new ByteContent(position.clone()); } @Override public int length() { return position.length; } @Override public int min() { return Byte.MIN_VALUE; } @Override public int base() { return 8; } @Override public int hashCode() { int hash = 7; hash = 79 * hash + Arrays.hashCode(this.position); return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final ByteContent other = (ByteContent) obj; if (!Arrays.equals(this.position, other.position)) { return false; } return true; } @Override public int mask() { return 0xFF; } } class ShortContent implements Content, Serializable { final private short[] position; ShortContent(int size) { position = new short[size]; } @Override public int get(int i) { return position[i]; } @Override public void set(int i, int v) { position[i] = (short) v; } ShortContent(short [] pos) { position = pos; } @Override public Content clone() { return new ShortContent(position.clone()); } @Override public int length() { return position.length; } @Override public int min() { return Short.MIN_VALUE; } @Override public int base() { return 16; } @Override public int hashCode() { int hash = 3; hash = 61 * hash + Arrays.hashCode(this.position); return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final ShortContent other = (ShortContent) obj; if (!Arrays.equals(this.position, other.position)) { return false; } return true; } @Override public int mask() { return 0xFFFF; } } class IntContent implements Content, Serializable { final private int[] position; IntContent(int size) { position = new int[size]; } @Override public int get(int i) { return position[i]; } @Override public void set(int i, int v) { position[i] = (int) v; } IntContent(int [] pos) { position = pos; } @Override public Content clone() { return new IntContent(position.clone()); } @Override public int length() { return position.length; } @Override public int min() { return Integer.MIN_VALUE; } @Override public int base() { return 32; } @Override public int hashCode() { int hash = 7; hash = 43 * hash + Arrays.hashCode(this.position); return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final IntContent other = (IntContent) obj; if (!Arrays.equals(this.position, other.position)) { return false; } return true; } @Override public int mask() { return 0xFFFFFFFF; } }