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

com.autonomouslogic.commons.rxjava3.internal.OrderedMerger Maven / Gradle / Ivy

There is a newer version: 1.9.2
Show newest version
package com.autonomouslogic.commons.rxjava3.internal;

import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.Emitter;
import io.reactivex.rxjava3.core.Flowable;
import io.reactivex.rxjava3.functions.BiFunction;
import io.reactivex.rxjava3.schedulers.Schedulers;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import lombok.Value;
import org.reactivestreams.Publisher;

/**
 * Implementation for the sorted merge operation.
 * The current implementation naively blocks on an IO thread.
 * This is far from ideal and commits are welcome.
 * @param 
 */
@RequiredArgsConstructor
public class OrderedMerger {
	@NonNull
	private final Comparator comparator;

	@NonNull
	private final Publisher[] sources;

	public Publisher createPublisher() {
		if (sources.length == 0) {
			return Flowable.empty();
		}
		return Flowable.generate(
						() -> new MergeState<>(comparator, sources),
						(BiFunction, Emitter, MergeState>) (state, emitter) -> {
							state.next(emitter);
							return state;
						},
						mergeState -> mergeState.dispose())
				.subscribeOn(Schedulers.io())
				.observeOn(Schedulers.computation());
	}

	private static class MergeState

{ private final int n; private final Comparator

comparator; private final Iterator

[] iterators; private final Object[] current; private final List entries; private final Comparator entryComparator; @SuppressWarnings("unchecked") MergeState(Comparator

comparator, Publisher

[] sources) { this.comparator = comparator; n = sources.length; iterators = new Iterator[n]; entries = new ArrayList<>(n); current = new Object[n]; for (int i = 0; i < n; i++) { iterators[i] = Flowable.fromPublisher(sources[i]).blockingIterable().iterator(); } entryComparator = Comparator.comparing(entry -> (P) entry.getObj(), comparator); fill(); } private void fill() { var changed = false; for (int i = 0; i < n; i++) { if (current[i] == null && iterators[i].hasNext()) { current[i] = iterators[i].next(); entries.add(new Entry(i, current[i])); changed = true; } } if (changed) { entries.sort(entryComparator); } } @SuppressWarnings("unchecked") private P remove(int i) { var obj = current[i]; current[i] = null; entries.remove(new Entry(i, null)); return (P) obj; } private int nextIndex() { fill(); if (entries.isEmpty()) { return -1; } return entries.get(0).getIndex(); } protected void next(Emitter

emitter) { var i = nextIndex(); if (i == -1) { emitter.onComplete(); } else { emitter.onNext(remove(i)); } } protected void dispose() { // @todo not implemented } } @Value @EqualsAndHashCode(onlyExplicitlyIncluded = true) @ToString private static class Entry { @EqualsAndHashCode.Include int index; Object obj; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy