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

net.jqwik.engine.properties.arbitraries.RecursiveArbitrary Maven / Gradle / Ivy

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

import java.util.*;
import java.util.function.*;

import net.jqwik.api.*;
import net.jqwik.api.support.*;

import org.jspecify.annotations.*;

public class RecursiveArbitrary implements Arbitrary {
	private final Supplier> base;
	private final Function, ? extends Arbitrary> recur;
	private final int depth;

	// Not used for exhaustive generation
	private final Arbitrary arbitrary;

	private boolean isGeneratorMemoizable = true;

	public RecursiveArbitrary(Supplier> base, Function, ? extends Arbitrary> recur, int depth) {
		this.base = base;
		this.recur = recur;
		this.depth = depth;
		this.arbitrary = iteratedArbitrary();
	}

	@Override
	public RandomGenerator generator(int genSize) {
		return arbitrary.generator(genSize);
	}

	@Override
	public EdgeCases edgeCases(int maxEdgeCases) {
		// Very deep nesting tends to overflow the stack
		if (depth > 100) {
			return EdgeCases.none();
		}
		return arbitrary.edgeCases(maxEdgeCases);
	}

	@Override
	public boolean isGeneratorMemoizable() {
		return isGeneratorMemoizable;
	}

	@Override
	public Optional> exhaustive(long maxNumberOfSamples) {
		// The straightforward implementation can easily overflow:
		// return arbitrary.exhaustive(maxNumberOfSamples);

		Arbitrary current = base.get();
		Optional> last = current.exhaustive(maxNumberOfSamples);
		for (int i = 0; i < depth; i++) {
			if (!last.isPresent()) {
				return Optional.empty();
			}
			current = recur.apply(current);
			last = current.exhaustive(maxNumberOfSamples);
		}
		return last;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;

		RecursiveArbitrary that = (RecursiveArbitrary) o;
		if (depth != that.depth) return false;
		if (!LambdaSupport.areEqual(base, that.base)) return false;
		return LambdaSupport.areEqual(recur, that.recur);
	}

	@Override
	public int hashCode() {
		return HashCodeSupport.hash(base.getClass(), recur.getClass(), depth);
	}

	private Arbitrary iteratedArbitrary() {
		// Real recursion can blow the stack
		Arbitrary current = base.get();
		isGeneratorMemoizable = current.isGeneratorMemoizable();
		for (int i = 0; i < depth; i++) {
			current = recur.apply(current);
			if (!current.isGeneratorMemoizable()) {
				isGeneratorMemoizable = false;
			}
		}
		return current;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy