001/* 002 * Java Genetic Algorithm Library (jenetics-8.1.0). 003 * Copyright (c) 2007-2024 Franz Wilhelmstötter 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 * 017 * Author: 018 * Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com) 019 */ 020package io.jenetics.util; 021 022import static java.lang.String.format; 023import static io.jenetics.internal.util.Hashes.hash; 024import static io.jenetics.internal.util.SerialIO.readInt; 025import static io.jenetics.internal.util.SerialIO.writeInt; 026 027import java.io.DataInput; 028import java.io.DataOutput; 029import java.io.IOException; 030import java.io.InvalidObjectException; 031import java.io.ObjectInputStream; 032import java.io.Serial; 033import java.io.Serializable; 034import java.util.Optional; 035import java.util.stream.IntStream; 036 037/** 038 * Integer range class. 039 * 040 * @implNote 041 * This class is immutable and thread-safe. 042 * 043 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 044 * @version 6.0 045 * @since 3.2 046 */ 047public final /*record*/ class IntRange implements Serializable { 048 049 @Serial 050 private static final long serialVersionUID = 2L; 051 052 private final int _min; 053 private final int _max; 054 055 private IntRange(final int min, final int max) { 056 if (min > max) { 057 throw new IllegalArgumentException(format( 058 "Min greater than max: %s > %s", min, max 059 )); 060 } 061 062 _min = min; 063 _max = max; 064 } 065 066 /** 067 * Return the minimum value of the integer range. 068 * 069 * @return the minimum value of the integer range 070 */ 071 public int min() { 072 return _min; 073 } 074 075 /** 076 * Return the maximum value of the integer range. 077 * 078 * @return the maximum value of the integer range 079 */ 080 public int max() { 081 return _max; 082 } 083 084 /** 085 * Checks whether the given {@code value} is within the range 086 * {@code [min, max)}. 087 * 088 * @since 8.0 089 * 090 * @param value the value to check 091 * @return {@code true} if the {@code value} is with the range 092 * {@code [min, max)}, {@code false} otherwise 093 */ 094 public boolean contains(final int value) { 095 return value >= _min && value < _max; 096 } 097 098 /** 099 * Return the intersection of {@code this} range with the {@code other}. 100 * 101 * @since 8.0 102 * 103 * @param other the intersection range or {@link Optional#empty()} if there 104 * is none 105 * @return the range intersection 106 */ 107 public Optional<IntRange> intersect(final IntRange other) { 108 if (_max <= other._min || _min >= other._max) { 109 return Optional.empty(); 110 } else { 111 return Optional.of( 112 IntRange.of( 113 Math.max(_min, other._min), 114 Math.min(_max, other._max) 115 ) 116 ); 117 } 118 } 119 120 /** 121 * Return the size of the {@code IntRange}: {@code max - min}. 122 * 123 * @since 3.9 124 * 125 * @return the size of the int range 126 */ 127 public int size() { 128 return _max - _min; 129 } 130 131 /** 132 * Returns a sequential ordered {@code IntStream} from {@link #min()} 133 * (inclusive) to {@link #max()} (exclusive) by an incremental step of 134 * {@code 1}. 135 * <p> 136 * An equivalent sequence of increasing values can be produced sequentially 137 * using a {@code for} loop as follows: 138 * {@snippet lang="java": 139 * for (int i = range.min(); i < range.max(); ++i) { 140 * // ... 141 * } 142 * } 143 * 144 * @since 3.4 145 * 146 * @return a sequential {@link IntStream} for the range of {@code int} 147 * elements 148 */ 149 public IntStream stream() { 150 return IntStream.range(_min, _max); 151 } 152 153 /** 154 * Create a new {@code IntRange} object with the given {@code min} and 155 * {@code max} values. 156 * 157 * @param min the lower bound of the integer range 158 * @param max the upper bound of the integer range 159 * @return a new {@code IntRange} object 160 * @throws IllegalArgumentException if {@code min > max} 161 */ 162 public static IntRange of(final int min, final int max) { 163 return new IntRange(min, max); 164 } 165 166 /** 167 * Return a new (half-open) range, which contains only the given value: 168 * {@code [value, value + 1)}. 169 * 170 * @since 4.0 171 * 172 * @param value the value of the created (half-open) integer range 173 * @return a new (half-open) range, which contains only the given value 174 */ 175 public static IntRange of(final int value) { 176 return of(value, value + 1); 177 } 178 179 @Override 180 public int hashCode() { 181 return hash(_min, hash(_max)); 182 } 183 184 @Override 185 public boolean equals(final Object obj) { 186 return obj == this || 187 obj instanceof IntRange other && 188 _min == other._min && 189 _max == other._max; 190 } 191 192 @Override 193 public String toString() { 194 return "[" + _min + ", " + _max + "]"; 195 } 196 197 198 /* ************************************************************************* 199 * Java object serialization 200 * ************************************************************************/ 201 202 @Serial 203 private Object writeReplace() { 204 return new SerialProxy(SerialProxy.INT_RANGE, this); 205 } 206 207 @Serial 208 private void readObject(final ObjectInputStream stream) 209 throws InvalidObjectException 210 { 211 throw new InvalidObjectException("Serialization proxy required."); 212 } 213 214 void write(final DataOutput out) throws IOException { 215 writeInt(_min, out); 216 writeInt(_max, out); 217 } 218 219 static IntRange read(final DataInput in) throws IOException { 220 return of(readInt(in), readInt(in)); 221 } 222 223}