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

com.regnosys.rosetta.common.util.StreamUtils Maven / Gradle / Ivy

Go to download

Rune Common is a java library that is utilised by Rosetta Code Generators and models expressed in the Rosetta DSL.

There is a newer version: 11.27.1
Show newest version
package com.regnosys.rosetta.common.util;

/*-
 * ==============
 * Rune Common
 * ==============
 * Copyright (C) 2018 - 2024 REGnosys
 * ==============
 * Licensed 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.
 * ==============
 */

import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import java.util.stream.Collector;
import java.util.stream.Collector.Characteristics;
import java.util.stream.Stream;

public class StreamUtils {
	public static  Function> flattenTreeC(Function> extract) {
		Function> streamExtract = extract.andThen(as -> as.stream());
		return flattenTree(streamExtract, new HashSet<>());
	}

	public static  Function> flattenTree(Function> extract) {
		return flattenTree(extract, new HashSet<>());
	}

	public static  Stream flattenTreeC(A initial, Function> extract) {
		return Stream.of(initial).flatMap(flattenTreeC(extract));
	}

	public static  Stream flattenTree(A initial, Function> extract) {
		return Stream.of(initial).flatMap(flattenTree(extract));
	}

	public static  Function> flattenTree(Function> extract, Collection visited) {
		return a -> {
			if (visited.contains(a))
				return Stream.empty();
			visited.add(a);
			return Stream.concat(Stream.of(a), extract.apply(a).flatMap(flattenTree(extract, visited)));
		};
	}

	public static  void visitTreeC(A initial, Consumer visitFunc, Function> traverseFunc) {
		Deque toVisit = new ArrayDeque<>();
		Set visited = new HashSet<>();
		toVisit.add(initial);
		while (!toVisit.isEmpty()) {
			A a = toVisit.removeFirst();
			if (visited.contains(a))
				continue;
			visitFunc.accept(a);
			Collection nexts = traverseFunc.apply(a);
			toVisit.addAll(nexts);
			visited.add(a);
		}
	}

	public static  void visitBiTree(A initial, Consumer visitFunction, Function> traverseFunc1,
			Function> traverseFunc2) {
		Deque toVisit = new ArrayDeque<>();
		Set visited = new HashSet<>();
		toVisit.add(initial);
		while (!toVisit.isEmpty()) {
			A a = toVisit.removeFirst();
			if (visited.contains(a))
				continue;
			visitFunction.accept(a);
			Collection nexts = traverseFunc1.apply(a);
			toVisit.addAll(nexts);
			nexts = traverseFunc2.apply(a);
			toVisit.addAll(nexts);
			visited.add(a);
		}
	}

	public static  void visitTreeS(A initial, Consumer visitFunc, Function> traversFunc) {
		Deque toVisit = new ArrayDeque<>();
		Set visited = new HashSet<>();
		toVisit.add(initial);
		while (!toVisit.isEmpty()) {
			A a = toVisit.removeFirst();
			if (visited.contains(a))
				continue;
			visited.add(a);
			visitFunc.accept(a);
			traversFunc.apply(a).forEach(toVisit::add);
		}
	}

	public static  Stream recurse(A a, Function func) {
		return recurse(a, func, new HashSet<>());
	}

	public static  Stream recurse(A a, Function func, Collection visited) {
		if (a == null)
			return Stream.empty();
		if (visited.contains(a))
			return Stream.empty();
		visited.add(a);
		return Stream.concat(Stream.of(a), recurse(func.apply(a), func, visited));
	}

	public static  Stream optionalStream(Collection c) {
		if (c == null)
			return Stream.empty();
		return c.stream();
	}

	public static  Predicate distinctByKey(Function ke) {
		Map seen = new ConcurrentHashMap<>();
		return t -> seen.putIfAbsent(ke.apply(t), Boolean.TRUE) == null;
	}

	public static  UnaryOperator peek(Consumer c) {
		return x -> {
			c.accept(x);
			return x;
		};
	}

	public  Collector, Optional> only() {
		return only(
				(s) -> new IllegalStateException("Expected only one result from collector but got " + s.toString()));
	}

	public static  Collector, Optional> only(Function, RuntimeException> exceptionSupplier) {
		return Collector.of(HashSet::new, Set::add, (a, b) -> {
			a.addAll(b);
			return a;
		}, (s) -> {
			if (s.size() > 1)
				throw exceptionSupplier.apply(s);
			else if (s.size() == 0)
				return Optional.empty();
			else {
				return Optional.of(s.iterator().next());
			}
		}, Characteristics.CONCURRENT, Characteristics.UNORDERED);
	}

	public static  Function> instancesOf(Class clazz) {
		return o -> clazz.isInstance(o) ? Stream.of(clazz.cast(o)) : Stream.empty();
	}

	public static  Stream instancesOf(Stream stream, Class clazz) {
		return stream.filter(clazz::isInstance).map(clazz::cast);
	}
}