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.readLong; 025import static io.jenetics.internal.util.SerialIO.writeLong; 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.LongStream; 036 037/** 038 * Long 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 LongRange implements Serializable { 048 049 @Serial 050 private static final long serialVersionUID = 2L; 051 052 private final long _min; 053 private final long _max; 054 055 private LongRange(final long min, final long 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 long range. 068 * 069 * @return the minimum value of the long range 070 */ 071 public long min() { 072 return _min; 073 } 074 075 /** 076 * Return the maximum value of the long range. 077 * 078 * @return the maximum value of the long range 079 */ 080 public long 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 long 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<LongRange> intersect(final LongRange other) { 108 if (_max <= other._min || _min >= other._max) { 109 return Optional.empty(); 110 } else { 111 return Optional.of( 112 LongRange.of( 113 Math.max(_min, other._min), 114 Math.min(_max, other._max) 115 ) 116 ); 117 } 118 } 119 120 /** 121 * Returns a sequential ordered {@code LongStream} from {@link #min()} 122 * (inclusive) to {@link #max()} (exclusive) by an incremental step of 123 * {@code 1}. 124 * <p> 125 * An equivalent sequence of increasing values can be produced sequentially 126 * using a {@code for} loop as follows: 127 * {@snippet lang="java": 128 * for (long i = range.min(); i < range.max(); ++i) { 129 * // ... 130 * } 131 * } 132 * 133 * @since 3.4 134 * 135 * @return a sequential {@link LongStream} for the range of {@code long} 136 * elements 137 */ 138 public LongStream stream() { 139 return LongStream.range(_min, _max); 140 } 141 142 /** 143 * Create a new {@code LongRange} object with the given {@code min} and 144 * {@code max} values. 145 * 146 * @param min the lower bound of the long range 147 * @param max the upper bound of the long range 148 * @return a new {@code LongRange} object 149 * @throws IllegalArgumentException if {@code min > max} 150 */ 151 public static LongRange of(final long min, final long max) { 152 return new LongRange(min, max); 153 } 154 155 /** 156 * Return a new (half-open) range, which contains only the given value: 157 * {@code [value, value + 1)}. 158 * 159 * @since 4.0 160 * 161 * @param value the value of the created (half-open) integer range 162 * @return a new (half-open) range, which contains only the given value 163 */ 164 public static LongRange of(final long value) { 165 return of(value, value + 1); 166 } 167 168 @Override 169 public int hashCode() { 170 return hash(_min, hash(_max, hash(getClass()))); 171 } 172 173 @Override 174 public boolean equals(final Object obj) { 175 return obj == this || 176 obj instanceof LongRange other && 177 _min == other._min && 178 _max == other._max; 179 } 180 181 @Override 182 public String toString() { 183 return "[" + _min + ", " + _max + "]"; 184 } 185 186 187 /* ************************************************************************* 188 * Java object serialization 189 * ************************************************************************/ 190 191 @Serial 192 private Object writeReplace() { 193 return new SerialProxy(SerialProxy.LONG_RANGE, this); 194 } 195 196 @Serial 197 private void readObject(final ObjectInputStream stream) 198 throws InvalidObjectException 199 { 200 throw new InvalidObjectException("Serialization proxy required."); 201 } 202 203 void write(final DataOutput out) throws IOException { 204 writeLong(_min, out); 205 writeLong(_max, out); 206 } 207 208 static LongRange read(final DataInput in) throws IOException { 209 return of(readLong(in), readLong(in)); 210 } 211 212}