    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                if (slice != null) {
    273                        checkSliceND(slice);
    274                }
    275                internalSetSlice(monitor, writeAsync, data, slice);
    276        }
    277
    278        @Override
    279        public void setSliceSync(IMonitor monitor, IDataset data, SliceND slice) throws DatasetException {
    280                if (slice != null) {
    281                        checkSliceND(slice);
    282                }
    283                internalSetSlice(monitor, false, data, slice);
    284        }
    285
    286        private void internalSetSlice(IMonitor monitor, final boolean async, IDataset data, SliceND slice) throws DatasetException {
    287                if (slice != null) {
    288                        int[] dshape = data instanceof Dataset ? ((Dataset) data).getShapeRef() : data.getShape();
    289
    290                        // if necessary, reshape the input data according to the shape of the slice
    291                        if (!Arrays.equals(slice.getShape(), dshape)) {
    292                                data = data.getSliceView();
    293                                data.setShape(slice.getShape());
    294                        }
    295                }
    296
    297                SliceND nslice = calcTrueSlice(slice);
    298                if (nslice == null) {
    299                        return; // nothing to set
    300                }
    301
    302                data = transformInput(data, slice);
    303
    304                if (saver == null) {
    305                        throw new DatasetException("Cannot write to file as saver not defined!");
    306                }
    307
    308                try {
    309                        if (async && saver instanceof ILazyAsyncSaver) {
    310                                ((ILazyAsyncSaver)saver).setSliceAsync(monitor, data, nslice);
    311                        } else {
    312                                if (!saver.isFileWriteable()) {
    313                                        throw new DatasetException("Cannot write to file as it is not writeable!");
    314                                }
    315                                saver.setSlice(monitor, data, nslice);
    316                        }
    317                } catch (IOException e) {
    318                        throw new DatasetException("Could not save dataset", e);
    319                }
    320                if (!refreshShape()) { // send event as data has changed
    321                        eventDelegate.fire(new DataEvent(name, shape));
    322                }
    323        }
    324
    325        /**
    326         * Set saver (and also loader)
    327         * @param saver lazy saver
    328         */
    329        @Override
    330        public void setSaver(ILazySaver saver) {
    331                this.saver = saver;
    332                this.loader = saver;
    333        }
    334
    335        @Override
    336        public Object getFillValue() {
    337                return fillValue;
    338        }
    339
    340        @Override
    341        public void setFillValue(Object fill) {
    342                fillValue = fill;
    343        }
    344
    345        @Override
    346        public LazyWriteableDataset squeezeEnds() {
    347                return (LazyWriteableDataset) super.squeezeEnds();
    348        }
    349}