001/* 002 * Copyright (c) 2012-2021 Institut National des Sciences Appliquées de Lyon (INSA Lyon) and others 003 * 004 * This program and the accompanying materials are made available under the 005 * terms of the Eclipse Public License 2.0 which is available at 006 * http://www.eclipse.org/legal/epl-2.0. 007 * 008 * SPDX-License-Identifier: EPL-2.0 009 */ 010 011package gololang; 012 013import java.util.Collection; 014import java.util.Iterator; 015import java.util.Arrays; 016 017import org.eclipse.golo.runtime.InvalidDestructuringException; 018 019/** 020 * Represents a generic value range. 021 * <p> 022 * A range represent a set of values between to bounds, optionally with a step (or increment) from 023 * one value to the next. 024 */ 025public interface Range<T> extends Collection<T>, HeadTail<T> { 026 027 /** 028 * Gets the lower bound of the range. 029 * 030 * @return the starting value of the range. 031 */ 032 T from(); 033 034 /** 035 * Gets the upper bound of the range. 036 * 037 * @return the excluded ending value of the range. 038 */ 039 T to(); 040 041 /** 042 * Gets the increment of the range. 043 * 044 * @return the number of value to between two elements in the range. 045 */ 046 int increment(); 047 048 /** 049 * Sets the increment of the range. 050 * 051 * @param value the new increment. 052 * @return the range itself. 053 */ 054 Range<T> incrementBy(int value); 055 056 /** 057 * Sets the negative increment of the range. 058 *<p> 059 * this is equivalent to: 060 * <pre class="listing"><code class="lang-java" data-lang="java"> 061 * range.incrementBy(-value) 062 * </code></pre> 063 * 064 * @param value the new increment. 065 * @return the range itself. 066 */ 067 Range<T> decrementBy(int value); 068 069 /** 070 * Checks if the range encloses the value. 071 * <p> 072 * i.e. if {@code from() <= value} and {@code value < to()} (for positive increments, resp. for 073 * negative ones), regardless the increment value. 074 * <p> 075 * For instance a range between 0 and 5 with an increment of 2 encloses 1 but don't contains it. 076 * 077 * @param value the value to check. 078 */ 079 boolean encloses(T value); 080 081 /** 082 * Creates a new reversed range from this range. 083 * <p> 084 * i.e. swaps the {@code from()} and {@code to()} values and sets the increment to 085 * {@code -increment()}. 086 */ 087 Range<T> reversed(); 088 089 /** 090 * New style destructuring helper. 091 * 092 * <p>If a remainer if included, it will be a new range with same step and end values, starting to the next available 093 * value. 094 * 095 * @param number number of variable that will be affected. 096 * @param substruct whether the destructuring is complete or should contains a sub structure. 097 * @param toSkip a boolean array indicating the elements to skip. 098 * @return an array containing the values to assign. 099 */ 100 default Object[] __$$_destruct(int number, boolean substruct, Object[] toSkip) { 101 if (number < size() && !substruct) { 102 throw InvalidDestructuringException.notEnoughValues(number, size(), substruct); 103 } 104 if (number == size() && !substruct) { 105 return org.eclipse.golo.runtime.ArrayHelper.nullify(toArray(), toSkip); 106 } 107 if (number <= size() && substruct) { 108 Object[] d = new Object[number]; 109 Iterator<T> it = this.iterator(); 110 for (int i = 0; i < number - 1; i++) { 111 if (Boolean.valueOf(true).equals(toSkip[i])) { 112 it.next(); 113 } else { 114 d[i] = it.next(); 115 } 116 } 117 if (Boolean.valueOf(false).equals(toSkip[number - 1])) { 118 d[number - 1] = newStartingFrom(it.next()); 119 } 120 return d; 121 } 122 if (number == size() + 1 && substruct) { 123 Object[] d = Arrays.copyOf(toArray(), number); 124 if (Boolean.valueOf(false).equals(toSkip[number - 1])) { 125 d[number - 1] = newStartingFrom(to()); 126 } 127 return org.eclipse.golo.runtime.ArrayHelper.nullify(d, toSkip); 128 } 129 throw InvalidDestructuringException.tooManyValues(number); 130 } 131 132 /** 133 * Returns a copy of this range with a new starting value. 134 * 135 * <p>There is no check that the {@code newStart} value is compatible with the current start and increment. It is 136 * therefore possible that the new range yields different values than the original. 137 */ 138 public Range<T> newStartingFrom(T newStart); 139}