001/*- 002 * Copyright 2015, 2016 Diamond Light Source Ltd. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 */ 009 010package org.eclipse.january.dataset; 011 012import java.io.IOException; 013import java.util.Arrays; 014 015import org.eclipse.january.DatasetException; 016import org.eclipse.january.IMonitor; 017import org.eclipse.january.io.ILazyAsyncSaver; 018import org.eclipse.january.io.ILazySaver; 019 020/** 021 * Subclass of lazy dataset that allows setting slices 022 */ 023public class LazyWriteableDataset extends LazyDynamicDataset implements ILazyWriteableDataset { 024 private static final long serialVersionUID = -679846418938412535L; 025 private ILazySaver saver; 026 private Object fillValue; 027 private boolean writeAsync; 028 029 /** 030 * Create a lazy dataset 031 * @param name of dataset 032 * @param dtype dataset type 033 * @param elements item size 034 * @param shape dataset shape 035 * @param maxShape maximum shape 036 * @param chunks chunk shape 037 * @param saver lazy saver 038 * @deprecated Use {@link #LazyWriteableDataset(ILazySaver, String, int, Class, int[], int[], int[])} 039 */ 040 @Deprecated 041 public LazyWriteableDataset(String name, int dtype, int elements, int[] shape, int[] maxShape, int[] chunks, ILazySaver saver) { 042 this(saver, name, elements, DTypeUtils.getInterface(dtype), shape, maxShape, chunks); 043 } 044 045 /** 046 * Create a lazy dataset 047 * @param saver lazy saver 048 * @param name of dataset 049 * @param clazz dataset sub-interface 050 * @param shape dataset shape 051 * @param maxShape maximum shape 052 * @param chunks chunk shape 053 * @since 2.3 054 */ 055 public LazyWriteableDataset(ILazySaver saver, String name, Class<? extends Dataset> clazz, int[] shape, int[] maxShape, int[] chunks) { 056 this(saver, name, 1, clazz, shape, maxShape, chunks); 057 } 058 059 /** 060 * Create a lazy dataset 061 * @param saver lazy saver 062 * @param name of dataset 063 * @param elements item size 064 * @param clazz dataset sub-interface 065 * @param shape dataset shape 066 * @param maxShape maximum shape 067 * @param chunks chunk shape 068 * @since 2.3 069 */ 070 public LazyWriteableDataset(ILazySaver saver, String name, int elements, Class<? extends Dataset> clazz, int[] shape, int[] maxShape, int[] chunks) { 071 super(saver, name, elements, clazz, shape, maxShape, chunks); 072 this.saver = saver; 073 074 size = ShapeUtils.calcLongSize(this.shape); 075 } 076 077 /** 078 * Create a lazy dataset 079 * @param name of dataset 080 * @param dtype dataset type 081 * @param shape dataset shape 082 * @param maxShape maximum shape 083 * @param chunks chunk shape 084 * @param saver lazy saver 085 * @deprecated Use {@link #LazyWriteableDataset(ILazySaver, String, int, Class, int[], int[], int[])} 086 */ 087 @Deprecated 088 public LazyWriteableDataset(String name, int dtype, int[] shape, int[] maxShape, int[] chunks, ILazySaver saver) { 089 this(name, dtype, 1, shape, maxShape, chunks, saver); 090 } 091 092 /** 093 * Create a lazy dataset using element class 094 * @param name of dataset 095 * @param eClass element class 096 * @param elements item size 097 * @param shape dataset shape 098 * @param maxShape maximum shape 099 * @param chunks chunk shape 100 * @param saver lazy saver 101 */ 102 public LazyWriteableDataset(String name, Class<?> eClass, int elements, int[] shape, int[] maxShape, int[] chunks, ILazySaver saver) { 103 this(saver, name, elements, InterfaceUtils.getInterfaceFromClass(elements, eClass), shape, maxShape, chunks); 104 } 105 106 /** 107 * Create a lazy dataset using element class 108 * @param name of dataset 109 * @param eClass element class 110 * @param shape dataset shape 111 * @param maxShape maximum shape 112 * @param chunks chunk shape 113 * @param saver lazy saver 114 */ 115 public LazyWriteableDataset(String name, Class<?> eClass, int[] shape, int[] maxShape, int[] chunks, ILazySaver saver) { 116 this(saver, name, 1, InterfaceUtils.getInterfaceFromClass(1, eClass), shape, maxShape, chunks); 117 } 118 119 /** 120 * @param other dataset 121 * @since 2.2 122 */ 123 protected LazyWriteableDataset(LazyWriteableDataset other) { 124 super(other); 125 126 chunks = other.chunks; 127 saver = other.saver; 128 fillValue = other.fillValue; 129 writeAsync = other.writeAsync; 130 } 131 132 /** 133 * Create a lazy writeable dataset based on in-memory data (handy for testing) 134 * @param dataset input 135 * @return lazy writeable dataset 136 */ 137 public static LazyWriteableDataset createLazyDataset(final Dataset dataset) { 138 return createLazyDataset(dataset, null); 139 } 140 141 /** 142 * Create a lazy writeable dataset based on in-memory data (handy for testing) 143 * @param dataset input 144 * @param maxShape maximum shape 145 * @return lazy writeable dataset 146 */ 147 public static LazyWriteableDataset createLazyDataset(final Dataset dataset, final int[] maxShape) { 148 return new LazyWriteableDataset(new ILazySaver() { 149 private static final long serialVersionUID = ILazySaver.serialVersionUID; 150 151 Dataset d = dataset; 152 @Override 153 public boolean isFileReadable() { 154 return true; 155 } 156 157 @Override 158 public boolean isFileWriteable() { 159 return true; 160 } 161 162 @Override 163 public void initialize() throws IOException { 164 } 165 166 @Override 167 public Dataset getDataset(IMonitor mon, SliceND slice) throws IOException { 168 return d.getSlice(mon, slice); 169 } 170 171 @Override 172 public void setSlice(IMonitor mon, IDataset data, SliceND slice) throws IOException { 173 if (slice.isExpanded()) { 174 Dataset od = d; 175 d = DatasetFactory.zeros(od.getClass(), slice.getSourceShape()); 176 d.setSlice(od, SliceND.createSlice(d, null, od.getShapeRef())); 177 } 178 d.setSlice(data, slice); 179 } 180 }, 181 dataset.getName(), dataset.getElementsPerItem(), dataset.getClass(), dataset.getShapeRef(), maxShape, null); 182 } 183 184 @Override 185 public int hashCode() { 186 final int prime = 31; 187 int result = super.hashCode(); 188 result = prime * result + ((fillValue == null) ? 0 : fillValue.hashCode()); 189 result = prime * result + (writeAsync ? 1231 : 1237); 190 return result; 191 } 192 193 @Override 194 public boolean equals(Object obj) { 195 if (this == obj) { 196 return true; 197 } 198 if (!super.equals(obj)) { 199 return false; 200 } 201 202 LazyWriteableDataset other = (LazyWriteableDataset) obj; 203 if (fillValue == null) { 204 if (other.fillValue != null) { 205 return false; 206 } 207 } else if (!fillValue.equals(other.fillValue)) { 208 return false; 209 } 210 if (saver == null) { 211 if (other.saver != null) { 212 return false; 213 } 214 } else if (!saver.equals(other.saver)) { 215 return false; 216 } 217 if (writeAsync != other.writeAsync) { 218 return false; 219 } 220 221 return true; 222 } 223 224 @Override 225 public LazyWriteableDataset clone() { 226 return new LazyWriteableDataset(this); 227 } 228 229 @Override 230 public LazyWriteableDataset getSliceView(int[] start, int[] stop, int[] step) { 231 return (LazyWriteableDataset) super.getSliceView(start, stop, step); 232 } 233 234 @Override 235 public LazyWriteableDataset getSliceView(Slice... slice) { 236 return (LazyWriteableDataset) super.getSliceView(slice); 237 } 238 239 @Override 240 public LazyWriteableDataset getSliceView(SliceND slice) { 241 return (LazyWriteableDataset) super.getSliceView(slice); 242 } 243 244 @Override 245 public LazyWriteableDataset getTransposedView(int... axes) { 246 return (LazyWriteableDataset) super.getTransposedView(axes); 247 } 248 249 @Override 250 public void setWritingAsync(boolean async) { 251 writeAsync = async; 252 } 253 254 /** 255 * Set a slice of the dataset 256 * 257 * @param data to set 258 * @param slice an n-D slice 259 * @throws DatasetException when cannot write data 260 */ 261 public void setSlice(IDataset data, SliceND slice) throws DatasetException { 262 setSlice(null, data, slice); 263 } 264 265 @Override 266 public void setSlice(IMonitor monitor, IDataset data, int[] start, int[] stop, int[] step) throws DatasetException { 267 internalSetSlice(monitor, writeAsync, data, new SliceND(shape, maxShape, start, stop, step)); 268 } 269 270 @Override 271 public void setSlice(IMonitor monitor, IDataset data, SliceND slice) throws DatasetException { 272 checkSliceND(slice); 273 internalSetSlice(monitor, writeAsync, data, slice); 274 } 275 276 @Override 277 public void setSliceSync(IMonitor monitor, IDataset data, SliceND slice) throws DatasetException { 278 checkSliceND(slice); 279 internalSetSlice(monitor, false, data, slice); 280 } 281 282 private void internalSetSlice(IMonitor monitor, final boolean async, IDataset data, SliceND slice) throws DatasetException { 283 if (slice != null) { 284 int[] dshape = data instanceof Dataset ? ((Dataset) data).getShapeRef() : data.getShape(); 285 286 // if necessary, reshape the input data according to the shape of the slice 287 if (!Arrays.equals(slice.getShape(), dshape)) { 288 data = data.getSliceView(); 289 data.setShape(slice.getShape()); 290 } 291 } 292 293 SliceND nslice = calcTrueSlice(slice); 294 if (nslice == null) { 295 return; // nothing to set 296 } 297 298 data = transformInput(data, slice); 299 300 if (saver == null) { 301 throw new DatasetException("Cannot write to file as saver not defined!"); 302 } 303 304 try { 305 if (async && saver instanceof ILazyAsyncSaver) { 306 ((ILazyAsyncSaver)saver).setSliceAsync(monitor, data, nslice); 307 } else { 308 if (!saver.isFileWriteable()) { 309 throw new DatasetException("Cannot write to file as it is not writeable!"); 310 } 311 saver.setSlice(monitor, data, nslice); 312 } 313 } catch (IOException e) { 314 throw new DatasetException("Could not save dataset", e); 315 } 316 if (!refreshShape()) { // send event as data has changed 317 eventDelegate.fire(new DataEvent(name, shape)); 318 } 319 } 320 321 /** 322 * Set saver (and also loader) 323 * @param saver lazy saver 324 */ 325 @Override 326 public void setSaver(ILazySaver saver) { 327 this.saver = saver; 328 this.loader = saver; 329 } 330 331 @Override 332 protected SliceND createSlice(int[] nstart, int[] nstop, int[] nstep) { 333 return SliceND.createSlice(oShape, maxShape, nstart, nstop, nstep); 334 } 335 336 @Override 337 public Object getFillValue() { 338 return fillValue; 339 } 340 341 @Override 342 public void setFillValue(Object fill) { 343 fillValue = fill; 344 } 345 346 @Override 347 public LazyWriteableDataset squeezeEnds() { 348 return (LazyWriteableDataset) super.squeezeEnds(); 349 } 350}