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