All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.jqwik.engine.properties.shrinking.BigIntegerGrower Maven / Gradle / Ivy

There is a newer version: 1.9.1
Show newest version
package net.jqwik.engine.properties.shrinking;

import java.math.*;
import java.util.*;
import java.util.stream.*;

import net.jqwik.api.*;
import net.jqwik.engine.properties.*;

class BigIntegerGrower {

	Optional> grow(
		BigInteger value,
		Range range,
		BigInteger shrinkingTarget,
		Shrinkable before,
		Shrinkable after
	) {
		Object beforeValue = before.value();
		Object afterValue = after.value();
		BigInteger diff = calculateDiff(beforeValue, afterValue, value);
		if (diff.compareTo(BigInteger.ZERO) != 0) {
			BigInteger grownValue = value.add(diff);
			if (sameSign(shrinkingTarget.subtract(value), shrinkingTarget.subtract(grownValue)) && range.includes(grownValue)) {
				return Optional.of(new ShrinkableBigInteger(grownValue, range, shrinkingTarget));
			}
		}
		return Optional.empty();
	}

	private BigInteger calculateDiff(Object beforeValue, Object afterValue, BigInteger current) {
		BigInteger before;
		BigInteger after;
		if (beforeValue instanceof BigInteger && afterValue instanceof BigInteger) {
			before = (BigInteger) beforeValue;
			after = (BigInteger) afterValue;
		} else {
			before = BigInteger.valueOf(toLong(beforeValue));
			after = BigInteger.valueOf(toLong(afterValue));
		}
		if (sameSign(before, current)) {
			return before.subtract(after);
		} else {
			return after.subtract(before);
		}
	}

	private boolean sameSign(BigInteger first, BigInteger second) {
		return Math.abs(first.signum() - second.signum()) <= 1;
	}

	private long toLong(Object value) {
		return tryNumberTypeCasts(value, Integer.class, Long.class, Short.class, Byte.class);
	}

	private long tryNumberTypeCasts(Object value, Class... targetClasses) {
		return tryNumberTypeCasts(value, new ArrayList<>(Arrays.asList(targetClasses)));
	}

	private long tryNumberTypeCasts(Object value, List> targetClasses) {
		if (targetClasses.isEmpty()) {
			return 0L;
		}
		try {
			Class targetClass = targetClasses.remove(0);
			return ((Number) targetClass.cast(value)).longValue();
		} catch (Throwable cannotCastToTargetClass) {
			return tryNumberTypeCasts(value, targetClasses);
		}
	}

	public Stream> grow(BigInteger value, Range range, BigInteger shrinkingTarget) {
		if (value.compareTo(shrinkingTarget) < 0) {
			return growLeft(value, range, shrinkingTarget);
		} else {
			return growRight(value, range, shrinkingTarget);
		}
	}

	private Stream> growRight(BigInteger value, Range range, BigInteger shrinkingTarget) {
		return Stream
				   .of(
					   range.max,
					   value.add(range.max.subtract(value).divide(BigInteger.valueOf(2))),
					   value.add(BigInteger.TEN),
					   value.add(BigInteger.ONE)
				   )
				   .filter(grownValue -> grownValue.compareTo(value) > 0)
				   .filter(range::includes)
				   .distinct()
				   .map(grown -> new ShrinkableBigInteger(grown, range, shrinkingTarget));
	}

	private Stream> growLeft(BigInteger value, Range range, BigInteger shrinkingTarget) {
		return Stream
				   .of(
					   range.min,
					   value.subtract(value.subtract(range.min).divide(BigInteger.valueOf(2))),
					   value.subtract(BigInteger.TEN),
					   value.subtract(BigInteger.ONE)
				   )
				   .filter(grownValue -> grownValue.compareTo(value) < 0)
				   .filter(range::includes)
				   .distinct()
				   .map(grown -> new ShrinkableBigInteger(grown, range, shrinkingTarget));
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy