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 int rank = 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.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 if (shape.length == 0) { 267 index = -istep; 268 } else { 269 // work out index of first position 270 for (int i = 0; i < shape.length; i++) { 271 pos[i] = start[i]; 272 } 273 pos[endrank] -= step[endrank]; 274 275 index = pos[0]; 276 for (int j = 1; j <= endrank; j++) 277 index = index * shape[j] + pos[j]; 278 index *= isize; 279 } 280 } 281 282 /** 283 * Returns {@code true} if there is an other element after the current 284 * Slice. 285 * 286 * @return Returns {@true} if the iteration has more Slice, {@code false} in 287 * the other case 288 */ 289 @Override 290 public boolean hasNext() { 291 // now move on one position in slice 292 int j = endrank; 293 for (; j >= 0; j--) { 294 pos[j] += step[j]; 295 296 if ((pos[j] >= stop[j]) == (step[j] > 0)) { 297 pos[j] = start[j]; // stop index has been adjusted in code for -ve steps 298 index += gap[j]; 299 } else { 300 break; 301 } 302 } 303 if (j == -1 && endrank >= 0) { 304 return false; 305 } 306 307 index += istep; 308 return index < imax; 309 } 310 311 /** 312 * Returns an array of starts indexes. 313 * 314 * @return Array of starts indexes 315 */ 316 public int[] getStart() { 317 return start; 318 } 319 320 /** 321 * Returns the current position of the iterator. 322 * 323 * @return Iterator current position 324 */ 325 @Override 326 public int[] getPos() { 327 return pos; 328 } 329 330 /** 331 * Returns an array of steps 332 * 333 * @return Array of steps 334 */ 335 public int[] getStep() { 336 return step; 337 } 338 339 /** 340 * Returns an array of the Slices shapes. 341 * 342 * @return Array of shapes. 343 */ 344 @Override 345 public int[] getShape() { 346 return sshape; 347 } 348}