001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package org.wpilib.math.autodiff; 006 007import java.util.OptionalInt; 008 009/** Represents a sequence of elements in an iterable object. */ 010public class Slice { 011 /** Type tag used to designate an omitted argument of the slice. */ 012 public static class None { 013 /** Default constructor. */ 014 public None() {} 015 } 016 017 /** Designates an omitted argument of the slice. */ 018 public static final None __ = null; 019 020 /** Start index (inclusive). */ 021 public int start = 0; 022 023 /** Stop index (exclusive). */ 024 public int stop = 0; 025 026 /** Step. */ 027 public int step = 1; 028 029 /** Constructs a Slice. */ 030 public Slice() {} 031 032 /** 033 * Constructs a slice. 034 * 035 * @param start Slice start index (inclusive). 036 */ 037 public Slice(None start) { 038 this(OptionalInt.of(0), OptionalInt.of(Integer.MAX_VALUE), OptionalInt.of(1)); 039 } 040 041 /** 042 * Constructs a slice. 043 * 044 * @param start Slice start index (inclusive). 045 */ 046 public Slice(int start) { 047 this.start = start; 048 this.stop = (start == -1) ? Integer.MAX_VALUE : start + 1; 049 this.step = 1; 050 } 051 052 /** 053 * Constructs a slice. 054 * 055 * @param start Slice start index (inclusive). 056 * @param stop Slice stop index (exclusive). 057 */ 058 public Slice(None start, None stop) { 059 this(OptionalInt.empty(), OptionalInt.empty(), OptionalInt.of(1)); 060 } 061 062 /** 063 * Constructs a slice. 064 * 065 * @param start Slice start index (inclusive). 066 * @param stop Slice stop index (exclusive). 067 */ 068 public Slice(None start, int stop) { 069 this(OptionalInt.empty(), OptionalInt.of(stop), OptionalInt.of(1)); 070 } 071 072 /** 073 * Constructs a slice. 074 * 075 * @param start Slice start index (inclusive). 076 * @param stop Slice stop index (exclusive). 077 */ 078 public Slice(int start, None stop) { 079 this(OptionalInt.of(start), OptionalInt.empty(), OptionalInt.of(1)); 080 } 081 082 /** 083 * Constructs a slice. 084 * 085 * @param start Slice start index (inclusive). 086 * @param stop Slice stop index (exclusive). 087 */ 088 public Slice(int start, int stop) { 089 this(OptionalInt.of(start), OptionalInt.of(stop), OptionalInt.of(1)); 090 } 091 092 /** 093 * Constructs a slice. 094 * 095 * @param start Slice start index (inclusive). 096 * @param stop Slice stop index (exclusive). 097 * @param step Slice step. 098 */ 099 public Slice(None start, None stop, None step) { 100 this(OptionalInt.empty(), OptionalInt.empty(), OptionalInt.empty()); 101 } 102 103 /** 104 * Constructs a slice. 105 * 106 * @param start Slice start index (inclusive). 107 * @param stop Slice stop index (exclusive). 108 * @param step Slice step. 109 */ 110 public Slice(None start, None stop, int step) { 111 this(OptionalInt.empty(), OptionalInt.empty(), OptionalInt.of(step)); 112 } 113 114 /** 115 * Constructs a slice. 116 * 117 * @param start Slice start index (inclusive). 118 * @param stop Slice stop index (exclusive). 119 * @param step Slice step. 120 */ 121 public Slice(None start, int stop, None step) { 122 this(OptionalInt.empty(), OptionalInt.of(stop), OptionalInt.empty()); 123 } 124 125 /** 126 * Constructs a slice. 127 * 128 * @param start Slice start index (inclusive). 129 * @param stop Slice stop index (exclusive). 130 * @param step Slice step. 131 */ 132 public Slice(None start, int stop, int step) { 133 this(OptionalInt.empty(), OptionalInt.of(stop), OptionalInt.of(step)); 134 } 135 136 /** 137 * Constructs a slice. 138 * 139 * @param start Slice start index (inclusive). 140 * @param stop Slice stop index (exclusive). 141 * @param step Slice step. 142 */ 143 public Slice(int start, None stop, None step) { 144 this(OptionalInt.of(start), OptionalInt.empty(), OptionalInt.empty()); 145 } 146 147 /** 148 * Constructs a slice. 149 * 150 * @param start Slice start index (inclusive). 151 * @param stop Slice stop index (exclusive). 152 * @param step Slice step. 153 */ 154 public Slice(int start, None stop, int step) { 155 this(OptionalInt.of(start), OptionalInt.empty(), OptionalInt.of(step)); 156 } 157 158 /** 159 * Constructs a slice. 160 * 161 * @param start Slice start index (inclusive). 162 * @param stop Slice stop index (exclusive). 163 * @param step Slice step. 164 */ 165 public Slice(int start, int stop, None step) { 166 this(OptionalInt.of(start), OptionalInt.of(stop), OptionalInt.empty()); 167 } 168 169 /** 170 * Constructs a slice. 171 * 172 * @param start Slice start index (inclusive). 173 * @param stop Slice stop index (exclusive). 174 * @param step Slice step. 175 */ 176 public Slice(int start, int stop, int step) { 177 this(OptionalInt.of(start), OptionalInt.of(stop), OptionalInt.of(step)); 178 } 179 180 /** 181 * Constructs a slice. 182 * 183 * @param start Slice start index (inclusive). 184 * @param stop Slice stop index (exclusive). 185 * @param step Slice step. 186 */ 187 public Slice(OptionalInt start, OptionalInt stop, OptionalInt step) { 188 if (!step.isPresent()) { 189 this.step = 1; 190 } else { 191 assert step.getAsInt() != 0; 192 193 this.step = step.getAsInt(); 194 } 195 196 // Avoid UB for step = -step if step is INT_MIN 197 if (this.step == Integer.MIN_VALUE) { 198 this.step = -Integer.MAX_VALUE; 199 } 200 201 if (!start.isPresent()) { 202 if (this.step < 0) { 203 this.start = Integer.MAX_VALUE; 204 } else { 205 this.start = 0; 206 } 207 } else { 208 this.start = start.getAsInt(); 209 } 210 211 if (!stop.isPresent()) { 212 if (this.step < 0) { 213 this.stop = Integer.MIN_VALUE; 214 } else { 215 this.stop = Integer.MAX_VALUE; 216 } 217 } else { 218 this.stop = stop.getAsInt(); 219 } 220 } 221 222 /** 223 * Adjusts start and end slice indices assuming a sequence of the specified length. 224 * 225 * @param length The sequence length. 226 * @return The slice length. 227 */ 228 public int adjust(int length) { 229 assert step != 0; 230 assert step >= -Integer.MAX_VALUE; 231 232 if (start < 0) { 233 start += length; 234 235 if (start < 0) { 236 start = (step < 0) ? -1 : 0; 237 } 238 } else if (start >= length) { 239 start = (step < 0) ? length - 1 : length; 240 } 241 242 if (stop < 0) { 243 stop += length; 244 245 if (stop < 0) { 246 stop = (step < 0) ? -1 : 0; 247 } 248 } else if (stop >= length) { 249 stop = (step < 0) ? length - 1 : length; 250 } 251 252 if (step < 0) { 253 if (stop < start) { 254 return (start - stop - 1) / -step + 1; 255 } else { 256 return 0; 257 } 258 } else { 259 if (start < stop) { 260 return (stop - start - 1) / step + 1; 261 } else { 262 return 0; 263 } 264 } 265 } 266}