blob: bf48276a78c2ba2bf4dd57cd9afc0a1e6f3ca2ba [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.geode.benchmark;
import static java.lang.Long.max;
import static java.lang.Long.min;
import java.io.Serializable;
import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.LongConsumer;
/**
* Describes a range [min, max) in long values between min inclusive and max exclusive.
*/
public class LongRange implements Serializable {
private static final long serialVersionUID = 1L;
private final long min;
private final long max;
public LongRange(long min, long max) {
try {
if (Math.subtractExact(max, min) <= 0) {
throw new IllegalArgumentException();
}
} catch (ArithmeticException e) {
throw new IllegalArgumentException(e);
}
this.min = min;
this.max = max;
}
public long getMin() {
return min;
}
public long getMax() {
return max;
}
public long size() {
return max - min;
}
/**
* Slices the range in relatively equal ranges in each slice with the remainder distributed across
* the slices.
*
* @param count of slices
* @return array of {@code count} slices
*/
public LongRange[] slice(final int count) {
final LongRange[] slices = new LongRange[count];
for (int i = 0; i < slices.length; i++) {
slices[i] = sliceFor(count, i);
}
return slices;
}
/**
* Get a single slice for {@code count} slices at {@code index}
*
* @param count of slices
* @param index of slice
* @return Single slice at index.
* @throws IndexOutOfBoundsException if index is less than 0 or greater than slices.
*/
public LongRange sliceFor(final int count, final int index) throws IndexOutOfBoundsException {
if (index < 0 || index >= count) {
throw new IndexOutOfBoundsException();
}
final long size = max - min;
final long increment = size / count;
final long remainder = size % count;
final long sliceMin =
min + ((increment + 1) * min(remainder, index)) + (increment * max(0, index - remainder));
final long sliceMax = sliceMin + increment + (index < remainder ? 1 : 0);
return new LongRange(sliceMin, sliceMax);
}
public LongRange[] slicesOfSize(final long sliceSize) {
final int count = (int) Math.ceil((double) size() / sliceSize);
return slice(count);
}
/**
* Iterates over each value in the range.
*
* @param consumer to invoke with current value.
*/
public void forEach(LongConsumer consumer) {
for (long i = min; i < max; i++) {
consumer.accept(i);
}
}
/**
* Randomly select a value withing range.
*
* @return a random value within range.
*/
public long random() {
return ThreadLocalRandom.current().nextLong(min, max);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final LongRange longRange = (LongRange) o;
return min == longRange.min &&
max == longRange.max;
}
@Override
public int hashCode() {
return Objects.hash(min, max);
}
@Override
public String toString() {
return "LongRange{" + "min=" + min + ", max=" + max + '}';
}
}