]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.impl/src/org/simantics/db/impl/Table.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.db.impl / src / org / simantics / db / impl / Table.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.db.impl;\r
13 \r
14 import org.simantics.db.exception.DatabaseException;\r
15 import org.simantics.db.impl.ClusterI.Procedure;\r
16 import org.simantics.db.service.Bytes;\r
17 \r
18 interface TableFactoryI<TableType> {\r
19     TableType newTable(int size);\r
20     boolean isEqual(TableType t1, int t1Start, int size, TableType t2, int t2Start);\r
21 }\r
22 \r
23 class ByteFactory implements TableFactoryI<byte[]> {\r
24     @Override\r
25     public byte[] newTable(int size) {\r
26         return new byte[size];\r
27     }\r
28 \r
29     @Override\r
30     public boolean isEqual(byte[] t1, int start, int size, byte[] t2, int start2) {\r
31         for (int i=0; i<size; ++i)\r
32             if (t1[start + i] != t2[start2 + i])\r
33                 return false;\r
34         return true;\r
35     }\r
36 }\r
37 \r
38 class IntFactory implements TableFactoryI<int[]> {\r
39     @Override\r
40     public int[] newTable(int size) {\r
41         return new int[size];\r
42     }\r
43 \r
44     @Override\r
45     public boolean isEqual(int[] t1, int start, int size, int[] t2, int start2) {\r
46         for (int i=0; i<size; ++i)\r
47             if (t1[start + i] != t2[start2 + i])\r
48                 return false;\r
49         return true;\r
50     }\r
51 }\r
52 \r
53 class LongFactory implements TableFactoryI<long[]> {\r
54     @Override\r
55     public long[] newTable(int size) {\r
56         return new long[size];\r
57     }\r
58 \r
59     @Override\r
60     public boolean isEqual(long[] t1, int start, int size, long[] t2, int start2) {\r
61         for (int i=0; i<size; ++i)\r
62             if (t1[start + i] != t2[start2 + i])\r
63                 return false;\r
64         return true;\r
65     }\r
66 }\r
67 \r
68 public abstract class Table<TableType> {\r
69     private static final int INITIAL_SIZE = 100; // Initial size of the table. Must be greater or equal than header_size;\r
70     private static final int INCREMENT_SIZE = 1000; // Minimum increment size of the table.\r
71     protected static final int ZERO_SHIFT = 1; // Indexes are guaranteed not to be zero.\r
72     final private TableHeader header;\r
73     final private TableFactoryI<TableType> factory;\r
74     final private TableSizeListener sizeListener;\r
75     public int offset; // Offset of table in containing array.\r
76     public TableType table;\r
77     protected Table(TableFactoryI<TableType> factory, TableSizeListener sizeListener, int[] header, int headerBase) {\r
78         this.factory = factory;\r
79         this.sizeListener = sizeListener;\r
80         this.header = new TableHeader(header, headerBase);\r
81         this.offset = -ZERO_SHIFT;\r
82         newTable(INITIAL_SIZE);\r
83         this.header.setSize(0);\r
84         this.header.setCount(0);\r
85         this.header.setOffset(offset);\r
86     }\r
87 \r
88 //    final int size(Object bytes) {\r
89 //        if(bytes instanceof byte[]) return ((byte[])bytes).length;\r
90 //        if(bytes instanceof int[]) return ((int[])bytes).length;\r
91 //        if(bytes instanceof long[]) return ((long[])bytes).length;\r
92 //        return 0;\r
93 //    }\r
94 \r
95     protected Table(TableFactoryI<TableType> factory, TableSizeListener sizeListener, int[] header, int headerBase, TableType bytes) {\r
96 //        System.out.println("Table size=" + size(bytes) + " header = " + Arrays.toString(Arrays.copyOfRange(header, headerBase, headerBase + 4)));\r
97         this.factory = factory;\r
98         this.sizeListener = sizeListener;\r
99         this.header = new TableHeader(header, headerBase);\r
100         offset = this.header.getOffset();\r
101         this.table = bytes;\r
102     }\r
103     /**\r
104      * Create and initialize this with a new table.\r
105      *\r
106      * @param capacity of the table. How many elements the table can hold without allocating new space.\r
107      * @param size of the table. How many elements have been used.\r
108      * @param count of how many segments has been have been allocated.\r
109      * @return old table.\r
110      */\r
111     final protected TableType createNewTable(int capacity, int size, int count) {\r
112         TableType t = table;\r
113         this.offset = -ZERO_SHIFT;\r
114         newTable(capacity);\r
115         sizeListener.resized();\r
116         header.setSize(size);\r
117         header.setCount(count);\r
118         header.setOffset(offset);\r
119         return t;\r
120     }\r
121     public final int getTableCapacity() {\r
122         return header.getCapacity();\r
123     }\r
124     public final int getTableSize() {\r
125         return header.getSize();\r
126     }\r
127     public final int getTableCount() {\r
128         return header.getCount();\r
129     }\r
130     protected int convertRealIndexToTableIndex(int realIndex) {\r
131         return realIndex - offset;\r
132     }\r
133     protected final int checkIndexAndGetRealIndex(int index, int size)  {\r
134         if (index < ZERO_SHIFT)\r
135             throw new IllegalArgumentException("Underflow, index=" + index);\r
136         if ((size > 0 && index - ZERO_SHIFT + size > header.getSize()))\r
137             throw new IllegalArgumentException("Overflow, index=" + index + " size=" + size);\r
138         return index + offset;\r
139     }\r
140     protected final int checkIndexAndGetRealIndexEx(int index, int size)  {\r
141         if (index < ZERO_SHIFT || size < 1)\r
142             throw new IllegalArgumentException("Underflow, index=" + index + " size=" + size);\r
143         if (index - ZERO_SHIFT + size < header.getSize())\r
144             return index + offset;\r
145         else if (index - ZERO_SHIFT + size == header.getSize())\r
146             return -1;\r
147         else\r
148             throw new IllegalArgumentException("Underflow, index=" + index + " size=" + size);\r
149     }\r
150     final protected void getCopy(int index, byte[] to, int start, int size) {\r
151         int realIndex = checkIndexAndGetRealIndex(index, size);\r
152         if (size < 0)\r
153             throw new IllegalArgumentException("Illgal table size " + size);\r
154         System.arraycopy(table, realIndex, to, start, size);\r
155     }\r
156     final protected void getCopy(int index, char[] to, int start, int size) {\r
157 //        int realIndex = checkIndexAndGetRealIndex(index, size);\r
158 //        if (size < 0)\r
159 //            throw new IllegalArgumentException("Illgal table size " + size);\r
160         byte[] bs = (byte[])table;\r
161         start += index+offset+1;\r
162         for(int i=0;i<size;i++) to[i] = (char)bs[start++];\r
163 //        System.arraycopy(table, realIndex, to, start, size);\r
164     }\r
165     final protected void setCopy(int index, int size, TableType from, int fromStartIndex) {\r
166 //        System.out.println("setCopy index=" + index + " size=" + size + "fromStartIndex=" + fromStartIndex + "from.length=" + ((byte[])from).length + "table.length=" + ((byte[])table).length);\r
167         int realIndex = checkIndexAndGetRealIndex(index, size);\r
168         System.arraycopy(from, fromStartIndex, table, realIndex, size);\r
169     }\r
170     final protected boolean isEqual(int index, TableType to, int toStartIndex, int toSize) {\r
171         int realIndex = checkIndexAndGetRealIndex(index, toSize);\r
172         return factory.isEqual(table, realIndex, toSize, to, toStartIndex);\r
173     }\r
174     /**\r
175      * @param size of the element (how many table slots is allocated).\r
176      * @return table index not the real index. To get real index use checkIndexAndGetRealIndex.\r
177      */\r
178     final protected int createNewElement(int size) {\r
179         if (size < 0)\r
180             throw new IllegalArgumentException("Illegal table size " + size);\r
181         if (0 == size)\r
182             return ZERO_SHIFT;\r
183         int oldSize = header.getSize();\r
184         int newSize = oldSize + size;\r
185         if (newSize > header.getCapacity())\r
186             realloc(newSize);\r
187         header.setSize(newSize);\r
188         header.setCount(header.getCount()+1);\r
189         return ZERO_SHIFT + oldSize;\r
190     }\r
191     final protected void deleteOldElement(int index, int size) {\r
192         checkIndexAndGetRealIndex(index, size);\r
193         header.setCount(header.getCount()-1);\r
194     }\r
195     final protected TableHeader getHeader() {\r
196         return header;\r
197     }\r
198     final protected int getTableBase() {\r
199         return offset + ZERO_SHIFT;\r
200     }\r
201     final protected TableType getTable() {\r
202         return table;\r
203     }\r
204     final protected int getExtra(int index) {\r
205                 return header.getExtra(index);\r
206         }\r
207     final protected void setExtra(int index, int value) {\r
208                 header.setExtra(index, value);\r
209         }\r
210     final private void realloc(int newSize) {\r
211         int realCapacity = newSize + Math.max(INCREMENT_SIZE, newSize/10);\r
212         TableType oldTable = table;\r
213         newTable(realCapacity);\r
214         sizeListener.resized();\r
215         int oldBase = getTableBase();\r
216         offset = -ZERO_SHIFT;\r
217         header.setOffset(offset);\r
218         int oldSize = header.getSize();\r
219         // If zero can cause ArrayIndexOutOfBoundsException because oldBase\r
220         // (index) can be out of bounds in this case and it is checked even\r
221         // if olsSize is zero (i.e. number of copied bytes is zero).\r
222         if (oldSize > 0) {\r
223                 System.arraycopy(oldTable, oldBase, table, 0, oldSize);\r
224         }\r
225     }\r
226     final private void newTable(int capacity) {\r
227         table = factory.newTable(capacity);\r
228         header.setCapacity(capacity);\r
229         }\r
230     \r
231     public <T> int store(T _ret, int retPos) {\r
232         \r
233         int off = retPos;\r
234         \r
235         if(table instanceof byte[]) {\r
236             System.arraycopy(table, getTableBase(), _ret, retPos, getHeader().getSize());\r
237             retPos += getHeader().getSize();\r
238         } else if(table instanceof int[]) {\r
239             int[] t = (int[])table;\r
240             int[] ret = (int[])_ret;\r
241             for(int i=getTableBase();i<getTableBase() + getHeader().getSize();i++) {\r
242                 int v = t[i];\r
243                 ret[retPos++] = v;\r
244 //              Bytes.writeLE(ret, retPos, v);\r
245 //              retPos += 4;\r
246             }\r
247         } else if(table instanceof long[]) {\r
248             long[] t = (long[])table;\r
249             long[] ret = (long[])_ret;\r
250             for(int i=getTableBase();i<getTableBase() + getHeader().getSize();i++) {\r
251                 long v = t[i];\r
252                 ret[retPos++] = v;\r
253 //              Bytes.writeLE8(ret, retPos, v);\r
254 //              retPos += 8;\r
255             }\r
256         }\r
257         getHeader().setOffset(off-1);\r
258         getHeader().setCapacity(getHeader().getSize());\r
259         return retPos;\r
260     }\r
261     \r
262     public <T> int storeBytes(byte[] _ret, int off, int retPos) {\r
263         \r
264         //int off = retPos;\r
265         \r
266         if(table instanceof byte[]) {\r
267             System.arraycopy(table, getTableBase(), _ret, retPos, getHeader().getSize());\r
268             retPos += getHeader().getSize();\r
269         } else if(table instanceof int[]) {\r
270             int[] t = (int[])table;\r
271             for(int i=getTableBase();i<getTableBase() + getHeader().getSize();i++) {\r
272                 int v = t[i];\r
273 //              ret[retPos++] = v;\r
274                 Bytes.writeLE(_ret, retPos, v);\r
275                 retPos += 4;\r
276             }\r
277         } else if(table instanceof long[]) {\r
278             long[] t = (long[])table;\r
279             for(int i=getTableBase();i<getTableBase() + getHeader().getSize();i++) {\r
280                 long v = t[i];\r
281                 Bytes.writeLE8(_ret, retPos, v);\r
282                 retPos += 8;\r
283             }\r
284         }\r
285         \r
286         getHeader().setOffset(off-1);\r
287         getHeader().setCapacity(getHeader().getSize());\r
288         return retPos;\r
289         \r
290     }\r
291     \r
292     public abstract <Context> boolean foreach(int setIndex, Procedure procedure, final Context context, final ClusterSupport support, Modifier modifier) throws DatabaseException;\r
293     \r
294 }\r