1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.db.impl;
14 import org.simantics.db.exception.DatabaseException;
15 import org.simantics.db.impl.ClusterI.Procedure;
16 import org.simantics.db.service.Bytes;
18 interface TableFactoryI<TableType> {
19 TableType newTable(int size);
20 boolean isEqual(TableType t1, int t1Start, int size, TableType t2, int t2Start);
23 class ByteFactory implements TableFactoryI<byte[]> {
25 public byte[] newTable(int size) {
26 return new byte[size];
30 public boolean isEqual(byte[] t1, int start, int size, byte[] t2, int start2) {
31 for (int i=0; i<size; ++i)
32 if (t1[start + i] != t2[start2 + i])
38 class IntFactory implements TableFactoryI<int[]> {
40 public int[] newTable(int size) {
45 public boolean isEqual(int[] t1, int start, int size, int[] t2, int start2) {
46 for (int i=0; i<size; ++i)
47 if (t1[start + i] != t2[start2 + i])
53 class LongFactory implements TableFactoryI<long[]> {
55 public long[] newTable(int size) {
56 return new long[size];
60 public boolean isEqual(long[] t1, int start, int size, long[] t2, int start2) {
61 for (int i=0; i<size; ++i)
62 if (t1[start + i] != t2[start2 + i])
68 public abstract class Table<TableType> {
69 private static final int INITIAL_SIZE = 100; // Initial size of the table. Must be greater or equal than header_size;
70 private static final int INCREMENT_SIZE = 1000; // Minimum increment size of the table.
71 protected static final int ZERO_SHIFT = 1; // Indexes are guaranteed not to be zero.
72 final private TableHeader header;
73 final private TableFactoryI<TableType> factory;
74 final private TableSizeListener sizeListener;
75 public int offset; // Offset of table in containing array.
76 public TableType table;
77 protected Table(TableFactoryI<TableType> factory, TableSizeListener sizeListener, int[] header, int headerBase) {
78 this.factory = factory;
79 this.sizeListener = sizeListener;
80 this.header = new TableHeader(header, headerBase);
81 this.offset = -ZERO_SHIFT;
82 newTable(INITIAL_SIZE);
83 this.header.setSize(0);
84 this.header.setCount(0);
85 this.header.setOffset(offset);
88 // final int size(Object bytes) {
89 // if(bytes instanceof byte[]) return ((byte[])bytes).length;
90 // if(bytes instanceof int[]) return ((int[])bytes).length;
91 // if(bytes instanceof long[]) return ((long[])bytes).length;
95 protected Table(TableFactoryI<TableType> factory, TableSizeListener sizeListener, int[] header, int headerBase, TableType bytes) {
96 // System.out.println("Table size=" + size(bytes) + " header = " + Arrays.toString(Arrays.copyOfRange(header, headerBase, headerBase + 4)));
97 this.factory = factory;
98 this.sizeListener = sizeListener;
99 this.header = new TableHeader(header, headerBase);
100 offset = this.header.getOffset();
104 * Create and initialize this with a new table.
106 * @param capacity of the table. How many elements the table can hold without allocating new space.
107 * @param size of the table. How many elements have been used.
108 * @param count of how many segments has been have been allocated.
111 final protected TableType createNewTable(int capacity, int size, int count) {
113 this.offset = -ZERO_SHIFT;
115 sizeListener.resized();
116 header.setSize(size);
117 header.setCount(count);
118 header.setOffset(offset);
121 public final int getTableCapacity() {
122 return header.getCapacity();
124 public final int getTableSize() {
125 return header.getSize();
127 public final int getTableCount() {
128 return header.getCount();
130 protected int convertRealIndexToTableIndex(int realIndex) {
131 return realIndex - offset;
133 protected final int checkIndexAndGetRealIndex(int index, int size) {
134 if (index < ZERO_SHIFT)
135 throw new IllegalArgumentException("Underflow, index=" + index);
136 if ((size > 0 && index - ZERO_SHIFT + size > header.getSize()))
137 throw new IllegalArgumentException("Overflow, index=" + index + " size=" + size);
138 return index + offset;
140 protected final int checkIndexAndGetRealIndexEx(int index, int size) {
141 if (index < ZERO_SHIFT || size < 1)
142 throw new IllegalArgumentException("Underflow, index=" + index + " size=" + size);
143 if (index - ZERO_SHIFT + size < header.getSize())
144 return index + offset;
145 else if (index - ZERO_SHIFT + size == header.getSize())
148 throw new IllegalArgumentException("Underflow, index=" + index + " size=" + size);
150 final protected void getCopy(int index, byte[] to, int start, int size) {
151 int realIndex = checkIndexAndGetRealIndex(index, size);
153 throw new IllegalArgumentException("Illgal table size " + size);
154 System.arraycopy(table, realIndex, to, start, size);
156 final protected void getCopy(int index, char[] to, int start, int size) {
157 // int realIndex = checkIndexAndGetRealIndex(index, size);
159 // throw new IllegalArgumentException("Illgal table size " + size);
160 byte[] bs = (byte[])table;
161 start += index+offset+1;
162 for(int i=0;i<size;i++) to[i] = (char)bs[start++];
163 // System.arraycopy(table, realIndex, to, start, size);
165 final protected void setCopy(int index, int size, TableType from, int fromStartIndex) {
166 // System.out.println("setCopy index=" + index + " size=" + size + "fromStartIndex=" + fromStartIndex + "from.length=" + ((byte[])from).length + "table.length=" + ((byte[])table).length);
167 int realIndex = checkIndexAndGetRealIndex(index, size);
168 System.arraycopy(from, fromStartIndex, table, realIndex, size);
170 final protected boolean isEqual(int index, TableType to, int toStartIndex, int toSize) {
171 int realIndex = checkIndexAndGetRealIndex(index, toSize);
172 return factory.isEqual(table, realIndex, toSize, to, toStartIndex);
175 * @param size of the element (how many table slots is allocated).
176 * @return table index not the real index. To get real index use checkIndexAndGetRealIndex.
178 final protected int createNewElement(int size) {
180 throw new IllegalArgumentException("Illegal table size " + size);
183 int oldSize = header.getSize();
184 int newSize = oldSize + size;
185 if (newSize > header.getCapacity())
187 header.setSize(newSize);
188 header.setCount(header.getCount()+1);
189 return ZERO_SHIFT + oldSize;
191 final protected void deleteOldElement(int index, int size) {
192 checkIndexAndGetRealIndex(index, size);
193 header.setCount(header.getCount()-1);
195 final protected TableHeader getHeader() {
198 final protected int getTableBase() {
199 return offset + ZERO_SHIFT;
201 final protected TableType getTable() {
204 final protected int getExtra(int index) {
205 return header.getExtra(index);
207 final protected void setExtra(int index, int value) {
208 header.setExtra(index, value);
210 final private void realloc(int newSize) {
211 int realCapacity = newSize + Math.max(INCREMENT_SIZE, newSize/10);
212 TableType oldTable = table;
213 newTable(realCapacity);
214 sizeListener.resized();
215 int oldBase = getTableBase();
216 offset = -ZERO_SHIFT;
217 header.setOffset(offset);
218 int oldSize = header.getSize();
219 // If zero can cause ArrayIndexOutOfBoundsException because oldBase
220 // (index) can be out of bounds in this case and it is checked even
221 // if olsSize is zero (i.e. number of copied bytes is zero).
223 System.arraycopy(oldTable, oldBase, table, 0, oldSize);
226 final private void newTable(int capacity) {
227 table = factory.newTable(capacity);
228 header.setCapacity(capacity);
231 public <T> int store(T _ret, int retPos) {
235 if(table instanceof byte[]) {
236 System.arraycopy(table, getTableBase(), _ret, retPos, getHeader().getSize());
237 retPos += getHeader().getSize();
238 } else if(table instanceof int[]) {
239 int[] t = (int[])table;
240 int[] ret = (int[])_ret;
241 for(int i=getTableBase();i<getTableBase() + getHeader().getSize();i++) {
244 // Bytes.writeLE(ret, retPos, v);
247 } else if(table instanceof long[]) {
248 long[] t = (long[])table;
249 long[] ret = (long[])_ret;
250 for(int i=getTableBase();i<getTableBase() + getHeader().getSize();i++) {
253 // Bytes.writeLE8(ret, retPos, v);
257 getHeader().setOffset(off-1);
258 getHeader().setCapacity(getHeader().getSize());
262 public <T> int storeBytes(byte[] _ret, int off, int retPos) {
266 if(table instanceof byte[]) {
267 System.arraycopy(table, getTableBase(), _ret, retPos, getHeader().getSize());
268 retPos += getHeader().getSize();
269 } else if(table instanceof int[]) {
270 int[] t = (int[])table;
271 for(int i=getTableBase();i<getTableBase() + getHeader().getSize();i++) {
273 // ret[retPos++] = v;
274 Bytes.writeLE(_ret, retPos, v);
277 } else if(table instanceof long[]) {
278 long[] t = (long[])table;
279 for(int i=getTableBase();i<getTableBase() + getHeader().getSize();i++) {
281 Bytes.writeLE8(_ret, retPos, v);
286 getHeader().setOffset(off-1);
287 getHeader().setCapacity(getHeader().getSize());
292 public abstract <Context> boolean foreach(int setIndex, Procedure procedure, final Context context, final ClusterSupport support, Modifier modifier) throws DatabaseException;