--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.databoard.accessor.impl;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.accessor.MapAccessor;\r
+import org.simantics.databoard.accessor.error.AccessorException;\r
+import org.simantics.databoard.binding.ArrayBinding;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.BooleanBinding;\r
+import org.simantics.databoard.binding.NumberBinding;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.binding.impl.BooleanArrayBinding;\r
+import org.simantics.databoard.binding.impl.ByteArrayBinding;\r
+import org.simantics.databoard.binding.impl.DoubleArrayBinding;\r
+import org.simantics.databoard.binding.impl.FloatArrayBinding;\r
+import org.simantics.databoard.binding.impl.IntArrayBinding;\r
+import org.simantics.databoard.binding.impl.LongArrayBinding;\r
+import org.simantics.databoard.type.ArrayType;\r
+import org.simantics.databoard.util.Limit;\r
+import org.simantics.databoard.util.Range;\r
+\r
+/**\r
+ * This helper class creates an iterator to MapAccessor\r
+ *\r
+ * @param <K> key class\r
+ * @param <V> value class\r
+ * @author Toni Kalajainen <toni.kalajainen@vtt.fi>\r
+ */\r
+public class MapAccessorIterator<K, V> {\r
+ \r
+ MapAccessor map;\r
+ Binding keyBinding;\r
+ Binding valueBinding;\r
+ \r
+ Object from;\r
+ boolean fromInclusive;\r
+ \r
+ Object end;\r
+ boolean endInclusive;\r
+\r
+ ArrayBinding keyCacheBinding;\r
+ Object keyCache;\r
+ \r
+ ArrayBinding valueCacheBinding;\r
+ Object valueCache;\r
+ \r
+ // Entry index, i.e. the number of entries read starting from 0\r
+ int index = -1;\r
+ \r
+ // The number of samples written to cache\r
+ int samplesInCache = 0;\r
+ \r
+ // The index in cache\r
+ int cacheIndex = -1;\r
+ \r
+ /**\r
+ * Initialize iterator with a cache. The cache should already be allocated with some empty elements.\r
+ * @param map\r
+ * @param keyBinding\r
+ * @param from\r
+ * @param fromInclusive\r
+ * @param end\r
+ * @param endInclusive\r
+ * @param keyCacheBinding\r
+ * @param keyCache\r
+ * @param valueCacheBinding\r
+ * @param valueCache\r
+ */\r
+ public MapAccessorIterator(\r
+ MapAccessor map, \r
+ Binding keyBinding, Object from, boolean fromInclusive, Object end, boolean endInclusive, \r
+ ArrayBinding keyCacheBinding, Object keyCache,\r
+ ArrayBinding valueCacheBinding, Object valueCache) {\r
+ this.map = map;\r
+ this.keyBinding = keyBinding;\r
+ this.from = from;\r
+ this.fromInclusive = fromInclusive;\r
+ this.end = end;\r
+ this.endInclusive = endInclusive;\r
+ this.valueBinding = valueCacheBinding.getComponentBinding();\r
+ this.keyCacheBinding = keyCacheBinding;\r
+ this.keyCache = keyCache;\r
+ this.valueCacheBinding = valueCacheBinding;\r
+ this.valueCache = valueCache;\r
+ }\r
+\r
+ /**\r
+ * Initialize map accessor iterator with a default cache\r
+ * @param map\r
+ * @param keyBinding\r
+ * @param from\r
+ * @param fromInclusive\r
+ * @param end\r
+ * @param endInclusive\r
+ * @param valueBinding\r
+ * @param cacheSize\r
+ * @throws BindingException \r
+ * @throws AccessorException \r
+ */\r
+ public MapAccessorIterator(\r
+ MapAccessor map, \r
+ Binding keyBinding, Object from, boolean fromInclusive, Object end, boolean endInclusive,\r
+ Binding valueBinding,\r
+ int cacheSize) throws BindingException, AccessorException {\r
+ this.map = map;\r
+ this.keyBinding = keyBinding;\r
+ this.from = from;\r
+ this.fromInclusive = fromInclusive;\r
+ this.end = end;\r
+ this.endInclusive = endInclusive;\r
+ this.valueBinding = valueBinding;\r
+ \r
+ // TODO calc num of elements if source\r
+// int count = map.count(keyBinding, from, fromInclusive, end, endInclusive); \r
+// int len = Math.min(count, 256);\r
+ Range range = new Range(Limit.inclusive(cacheSize), Limit.nolimit());\r
+ this.keyCacheBinding = Bindings.getBinding( new ArrayType(keyBinding.type(), range) );\r
+ this.keyCache = keyCacheBinding.createDefault();\r
+ this.valueCacheBinding = Bindings.getBinding( new ArrayType(valueBinding.type(), range) );\r
+ this.valueCache = valueCacheBinding.createDefault();\r
+ }\r
+\r
+ /**\r
+ * Reads data to cache.\r
+ * \r
+ * Updates from and fromInclusive fields for next read.\r
+ * Updates samplesInCache field.\r
+ * Sets cacheIndex to 0.\r
+ * \r
+ * @throws AccessorException\r
+ */\r
+ private void fillCache() throws AccessorException {\r
+ try {\r
+ int limit = Math.min(keyCacheBinding.size(keyCache), valueCacheBinding.size(valueCache));\r
+ if (limit==0) throw new AccessorException("You should have some entries in the cache");\r
+ \r
+ cacheIndex = -1;\r
+ \r
+ if (from==null) {\r
+ samplesInCache = 0;\r
+ return;\r
+ }\r
+ \r
+ samplesInCache = map.getEntries(\r
+ keyBinding, from, fromInclusive, \r
+ end, endInclusive, \r
+ keyCacheBinding, keyCache, \r
+ valueCacheBinding, valueCache, \r
+ limit);\r
+ \r
+ if (samplesInCache==0) {\r
+ from = null;\r
+ return;\r
+ }\r
+ \r
+ from = keyCacheBinding.get(keyCache, samplesInCache-1);\r
+ fromInclusive = false;\r
+ } catch (BindingException e) {\r
+ throw new AccessorException(e);\r
+ }\r
+ }\r
+ \r
+ public boolean hasNext() throws AccessorException {\r
+ if (from==null) return false; \r
+ if (cacheIndex>=samplesInCache-1) fillCache();\r
+ if (cacheIndex>=samplesInCache-1) return false;\r
+ return cacheIndex+1<samplesInCache;\r
+ }\r
+ \r
+ public boolean next() throws AccessorException {\r
+ if (from==null) return false;\r
+ if (cacheIndex>=samplesInCache-1) fillCache();\r
+ if (cacheIndex>=samplesInCache-1) return false; \r
+ cacheIndex++;\r
+ index++;\r
+ return true;\r
+ }\r
+\r
+ @SuppressWarnings("unchecked")\r
+ public K key() throws AccessorException {\r
+ try {\r
+ return (K) keyCacheBinding.get(keyCache, cacheIndex);\r
+ } catch (IndexOutOfBoundsException e) {\r
+ throw new AccessorException(e);\r
+ } catch (BindingException e) {\r
+ throw new AccessorException(e);\r
+ }\r
+ }\r
+ \r
+ @SuppressWarnings("unchecked")\r
+ public V value() throws AccessorException {\r
+ try {\r
+ return (V) valueCacheBinding.get(valueCache, cacheIndex);\r
+ } catch (IndexOutOfBoundsException e) {\r
+ throw new AccessorException(e);\r
+ } catch (BindingException e) {\r
+ throw new AccessorException(e);\r
+ }\r
+ }\r
+ \r
+ public double keyDouble() throws AccessorException {\r
+ try {\r
+ if (keyCacheBinding instanceof FloatArrayBinding) {\r
+ return ((float[]) keyCache)[cacheIndex];\r
+ }\r
+ if (keyCacheBinding instanceof DoubleArrayBinding) {\r
+ return ((double[]) keyCache)[cacheIndex];\r
+ }\r
+ if (keyCacheBinding instanceof ByteArrayBinding) {\r
+ return ((byte[]) keyCache)[cacheIndex];\r
+ }\r
+ if (keyCacheBinding instanceof IntArrayBinding) {\r
+ return ((int[]) keyCache)[cacheIndex];\r
+ }\r
+ if (keyCacheBinding instanceof LongArrayBinding) {\r
+ return ((long[]) keyCache)[cacheIndex];\r
+ }\r
+ if (keyCacheBinding instanceof BooleanArrayBinding) {\r
+ return ((boolean[]) keyCache)[cacheIndex] ? 1.0 : 0.0;\r
+ }\r
+ Object o = keyCacheBinding.get(keyCache, cacheIndex);\r
+ Binding b = keyCacheBinding.getComponentBinding();\r
+ if (b instanceof BooleanBinding)\r
+ return ((BooleanBinding)b).getValue(o) ? 1.0 : 0.0;\r
+ NumberBinding nb = (NumberBinding) b;\r
+ return nb.getValue(o).doubleValue();\r
+ } catch (IndexOutOfBoundsException e) {\r
+ throw new AccessorException(e);\r
+ } catch (BindingException e) {\r
+ throw new AccessorException(e);\r
+ }\r
+ }\r
+ \r
+ public double valueDouble() throws AccessorException {\r
+ try {\r
+ if (valueCacheBinding instanceof FloatArrayBinding) {\r
+ return ((float[]) valueCache)[cacheIndex];\r
+ }\r
+ if (valueCacheBinding instanceof DoubleArrayBinding) {\r
+ return ((double[]) valueCache)[cacheIndex];\r
+ }\r
+ if (valueCacheBinding instanceof ByteArrayBinding) {\r
+ return ((byte[]) valueCache)[cacheIndex];\r
+ }\r
+ if (valueCacheBinding instanceof IntArrayBinding) {\r
+ return ((int[]) valueCache)[cacheIndex];\r
+ }\r
+ if (valueCacheBinding instanceof LongArrayBinding) {\r
+ return ((long[]) valueCache)[cacheIndex];\r
+ }\r
+ if (valueCacheBinding instanceof BooleanArrayBinding) {\r
+ return ((boolean[]) valueCache)[cacheIndex] ? 1.0 : 0.0;\r
+ }\r
+ Object o = valueCacheBinding.get(valueCache, cacheIndex);\r
+ Binding b = valueCacheBinding.getComponentBinding();\r
+ if (b instanceof BooleanBinding)\r
+ return ((BooleanBinding)b).getValue(o) ? 1.0 : 0.0;\r
+ NumberBinding nb = (NumberBinding) b;\r
+ return nb.getValue(o).doubleValue();\r
+ } catch (IndexOutOfBoundsException e) {\r
+ throw new AccessorException(e);\r
+ } catch (BindingException e) {\r
+ throw new AccessorException(e);\r
+ }\r
+ }\r
+ \r
+ public int index() {\r
+ return index;\r
+ }\r
+\r
+}\r
+\r