/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.db.procore.cluster; import java.util.Arrays; import java.util.Map; import java.util.TreeMap; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.ValidationException; import org.simantics.db.impl.ClusterI.ObjectProcedure; import org.simantics.db.impl.ClusterI.Procedure; import org.simantics.db.impl.ClusterSupport; import org.simantics.db.impl.Modifier; import org.simantics.db.impl.Table; import org.simantics.db.impl.TableFactory; import org.simantics.db.impl.TableSizeListener; public final class ValueTableSmall extends Table { private static final boolean DEBUG = ClusterImpl.DEBUG; public ValueTableSmall(TableSizeListener sizeListener, int[] header, int headerBase) { super(TableFactory.getByteFactory(), sizeListener, header, headerBase); } public ValueTableSmall(TableSizeListener sizeListener, int[] header, int headerBase, byte[] bytes) { super(TableFactory.getByteFactory(), sizeListener, header, headerBase, bytes); } private static final class IndexAndSize { int index; // Real index (zero based) to start of value data. short size; // Size of value data. } private IndexAndSize checkIndexAndGetRealIndex(int index) { if (index < ZERO_SHIFT) // Index starts with ZERO_SHIFT. throw new IllegalArgumentException("Underflow, index=" + index); int tableSize = getTableSize(); if (index >= tableSize) // Element size is at least two (one byte length and one byte data). throw new IllegalArgumentException("Overflow, index=" + index); int i = index + offset; byte[] table = getTable(); IndexAndSize is = new IndexAndSize(); is.size = table[i++]; if (is.size == 0) throw new IllegalArgumentException("Removed, index=" + index); if (is.size < 0) // two byte size is.size = (short)(((is.size & 0x7F) << 8) | (table[i++] & 0xFF)); is.index = i; if (is.index + is.size > tableSize) // Element size too big. throw new IllegalArgumentException("Illegal size, index=" + is.index + " size=" + is.size); return is; } public byte[] getValue(int valueIndex) { IndexAndSize is = checkIndexAndGetRealIndex(valueIndex); byte[] value = new byte[is.size]; System.arraycopy(table, is.index, value, 0, is.size); if (DEBUG) System.out.println("ValueTableSmall.getValue " + valueIndex + " " + Arrays.toString(value)); return value; } char[] getString(int valueIndex) { IndexAndSize is = checkIndexAndGetRealIndex(valueIndex); final int size = is.size-1; char[] t = new char[size]; int start = is.index; for(int i=0; i (1<<15)-1) throw new IllegalArgumentException("Illegal internal value size=" + vsize + "."); int size = vsize; if (vsize > 0x7F) size += 2; else size += 1; int valueIndex = createNewElement(size); int i = checkIndexAndGetRealIndex(valueIndex, 1); if (vsize > 0x7F) { table[i++] = (byte)((vsize >>> 8) | 1<<7); // msb table[i++] = (byte)(vsize & 0xFF); // lsb } else table[i++] = (byte)vsize; System.arraycopy(value, voffset, table, i, vsize); return valueIndex; } void removeValue(int valueIndex) { IndexAndSize is = checkIndexAndGetRealIndex(valueIndex); int length = is.size; int index = is.index; if (is.size > 0x7F) { length += 2; index -= 2; table[index+1] = 0; } else { length += 1; index -= 1; } table[index] = 0; deleteOldElement(valueIndex, length); } // boolean isEqual(int valueIndex, byte[] value, int voffset, int vsize) { // return isEqual(valueIndex, value, 0, value.length); // } private TreeMap valueMap = new TreeMap(); private int VALUE_SIZE = 0; private int VALUE_OFFSET = 0; public void checkValueInit() throws DatabaseException { valueMap.clear(); final int s = getTableSize(); final int c = getTableCapacity(); if (s < 0 || s > c) throw new ValidationException("Illegal value table size=" + s + " cap=" + c); VALUE_SIZE = s; VALUE_OFFSET = getTableBase() - ValueTableSmall.ZERO_SHIFT; } public void checkValue(int capacity, int index) throws DatabaseException { if (0 == capacity && 0 == index) return; if (capacity < 1) throw new ValidationException("Illegal resource value capacity=" + capacity); if (index < 1) throw new ValidationException("Illegal resource value index=" + index); if (VALUE_SIZE < capacity + index + VALUE_OFFSET) throw new ValidationException("Illegal resource value c=" + capacity + " i=" + index + " ts=" + VALUE_SIZE + " off=" + VALUE_OFFSET); // Duplicate index is allowed because new index is created only if new size is greater than old. Integer valueCap = valueMap.get(index); if (null == valueCap) valueMap.put(index, capacity); else if (capacity > valueCap) valueMap.put(index, capacity); else valueMap.put(index, valueCap); } public void checkValueFini() throws DatabaseException { int last = 0; for (Map.Entry e : valueMap.entrySet()) { int i = e.getKey(); int c = e.getValue(); int cur = VALUE_OFFSET + i; if (last > cur) throw new ValidationException("Index error with resource value c=" + c + " i=" + i + " ts=" + VALUE_SIZE + " off=" + VALUE_OFFSET); last = cur + c; } } @Override public boolean foreach(int setIndex, Procedure procedure, Context context, ClusterSupport support, Modifier modifier) throws DatabaseException { throw new UnsupportedOperationException(); } }