net.openhft.chronicle.testframework.Product Maven / Gradle / Ivy
package net.openhft.chronicle.testframework;
import net.openhft.chronicle.testframework.internal.ProductUtil;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.function.BiFunction;
import java.util.stream.Stream;
import static java.util.Objects.requireNonNull;
public final class Product {
// Suppresses default constructor, ensuring non-instantiability.
private Product() {
}
/**
* Creates and returns a Stream representing the Cartesian product of the given {@code ts} and {@code us} collections.
*
* This method returns a Stream of {@link Product2} objects, which pairs each element in {@code ts} with each
* element in {@code us}. The order of the product is by {@code T} (most significant factor) and then {@code U}.
*
* The provided collections must not be {@code null}, or a {@code NullPointerException} will be thrown.
*
* Example:
* If {@code ts = ["A", "B"]} and {@code us = [1, 2]}, the method will return a Stream with elements:
* {@code [("A", 1), ("A", 2), ("B", 1), ("B", 2)]}.
*
* @param The element type for the first collection
* @param The element type for the second collection
* @param ts The first collection of elements (non-null)
* @param us The second collection of elements (non-null)
* @return the Cartesian product of the given elements, represented as a Stream of {@link Product2} objects
* @throws NullPointerException if any of the provided collections are {@code null}
*/
public static Stream> of(@NotNull final Collection ts,
@NotNull final Collection us) {
// Ensure that the provided collections are not null
requireNonNull(ts, "The first collection (ts) must not be null");
requireNonNull(us, "The second collection (us) must not be null");
// Utilize a helper method from ProductUtil to generate the Cartesian product and return as a stream
return of(ts, us, ProductUtil.Product2Impl::new);
}
/**
* Creates and returns the cartesian product of the given elements by applying the provided
* {@code constructor} to each tuple (pair of elements).
*
* This method calculates the Cartesian product of two collections, {@code ts} and {@code us},
* by pairing each element in {@code ts} with each element in {@code us} and applying the provided
* {@code constructor} to each pair. The order of the product is determined first by {@code T}
* (most significant factor) and then by {@code U}.
*
* Example:
* If {@code ts = ["A", "B"]} and {@code us = [1, 2]}, and the constructor concatenates the elements,
* the method will return a Stream with elements {@code ["A1", "A2", "B1", "B2"]}.
*
* @param Element type for the first collection
* @param Element type for the second collection
* @param Return type after applying the constructor to each tuple
* @param ts The first collection of elements (non-null)
* @param us The second collection of elements (non-null)
* @param constructor A BiFunction to be applied to all pairs, creating the result type {@code R} (non-null)
* @return A Stream representing the Cartesian product of the given elements after applying the constructor
* @throws NullPointerException if any of the provided parameters are {@code null}
*/
public static Stream of(@NotNull final Collection ts,
@NotNull final Collection us,
@NotNull final BiFunction super T, ? super U, ? extends R> constructor) {
// Ensure that the provided collections and constructor are not null
requireNonNull(ts, "The first collection (ts) must not be null");
requireNonNull(us, "The second collection (us) must not be null");
requireNonNull(constructor, "The constructor function must not be null");
// Utilize a helper method from ProductUtil to generate the Cartesian product and return as a stream
return ProductUtil.of(ts, us, constructor);
}
/**
* Creates and returns the cartesian product of the given elements by applying a default
* Product2 constructor to each tuple.
*
* The cartesian product is the combination of all possible pairs between the first stream {@code ts} and the second stream {@code us}.
* The order of the product is by {@code T} (most significant factor) and then {@code U}.
*
* This method applies a default constructor {@code ProductUtil.Product2Impl::new} to create objects of type {@code Product2}
* representing each tuple in the product.
*
* @param element type for the first factor order
* @param element type for the second factor order
* @param ts the first factor order (non-null)
* @param us the second factor order (non-null)
* @return a Stream of {@code Product2} representing the cartesian product of the given elements
* @throws NullPointerException if any of the provided parameters are {@code null}.
*/
public static Stream> of(@NotNull final Stream ts,
@NotNull final Stream us) {
requireNonNull(ts, "The first stream (ts) must not be null");
requireNonNull(us, "The second stream (us) must not be null");
return of(ts, us, ProductUtil.Product2Impl::new);
}
/**
* Creates and returns the cartesian product of the given elements by applying the provided
* {@code constructor} to each tuple.
*
* Similar to the previous method, this function creates pairs of all possible combinations
* between two streams, {@code ts} and {@code us}, and then applies the provided {@code constructor}
* to each pair to create objects of type {@code R}.
*
* The order of the product is determined first by {@code T} (most significant factor) and then by {@code U}.
* The provided stream {@code ts} is consumed lazily, and the other provided streams are not.
*
* @param Element type for the first stream
* @param Element type for the second stream
* @param Return type after applying the constructor to each tuple
* @param ts The first stream of elements (non-null)
* @param us The second stream of elements (non-null)
* @param constructor A BiFunction to be applied to all pairs, creating the result type {@code R} (non-null)
* @return A Stream representing the Cartesian product of the given elements after applying the constructor
* @throws NullPointerException if any of the provided parameters are {@code null}
*/
public static Stream of(@NotNull final Stream ts,
@NotNull final Stream us,
@NotNull final BiFunction super T, ? super U, ? extends R> constructor) {
requireNonNull(ts, "The first stream (ts) must not be null");
requireNonNull(us, "The second stream (us) must not be null");
requireNonNull(constructor, "The constructor function must not be null");
return ProductUtil.of(ts, us, constructor);
}
/**
* Creates and returns the cartesian product of the given elements by applying a default
* Product3 constructor to each tuple.
*
* The cartesian product is formed by creating all possible combinations of the three
* collections {@code ts}, {@code us}, and {@code vs}, with the order being determined first
* by {@code T} (most significant factor), then by {@code U}, and finally by {@code V}.
*
* The default constructor {@code ProductUtil.Product3Impl::new} is used to create objects of type
* {@code Product3} representing each tuple in the product.
*
* @param element type for the first factor order
* @param element type for the second factor order
* @param element type for the third factor order
* @param ts the first factor order (non-null)
* @param us the second factor order (non-null)
* @param vs the third factor order (non-null)
* @return a Stream of {@code Product3} representing the cartesian product of the given elements
* @throws NullPointerException if any of the provided parameters are {@code null}.
*/
public static Stream> of(@NotNull final Collection ts,
@NotNull final Collection us,
@NotNull final Collection vs) {
requireNonNull(ts, "The first collection (ts) must not be null");
requireNonNull(us, "The second collection (us) must not be null");
requireNonNull(vs, "The third collection (vs) must not be null");
return of(ts, us, vs, ProductUtil.Product3Impl::new);
}
/**
* Creates and returns the cartesian product of the given elements by applying the provided
* {@code constructor} to each tuple.
*
* Similar to the previous method, this function creates all possible combinations between
* the three collections {@code ts}, {@code us}, and {@code vs}, and then applies the provided
* {@code constructor} to each tuple to create objects of type {@code R}.
*
* The order of the product is determined first by {@code T} (most significant factor), then
* by {@code U}, and finally by {@code V}.
*
* @param Element type for the first collection
* @param Element type for the second collection
* @param Element type for the third collection
* @param Return type after applying the constructor to each tuple
* @param ts The first collection of elements (non-null)
* @param us The second collection of elements (non-null)
* @param vs The third collection of elements (non-null)
* @param constructor A TriFunction to be applied to all tuples, creating the result type {@code R} (non-null)
* @return A Stream representing the Cartesian product of the given elements after applying the constructor
* @throws NullPointerException if any of the provided parameters are {@code null}
*/
public static Stream of(@NotNull final Collection ts,
@NotNull final Collection us,
@NotNull final Collection vs,
@NotNull final TriFunction constructor) {
requireNonNull(ts, "The first collection (ts) must not be null");
requireNonNull(us, "The second collection (us) must not be null");
requireNonNull(vs, "The third collection (vs) must not be null");
requireNonNull(constructor, "The constructor function must not be null");
return ProductUtil.of(ts, us, vs, constructor);
}
/**
* Creates and returns the cartesian product of the given elements by applying a default
* Product3 constructor to each tuple.
*
* The order of the product is by T (most significant factor) and then U and then V. The provided stream
* {@code ts} is consumed lazily, and the other provided streams are not, which allows for more efficient
* processing of large or infinite streams.
*
* The default constructor {@code ProductUtil.Product3Impl::new} is used to represent each tuple in the product.
*
* @param element type for the first factor order
* @param element type for the second factor order
* @param element type for the third factor order
* @param ts the first factor order (non-null)
* @param us the second factor order (non-null)
* @param vs the third factor order (non-null)
* @return a Stream of {@code Product3} representing the cartesian product of the given elements
* @throws NullPointerException if any of the provided parameters are {@code null}.
*/
public static Stream> of(@NotNull final Stream ts,
@NotNull final Stream us,
@NotNull final Stream vs) {
requireNonNull(ts, "The first stream (ts) must not be null");
requireNonNull(us, "The second stream (us) must not be null");
requireNonNull(vs, "The third stream (vs) must not be null");
return of(ts, us, vs, ProductUtil.Product3Impl::new);
}
/**
* Creates and returns the cartesian product of the given elements by applying the provided
* {@code constructor} to each tuple.
*
* This function creates all possible combinations between the three streams {@code ts}, {@code us},
* and {@code vs}, and then applies the provided {@code constructor} to each tuple to create objects
* of type {@code R}.
*
* The order of the product is determined first by {@code T} (most significant factor), then
* by {@code U}, and finally by {@code V}. The stream {@code ts} is consumed lazily, while the
* others are not.
*
* @param Element type for the first stream
* @param Element type for the second stream
* @param Element type for the third stream
* @param Return type after applying the constructor to each tuple
* @param ts The first stream of elements (non-null)
* @param us The second stream of elements (non-null)
* @param vs The third stream of elements (non-null)
* @param constructor A TriFunction to be applied to all tuples, creating the result type {@code R} (non-null)
* @return A Stream representing the cartesian product of the given elements after applying the constructor
* @throws NullPointerException if any of the provided parameters are {@code null}
*/
public static Stream of(@NotNull final Stream ts,
@NotNull final Stream us,
@NotNull final Stream vs,
@NotNull final TriFunction constructor) {
requireNonNull(ts, "The first stream (ts) must not be null");
requireNonNull(us, "The second stream (us) must not be null");
requireNonNull(vs, "The third stream (vs) must not be null");
requireNonNull(constructor, "The constructor function must not be null");
return ProductUtil.of(ts, us, vs, constructor);
}
/**
* Function interface representing a function that accepts three arguments and produces a result.
*
* @param Type of the first argument
* @param Type of the second argument
* @param Type of the third argument
* @param Type of the result
*/
@FunctionalInterface
public interface TriFunction {
/**
* Applies this function to the given arguments, creating a result of type {@code R}.
*
* This functional interface is used to apply custom behavior to tuples within the cartesian
* product, allowing for flexible creation of objects to represent those tuples.
*
* @param t the first function argument
* @param u the second function argument
* @param v the third function argument
* @return the function result, which can be of any type {@code R}
*/
R apply(T t, U u, V v);
}
/**
* An interface representing an object that has a first component.
* This can be used to add functionality to objects that are made up of multiple components.
*
* @param The type of the first component.
*/
public interface HasFirst {
/**
* Returns the first component of the object.
* This method should be implemented to return the first component of the multi-component object.
*
* @return The first component of the object.
*/
T first();
}
/**
* An interface representing an object that has a second component.
* This can be used to add functionality to objects that are made up of multiple components.
*
* @param The type of the second component.
*/
public interface HasSecond {
/**
* Returns the second component of the object.
* This method should be implemented to return the second component of the multi-component object.
*
* @return The second component of the object.
*/
U second();
}
/**
* Interface representing an object that has a third component of type {@code V}.
* This can be used to add functionality to objects that are made up of three components.
*
* @param Type of the third component
*/
public interface HasThird {
/**
* Returns the third component of the object.
* This method should be implemented to return the third component of the multi-component object.
*
* @return The third component of the object.
*/
V third();
}
/**
* A Product2 is a composite object comprising two components.
* It's a part of a tuple-like structure with two elements, extending the HasFirst and HasSecond interfaces.
* This provides a way to group two related objects together into a single unit.
*
* @param Type of the first component
* @param Type of the second component
*/
public interface Product2 extends HasFirst, HasSecond {
// Interface doesn't have any additional methods or fields, but inherits those from HasFirst and HasSecond.
}
/**
* A Product3 is a composite object comprising three components.
* It's a part of a tuple-like structure with three elements, extending the HasFirst, HasSecond, and HasThird interfaces.
* This provides a way to group three related objects together into a single unit.
*
* @param Type of the first component
* @param Type of the second component
* @param Type of the third component
*/
public interface Product3 extends HasFirst, HasSecond, HasThird {
// Interface doesn't have any additional methods or fields, but inherits those from HasFirst, HasSecond, and HasThird.
}
}