001/*- 002 ******************************************************************************* 003 * Copyright (c) 2011, 2016 Diamond Light Source Ltd. 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 * Contributors: 010 * Peter Chang - initial API and implementation and/or initial documentation 011 *******************************************************************************/ 012 013package org.eclipse.january.dataset; 014 015 016import java.util.Arrays; 017 018/** 019 * The {@code SliceIterator} class is use to run over a Slice of a Dataset. 020 * 021 * This is an Iterator thats allows the programmer to traverse the elements of a sliced Dataset and obtain the current position, the starts, steps, 022 * shapes. 023 * Moreover, there is possibilities to set the start point to begin at the wanted position. 024 */ 025public class SliceIterator extends IndexIterator { 026 int[] shape; 027 int isize; 028 int endrank; // last shape index 029 int[] gap; // gaps in dataset 030 int imax; // maximum index in array 031 int[] start; 032 int[] stop; 033 int[] step; 034 int[] sshape; // slice shape 035 int[] pos; // position in dataset 036 int istep; // step in last index 037 038 SliceIterator() { 039 } 040 041 /** 042 * Constructs an SliceIterator Object, which can iterate over sliced 043 * Datasets elements, by default the start set to 0 and with a step of 1. 044 * 045 * @param shape 046 * Array of shapes of the Dataset 047 * @param length 048 * Length of entire data array 049 * @param sshape 050 * Shape of the new dataset, i.e. slice 051 */ 052 public SliceIterator(final int[] shape, final int length, final int[] sshape) { 053 this(shape, length, null, null, sshape, 1); 054 } 055 056 /** 057 * Constructs an SliceIterator Object, which can iterate over sliced 058 * Datasets elements, by default the start set to 0 and with a step of 1. 059 * 060 * @param shape 061 * Array of shapes of the Dataset 062 * @param length 063 * Length of entire data array 064 * @param start 065 * Array of starts indexes, may be {@code null} 066 * @param sshape 067 * Shape of the new dataset, i.e. slice 068 */ 069 public SliceIterator(final int[] shape, final int length, final int[] start, final int[] sshape) { 070 this(shape, length, start, null, sshape, 1); 071 } 072 073 /** 074 * Constructs an SliceIterator Object, which can iterate over sliced 075 * Datasets elements, by default the start set to 0 and with a step of 1. 076 * 077 * @param shape 078 * Array of shapes of the Dataset 079 * @param length 080 * Length of entire data array 081 * @param sshape 082 * Shape of the new dataset, i.e. slice 083 * @param isize 084 * Number of elements in an item 085 */ 086 public SliceIterator(final int[] shape, final int length, final int[] sshape, final int isize) { 087 this(shape, length, null, null, sshape, isize); 088 } 089 090 /** 091 * Constructs an SliceIterator Object, which can iterate over sliced 092 * Datasets elements, by default the start set to 0 and with a step of 1. 093 * 094 * @param shape 095 * Array of shapes of the Dataset 096 * @param length 097 * Length of entire data array 098 * @param start 099 * Array of starts indexes, may be {@code null} 100 * @param sshape 101 * Shape of the new dataset, i.e. slice 102 * @param isize 103 * Number of elements in an item 104 */ 105 public SliceIterator(final int[] shape, final int length, final int[] start, final int[] sshape, final int isize) { 106 this(shape, length, start, null, sshape, isize); 107 } 108 109 /** 110 * Constructs an SliceIterator Object, which can iterate over sliced 111 * Datasets elements, by default the start set to 0 and with a step of 1. 112 * 113 * @param shape 114 * Array of shapes of the Dataset 115 * @param length 116 * Length of entire data array 117 * @param start 118 * Array of starts indexes, may be {@code null} 119 * @param step 120 * Array of steps, may be {@code null}, but can't be 0 121 * @param sshape 122 * shape of new dataset, i.e. slice 123 */ 124 public SliceIterator(final int[] shape, final int length, final int[] start, final int[] step, final int[] sshape) { 125 this(shape, length, start, step, sshape, 1); 126 } 127 128 /** 129 * Constructs an SliceIterator Object, which can iterate over sliced 130 * Datasets elements, by default the start set to 0 and with a step of 1. 131 * 132 * @param shape 133 * Array of shapes of the Dataset 134 * @param length 135 * Length of entire data array 136 * @param slice 137 * SliceND to iterate on 138 */ 139 public SliceIterator(final int[] shape, final int length, final SliceND slice) { 140 this(shape, length, slice.getStart(), slice.getStep(), slice.getShape(), 1); 141 } 142 143 /** 144 * Constructs an SliceIterator Object, which can iterate over sliced 145 * Datasets elements, by default the start set to 0 and with a step of 1. 146 * 147 * @param shape 148 * Array of shapes of the Dataset 149 * @param length 150 * Length of entire data array 151 * @param isize 152 * Number of elements in an item 153 * @param slice 154 * SliceND to iterate on 155 */ 156 public SliceIterator(final int[] shape, final int length, final int isize, final SliceND slice) { 157 this(shape, length, slice.getStart(), slice.getStep(), slice.getShape(), isize); 158 } 159 160 /** 161 * Constructs an SliceIterator Object, which can iterate over sliced 162 * Datasets elements, by default the start set to 0 and with a step of 1. 163 * 164 * @param shape 165 * Array of shapes of the Dataset 166 * @param length 167 * Length of entire data array 168 * @param start 169 * Array of starts indexes, may be {@code null} 170 * @param step 171 * Array of steps, may be {@code null}, but can't be 0 172 * @param sshape 173 * Shape of the new dataset, i.e. slice 174 * @param isize 175 * Number of elements in an item 176 */ 177 public SliceIterator(final int[] shape, final int length, final int[] start, final int[] step, final int[] sshape, 178 final int isize) { 179 this.isize = isize; 180 final int rank = shape == null ? 0 : shape.length; 181 endrank = rank - 1; 182 this.shape = shape; 183 this.start = new int[rank]; 184 this.sshape = sshape; 185 if (step == null) { 186 this.step = new int[rank]; 187 Arrays.fill(this.step, 1); 188 } else { 189 this.step = step; 190 } 191 192 if (rank == 0) { 193 istep = isize; 194 imax = length * isize; 195 stop = new int[0]; 196 pos = new int[0]; 197 gap = null; 198 } else { 199 istep = this.step[endrank] * isize; 200 imax = length * isize; 201 stop = new int[rank]; 202 gap = new int[endrank + 1]; 203 pos = new int[rank]; 204 calcGap(); 205 } 206 207 setStart(start); 208 } 209 210 void calcGap() { 211 int chunk = isize; 212 for (int i = endrank; i >= 0; i--) { 213 stop[i] = start[i] + sshape[i] * step[i]; 214 215 if (step[i] < 0) { 216 stop[i]++; // adjust for -ve steps so later code has more succinct test 217 } 218 219 if (i > 0) { 220 gap[i] = (shape[i] * step[i - 1] - sshape[i] * step[i]) * chunk; 221 chunk *= shape[i]; 222 } 223 } 224 } 225 226 /** 227 * Set the starts indexes to new positions, {@code if null} the start index 228 * is set by default to 0 229 * 230 * @param newStart 231 * Array of new starts indexes (prefix with zeros if necessary), 232 * may be {@code null} 233 */ 234 public void setStart(int... newStart) { 235 final int rank = shape == null ? 0 : shape.length; 236 if (rank == 0) { 237 index = -istep; 238 return; 239 } 240 241 if (newStart == null) { 242 for (int i = 0; i < rank; i++) { 243 start[i] = 0; 244 } 245 } else if (newStart.length > rank) { 246 throw new IllegalArgumentException("Length of start array greater than rank"); 247 } else { 248 int extra = rank - newStart.length; 249 for (int i = 0; i < extra; i++) { 250 start[i] = 0; 251 } 252 for (int i = 0; i < newStart.length; i++) { 253 start[i + extra] = newStart[i]; 254 } 255 } 256 257 reset(); 258 calcGap(); 259 } 260 261 /** 262 * Reset the Iterator to the first Slice. 263 */ 264 @Override 265 public void reset() { 266 final int rank = shape == null ? 0 : shape.length; 267 if (rank == 0) { 268 index = -istep; 269 } else { 270 // work out index of first position 271 for (int i = 0; i < shape.length; i++) { 272 pos[i] = start[i]; 273 } 274 pos[endrank] -= step[endrank]; 275 276 index = pos[0]; 277 for (int j = 1; j <= endrank; j++) 278 index = index * shape[j] + pos[j]; 279 index *= isize; 280 } 281 } 282 283 /** 284 * Returns {@code true} if there is an other element after the current 285 * Slice. 286 * 287 * @return Returns {@code true} if the iteration has more Slice, {@code false} in 288 * the other case 289 */ 290 @Override 291 public boolean hasNext() { 292 // now move on one position in slice 293 int j = endrank; 294 for (; j >= 0; j--) { 295 pos[j] += step[j]; 296 297 if ((pos[j] >= stop[j]) == (step[j] > 0)) { 298 pos[j] = start[j]; // stop index has been adjusted in code for -ve steps 299 index += gap[j]; 300 } else { 301 break; 302 } 303 } 304 if (j == -1 && endrank >= 0) { 305 return false; 306 } 307 308 index += istep; 309 return index < imax; 310 } 311 312 /** 313 * Returns an array of starts indexes. 314 * 315 * @return Array of starts indexes 316 */ 317 public int[] getStart() { 318 return start; 319 } 320 321 /** 322 * Returns the current position of the iterator. 323 * 324 * @return Iterator current position 325 */ 326 @Override 327 public int[] getPos() { 328 return pos; 329 } 330 331 /** 332 * Returns an array of steps 333 * 334 * @return Array of steps 335 */ 336 public int[] getStep() { 337 return step; 338 } 339 340 /** 341 * Returns an array of the Slices shapes. 342 * 343 * @return Array of shapes. 344 */ 345 @Override 346 public int[] getShape() { 347 return sshape; 348 } 349}